Fix 1677632: newly drawn lines are joined on to existing lines and ducks wherever...
authordooglus <dooglus@1f10aa63-cdf2-0310-b900-c93c546f37ac>
Mon, 12 Mar 2007 22:01:54 +0000 (22:01 +0000)
committerdooglus <dooglus@1f10aa63-cdf2-0310-b900-c93c546f37ac>
Mon, 12 Mar 2007 22:01:54 +0000 (22:01 +0000)
  * closing a bline by drawing a new line from one end of it to the other end extends and loops the bline, as you would expect

  * connecting the end of one line to a duck in the middle of another (or even in the middle of the line itself) extends the existing line, and links the new end of the line to the duck

  * drawing a new line which starts and ends on the same duck now creates a new looped bline which is linked to the duck

git-svn-id: http://svn.voria.com/code@301 1f10aa63-cdf2-0310-b900-c93c546f37ac

synfig-studio/trunk/src/gtkmm/state_draw.cpp

index 2a9542d..f643359 100644 (file)
@@ -116,8 +116,8 @@ class studio::StateDraw_Context : public sigc::trackable
 
        Smach::event_result new_region(std::list<synfig::BLinePoint> bline,synfig::Real radius);
 
-       Smach::event_result extend_bline_from_begin(ValueNode_BLine::Handle value_node,std::list<synfig::BLinePoint> bline);
-       Smach::event_result extend_bline_from_end(ValueNode_BLine::Handle value_node,std::list<synfig::BLinePoint> bline);
+       Smach::event_result extend_bline_from_begin(ValueNode_BLine::Handle value_node,std::list<synfig::BLinePoint> bline,bool complete_loop);
+       Smach::event_result extend_bline_from_end(ValueNode_BLine::Handle value_node,std::list<synfig::BLinePoint> bline,bool complete_loop);
        void reverse_bline(std::list<synfig::BLinePoint> &bline);
 
        synfigapp::Settings& settings;
@@ -704,107 +704,169 @@ StateDraw_Context::new_bline(std::list<synfig::BLinePoint> bline,bool loop_bline
        }
 
        // Find any ducks at the start or end that we might attach to
-       // (If we aren't a loop)
-       if(!loop_bline_flag && get_auto_connect_flag())
+       // (this used to only run if we aren't a loop - ie. !loop_bline_flag
+       // but having loops auto-connect can be useful as well)
+       if(get_auto_connect_flag())
        {
+               bool extend_start=false,extend_finish=false,complete_loop=false;
+               bool extend_start_join_same=false,extend_start_join_different=false,extend_finish_join_same=false,extend_finish_join_different=false;
+               int start_duck_index,finish_duck_index;
                
                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));
                
+               synfigapp::ValueDesc start_duck_value_desc,finish_duck_value_desc;
+               ValueNode_BLine::Handle start_duck_value_node_bline=NULL,finish_duck_value_node_bline=NULL;
+
+               // 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
                {
-                       synfigapp::ValueDesc value_desc(start_duck->get_value_desc());
-                       if(!value_desc)
-                               break;
+                       if(!(start_duck_value_desc=start_duck->get_value_desc()))break;
+                       if(loop_bline_flag)break;
+                       if(!start_duck_value_desc.parent_is_value_node())break;
+                       start_duck_index=start_duck_value_desc.get_index();
+                       start_duck_value_node_bline=ValueNode_BLine::Handle::cast_dynamic(start_duck_value_desc.get_parent_value_node());
 
-                       ValueNode_BLine::Handle value_node_bline;
+                       // don't extend looped blines
+                       if(start_duck_value_node_bline&&!start_duck_value_node_bline->get_loop()&&
+                          (start_duck_index==0||start_duck_index==start_duck_value_node_bline->link_count()-1))
+                               extend_start=true;
+               }while(0);
 
-                       if(value_desc.parent_is_value_node())
-                               value_node_bline=ValueNode_BLine::Handle::cast_dynamic(value_desc.get_parent_value_node());
+               // 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());
 
                        // don't extend looped blines
-                       if(value_node_bline && !value_node_bline->get_loop())
-                       {
-                               if(value_desc.get_index()==0)
-                               {
-                                       // SPECIAL CASE -- EXTENSION
-                                       // We need to reverse the BLine first.
-                                       bline.pop_front();
-                                       reverse_bline(bline);
-                                       return extend_bline_from_begin(value_node_bline,bline);                                 
-                               }
-                               if(value_desc.get_index()==value_node_bline->link_count()-1)
+                       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)
                                {
-                                       // SPECIAL CASE -- EXTENSION
-                                       bline.pop_front();
-                                       return extend_bline_from_end(value_node_bline,bline);
-                               }
-                       }
+                                       // 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;
+               }while(0);
 
-                       switch(value_desc.get_value_type())
+               // 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&&start_duck&&start_duck_value_desc) {
+                       switch(start_duck_value_desc.get_value_type())
                        {
                        case synfig::ValueBase::TYPE_BLINEPOINT:
-                               //get_canvas_interface()->auto_export(value_desc);
-                               //value_node->list.front().value_node=value_desc.get_value_node();
-                               
-                               value_desc=synfigapp::ValueDesc(LinkableValueNode::Handle::cast_dynamic(value_desc.get_value_node()),0);
-                               //break;
+                               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:
-                               get_canvas_interface()->auto_export(value_desc);
-                               LinkableValueNode::Handle::cast_dynamic(value_node->list.front().value_node)->set_link(0,value_desc.get_value_node());
-                               break;
-                       default:
-                               break;
+                               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
+                                       LinkableValueNode::Handle::cast_dynamic(value_node->list.front().value_node)->
+                                         set_link(0,start_duck_value_desc.get_value_node());
+                               // fall through
+                       default:break;
                        }
-               }while(0);
-               
-               if(finish_duck)do
-               {
-                       synfigapp::ValueDesc value_desc(finish_duck->get_value_desc());
-                       if(!value_desc)
-                               break;
+               }               
 
-                       ValueNode_BLine::Handle value_node_bline;
+               // 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&&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:
+                               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
+                                       LinkableValueNode::Handle::cast_dynamic(value_node->list.back().value_node)->
+                                         set_link(0,finish_duck_value_desc.get_value_node());
+                               // fall through
+                       default:break;
+                       }
 
-                       if(value_desc.parent_is_value_node())
-                               value_node_bline=ValueNode_BLine::Handle::cast_dynamic(value_desc.get_parent_value_node());
+               Smach::event_result result;
+               synfig::ValueNode_DynamicList::ListEntry source;
+               int target_index;
 
-                       // don't extend looped blines
-                       if(value_node_bline && !value_node_bline->get_loop())
+               // the new line's start extends an existing line
+               if(extend_start)
+               {
+                       if(complete_loop)bline.pop_back();
+                       bline.pop_front();
+                       if(start_duck_index==0)
+                       {       // We need to reverse the BLine first.
+                               reverse_bline(bline);
+                               result=extend_bline_from_begin(start_duck_value_node_bline,bline,complete_loop);
+                               source=start_duck_value_node_bline->list.front();
+                               target_index=bline.size()+finish_duck_index;
+                       }
+                       else
                        {
-                               if(value_desc.get_index()==0)
-                               {
-                                       // SPECIAL CASE -- EXTENSION
-                                       bline.pop_back();
-                                       return extend_bline_from_begin(value_node_bline,bline);                                 
-                               }
-                               if(value_desc.get_index()==value_node_bline->link_count()-1)
-                               {
-                                       // SPECIAL CASE -- EXTENSION
-                                       // We need to reverse the BLine first.
-                                       bline.pop_back();
-                                       reverse_bline(bline);
-                                       return extend_bline_from_end(value_node_bline,bline);
-                               }
+                               result=extend_bline_from_end(start_duck_value_node_bline,bline,complete_loop);
+                               source=start_duck_value_node_bline->list.back();
+                               target_index=finish_duck_index;
                        }
 
-                       switch(value_desc.get_value_type())
-                       {
-                       case synfig::ValueBase::TYPE_BLINEPOINT:
-                               //get_canvas_interface()->auto_export(value_desc);
-                               //value_node->list.back().value_node=value_desc.get_value_node();
+                       if(extend_start_join_different)
+                               LinkableValueNode::Handle::cast_dynamic(source.value_node)->
+                                 set_link(0,finish_duck_value_desc.get_value_node());
+                       else if(extend_start_join_same)
+                               LinkableValueNode::Handle::cast_dynamic(source.value_node)->
+                                 set_link(0,synfigapp::ValueDesc(LinkableValueNode::Handle::cast_dynamic(start_duck_value_node_bline->
+                                                                                                         list[target_index].value_node),0).get_value_node());
+                       return result;
+               }
 
-                               value_desc=synfigapp::ValueDesc(LinkableValueNode::Handle::cast_dynamic(value_desc.get_value_node()),0);
-                               //break;
-                       case synfig::ValueBase::TYPE_VECTOR:
-                               get_canvas_interface()->auto_export(value_desc);
-                               LinkableValueNode::Handle::cast_dynamic(value_node->list.back().value_node)->set_link(0,value_desc.get_value_node());
-                               break;
-                       default:
-                               break;
+               // the new line's end extends an existing line
+               if(extend_finish)
+               {       // SPECIAL CASE -- EXTENSION
+                       bline.pop_back();
+                       if(finish_duck_index==0)
+                       {
+                               result=extend_bline_from_begin(finish_duck_value_node_bline,bline,false);
+                               source=finish_duck_value_node_bline->list.front();
+                               target_index=bline.size()+start_duck_index;
                        }
-                       
-               }while(0);
+                       else
+                       {       // We need to reverse the BLine first.
+                               reverse_bline(bline);
+                               result=extend_bline_from_end(finish_duck_value_node_bline,bline,false);
+                               source=finish_duck_value_node_bline->list.back();
+                               target_index=start_duck_index;
+                       }
+
+                       if(extend_finish_join_different)
+                               LinkableValueNode::Handle::cast_dynamic(source.value_node)->
+                                 set_link(0,start_duck_value_desc.get_value_node());
+                       else if(extend_finish_join_same)
+                               LinkableValueNode::Handle::cast_dynamic(source.value_node)->
+                                 set_link(0,synfigapp::ValueDesc(LinkableValueNode::Handle::cast_dynamic(finish_duck_value_node_bline->
+                                                                                                         list[target_index].value_node),0).get_value_node());
+                       return result;
+               }
        }
        
        // Create the layer
@@ -1199,11 +1261,28 @@ StateDraw_Context::refresh_ducks()
 
 
 Smach::event_result
-StateDraw_Context::extend_bline_from_begin(ValueNode_BLine::Handle value_node,std::list<synfig::BLinePoint> bline)
+StateDraw_Context::extend_bline_from_begin(ValueNode_BLine::Handle value_node,std::list<synfig::BLinePoint> bline,bool complete_loop)
 {
        // Create the action group
        synfigapp::Action::PassiveGrouper group(get_canvas_interface()->get_instance().get(),_("Extend BLine"));
        
+       if (complete_loop)
+       {
+               synfigapp::Action::Handle action(synfigapp::Action::create("value_node_dynamic_list_loop"));
+               assert(action);
+
+               action->set_param("canvas",get_canvas());                       
+               action->set_param("canvas_interface",get_canvas_interface());                   
+               action->set_param("value_node",ValueNode::Handle(value_node));
+               
+               if(!get_canvas_interface()->get_instance()->perform_action(action))
+               {
+                       get_canvas_view()->get_ui_interface()->error(_("Unable to set loop for bline"));
+                       group.cancel();
+                       return Smach::RESULT_ERROR;
+               }               
+       }
+
        std::list<synfig::BLinePoint>::reverse_iterator iter;
        iter=bline.rbegin();
        for(;!(iter==bline.rend());++iter)
@@ -1235,11 +1314,28 @@ StateDraw_Context::extend_bline_from_begin(ValueNode_BLine::Handle value_node,st
 }
 
 Smach::event_result
-StateDraw_Context::extend_bline_from_end(ValueNode_BLine::Handle value_node,std::list<synfig::BLinePoint> bline)
+StateDraw_Context::extend_bline_from_end(ValueNode_BLine::Handle value_node,std::list<synfig::BLinePoint> bline,bool complete_loop)
 {
        // Create the action group
        synfigapp::Action::PassiveGrouper group(get_canvas_interface()->get_instance().get(),_("Extend BLine"));
 
+       if (complete_loop)
+       {
+               synfigapp::Action::Handle action(synfigapp::Action::create("value_node_dynamic_list_loop"));
+               assert(action);
+
+               action->set_param("canvas",get_canvas());                       
+               action->set_param("canvas_interface",get_canvas_interface());                   
+               action->set_param("value_node",ValueNode::Handle(value_node));
+               
+               if(!get_canvas_interface()->get_instance()->perform_action(action))
+               {
+                       get_canvas_view()->get_ui_interface()->error(_("Unable to set loop for bline"));
+                       group.cancel();
+                       return Smach::RESULT_ERROR;
+               }               
+       }
+
        std::list<synfig::BLinePoint>::iterator iter;
        iter=bline.begin();
        for(;iter!=bline.end();++iter)