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 }