File indexing completed on 2025-03-02 04:03:53

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 "object.hpp"
0008 
0009 #include <unordered_map>
0010 
0011 #include "property/property.hpp"
0012 #include "model/document.hpp"
0013 #include "app/log/log.hpp"
0014 
0015 
0016 class glaxnimate::model::Object::Private
0017 {
0018 public:
0019     std::unordered_map<QString, BaseProperty*> props;
0020     std::vector<BaseProperty*> prop_order;
0021     Document* document;
0022     FrameTime current_time = 0;
0023 };
0024 
0025 
0026 glaxnimate::model::Object::Object(Document* document)
0027     : d(std::make_unique<glaxnimate::model::Object::Private>())
0028 {
0029     d->document = document;
0030     if ( document && thread() != document->thread() )
0031         moveToThread(document->thread());
0032 }
0033 
0034 glaxnimate::model::Object::~Object() = default;
0035 
0036 void glaxnimate::model::Object::assign_from(const glaxnimate::model::Object* other)
0037 {
0038     other->clone_into(this);
0039 }
0040 
0041 void glaxnimate::model::Object::transfer(glaxnimate::model::Document* document)
0042 {
0043     if ( thread() != document->thread() )
0044         moveToThread(document->thread());
0045 
0046     on_transfer(document);
0047     d->document = document;
0048     for ( auto prop: d->prop_order )
0049         prop->transfer(document);
0050 }
0051 
0052 
0053 void glaxnimate::model::Object::clone_into(glaxnimate::model::Object* dest) const
0054 {
0055     if ( dest->metaObject() != metaObject() )
0056     {
0057         app::log::Log log("Object", type_name());
0058         log.stream(app::log::Error) << "trying to clone into" << dest->type_name() << "from" << type_name();
0059         log.stream(app::log::Info) << "make sure clone_covariant is implemented for" << type_name() << "or use GLAXNIMATE_OBJECT";
0060         return;
0061     }
0062 
0063     for ( BaseProperty* prop : d->prop_order )
0064         dest->get_property(prop->name())->assign_from(prop);
0065 }
0066 
0067 
0068 void glaxnimate::model::Object::property_value_changed(const BaseProperty* prop, const QVariant& value)
0069 {
0070     on_property_changed(prop, value);
0071     Q_EMIT property_changed(prop, value);
0072     if ( prop->traits().flags & PropertyTraits::Visual )
0073     {
0074         d->document->graphics_invalidated();
0075         Q_EMIT visual_property_changed(prop, value);
0076     }
0077 }
0078 
0079 void glaxnimate::model::Object::add_property(glaxnimate::model::BaseProperty* prop)
0080 {
0081     d->props[prop->name()] = prop;
0082     d->prop_order.push_back(prop);
0083 }
0084 
0085 QVariant glaxnimate::model::Object::get(const QString& property) const
0086 {
0087     auto it = d->props.find(property);
0088     if ( it == d->props.end() )
0089          return QVariant{};
0090     return it->second->value();
0091 }
0092 
0093 glaxnimate::model::BaseProperty * glaxnimate::model::Object::get_property ( const QString& property )
0094 {
0095     auto it = d->props.find(property);
0096     if ( it == d->props.end() )
0097         return nullptr;
0098     return it->second;
0099 }
0100 
0101 bool glaxnimate::model::Object::set(const QString& property, const QVariant& value)
0102 {
0103     auto it = d->props.find(property);
0104     if ( it == d->props.end() )
0105         return false;
0106 
0107     return it->second->set_value(value);
0108 }
0109 
0110 bool glaxnimate::model::Object::has ( const QString& property ) const
0111 {
0112     return d->props.find(property) != d->props.end();
0113 }
0114 
0115 
0116 const std::vector<glaxnimate::model::BaseProperty*>& glaxnimate::model::Object::properties() const
0117 {
0118     return d->prop_order;
0119 }
0120 
0121 QString glaxnimate::model::Object::type_name() const
0122 {
0123     return detail::naked_type_name(metaObject()->className());
0124 }
0125 
0126 QString glaxnimate::model::detail::naked_type_name(QString class_name)
0127 {
0128     int ns = class_name.lastIndexOf(":");
0129     if ( ns != -1 )
0130         class_name = class_name.mid(ns+1);
0131     return class_name;
0132 }
0133 
0134 glaxnimate::model::Document * glaxnimate::model::Object::document() const
0135 {
0136     return d->document;
0137 }
0138 
0139 void glaxnimate::model::Object::push_command(QUndoCommand* cmd)
0140 {
0141     d->document->push_command(cmd);
0142 }
0143 
0144 
0145 bool glaxnimate::model::Object::set_undoable ( const QString& property, const QVariant& value )
0146 {
0147 
0148     auto it = d->props.find(property);
0149     if ( it != d->props.end() )
0150         return it->second->set_undoable(value);
0151     return false;
0152 }
0153 
0154 void glaxnimate::model::Object::set_time(glaxnimate::model::FrameTime t)
0155 {
0156     d->current_time = t;
0157     for ( auto prop: d->prop_order )
0158         prop->set_time(t);
0159 }
0160 
0161 glaxnimate::model::FrameTime glaxnimate::model::Object::time() const
0162 {
0163     return d->current_time;
0164 }
0165 
0166 void glaxnimate::model::Object::stretch_time(qreal multiplier)
0167 {
0168     for ( const auto& prop : d->prop_order )
0169         prop->stretch_time(multiplier);
0170 
0171     d->current_time *= multiplier;
0172 }