+ 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:
+ return canvas_interface->change_value(value_desc,value.mag());
+ case ValueBase::TYPE_ANGLE:
+ return canvas_interface->change_value(value_desc,Angle::tan(value[1],value[0]));
+ default:
+ return canvas_interface->change_value(value_desc,value);
+ }
+}
+
+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)
+ );