From 20e89d9a399f110a44b9d641723c17e0fc164a17 Mon Sep 17 00:00:00 2001 From: Nikita Kitaev Date: Sun, 5 Sep 2010 03:07:24 -0700 Subject: [PATCH] Move reverse manipulation code into ValueDescSet action Allows for changing ValueNodes previously manipulatable only via ducks. --- synfig-core/src/synfig/valuenode_range.cpp | 8 +- synfig-core/src/synfig/valuenode_scale.cpp | 2 +- synfig-studio/src/gui/duckmatic.cpp | 125 ---------- .../src/synfigapp/actions/valuedescset.cpp | 263 +++++++++++++++++++++ 4 files changed, 267 insertions(+), 131 deletions(-) diff --git a/synfig-core/src/synfig/valuenode_range.cpp b/synfig-core/src/synfig/valuenode_range.cpp index 2714d4e..4c62b02 100644 --- a/synfig-core/src/synfig/valuenode_range.cpp +++ b/synfig-core/src/synfig/valuenode_range.cpp @@ -202,11 +202,9 @@ synfig::ValueNode_Range::get_inverse(Time t, const synfig::Angle &target_value) switch (get_type()) { default: - // Notice that target_value is the rotation between the current - // 'link' value and the target angle in the canvas, so we need - // to add it to 'link' - if(Angle::rad(maximum).get()>=Angle::rad(link+target_value).get() && Angle::rad(link+target_value).get()>=Angle::rad(minimum).get()) - return link + target_value; + + if(Angle::rad(maximum).get()>=Angle::rad(target_value).get() && Angle::rad(target_value).get()>=Angle::rad(minimum).get()) + return target_value; else if (Angle::rad(minimum).get()>Angle::rad(target_value).get()) return minimum; else diff --git a/synfig-core/src/synfig/valuenode_scale.cpp b/synfig-core/src/synfig/valuenode_scale.cpp index b272d7d..4cfbb92 100644 --- a/synfig-core/src/synfig/valuenode_scale.cpp +++ b/synfig-core/src/synfig/valuenode_scale.cpp @@ -173,7 +173,7 @@ synfig::ValueNode_Scale::get_inverse(Time t, const synfig::Angle &target_value) switch (get_type()) { default: - return (*value_node)(t).get(Angle()) + target_value / scalar_value; + return target_value / scalar_value; } } return ValueBase(); diff --git a/synfig-studio/src/gui/duckmatic.cpp b/synfig-studio/src/gui/duckmatic.cpp index fe2d6a3..7fe1f19 100644 --- a/synfig-studio/src/gui/duckmatic.cpp +++ b/synfig-studio/src/gui/duckmatic.cpp @@ -716,104 +716,6 @@ Duckmatic::signal_edited_selected_ducks() bool Duckmatic::on_duck_changed(const synfig::Point &value,const synfigapp::ValueDesc& value_desc) { - if (ValueNode_BLineCalcWidth::Handle bline_width = ValueNode_BLineCalcWidth::Handle::cast_dynamic(value_desc.get_value_node())) - { - Real old_width((*bline_width)(get_time()).get(Real())); - Real new_width(value.mag()); - int scale_index(bline_width->get_link_index_from_name("scale")); - Real scale((*(bline_width->get_link(scale_index)))(get_time()).get(Real())); - return canvas_interface->change_value(synfigapp::ValueDesc(bline_width,scale_index), new_width * scale / old_width); - } - - if (ValueNode_BLineCalcVertex::Handle bline_vertex = ValueNode_BLineCalcVertex::Handle::cast_dynamic(value_desc.get_value_node())) - { - ValueNode_BLine::Handle bline = ValueNode_BLine::Handle::cast_dynamic(bline_vertex->get_link("bline")); - Real radius = 0.0; - if (((*(bline_vertex->get_link("loop")))(get_time()).get(bool()))){ - Real amount_old((*(bline_vertex->get_link("amount")))(get_time()).get(Real())); - Real amount_new = synfig::find_closest_point((*bline)(get_time()), value, radius, bline->get_loop()); - Real difference = fmod( fmod(amount_new - amount_old, 1.0) + 1.0 , 1.0); - //fmod is called twice to avoid negative values - if (difference > 0.5) difference=difference-1.0; - return canvas_interface->change_value(synfigapp::ValueDesc(bline_vertex,bline_vertex->get_link_index_from_name("amount")), amount_old+difference); - - } else { - Real amount = synfig::find_closest_point((*bline)(get_time()), value, radius, bline->get_loop()); - return canvas_interface->change_value(synfigapp::ValueDesc(bline_vertex,bline_vertex->get_link_index_from_name("amount")), amount); - } - } - - if (ValueNode_BLineCalcTangent::Handle bline_tangent = ValueNode_BLineCalcTangent::Handle::cast_dynamic(value_desc.get_value_node())) - { - switch(value_desc.get_value_type()) - { - case ValueBase::TYPE_REAL: - { - Real old_length = (*bline_tangent)(get_time()).get(Real()); - Real new_length = value.mag(); - int scale_index(bline_tangent->get_link_index_from_name("scale")); - int fixed_length_index(bline_tangent->get_link_index_from_name("fixed_length")); - Real scale((*(bline_tangent->get_link(scale_index)))(get_time()).get(Real())); - bool fixed_length((*(bline_tangent->get_link(fixed_length_index)))(get_time()).get(bool())); - if (fixed_length) - return canvas_interface->change_value(synfigapp::ValueDesc(bline_tangent,scale_index), new_length); - if (old_length == 0) - return true; - return canvas_interface->change_value(synfigapp::ValueDesc(bline_tangent,scale_index), new_length * scale / old_length); - } - - case ValueBase::TYPE_ANGLE: - assert(0); // doesn't happen? - break; - - case ValueBase::TYPE_VECTOR: - { - Vector old_tangent = (*bline_tangent)(get_time()).get(Vector()); - Angle old_angle = old_tangent.angle(); - Real old_length = old_tangent.mag(); - Angle new_angle = value.angle(); - Real new_length = value.mag(); - int offset_index(bline_tangent->get_link_index_from_name("offset")); - int scale_index(bline_tangent->get_link_index_from_name("scale")); - int fixed_length_index(bline_tangent->get_link_index_from_name("fixed_length")); - Angle old_offset((*(bline_tangent->get_link(offset_index)))(get_time()).get(Angle())); - Real scale((*(bline_tangent->get_link(scale_index)))(get_time()).get(Real())); - bool fixed_length((*(bline_tangent->get_link(fixed_length_index)))(get_time()).get(bool())); - if (fixed_length) - { - if (!(canvas_interface->change_value(synfigapp::ValueDesc(bline_tangent,scale_index), new_length))) - return false; - } - else if (old_length != 0 && !(canvas_interface->change_value(synfigapp::ValueDesc(bline_tangent,scale_index), new_length * scale / old_length))) - return false; - return canvas_interface->change_value(synfigapp::ValueDesc(bline_tangent,offset_index), old_offset + new_angle - old_angle); - } - default: - break; - } - } - - if (ValueNode_Scale::Handle scale_value_node = ValueNode_Scale::Handle::cast_dynamic(value_desc.get_value_node())) - { - int link_index(scale_value_node->get_link_index_from_name("link")); - if(scale_value_node->is_invertible(get_time())) - return canvas_interface->change_value( - synfigapp::ValueDesc(scale_value_node,link_index), - scale_value_node->get_inverse(get_time(), value) - ); - else - return false; - } - - if (ValueNode_Range::Handle range_value_node = ValueNode_Range::Handle::cast_dynamic(value_desc.get_value_node())) - { - int link_index(range_value_node->get_link_index_from_name("link")); - return canvas_interface->change_value( - synfigapp::ValueDesc(range_value_node,link_index), - range_value_node->get_inverse(get_time(), value) - ); - } - switch(value_desc.get_value_type()) { case ValueBase::TYPE_REAL: @@ -828,33 +730,6 @@ Duckmatic::on_duck_changed(const synfig::Point &value,const synfigapp::ValueDesc bool Duckmatic::on_duck_angle_changed(const synfig::Angle &rotation,const synfigapp::ValueDesc& value_desc) { - if (ValueNode_BLineCalcTangent::Handle bline_tangent = ValueNode_BLineCalcTangent::Handle::cast_dynamic(value_desc.get_value_node())) - { - int offset_index(bline_tangent->get_link_index_from_name("offset")); - Angle old_offset((*(bline_tangent->get_link(offset_index)))(get_time()).get(Angle())); - return canvas_interface->change_value(synfigapp::ValueDesc(bline_tangent,offset_index), old_offset + rotation); - } - - if (ValueNode_Scale::Handle scale_value_node = ValueNode_Scale::Handle::cast_dynamic(value_desc.get_value_node())) - { - int link_index(scale_value_node->get_link_index_from_name("link")); - if(scale_value_node->is_invertible(get_time())) - return canvas_interface->change_value( - synfigapp::ValueDesc(scale_value_node,link_index), - scale_value_node->get_inverse(get_time(), rotation) - ); - else - return false; - - } - if (ValueNode_Range::Handle range_value_node = ValueNode_Range::Handle::cast_dynamic(value_desc.get_value_node())) - { - int link_index(range_value_node->get_link_index_from_name("link")); - return canvas_interface->change_value( - synfigapp::ValueDesc(range_value_node,link_index), - range_value_node->get_inverse(get_time(), rotation) - ); - } // \todo will this really always be the case? assert(value_desc.get_value_type() == ValueBase::TYPE_ANGLE); return canvas_interface->change_value(value_desc, value_desc.get_value(get_time()).get(Angle()) + rotation); diff --git a/synfig-studio/src/synfigapp/actions/valuedescset.cpp b/synfig-studio/src/synfigapp/actions/valuedescset.cpp index 35f6d26..90264c8 100644 --- a/synfig-studio/src/synfigapp/actions/valuedescset.cpp +++ b/synfig-studio/src/synfigapp/actions/valuedescset.cpp @@ -37,9 +37,15 @@ #include "valuedescset.h" #include +#include +#include +#include +#include #include #include +#include #include +#include #include #include @@ -347,6 +353,263 @@ Action::ValueDescSet::prepare() return; } + // Perform reverse manipulations + + // If we are a scale value node, then edit the link + // such that it will scale to our target value + if (ValueNode_Scale::Handle scale_value_node = ValueNode_Scale::Handle::cast_dynamic(value_desc.get_value_node())) + { + if(! scale_value_node->is_invertible(time)) + { + synfig::warning(_("Attempt to edit scale ValueNode with a scale factor of zero.")); + return; + } + + ValueBase new_value; + + if (value.get_type() == ValueBase::TYPE_ANGLE) + new_value = scale_value_node->get_inverse(time, value.get(Angle())); + else if (value.get_type() == ValueBase::TYPE_REAL) + throw Error(_("Inverse manipulation of real scale values not implemented in core.")); + else + new_value = scale_value_node->get_inverse(time, value.get(Vector())); + + Action::Handle action(Action::create("ValueDescSet")); + + if(!action) + throw Error(_("Unable to find action ValueDescSet (bug)")); + + action->set_param("canvas",get_canvas()); + action->set_param("canvas_interface",get_canvas_interface()); + action->set_param("time",time); + action->set_param("new_value",new_value); + action->set_param("value_desc",ValueDesc(scale_value_node, scale_value_node->get_link_index_from_name("link"))); + + if(!action->is_ready()) + throw Error(Error::TYPE_NOTREADY); + + add_action(action); + return; + } + + // Range: disallow values outside the range + if (ValueNode_Range::Handle range_value_node = ValueNode_Range::Handle::cast_dynamic(value_desc.get_value_node())) + { + ValueBase new_value; + + if (value.get_type() == ValueBase::TYPE_ANGLE) + new_value = range_value_node->get_inverse(time, value.get(Angle())); + else if (value.get_type() == ValueBase::TYPE_REAL) + throw Error(_("Inverse manipulation of real range values not implemented in core.")); + else + new_value = range_value_node->get_inverse(time, value.get(Vector())); + + Action::Handle action(Action::create("ValueDescSet")); + + if(!action) + throw Error(_("Unable to find action ValueDescSet (bug)")); + + action->set_param("canvas",get_canvas()); + action->set_param("canvas_interface",get_canvas_interface()); + action->set_param("time",time); + action->set_param("new_value",new_value); + action->set_param("value_desc",ValueDesc(range_value_node,range_value_node->get_link_index_from_name("link"))); + + if(!action->is_ready()) + throw Error(Error::TYPE_NOTREADY); + + add_action(action); + return; + } + + // BlineCalcWidth: modify the scale value node + // so that the target width is achieved + if (ValueNode_BLineCalcWidth::Handle bline_width = ValueNode_BLineCalcWidth::Handle::cast_dynamic(value_desc.get_value_node())) + { + Real old_width((*bline_width)(time).get(Real())); + Real scale((*(bline_width->get_link("scale")))(time).get(Real())); + + ValueBase new_width(value.get(Real()) * scale / old_width); + + Action::Handle action(Action::create("ValueDescSet")); + + if(!action) + throw Error(_("Unable to find action ValueDescSet (bug)")); + + action->set_param("canvas",get_canvas()); + action->set_param("canvas_interface",get_canvas_interface()); + action->set_param("time",time); + action->set_param("new_value",new_width); + action->set_param("value_desc",ValueDesc(bline_width, bline_width->get_link_index_from_name("scale"))); + + if(!action->is_ready()) + throw Error(Error::TYPE_NOTREADY); + + add_action(action); + return; + } + + // BLineCalcVertex: snap the point to the nearest + // allowed position. + if (ValueNode_BLineCalcVertex::Handle bline_vertex = ValueNode_BLineCalcVertex::Handle::cast_dynamic(value_desc.get_value_node())) + { + ValueNode_BLine::Handle bline = ValueNode_BLine::Handle::cast_dynamic(bline_vertex->get_link("bline")); + Real radius = 0.0; + ValueBase new_amount; + if (((*(bline_vertex->get_link("loop")))(time).get(bool()))){ + // The bline is looped. Animation may require an amount parameter + // outside the range of 0-1, so make sure that the amount does + // not change drastically. + Real amount_old((*(bline_vertex->get_link("amount")))(time).get(Real())); + Real amount_new = synfig::find_closest_point((*bline)(time), value, radius, bline->get_loop()); + Real difference = fmod( fmod(amount_new - amount_old, 1.0) + 1.0 , 1.0); + //fmod is called twice to avoid negative values + if (difference > 0.5) difference=difference-1.0; + + new_amount = amount_old+difference; + } else { + new_amount = synfig::find_closest_point((*bline)(time), value, radius, bline->get_loop()); + } + + Action::Handle action(Action::create("ValueDescSet")); + + if(!action) + throw Error(_("Unable to find action ValueDescSet (bug)")); + + action->set_param("canvas",get_canvas()); + action->set_param("canvas_interface",get_canvas_interface()); + action->set_param("time",time); + action->set_param("new_value",new_amount); + action->set_param("value_desc",ValueDesc(bline_vertex, bline_vertex->get_link_index_from_name("amount"))); + + if(!action->is_ready()) + throw Error(Error::TYPE_NOTREADY); + + add_action(action); + return; + } + + + // BLineCalcTangent: adjust scale and offset + // to achieve the desired tangent + if (ValueNode_BLineCalcTangent::Handle bline_tangent = ValueNode_BLineCalcTangent::Handle::cast_dynamic(value_desc.get_value_node())) + { + ValueBase new_scale; + ValueDesc scale_value_desc(bline_tangent,bline_tangent->get_link_index_from_name("scale")); + ValueDesc offset_value_desc(bline_tangent,bline_tangent->get_link_index_from_name("offset")); + + switch(value_desc.get_value_type()) + { + case ValueBase::TYPE_REAL: + { + Real old_length = (*bline_tangent)(time).get(Real()); + Real new_length = value.get(Vector()).mag(); + Real scale((*(bline_tangent->get_link("scale")))(time).get(Real())); + bool fixed_length((*(bline_tangent->get_link("fixed_length")))(time).get(bool())); + + if (fixed_length) + { + new_scale = new_length; + break; + } + if (old_length == 0) + return; + new_scale = new_length * scale / old_length; + } + + case ValueBase::TYPE_VECTOR: + { + Vector old_tangent = (*bline_tangent)(time).get(Vector()); + Angle old_angle = old_tangent.angle(); + Real old_length = old_tangent.mag(); + Angle new_angle = value.get(Vector()).angle(); + Real new_length = value.get(Vector()).mag(); + Angle old_offset((*(bline_tangent->get_link("offset")))(time).get(Angle())); + Real scale((*(bline_tangent->get_link("scale")))(time).get(Real())); + bool fixed_length((*(bline_tangent->get_link("fixed_length")))(time).get(bool())); + if (fixed_length) + { + new_scale = new_length; + break; + } + if (old_length != 0) + { + new_scale = new_length * scale / old_length; + + + Action::Handle action(Action::create("ValueDescSet")); + + if(!action) + throw Error(_("Unable to find action ValueDescSet (bug)")); + + action->set_param("canvas",get_canvas()); + action->set_param("canvas_interface",get_canvas_interface()); + action->set_param("time",time); + action->set_param("new_value", ValueBase(old_offset + new_angle - old_angle)); + action->set_param("value_desc",offset_value_desc); + + if(!action->is_ready()) + throw Error(Error::TYPE_NOTREADY); + + add_action(action); + } + } + break; + + case ValueBase::TYPE_ANGLE: + { + Angle old_angle = (*bline_tangent)(time).get(Angle()); + Angle new_angle = value.get(Vector()).angle(); + Angle old_offset((*(bline_tangent->get_link("offset")))(time).get(Angle())); + + + Action::Handle action(Action::create("ValueDescSet")); + + if(!action) + throw Error(_("Unable to find action ValueDescSet (bug)")); + + action->set_param("canvas",get_canvas()); + action->set_param("canvas_interface",get_canvas_interface()); + action->set_param("time",time); + action->set_param("new_value", ValueBase(old_offset + new_angle - old_angle)); + action->set_param("value_desc",offset_value_desc); + + if(!action->is_ready()) + throw Error(Error::TYPE_NOTREADY); + + add_action(action); + return; + } + + default: + break; + } + + if (new_scale) + { + Action::Handle action(Action::create("ValueDescSet")); + + if(!action) + throw Error(_("Unable to find action ValueDescSet (bug)")); + + action->set_param("canvas",get_canvas()); + action->set_param("canvas_interface",get_canvas_interface()); + action->set_param("time",time); + action->set_param("new_value",new_scale); + action->set_param("value_desc",scale_value_desc); + + if(!action->is_ready()) + throw Error(Error::TYPE_NOTREADY); + + add_action(action); + } + return; + } + + // end reverse manipulations + + + // If we are merging the tangents of a BLinePoint, // we must also set the second tangent for things // to interpolate properly -- 2.7.4