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 }