/* === S Y N F I G ========================================================= */
-/*! \file rotoscope_bline.cpp
+/*! \file state_draw.cpp
** \brief Template File
**
-** $Id: state_draw.cpp,v 1.1.1.1 2005/01/07 03:34:36 darco Exp $
+** $Id$
**
** \legal
** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
+** Copyright (c) 2007 Chris Moore
**
** This package is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License as
Gtk::Table options_table;
Gtk::CheckButton checkbutton_pressure_width;
Gtk::CheckButton checkbutton_round_ends;
- Gtk::CheckButton checkbutton_auto_loop;
- Gtk::CheckButton checkbutton_auto_connect;
+ Gtk::CheckButton checkbutton_auto_loop; // whether to loop new strokes which start and end in the same place
+ Gtk::CheckButton checkbutton_auto_extend; // whether to extend existing lines
+ Gtk::CheckButton checkbutton_auto_link; // whether to link new ducks to existing ducks
Gtk::CheckButton checkbutton_region_only;
Gtk::Button button_fill_last_stroke;
bool get_auto_loop_flag()const { return checkbutton_auto_loop.get_active(); }
void set_auto_loop_flag(bool x) { return checkbutton_auto_loop.set_active(x); }
- bool get_auto_connect_flag()const { return checkbutton_auto_connect.get_active(); }
- void set_auto_connect_flag(bool x) { return checkbutton_auto_connect.set_active(x); }
+ bool get_auto_extend_flag()const { return checkbutton_auto_extend.get_active(); }
+ void set_auto_extend_flag(bool x) { return checkbutton_auto_extend.set_active(x); }
+
+ bool get_auto_link_flag()const { return checkbutton_auto_link.get_active(); }
+ void set_auto_link_flag(bool x) { return checkbutton_auto_link.set_active(x); }
bool get_region_only_flag()const { return checkbutton_region_only.get_active(); }
void set_region_only_flag(bool x) { return checkbutton_region_only.set_active(x); }
else
set_auto_loop_flag(true);
- if(settings.get_value("draw.auto_connect",value) && value=="0")
- set_auto_connect_flag(false);
+ if(settings.get_value("draw.auto_extend",value) && value=="0")
+ set_auto_extend_flag(false);
+ else
+ set_auto_extend_flag(true);
+
+ if(settings.get_value("draw.auto_link",value) && value=="0")
+ set_auto_link_flag(false);
else
- set_auto_connect_flag(true);
+ set_auto_link_flag(true);
if(settings.get_value("draw.region_only",value) && value=="1")
set_region_only_flag(true);
{
settings.set_value("draw.pressure_width",get_pressure_width_flag()?"1":"0");
settings.set_value("draw.auto_loop",get_auto_loop_flag()?"1":"0");
- settings.set_value("draw.auto_connect",get_auto_connect_flag()?"1":"0");
+ settings.set_value("draw.auto_extend",get_auto_extend_flag()?"1":"0");
+ settings.set_value("draw.auto_link",get_auto_link_flag()?"1":"0");
settings.set_value("draw.region_only",get_region_only_flag()?"1":"0");
settings.set_value("draw.min_pressure",strprintf("%f",get_min_pressure()));
settings.set_value("draw.feather",strprintf("%f",get_feather()));
settings(synfigapp::Main::get_selected_input_device()->settings()),
checkbutton_pressure_width(_("Pressure Width")),
checkbutton_auto_loop(_("Auto Loop")),
- checkbutton_auto_connect(_("Auto Connect")),
+ checkbutton_auto_extend(_("Auto Extend")),
+ checkbutton_auto_link(_("Auto Link")),
checkbutton_region_only(_("Create Region Only")),
button_fill_last_stroke(_("Fill Last Stroke")),
adj_min_pressure(0,0,1,0.01,0.1),
//options_table.attach(*manage(new Gtk::Label(_("Draw Tool"))), 0, 2, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
options_table.attach(checkbutton_pressure_width, 0, 2, 1, 2, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
options_table.attach(checkbutton_auto_loop, 0, 2, 2, 3, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
- options_table.attach(checkbutton_auto_connect, 0, 2, 3, 4, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
- options_table.attach(checkbutton_region_only, 0, 2, 4, 5, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
+ options_table.attach(checkbutton_auto_extend, 0, 2, 3, 4, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
+ options_table.attach(checkbutton_auto_link, 0, 2, 4, 5, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
+ options_table.attach(checkbutton_region_only, 0, 2, 5, 6, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
- options_table.attach(check_min_pressure, 0, 2, 5, 6, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
- options_table.attach(spin_min_pressure, 0, 2, 6, 7, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
+ options_table.attach(check_min_pressure, 0, 2, 6, 7, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
+ options_table.attach(spin_min_pressure, 0, 2, 7, 8, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
- options_table.attach(*manage(new Gtk::Label(_("Feather"))), 0, 1, 7, 8, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
- options_table.attach(spin_feather, 1, 2, 7, 8, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
+ options_table.attach(*manage(new Gtk::Label(_("Feather"))), 0, 1, 8, 9, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
+ options_table.attach(spin_feather, 1, 2, 8, 9, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
- options_table.attach(check_localerror, 0, 2, 8, 9, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
- options_table.attach(*manage(new Gtk::Label(_("Smooth"))), 0, 1, 9, 10, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
- options_table.attach(spin_globalthres, 1, 2, 9, 10, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
+ options_table.attach(check_localerror, 0, 2, 9, 10, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
+ options_table.attach(*manage(new Gtk::Label(_("Smooth"))), 0, 1, 10, 11, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
+ options_table.attach(spin_globalthres, 1, 2, 10, 11, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
- //options_table.attach(button_fill_last_stroke, 0, 2, 10, 11, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
+ //options_table.attach(button_fill_last_stroke, 0, 2, 11, 12, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
button_fill_last_stroke.signal_pressed().connect(sigc::mem_fun(*this,&StateDraw_Context::fill_last_stroke));
check_localerror.signal_toggled().connect(sigc::mem_fun(*this,&StateDraw_Context::UpdateErrorBox));
prev_table_status=get_canvas_view()->tables_are_visible();
//if(prev_table_status)get_canvas_view()->hide_tables();
- // Hide the time bar
- get_canvas_view()->hide_timebar();
+ // Disable the time bar
+ get_canvas_view()->set_sensitive_timebar(false);
// Connect a signal
//get_work_area()->signal_user_click().connect(sigc::mem_fun(*this,&studio::StateDraw_Context::on_user_click));
// Restore duck clicking
get_work_area()->allow_duck_clicks=true;
- // Show the time bar
- if(get_canvas_view()->get_canvas()->rend_desc().get_time_start()!=get_canvas_view()->get_canvas()->rend_desc().get_time_end())
- get_canvas_view()->show_timebar();
+ // Enable the time bar
+ get_canvas_view()->set_sensitive_timebar(true);
// Bring back the tables if they were out before
if(prev_table_status)get_canvas_view()->show_tables();
synfigapp::BLineConverter::EnforceMinWidth(bline,get_min_pressure());
}
- // If the start and end points are similar, then make then the same point
- if(get_auto_loop_flag())
- if(bline.size()>2&&(bline.front().get_vertex()-bline.back().get_vertex()).mag()<=radius)
+ // If the start and end points are similar, then make them the same point
+ if(get_auto_loop_flag() &&
+ bline.size()>2&&(bline.front().get_vertex()-bline.back().get_vertex()).mag()<=radius)
{
loop_bline_flag=true;
Vector tangent;
// Add the widths of the two points
{
- Real width(bline.front().get_width()+width);
- width=width<=1?width:1;
- bline.front().set_width(width);
+ Real tmp_width(bline.front().get_width()+width);
+ tmp_width=tmp_width<=1?tmp_width:1;
+ bline.front().set_width(tmp_width);
}
}
- // If the bline only has once blinepoint, then there is nothing to do.
+ // If the bline only has one blinepoint, then there is nothing to do.
if(bline.size()<=1)
return Smach::RESULT_OK;
// Create the action group
synfigapp::Action::PassiveGrouper group(get_canvas_interface()->get_instance().get(),_("Sketch BLine"));
- //ValueNode_BLine::Handle value_node(ValueNode_BLine::create(synfig::ValueBase(bline,loop_bline_flag)));
- ValueNode_BLine::Handle value_node;
-
- {
- std::list<synfig::BLinePoint> trans_bline;
- std::list<synfig::BLinePoint>::iterator iter;
- const synfig::TransformStack& transform(get_canvas_view()->get_curr_transform_stack());
-
- for(iter=bline.begin();iter!=bline.end();++iter)
- {
- BLinePoint bline_point(*iter);
- Point new_vertex(transform.unperform(bline_point.get_vertex()));
-
- bline_point.set_tangent1(
- transform.unperform(
- bline_point.get_tangent1()+bline_point.get_vertex()
- ) -new_vertex
- );
-
- bline_point.set_tangent2(
- transform.unperform(
- bline_point.get_tangent2()+bline_point.get_vertex()
- ) -new_vertex
- );
-
- bline_point.set_vertex(new_vertex);
-
- trans_bline.push_back(bline_point);
- }
- value_node=ValueNode_BLine::create(synfig::ValueBase(trans_bline,loop_bline_flag));
- }
+ 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,finish_duck_index;
+ 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 aren't a loop - ie. !loop_bline_flag
// but having loops auto-connect can be useful as well)
- if(get_auto_connect_flag())
+ if(get_auto_extend_flag() || get_auto_link_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
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());
+ if(!get_auto_extend_flag())break;
// 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;
+ shift_offset=true;
+ shift_offset_vector=start_duck->get_origin();
+ }
}while(0);
// check whether the end of the new line extends an
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()&&
// 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
+ }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&&start_duck&&start_duck_value_desc) {
+ 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)
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());
+ 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&&finish_duck&&finish_duck_value_desc)
+ 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)
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());
+ join_finish_no_extend=true;
// fall through
default:break;
}
+ }
- Smach::event_result result;
- synfig::ValueNode_DynamicList::ListEntry source;
- int target_index;
+ ValueNode_BLine::Handle value_node;
+ std::list<synfig::BLinePoint> trans_bline;
+
+ {
+ std::list<synfig::BLinePoint>::iterator iter;
+ const synfig::TransformStack& transform(get_canvas_view()->get_curr_transform_stack());
- // the new line's start extends an existing line
- if(extend_start)
+ for(iter=bline.begin();iter!=bline.end();++iter)
{
- 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
- {
- 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;
- }
+ BLinePoint bline_point(*iter);
+ Point new_vertex(transform.unperform(bline_point.get_vertex()));
+
+ bline_point.set_tangent1(
+ transform.unperform(
+ bline_point.get_tangent1()+bline_point.get_vertex()
+ ) -new_vertex
+ );
+
+ bline_point.set_tangent2(
+ transform.unperform(
+ bline_point.get_tangent2()+bline_point.get_vertex()
+ ) -new_vertex
+ );
+
+ if (shift_offset)
+ new_vertex=new_vertex-shift_offset_vector;
+
+ bline_point.set_vertex(new_vertex);
+
+ trans_bline.push_back(bline_point);
+ }
+ value_node=ValueNode_BLine::create(synfig::ValueBase(trans_bline,loop_bline_flag));
+ }
- 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;
+ Smach::event_result result;
+ synfig::ValueNode_DynamicList::ListEntry source;
+ int target_index;
+
+ // the new line's start extends an existing line
+ if(extend_start)
+ {
+ if(complete_loop)trans_bline.pop_back();
+ trans_bline.pop_front();
+ if(start_duck_index==0)
+ { // We need to reverse the BLine first.
+ reverse_bline(trans_bline);
+ result=extend_bline_from_begin(start_duck_value_node_bline,trans_bline,complete_loop);
+ source=start_duck_value_node_bline->list.front();
+ target_index=trans_bline.size()+finish_duck_index;
+ }
+ else
+ {
+ result=extend_bline_from_end(start_duck_value_node_bline,trans_bline,complete_loop);
+ source=start_duck_value_node_bline->list.back();
+ target_index=finish_duck_index;
}
- // 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;
- }
- 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_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;
+ }
- 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;
+ // the new line's end extends an existing line
+ if(extend_finish)
+ { // SPECIAL CASE -- EXTENSION
+ trans_bline.pop_back();
+ if(finish_duck_index==0)
+ {
+ result=extend_bline_from_begin(finish_duck_value_node_bline,trans_bline,false);
+ source=finish_duck_value_node_bline->list.front();
+ target_index=trans_bline.size()+start_duck_index;
}
+ else
+ { // We need to reverse the BLine first.
+ reverse_bline(trans_bline);
+ result=extend_bline_from_end(finish_duck_value_node_bline,trans_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;
}
+ if (join_start_no_extend)
+ LinkableValueNode::Handle::cast_dynamic(value_node->list.front().value_node)->
+ set_link(0,start_duck_value_desc.get_value_node());
+
+ if (join_finish_no_extend)
+ LinkableValueNode::Handle::cast_dynamic(value_node->list.back().value_node)->
+ set_link(0,finish_duck_value_desc.get_value_node());
+
// Create the layer
{
Layer::Handle layer;
//layer->set_description(strprintf("Stroke %d",number));
//get_canvas_interface()->signal_layer_new_description()(layer,layer->get_description());
-
+ if (shift_offset)
+ get_canvas_interface()->
+ change_value(synfigapp::ValueDesc(layer,"offset"),shift_offset_vector);
synfigapp::Action::Handle action(synfigapp::Action::create("layer_param_connect"));
}
std::list<synfig::BLinePoint>::reverse_iterator iter;
- iter=bline.rbegin();
- for(;!(iter==bline.rend());++iter)
+ for(iter=bline.rbegin();!(iter==bline.rend());++iter)
{
- //iter->reverse();
ValueNode_Composite::Handle composite(ValueNode_Composite::create(*iter));
synfigapp::Action::Handle action(synfigapp::Action::create("value_node_dynamic_list_insert"));
}
std::list<synfig::BLinePoint>::iterator iter;
- iter=bline.begin();
- for(;iter!=bline.end();++iter)
+ for(iter=bline.begin();iter!=bline.end();++iter)
{
ValueNode_Composite::Handle composite(ValueNode_Composite::create(*iter));