+ synfigapp::Action::PassiveGrouper group(get_canvas_interface()->get_instance().get(),_("Sketch BLine"));
+
+ bool shift_offset = false;
+ Vector shift_offset_vector;
+ bool join_start_no_extend=false,join_finish_no_extend=false;
+ synfigapp::ValueDesc start_duck_value_desc,finish_duck_value_desc;
+ bool extend_start=false,extend_finish=false,complete_loop=false;
+ bool extend_start_join_same=false,extend_start_join_different=false;
+ bool extend_finish_join_same=false,extend_finish_join_different=false;
+ int start_duck_index = 0,finish_duck_index = 0; // initialised to keep the compiler happy; shouldn't be needed though
+ ValueNode_BLine::Handle start_duck_value_node_bline=NULL,finish_duck_value_node_bline=NULL;
+
+ // Find any ducks at the start or end that we might attach to
+ // (this used to only run if we didn't just draw a loop - ie. !loop_bline_flag
+ // but having loops auto-connect can be useful as well)
+ if(get_auto_extend_flag() || get_auto_link_flag())
+ {
+ etl::handle<Duck> start_duck(get_work_area()->find_duck(bline.front().get_vertex(),radius,Duck::TYPE_VERTEX));
+ etl::handle<Duck> finish_duck(get_work_area()->find_duck(bline.back().get_vertex(),radius,Duck::TYPE_VERTEX));
+
+ // check whether the start of the new line extends an
+ // existing line. this is only the case if the new
+ // line isn't a self-contained loop, and if the new
+ // line starts at one of the ends of an existing line
+ if(start_duck)do
+ {
+ if(!(start_duck_value_desc=start_duck->get_value_desc()))break;
+ if(loop_bline_flag)break; // loops don't extend anything
+ if(!start_duck_value_desc.parent_is_value_node())break;
+ start_duck_index=start_duck_value_desc.get_index(); // which point on the line did we start drawing at
+ start_duck_value_node_bline=ValueNode_BLine::Handle::cast_dynamic(start_duck_value_desc.get_parent_value_node());
+ if(!get_auto_extend_flag())break;
+
+ // don't extend looped blines
+ if(start_duck_value_node_bline&&!start_duck_value_node_bline->get_loop()&&
+ // did we start drawing at either end of the line?
+ (start_duck_index==0||start_duck_index==start_duck_value_node_bline->link_count()-1))
+ {
+ extend_start=true;
+ shift_offset=true;
+ shift_offset_vector=start_duck->get_origin();
+ }
+ }while(0);
+
+ // check whether the end of the new line extends an
+ // existing line. this is only the case if the new
+ // line isn't a self-contained loop, and if the new
+ // line ends at one of the ends of an existing line
+ if(finish_duck)do
+ {
+ if(!(finish_duck_value_desc=finish_duck->get_value_desc()))break;
+ if(loop_bline_flag)break;
+ if(!finish_duck_value_desc.parent_is_value_node())break;
+ finish_duck_index=finish_duck_value_desc.get_index();
+ finish_duck_value_node_bline=ValueNode_BLine::Handle::cast_dynamic(finish_duck_value_desc.get_parent_value_node());
+ if(!get_auto_extend_flag())break;
+
+ // don't extend looped blines
+ if(finish_duck_value_node_bline&&!finish_duck_value_node_bline->get_loop()&&
+ (finish_duck_index==0||finish_duck_index==finish_duck_value_node_bline->link_count()-1))
+ if(extend_start)
+ {
+ // we've started and finished drawing at the end of a bline. we can't
+ // extend both blines, so unless we started and finished at the 2 ends
+ // of the same bline, only extend the one we started on
+ if(start_duck_value_node_bline==finish_duck_value_node_bline)
+ complete_loop=extend_finish=true;
+ }else{
+ extend_finish=true;
+ shift_offset=true;
+ shift_offset_vector=finish_duck->get_origin();
+ }
+ }while(0);
+
+ // if the new line's start didn't extend an existing line,
+ // check whether it needs to be linked to an existing duck
+ if(!extend_start&&get_auto_link_flag()&&start_duck&&start_duck_value_desc)
+ switch(start_duck_value_desc.get_value_type())
+ {
+ case synfig::ValueBase::TYPE_BLINEPOINT:
+ start_duck_value_desc=synfigapp::ValueDesc(LinkableValueNode::Handle::cast_dynamic(start_duck_value_desc.get_value_node()),0);
+ // fall through
+ case synfig::ValueBase::TYPE_VECTOR:
+ if (shift_offset && shift_offset_vector != start_duck->get_origin())
+ break;
+ shift_offset = true;
+ shift_offset_vector = start_duck->get_origin();
+ get_canvas_interface()->auto_export(start_duck_value_desc);
+ if (extend_finish)
+ if(start_duck_value_node_bline&&start_duck_value_node_bline==finish_duck_value_node_bline)
+ extend_finish_join_same=true;
+ else
+ extend_finish_join_different=true;
+ else
+ join_start_no_extend=true;
+ // fall through
+ default:break;
+ }
+
+ // if the new line's end didn't extend an existing line,
+ // check whether it needs to be linked to an existing duck
+ if(!extend_finish&&get_auto_link_flag()&&finish_duck&&finish_duck_value_desc)
+ switch(finish_duck_value_desc.get_value_type())
+ {
+ case synfig::ValueBase::TYPE_BLINEPOINT:
+ finish_duck_value_desc=synfigapp::ValueDesc(LinkableValueNode::Handle::cast_dynamic(finish_duck_value_desc.get_value_node()),0);
+ // fall through
+ case synfig::ValueBase::TYPE_VECTOR:
+ if (shift_offset && shift_offset_vector != finish_duck->get_origin())
+ break;
+ shift_offset = true;
+ shift_offset_vector = finish_duck->get_origin();
+ get_canvas_interface()->auto_export(finish_duck_value_desc);
+ if(extend_start)
+ if(finish_duck_value_node_bline&&start_duck_value_node_bline==finish_duck_value_node_bline)
+ extend_start_join_same=true;
+ else
+ extend_start_join_different=true;
+ else
+ join_finish_no_extend=true;
+ // fall through
+ default:break;
+ }
+ }