File indexing completed on 2025-02-02 04:11:03
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 "animatable_path.hpp" 0008 0009 #include "command/undo_macro_guard.hpp" 0010 #include "command/animation_commands.hpp" 0011 0012 using namespace glaxnimate; 0013 0014 void glaxnimate::model::detail::AnimatedPropertyBezier::set_closed(bool closed) 0015 { 0016 value_.set_closed(closed); 0017 for ( auto& keyframe : keyframes_ ) 0018 { 0019 auto v = keyframe->get(); 0020 v.set_closed(closed); 0021 keyframe->set(v); 0022 } 0023 value_changed(); 0024 emitter(object(), value_); 0025 } 0026 0027 0028 void glaxnimate::model::detail::AnimatedPropertyBezier::split_segment(int index, qreal factor) 0029 { 0030 command::UndoMacroGuard guard(i18n("Split Segment"), object()->document()); 0031 0032 QVariant before = QVariant::fromValue(value_); 0033 auto bez = value_; 0034 0035 bool set = true; 0036 for ( const auto& kf : keyframes_ ) 0037 { 0038 auto bez = kf->get(); 0039 bez.split_segment(index, factor); 0040 if ( !mismatched_ && kf->time() == time() ) 0041 set = false; 0042 object()->push_command(new command::SetKeyframe(this, kf->time(), QVariant::fromValue(bez), true)); 0043 } 0044 0045 if ( set ) 0046 { 0047 bez.split_segment(index, factor); 0048 QVariant after = QVariant::fromValue(bez); 0049 object()->push_command(new command::SetMultipleAnimated("", {this}, {before}, {after}, true)); 0050 } 0051 } 0052 0053 void glaxnimate::model::detail::AnimatedPropertyBezier::remove_point(int index) 0054 { 0055 remove_points({index}); 0056 } 0057 0058 void glaxnimate::model::detail::AnimatedPropertyBezier::remove_points(const std::set<int>& indices) 0059 { 0060 command::UndoMacroGuard guard(i18n("Remove Nodes"), object()->document()); 0061 0062 QVariant before = QVariant::fromValue(value_); 0063 auto bez = value_; 0064 0065 bool set = true; 0066 for ( const auto& kf : keyframes_ ) 0067 { 0068 auto bez = kf->get().removed_points(indices); 0069 if ( !mismatched_ && kf->time() == time() ) 0070 set = false; 0071 object()->push_command(new command::SetKeyframe(this, kf->time(), QVariant::fromValue(bez), true)); 0072 } 0073 0074 if ( set ) 0075 { 0076 bez = bez.removed_points(indices); 0077 object()->push_command(new command::SetMultipleAnimated(this, QVariant::fromValue(bez), true)); 0078 } 0079 } 0080 0081 static QVariant extend_impl(math::bezier::Bezier subject, const math::bezier::Bezier& target, bool at_end) 0082 { 0083 if ( target.closed() ) 0084 { 0085 subject.set_closed(true); 0086 0087 if ( !subject.empty() ) 0088 { 0089 if ( at_end ) 0090 subject[0].type = math::bezier::Corner; 0091 else 0092 subject.back().type = math::bezier::Corner; 0093 0094 if ( !target.empty() ) 0095 { 0096 subject[0].tan_in = target[0].tan_in; 0097 subject.back().tan_out = target.back().tan_out; 0098 } 0099 } 0100 } 0101 0102 if ( subject.size() < target.size() ) 0103 { 0104 if ( at_end ) 0105 { 0106 if ( !subject.empty() ) 0107 { 0108 subject.back().type = math::bezier::Corner; 0109 subject.back().tan_out = target.back().tan_out; 0110 } 0111 0112 subject.points().insert( 0113 subject.points().end(), 0114 target.points().begin() + subject.size(), 0115 target.points().end() 0116 ); 0117 } 0118 else 0119 { 0120 if ( !subject.empty() ) 0121 { 0122 subject[0].type = math::bezier::Corner; 0123 subject[0].tan_in = target[0].tan_in; 0124 } 0125 0126 subject.points().insert( 0127 subject.points().begin(), 0128 target.points().begin(), 0129 target.points().begin() + target.size() - subject.size() 0130 ); 0131 } 0132 } 0133 0134 return QVariant::fromValue(subject); 0135 } 0136 0137 void glaxnimate::model::detail::AnimatedPropertyBezier::extend(const math::bezier::Bezier& target, bool at_end) 0138 { 0139 command::UndoMacroGuard guard(i18n("Extend Shape"), object()->document()); 0140 0141 auto bez = value_; 0142 0143 bool set = true; 0144 0145 for ( auto& kf : keyframes_ ) 0146 { 0147 if ( !mismatched_ && kf->time() == time() ) 0148 set = false; 0149 object()->push_command( 0150 new command::SetKeyframe(this, kf->time(), extend_impl(kf->get(), target, at_end), true) 0151 ); 0152 } 0153 0154 if ( set ) 0155 { 0156 QVariant before = QVariant::fromValue(bez); 0157 QVariant after = extend_impl(bez, target, at_end); 0158 object()->push_command(new command::SetMultipleAnimated("", {this}, {before}, {after}, true)); 0159 } 0160 }