Warning, file /graphics/glaxnimate/src/core/model/document_node.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best> 0003 * 0004 * SPDX-License-Identifier: GPL-3.0-or-later 0005 */ 0006 0007 #include "document_node.hpp" 0008 #include "document.hpp" 0009 0010 #include <QPainter> 0011 #include <QGraphicsItem> 0012 0013 #include "model/shapes/shape.hpp" 0014 #include "model/property/reference_property.hpp" 0015 #include "model/property/sub_object_property.hpp" 0016 #include "utils/pseudo_mutex.hpp" 0017 0018 class glaxnimate::model::DocumentNode::Private 0019 { 0020 public: 0021 std::unordered_set<User*> users; 0022 utils::PseudoMutex detaching; 0023 DocumentNode* list_parent = nullptr; 0024 }; 0025 0026 glaxnimate::model::DocumentNode::DocumentNode(glaxnimate::model::Document* document) 0027 : DocumentNode(document, std::make_unique<Private>()) 0028 { 0029 } 0030 0031 glaxnimate::model::DocumentNode::DocumentNode(glaxnimate::model::Document* document, std::unique_ptr<Private> d) 0032 : Object ( document ), d(std::move(d)) 0033 { 0034 uuid.set_value(QUuid::createUuid()); 0035 } 0036 0037 0038 glaxnimate::model::DocumentNode::~DocumentNode() = default; 0039 0040 void glaxnimate::model::DocumentNode::removed_from_list() 0041 { 0042 auto old = d->list_parent; 0043 d->list_parent = nullptr; 0044 document()->decrease_node_name(name.get()); 0045 on_parent_changed(old, d->list_parent); 0046 Q_EMIT removed(); 0047 } 0048 0049 void glaxnimate::model::DocumentNode::added_to_list ( glaxnimate::model::DocumentNode* new_parent ) 0050 { 0051 auto old = d->list_parent; 0052 d->list_parent = new_parent; 0053 document()->increase_node_name(name.get()); 0054 on_parent_changed(old, d->list_parent); 0055 } 0056 0057 void glaxnimate::model::DocumentNode::on_name_changed(const QString& name, const QString& old_name) 0058 { 0059 if ( old_name != name ) 0060 { 0061 document()->decrease_node_name(old_name); 0062 document()->increase_node_name(name); 0063 Q_EMIT name_changed(name); 0064 } 0065 } 0066 0067 glaxnimate::model::DocumentNode * glaxnimate::model::DocumentNode::docnode_parent() const 0068 { 0069 return d->list_parent; 0070 } 0071 0072 bool glaxnimate::model::DocumentNode::docnode_is_instance(const QString& type_name) const 0073 { 0074 if ( type_name.isEmpty() ) 0075 return true; 0076 0077 for ( const QMetaObject* meta = metaObject(); meta; meta = meta->superClass() ) 0078 { 0079 if ( detail::naked_type_name(meta->className()) == type_name ) 0080 return true; 0081 } 0082 0083 return false; 0084 } 0085 0086 void glaxnimate::model::DocumentNode::recursive_rename() 0087 { 0088 document()->set_best_name(this, name.get()); 0089 for ( auto child : docnode_children() ) 0090 child->recursive_rename(); 0091 } 0092 0093 0094 void glaxnimate::model::DocumentNode::refresh_uuid() 0095 { 0096 uuid.set_value(QUuid::createUuid()); 0097 for ( auto prop : properties() ) 0098 { 0099 if ( prop->traits().type == PropertyTraits::Object ) 0100 { 0101 if ( prop->traits().flags & PropertyTraits::List ) 0102 { 0103 for ( auto v : prop->value().toList() ) 0104 { 0105 if ( auto obj = v.value<glaxnimate::model::DocumentNode*>() ) 0106 obj->refresh_uuid(); 0107 } 0108 } 0109 else 0110 { 0111 if ( auto obj = qobject_cast<DocumentNode*>(static_cast<glaxnimate::model::SubObjectPropertyBase*>(prop)->sub_object()) ) 0112 obj->refresh_uuid(); 0113 } 0114 } 0115 } 0116 } 0117 0118 QString glaxnimate::model::DocumentNode::object_name() const 0119 { 0120 if ( name.get().isEmpty() ) 0121 return type_name_human(); 0122 return name.get(); 0123 } 0124 0125 void glaxnimate::model::DocumentNode::add_user(glaxnimate::model::DocumentNode::User* user) 0126 { 0127 if ( !d->detaching ) 0128 { 0129 d->users.insert(user); 0130 Q_EMIT users_changed(); 0131 } 0132 } 0133 0134 void glaxnimate::model::DocumentNode::remove_user(glaxnimate::model::DocumentNode::User* user) 0135 { 0136 if ( !d->detaching ) 0137 { 0138 d->users.erase(user); 0139 Q_EMIT users_changed(); 0140 } 0141 } 0142 0143 const std::unordered_set<glaxnimate::model::DocumentNode::User*> & glaxnimate::model::DocumentNode::users() const 0144 { 0145 return d->users; 0146 } 0147 0148 void glaxnimate::model::DocumentNode::attach() 0149 { 0150 if ( auto lock = d->detaching.get_lock() ) 0151 { 0152 for ( auto user : d->users ) 0153 user->set_ref(this); 0154 } 0155 } 0156 0157 void glaxnimate::model::DocumentNode::detach() 0158 { 0159 if ( auto lock = d->detaching.get_lock() ) 0160 { 0161 for ( auto user : d->users ) 0162 user->set_ref(nullptr); 0163 } 0164 } 0165 0166 bool glaxnimate::model::DocumentNode::is_descendant_of(const model::DocumentNode* other) const 0167 { 0168 if ( !other ) 0169 return false; 0170 0171 if ( other == this ) 0172 return true; 0173 0174 auto parent = docnode_parent(); 0175 if ( parent ) 0176 return parent->is_descendant_of(other); 0177 0178 return false; 0179 } 0180 0181 0182 class glaxnimate::model::VisualNode::Private : public DocumentNode::Private 0183 { 0184 public: 0185 std::unique_ptr<QPixmap> group_icon; 0186 }; 0187 0188 glaxnimate::model::VisualNode::VisualNode(model::Document* document) 0189 : DocumentNode(document, std::make_unique<Private>()) 0190 { 0191 } 0192 0193 glaxnimate::model::VisualNode::Private * glaxnimate::model::VisualNode::dd() const 0194 { 0195 return static_cast<Private*>(d.get()); 0196 } 0197 0198 glaxnimate::model::VisualNode* glaxnimate::model::VisualNode::docnode_group_parent() const 0199 { 0200 return nullptr; 0201 } 0202 int glaxnimate::model::VisualNode::docnode_group_child_count() const 0203 { 0204 return 0; 0205 } 0206 glaxnimate::model::VisualNode* glaxnimate::model::VisualNode::docnode_group_child(int) const 0207 { 0208 return nullptr; 0209 } 0210 glaxnimate::model::VisualNode* glaxnimate::model::VisualNode::docnode_fuzzy_parent() const 0211 { 0212 if ( auto p = docnode_group_parent() ) 0213 return p; 0214 return docnode_visual_parent(); 0215 } 0216 0217 QColor glaxnimate::model::VisualNode::docnode_group_color() const 0218 { 0219 if ( !docnode_valid_color() ) 0220 { 0221 if ( auto parent = docnode_fuzzy_parent() ) 0222 return parent->docnode_group_color(); 0223 0224 return Qt::transparent; 0225 } 0226 return group_color.get(); 0227 } 0228 0229 glaxnimate::model::VisualNode* glaxnimate::model::VisualNode::docnode_visual_child(int index) const 0230 { 0231 return static_cast<glaxnimate::model::VisualNode*>(docnode_child(index)); 0232 } 0233 0234 glaxnimate::model::VisualNode* glaxnimate::model::VisualNode::docnode_visual_parent() const 0235 { 0236 auto p = docnode_parent(); 0237 if ( p ) 0238 return p->cast<glaxnimate::model::VisualNode>(); 0239 return nullptr; 0240 } 0241 0242 void glaxnimate::model::VisualNode::on_group_color_changed(const QColor&) 0243 { 0244 if ( dd()->group_icon && !dd()->group_icon->isNull() ) 0245 { 0246 if ( docnode_valid_color() ) 0247 dd()->group_icon->fill(group_color.get()); 0248 else 0249 dd()->group_icon->fill(Qt::white); 0250 } 0251 docnode_on_update_group(true); 0252 } 0253 0254 0255 void glaxnimate::model::VisualNode::docnode_on_update_group(bool) 0256 { 0257 // if ( force || docnode_valid_color() ) 0258 { 0259 Q_EMIT docnode_group_color_changed(docnode_group_color()); 0260 for ( auto gc : docnode_group_children() ) 0261 gc->docnode_on_update_group(); 0262 for ( auto gc : docnode_visual_children() ) 0263 gc->docnode_on_update_group(); 0264 } 0265 0266 Q_EMIT group_transform_matrix_changed(group_transform_matrix(time())); 0267 } 0268 0269 bool glaxnimate::model::VisualNode::docnode_valid_color() const 0270 { 0271 QColor col = group_color.get(); 0272 return col.isValid() && col.alpha() > 0; 0273 } 0274 0275 QIcon glaxnimate::model::VisualNode::instance_icon() const 0276 { 0277 if ( !docnode_valid_color() ) 0278 { 0279 if ( auto parent = docnode_fuzzy_parent() ) 0280 return parent->instance_icon(); 0281 } 0282 0283 if ( !dd()->group_icon ) 0284 { 0285 dd()->group_icon = std::make_unique<QPixmap>(33, 33); 0286 dd()->group_icon->fill(docnode_group_color()); 0287 } 0288 0289 return *dd()->group_icon; 0290 } 0291 0292 bool glaxnimate::model::VisualNode::docnode_locked_recursive() const 0293 { 0294 for ( const VisualNode* n = this; n; n = n->docnode_visual_parent() ) 0295 { 0296 if ( n->locked.get() ) 0297 return true; 0298 } 0299 0300 return false; 0301 } 0302 0303 void glaxnimate::model::VisualNode::paint(QPainter* painter, FrameTime time, PaintMode mode, glaxnimate::model::Modifier* modifier) const 0304 { 0305 if ( !visible.get() ) 0306 return; 0307 0308 painter->save(); 0309 painter->setTransform(group_transform_matrix(time), true); 0310 0311 on_paint(painter, time, mode, modifier); 0312 for ( auto c : docnode_visual_children() ) 0313 { 0314 c->paint(painter, time, mode, modifier); 0315 if ( c->is_instance<glaxnimate::model::Modifier>() && c->visible.get() ) 0316 break; 0317 } 0318 painter->restore(); 0319 } 0320 0321 bool glaxnimate::model::VisualNode::docnode_selectable() const 0322 { 0323 if ( !visible.get() || locked.get() ) 0324 return false; 0325 if ( auto p = docnode_visual_parent() ) 0326 return p->docnode_selectable(); 0327 return true; 0328 } 0329 0330 bool glaxnimate::model::VisualNode::docnode_visible_recursive() const 0331 { 0332 if ( !visible.get() ) 0333 return false; 0334 if ( auto p = docnode_visual_parent() ) 0335 return p->docnode_visible_recursive(); 0336 return true; 0337 } 0338 0339 QTransform glaxnimate::model::VisualNode::transform_matrix(glaxnimate::model::FrameTime t) const 0340 { 0341 auto matrix = local_transform_matrix(t); 0342 0343 glaxnimate::model::VisualNode* parent = docnode_visual_parent(); 0344 if ( parent ) 0345 matrix *= parent->transform_matrix(t); 0346 0347 parent = docnode_group_parent(); 0348 if ( parent ) 0349 matrix *= parent->transform_matrix(t); 0350 0351 return matrix; 0352 } 0353 0354 QTransform glaxnimate::model::VisualNode::group_transform_matrix(glaxnimate::model::FrameTime t) const 0355 { 0356 auto parent = docnode_group_parent(); 0357 if ( parent ) 0358 return local_transform_matrix(t) * parent->transform_matrix(t); 0359 return local_transform_matrix(t); 0360 } 0361 0362 void glaxnimate::model::VisualNode::on_visible_changed(bool visible) 0363 { 0364 Q_EMIT docnode_visible_changed(visible); 0365 Q_EMIT docnode_visible_recursive_changed(visible); 0366 0367 for ( auto ch : docnode_visual_children() ) 0368 ch->propagate_visible(visible); 0369 } 0370 0371 void glaxnimate::model::VisualNode::propagate_visible(bool visible) 0372 { 0373 if ( !this->visible.get() ) 0374 return; 0375 Q_EMIT docnode_visible_recursive_changed(visible); 0376 for ( auto ch : docnode_visual_children() ) 0377 ch->propagate_visible(visible && this->visible.get()); 0378 } 0379 0380 void glaxnimate::model::VisualNode::propagate_transform_matrix_changed(const QTransform& t_global, const QTransform& t_group) 0381 { 0382 Q_EMIT transform_matrix_changed(t_global); 0383 Q_EMIT group_transform_matrix_changed(t_group); 0384 0385 for ( auto ch : docnode_group_children() ) 0386 { 0387 auto ltm = ch->local_transform_matrix(ch->time()); 0388 ch->propagate_transform_matrix_changed(ltm * t_global, ltm * t_group); 0389 } 0390 0391 for ( auto ch : docnode_visual_children() ) 0392 { 0393 auto ltm = ch->local_transform_matrix(ch->time()); 0394 ch->propagate_transform_matrix_changed(ltm * t_global, ltm); 0395 } 0396 } 0397 0398 void glaxnimate::model::VisualNode::propagate_bounding_rect_changed() 0399 { 0400 on_graphics_changed(); 0401 Q_EMIT bounding_rect_changed(); 0402 if ( auto parent = docnode_visual_parent() ) 0403 parent->propagate_bounding_rect_changed(); 0404 0405 }