Move reverse manipulation code into ValueDescSet action
[synfig.git] / synfig-studio / src / synfigapp / actions / valuedescset.cpp
index e3959ce..90264c8 100644 (file)
 
 #include "valuedescset.h"
 #include <synfigapp/canvasinterface.h>
+#include <synfig/valuenode_bline.h>
+#include <synfig/valuenode_blinecalctangent.h>
+#include <synfig/valuenode_blinecalcvertex.h>
+#include <synfig/valuenode_blinecalcwidth.h>
 #include <synfig/valuenode_composite.h>
 #include <synfig/valuenode_radialcomposite.h>
+#include <synfig/valuenode_range.h>
 #include <synfig/valuenode_reference.h>
+#include <synfig/valuenode_scale.h>
 #include <synfigapp/main.h>
 
 #include <synfigapp/general.h>
@@ -156,7 +162,8 @@ Action::ValueDescSet::prepare()
        // tangent.
        if(     value_desc.parent_is_value_node() &&
                value_desc.get_parent_value_node()->get_type()==ValueBase::TYPE_BLINEPOINT &&
-               (value_desc.get_index()==4 || value_desc.get_index()==5) &&
+               (value_desc.get_name()=="t1" || value_desc.get_name()=="t2") &&
+               //(value_desc.get_index()==4 || value_desc.get_index()==5) &&
                (*value_desc.get_parent_value_node())(time).get(BLinePoint()).get_split_tangent_flag()==false)
        {
                {
@@ -168,7 +175,8 @@ Action::ValueDescSet::prepare()
                        Vector t2((*parent_value_node->get_link("t2"))(time));
                }
 
-               if (value_desc.get_index()==4) {
+               //if (value_desc.get_index()==4) {
+               if (value_desc.get_name()=="t1") {
                        ValueNode_Composite::Handle parent_value_node;
                        parent_value_node=parent_value_node.cast_dynamic(value_desc.get_parent_value_node());
 
@@ -183,7 +191,7 @@ Action::ValueDescSet::prepare()
                        action->set_param("canvas_interface",get_canvas_interface());
                        action->set_param("time",time);
                        action->set_param("new_value",value);
-                       action->set_param("value_desc",ValueDesc(parent_value_node,5));
+                       action->set_param("value_desc",ValueDesc(parent_value_node, parent_value_node->get_link_index_from_name("t2")));
 
                        if(!action->is_ready())
                                throw Error(Error::TYPE_NOTREADY);
@@ -300,7 +308,7 @@ Action::ValueDescSet::prepare()
                case ValueBase::TYPE_VECTOR:
                {
                        Angle old_angle = (*(ValueNode_RadialComposite::Handle::cast_dynamic(
-                                                                        value_desc.get_value_node())->get_link_vfunc(1)))(time).get(Angle());
+                                                                        value_desc.get_value_node())->get_link("theta")))(time).get(Angle());
                        Vector vect(value.get(Vector()));
                        components[0]=vect.mag();
                        Angle change = Angle(Angle::tan(vect[1],vect[0])) - old_angle;
@@ -345,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
@@ -370,8 +635,8 @@ Action::ValueDescSet::prepare()
                        action->set_param("canvas",get_canvas());
                        action->set_param("canvas_interface",get_canvas_interface());
                        action->set_param("time",time);
-                       action->set_param("new_value",(*parent_value_node->get_link(4))(time));
-                       action->set_param("value_desc",ValueDesc(parent_value_node,5));
+                       action->set_param("new_value",(*parent_value_node->get_link("t1"))(time));
+                       action->set_param("value_desc",ValueDesc(parent_value_node,parent_value_node->get_link_index_from_name("t2")));
 
                        if(!action->is_ready())
                                throw Error(Error::TYPE_NOTREADY);
@@ -396,7 +661,7 @@ Action::ValueDescSet::prepare()
                                action->set_param("canvas_interface",get_canvas_interface());
                                action->set_param("time",time);
                                action->set_param("new_value",average);
-                               action->set_param("value_desc",ValueDesc(parent_value_node,4));
+                               action->set_param("value_desc",ValueDesc(parent_value_node,parent_value_node->get_link_index_from_name("t1")));
 
                                if(!action->is_ready())
                                        throw Error(Error::TYPE_NOTREADY);
@@ -414,7 +679,7 @@ Action::ValueDescSet::prepare()
                                action->set_param("canvas_interface",get_canvas_interface());
                                action->set_param("time",time);
                                action->set_param("new_value",average);
-                               action->set_param("value_desc",ValueDesc(parent_value_node,5));
+                               action->set_param("value_desc",ValueDesc(parent_value_node,parent_value_node->get_link_index_from_name("t2")));
 
                                if(!action->is_ready())
                                        throw Error(Error::TYPE_NOTREADY);
@@ -444,9 +709,17 @@ Action::ValueDescSet::prepare()
        }
 */
 
-
+       ValueBase local_value;
+       local_value.set_static(false);
+               if(!value_desc.is_value_node() || ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
+               {
+                       if(value_desc.is_value_node())
+                               local_value=ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node())->get_value();
+                       else
+                               local_value=value_desc.get_value();
+               }
        // If we are in animate editing mode
-       if(get_edit_mode()&MODE_ANIMATE)
+       if(get_edit_mode()&MODE_ANIMATE && !local_value.get_static())
        {
 
                ValueNode_Animated::Handle& value_node(value_node_animated);
@@ -525,7 +798,8 @@ Action::ValueDescSet::prepare()
                        if(ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
                        {
                                Action::Handle action(ValueNodeConstSet::create());
-
+                               synfig::ValueNode_Const::Handle localvaluenode(ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()));
+                               value.set_static(localvaluenode->get_static());
                                action->set_param("canvas",get_canvas());
                                action->set_param("canvas_interface",get_canvas_interface());
                                action->set_param("value_node",value_desc.get_value_node());
@@ -547,7 +821,8 @@ Action::ValueDescSet::prepare()
                if(value_desc.parent_is_layer_param() && !value_desc.is_value_node())
                {
                        Action::Handle layer_param_set(LayerParamSet::create());
-
+                       synfig::ValueBase localvalue(value_desc.get_value());
+                       value.set_static(local_value.get_static());
                        layer_param_set->set_param("canvas",get_canvas());
                        layer_param_set->set_param("canvas_interface",get_canvas_interface());
                        layer_param_set->set_param("layer",value_desc.get_layer());