X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=synfig-studio%2Ftags%2Fsynfigstudio_0_61_07_rc2%2Fsrc%2Fgtkmm%2Fduckmatic.cpp;fp=synfig-studio%2Ftags%2Fsynfigstudio_0_61_07_rc2%2Fsrc%2Fgtkmm%2Fduckmatic.cpp;h=61ecef4d0736bfd510c3de25658b020b0f8670fd;hb=88a983aae927e85c110bb243a5197df5548c2cf2;hp=0000000000000000000000000000000000000000;hpb=3078b7103aa069392b711486dbc1eaf6d4804acc;p=synfig.git diff --git a/synfig-studio/tags/synfigstudio_0_61_07_rc2/src/gtkmm/duckmatic.cpp b/synfig-studio/tags/synfigstudio_0_61_07_rc2/src/gtkmm/duckmatic.cpp new file mode 100644 index 0000000..61ecef4 --- /dev/null +++ b/synfig-studio/tags/synfigstudio_0_61_07_rc2/src/gtkmm/duckmatic.cpp @@ -0,0 +1,1826 @@ +/* === S Y N F I G ========================================================= */ +/*! \file duckmatic.cpp +** \brief Template File +** +** $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 +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === H E A D E R S ======================================================= */ + +#ifdef USING_PCH +# include "pch.h" +#else +#ifdef HAVE_CONFIG_H +# include +#endif +#include +#include +#include + +#include + +#include "duckmatic.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "canvasview.h" + +#include "onemoment.h" + +#endif + +/* === U S I N G =========================================================== */ + +using namespace std; +using namespace etl; +using namespace synfig; +using namespace studio; + +/* === M A C R O S ========================================================= */ + +/* 0.33333333333333333 makes for nice short tangent handles, + 1.0 makes them draw as their real length */ +#define TANGENT_HANDLE_SCALE 0.33333333333333333 + +/* leave this alone or the bezier won't lie on top of the bline */ +#define TANGENT_BEZIER_SCALE 0.33333333333333333 + +/* === G L O B A L S ======================================================= */ + +/* === P R O C E D U R E S ================================================= */ + +/* === M E T H O D S ======================================================= */ + +/* === E N T R Y P O I N T ================================================= */ + +Duckmatic::Duckmatic(): + type_mask(Duck::TYPE_ALL-Duck::TYPE_WIDTH), + grid_snap(false), + guide_snap(false), + grid_size(1.0/4.0,1.0/4.0), + show_persistant_strokes(true) +{ + axis_lock=false; + drag_offset_=Point(0,0); + clear_duck_dragger(); +} + +Duckmatic::~Duckmatic() +{ + clear_ducks(); + //synfig::info("Duckmatic::~Duckmatic(): Deleted. Duck Count=%d",Duck::duck_count); +} + +void +Duckmatic::clear_ducks() +{ + duck_data_share_map.clear(); + duck_map.clear(); + + //duck_list_.clear(); + bezier_list_.clear(); + stroke_list_.clear(); + + if(show_persistant_strokes) + stroke_list_=persistant_stroke_list_; +} + +//! Returns \a true if the given duck is currently selected +bool +Duckmatic::duck_is_selected(const etl::handle &duck)const +{ + return duck && selected_ducks.count(duck->get_guid()); +} + +void +Duckmatic::set_grid_size(const synfig::Vector &s) +{ + if(grid_size!=s) + { + grid_size=s; + signal_grid_changed(); + } +} + +void +Duckmatic::set_grid_snap(bool x) +{ + if(grid_snap!=x) + { + grid_snap=x; + signal_grid_changed(); + } +} + +void +Duckmatic::set_guide_snap(bool x) +{ + if(guide_snap!=x) + { + guide_snap=x; + signal_grid_changed(); + } +} + + + +Duckmatic::GuideList::iterator +Duckmatic::find_guide_x(synfig::Point pos, float radius) +{ + GuideList::iterator iter,best(guide_list_x_.end()); + float dist(radius); + for(iter=guide_list_x_.begin();iter!=guide_list_x_.end();++iter) + { + float amount(abs(*iter-pos[0])); + if(amount +Duckmatic::get_selected_duck()const +{ + if(selected_ducks.empty() || duck_map.empty()) + return 0; + return duck_map.find(*selected_ducks.begin())->second; +} + +void +Duckmatic::refresh_selected_ducks() +{ +/* + std::set >::iterator iter; + std::set > new_set; + if(duck_list().empty()) + { + selected_duck_list.clear(); + signal_duck_selection_changed_(); + return; + } + + for(iter=selected_duck_list.begin();iter!=selected_duck_list.end();++iter) + { + etl::handle similar(find_similar_duck(*iter)); + if(similar) + { + new_set.insert(similar); + } + } + selected_duck_list=new_set; +*/ + GUIDSet old_set(selected_ducks); + GUIDSet::const_iterator iter; + + for(iter=old_set.begin();iter!=old_set.end();++iter) + { + if(duck_map.count(*iter)==0) + selected_ducks.erase(*iter); + } + + signal_duck_selection_changed_(); +} + +bool +Duckmatic::is_duck_group_selectable(const etl::handle& x)const +{ + const Type type(get_type_mask()); + + if(( x->get_type() && (!(type & x->get_type())) ) ) + { + return false; + } + if(x->get_value_desc().parent_is_layer_param() && type & Duck::TYPE_POSITION) + { + Layer::Handle layer(x->get_value_desc().get_layer()); + String layer_name(layer->get_name()); + if( + layer_name=="outline" || + layer_name=="region" || + layer_name=="polygon" || + layer_name=="curve_gradient" + ) + return false; + if((layer_name=="PasteCanvas"|| layer_name=="paste_canvas") && + !layer->get_param("children_lock").get(bool())) + return false; + } + return true; +} + +void +Duckmatic::select_all_ducks() +{ + DuckMap::const_iterator iter; + for(iter=duck_map.begin();iter!=duck_map.end();++iter) + if(is_duck_group_selectable(iter->second)) + select_duck(iter->second); +} + +void +Duckmatic::toggle_select_ducks_in_box(const synfig::Vector& tl,const synfig::Vector& br) +{ + Vector vmin, vmax; + vmin[0]=std::min(tl[0],br[0]); + vmin[1]=std::min(tl[1],br[1]); + vmax[0]=std::max(tl[0],br[0]); + vmax[1]=std::max(tl[1],br[1]); + + DuckMap::const_iterator iter; + for(iter=duck_map.begin();iter!=duck_map.end();++iter) + { + Point p(iter->second->get_trans_point()); + if(p[0]<=vmax[0] && p[0]>=vmin[0] && p[1]<=vmax[1] && p[1]>=vmin[1] && + is_duck_group_selectable(iter->second)) + toggle_select_duck(iter->second); + } +} + +void +Duckmatic::select_ducks_in_box(const synfig::Vector& tl,const synfig::Vector& br) +{ + Vector vmin, vmax; + vmin[0]=std::min(tl[0],br[0]); + vmin[1]=std::min(tl[1],br[1]); + vmax[0]=std::max(tl[0],br[0]); + vmax[1]=std::max(tl[1],br[1]); + +// Type type(get_type_mask()); + + DuckMap::const_iterator iter; + for(iter=duck_map.begin();iter!=duck_map.end();++iter) + { + Point p(iter->second->get_trans_point()); + if(p[0]<=vmax[0] && p[0]>=vmin[0] && p[1]<=vmax[1] && p[1]>=vmin[1]) + { + if(is_duck_group_selectable(iter->second)) + select_duck(iter->second); + } + } +} + +int +Duckmatic::count_selected_ducks()const +{ + return selected_ducks.size(); +} + +void +Duckmatic::select_duck(const etl::handle &duck) +{ + if(duck) + { + selected_ducks.insert(duck->get_guid()); + signal_duck_selection_changed_(); + } +} + +DuckList +Duckmatic::get_selected_ducks()const +{ + DuckList ret; + GUIDSet::const_iterator iter; + const Type type(get_type_mask()); + + for(iter=selected_ducks.begin();iter!=selected_ducks.end();++iter) + { + const DuckMap::const_iterator d_iter(duck_map.find(*iter)); + + if(d_iter==duck_map.end()) + continue; + + if(( d_iter->second->get_type() && (!(type & d_iter->second->get_type())) ) ) + continue; + + ret.push_back(d_iter->second); + } + return ret; +} + +DuckList +Duckmatic::get_duck_list()const +{ + DuckList ret; + DuckMap::const_iterator iter; + for(iter=duck_map.begin();iter!=duck_map.end();++iter) + ret.push_back(iter->second); + return ret; +} + +void +Duckmatic::unselect_duck(const etl::handle &duck) +{ + if(duck && selected_ducks.count(duck->get_guid())) + { + selected_ducks.erase(duck->get_guid()); + signal_duck_selection_changed_(); + } +} + +void +Duckmatic::toggle_select_duck(const etl::handle &duck) +{ + if(duck_is_selected(duck)) + unselect_duck(duck); + else + select_duck(duck); +} + + +void +Duckmatic::translate_selected_ducks(const synfig::Vector& vector) +{ + if(duck_dragger_) + duck_dragger_->duck_drag(this,vector); +} + +void +Duckmatic::start_duck_drag(const synfig::Vector& offset) +{ + if(duck_dragger_) + duck_dragger_->begin_duck_drag(this,offset); + + //drag_offset_=offset; + drag_offset_=find_duck(offset)->get_trans_point(); +} + +bool +Duckmatic::end_duck_drag() +{ + if(duck_dragger_) + return duck_dragger_->end_duck_drag(this); + return false; +} + +Point +Duckmatic::snap_point_to_grid(const Point& x, float radius)const +{ + Point ret(x); + + GuideList::const_iterator guide_x,guide_y; + bool has_guide_x(false), has_guide_y(false); + + guide_x=find_guide_x(ret,radius); + if(guide_x!=guide_list_x_.end()) + has_guide_x=true; + + guide_y=find_guide_y(ret,radius); + if(guide_y!=guide_list_y_.end()) + has_guide_y=true; + + if(get_grid_snap()) + { + Point snap( + floor(ret[0]/get_grid_size()[0]+0.5)*get_grid_size()[0], + floor(ret[1]/get_grid_size()[1]+0.5)*get_grid_size()[1] + ); + + if(abs(snap[0]-ret[0])<=radius && (!has_guide_x || abs(snap[0]-ret[0])<=abs(*guide_x-ret[0]))) + ret[0]=snap[0],has_guide_x=false; + if(abs(snap[1]-ret[1])<=radius && (!has_guide_y || abs(snap[1]-ret[1])<=abs(*guide_y-ret[1]))) + ret[1]=snap[1],has_guide_y=false; + } + + if(guide_snap) + { + if(has_guide_x) + ret[0]=*guide_x; + if(has_guide_y) + ret[1]=*guide_y; + } + + if(axis_lock) + { + ret-=drag_offset_; + if(abs(ret[0])find_duck(offset)->get_trans_point(); + + snap=Vector(0,0); + } + + const DuckList selected_ducks(duckmatic->get_selected_ducks()); + DuckList::const_iterator iter; + + positions.clear(); + for(iter=selected_ducks.begin();iter!=selected_ducks.end();++iter) + { + Point p((*iter)->get_trans_point()); + positions.push_back(p); + } +} + +bool +DuckDrag_Translate::end_duck_drag(Duckmatic* duckmatic) +{ + if(last_translate_.mag()>0.0001) + { + duckmatic->signal_edited_selected_ducks(); + return true; + } + else + { + duckmatic->signal_user_click_selected_ducks(0); + return false; + } +} + +void +DuckDrag_Translate::duck_drag(Duckmatic* duckmatic, const synfig::Vector& vector) +{ + const DuckList selected_ducks(duckmatic->get_selected_ducks()); + DuckList::const_iterator iter; + + synfig::Vector vect(duckmatic->snap_point_to_grid(vector)-drag_offset_); + int i; + + for(i=0,iter=selected_ducks.begin();iter!=selected_ducks.end();++iter,i++) + { + if((*iter)->get_type()!=Duck::TYPE_VERTEX&&(*iter)->get_type()!=Duck::TYPE_POSITION)continue; + (*iter)->set_trans_point(positions[i]+vect); + } + for(i=0,iter=selected_ducks.begin();iter!=selected_ducks.end();++iter,i++) + { + if((*iter)->get_type()==Duck::TYPE_VERTEX||(*iter)->get_type()==Duck::TYPE_POSITION)continue; + (*iter)->set_trans_point(positions[i]+vect); + } + last_translate_=vect; +} + + + + + + + + + + +void +Duckmatic::signal_edited_selected_ducks() +{ + const DuckList ducks(get_selected_ducks()); + DuckList::const_iterator iter; + + synfig::GUIDSet old_set(selected_ducks); + + // If we have more than 20 things to move, then display + // something to explain that it may take a moment + smart_ptr wait; if(ducks.size()>20)wait.spawn(); + + // Go ahead and call everyone's signals + for(iter=ducks.begin();iter!=ducks.end();++iter) + { + if(!(*iter)->signal_edited()((*iter)->get_point())) + { + selected_ducks=old_set; + throw String("Bad edit"); + } + } + selected_ducks=old_set; +} + +void +Duckmatic::signal_user_click_selected_ducks(int button) +{ + const DuckList ducks(get_selected_ducks()); + DuckList::const_iterator iter; + + for(iter=ducks.begin();iter!=ducks.end();++iter) + { + (*iter)->signal_user_click(button)(); + } +} + + + + + +void +Duckmatic::add_duck(const etl::handle &duck) +{ + //if(!duck_map.count(duck->get_guid())) + { + if(duck_data_share_map.count(duck->get_data_guid())) + { + duck->set_shared_point(duck_data_share_map[duck->get_data_guid()]); + } + else + { + etl::smart_ptr point(new Point(duck->get_point())); + duck->set_shared_point(point); + duck_data_share_map[duck->get_data_guid()]=point; + } + + duck_map.insert(duck); + } + + last_duck_guid=duck->get_guid(); +} + +void +Duckmatic::add_bezier(const etl::handle &bezier) +{ + bezier_list_.push_back(bezier); +} + +void +Duckmatic::add_stroke(etl::smart_ptr > stroke_point_list, const synfig::Color& color) +{ + assert(stroke_point_list); + + std::list >::iterator iter; + + for(iter=stroke_list_.begin();iter!=stroke_list_.end();++iter) + { + if((*iter)->stroke_data==stroke_point_list) + return; + } + + etl::handle stroke(new Stroke()); + + stroke->stroke_data=stroke_point_list; + stroke->color=color; + + stroke_list_.push_back(stroke); +} + +void +Duckmatic::add_persistant_stroke(etl::smart_ptr > stroke_point_list, const synfig::Color& color) +{ + add_stroke(stroke_point_list,color); + persistant_stroke_list_.push_back(stroke_list_.back()); +} + +void +Duckmatic::clear_persistant_strokes() +{ + persistant_stroke_list_.clear(); +} + +void +Duckmatic::set_show_persistant_strokes(bool x) +{ + if(x!=show_persistant_strokes) + { + show_persistant_strokes=x; + if(x) + stroke_list_=persistant_stroke_list_; + else + stroke_list_.clear(); + } +} + +void +Duckmatic::erase_duck(const etl::handle &duck) +{ + duck_map.erase(duck->get_guid()); +} + +etl::handle +Duckmatic::find_similar_duck(etl::handle duck) +{ + DuckMap::const_iterator iter(duck_map.find(duck->get_guid())); + if(iter!=duck_map.end()) + return iter->second; + return 0; + +/* std::list >::reverse_iterator iter; + + for(iter=duck_list_.rbegin();iter!=duck_list_.rend();++iter) + { + if(*iter!=duck && **iter==*duck) + { + //synfig::info("Found similar duck! (iter:%08x vs. duck:%08x)",iter->get(), duck.get()); + return *iter; + } + } + return 0; +*/ +} + +etl::handle +Duckmatic::add_similar_duck(etl::handle duck) +{ + etl::handle similar(find_similar_duck(duck)); + if(!similar) + { + add_duck(duck); + return duck; + } + return similar; +} + +void +Duckmatic::erase_bezier(const etl::handle &bezier) +{ + std::list >::iterator iter; + + for(iter=bezier_list_.begin();iter!=bezier_list_.end();++iter) + { + if(*iter==bezier) + { + bezier_list_.erase(iter); + return; + } + } + synfig::warning("Unable to find bezier to erase!"); +} + +etl::handle +Duckmatic::last_duck()const +{ + DuckMap::const_iterator iter(duck_map.find(last_duck_guid)); + if(iter!=duck_map.end()) + return iter->second; + return 0; +} + +etl::handle +Duckmatic::last_bezier()const +{ + return bezier_list_.back(); +} + + +etl::handle +Duckmatic::find_duck(synfig::Point point, synfig::Real radius, Duck::Type type) +{ + if(radius==0)radius=10000000; + + if(type==Duck::TYPE_DEFAULT) + type=get_type_mask(); + + Real closest(10000000); + etl::handle ret; + + DuckMap::const_iterator iter; + + for(iter=duck_map.begin();iter!=duck_map.end();++iter) + { + const Duck::Handle& duck(iter->second); + + if(!duck->get_editable()) + continue; + Real dist((duck->get_trans_point()-point).mag_squared()); + + if(duck->get_type()&Duck::TYPE_VERTEX) + dist*=1.0001; + + if(dist<=closest && !( duck->get_type() && (!(type & duck->get_type())) ) ) + { + { + closest=dist; + ret=duck; + } + } + } + + if(radius==0 || closest +Duckmatic::find_bezier(synfig::Point point, synfig::Real radius,float* location) +{ + return find_bezier(point,radius,radius,location); +} + +etl::handle +Duckmatic::find_bezier(synfig::Point pos, synfig::Real scale, synfig::Real radius, float* location) +{ + if(radius==0)radius=10000000; + Real closest(10000000); + etl::handle ret; + + bezier curve; + + Real d,step; + float time = 0; + float best_time = 0; + + for(std::list >::const_iterator iter=bezier_list().begin();iter!=bezier_list().end();++iter) + { + curve[0] = (*iter)->p1->get_trans_point(); + curve[1] = (*iter)->c1->get_trans_point(); + curve[2] = (*iter)->c2->get_trans_point(); + curve[3] = (*iter)->p2->get_trans_point(); + curve.sync(); + +#if 0 + // I don't know why this doesn't work + time=curve.find_closest(pos,6); + d=((curve(time)-pos).mag_squared()); + +#else + //set the step size based on the size of the picture + d = (curve[1] - curve[0]).mag() + (curve[2]-curve[1]).mag() + (curve[3]-curve[2]).mag(); + + step = d/(2*scale); //want to make the distance between lines happy + + step = max(step,0.01); //100 samples should be plenty + step = min(step,0.1); //10 is minimum + + d = find_closest(curve,pos,step,&closest,&time); +#endif + + if(d < closest) + { + closest = d; + ret = *iter; + best_time=time; + } + } + + if(closest < radius*radius) + { + if(location) + *location = best_time; // We need to square-root this because we were dealing with squared distances + + return ret; + } + + return 0; +} + + + +bool +Duckmatic::save_sketch(const synfig::String& filename)const +{ + std::ofstream file(filename.c_str()); + + if(!file)return false; + + file<<"SKETCH"< >::const_iterator iter; + + for(iter=persistant_stroke_list_.begin();iter!=persistant_stroke_list_.end();++iter) + { + file<<"C " + <<(*iter)->color.get_r()<<' ' + <<(*iter)->color.get_g()<<' ' + <<(*iter)->color.get_b() + <::const_iterator viter; + for(viter=(*iter)->stroke_data->begin();viter!=(*iter)->stroke_data->end();++viter) + { + file<<"V " + <<(*viter)[0]<<' ' + <<(*viter)[1] + < > stroke_data; + + while(file) + { + getline(file,line); + + if(line.empty()) + continue; + + switch(line[0]) + { + case 'C': + case 'c': + { + stroke_data.spawn(); + float r,g,b; + if(!strscanf(line,"C %f %f %f",&r, &g, &b)) + { + synfig::warning("Bad color line \"%s\"",line.c_str()); + r=0;g=0;b=0; + } + add_persistant_stroke(stroke_data, synfig::Color(r,g,b)); + } + break; + case 'V': + case 'v': + if(!stroke_data) + { + stroke_data.spawn(); + add_persistant_stroke(stroke_data, synfig::Color(0,0,0)); + } + float x,y; + if(!strscanf(line,"V %f %f",&x, &y)) + synfig::warning("Bad vertex \"%s\"",line.c_str()); + else + stroke_data->push_back(synfig::Vector(x,y)); + break; + default: + synfig::warning("Unexpected sketch token '%c'",line[0]); + break; + } + } + + sketch_filename_=filename; + return true; +} + + + + + + + + +Duckmatic::Push::Push(Duckmatic *duckmatic_): + duckmatic_(duckmatic_) +{ + duck_map=duckmatic_->duck_map; + bezier_list_=duckmatic_->bezier_list_; + duck_data_share_map=duckmatic_->duck_data_share_map; + stroke_list_=duckmatic_->stroke_list_; + duck_dragger_=duckmatic_->duck_dragger_; + needs_restore=true; +} + +Duckmatic::Push::~Push() +{ + if(needs_restore) + restore(); +} + +void +Duckmatic::Push::restore() +{ + duckmatic_->duck_map=duck_map; + duckmatic_->bezier_list_=bezier_list_; + duckmatic_->duck_data_share_map=duck_data_share_map; + duckmatic_->stroke_list_=stroke_list_; + duckmatic_->duck_dragger_=duck_dragger_; + needs_restore=false; +} + + + + + + + + + +inline String guid_string(const synfigapp::ValueDesc& x) +{ + if(x.parent_is_layer_param()) + return strprintf("%s",x.get_layer()->get_guid().get_string().c_str())+x.get_param_name(); + //if(x.is_value_node()) + return strprintf("%s",x.get_value_node()->get_guid().get_string().c_str()); +} + +inline GUID calc_duck_guid(const synfigapp::ValueDesc& x,const synfig::TransformStack& transform_stack) +{ + GUID ret(0); + + if(x.parent_is_layer_param()) + { + ret=x.get_layer()->get_guid()^GUID::hasher(x.get_param_name()); + } + else + { + ret=x.get_value_node()->get_guid(); + } + + ret^=transform_stack.get_guid(); + return ret; +} + +/* +Duck::Handle +Duckmatic::create_duck_from(const synfigapp::ValueDesc& value_desc,etl::handle canvas_view, const synfig::TransformStack& transform_stack, int modifier, synfig::ParamDesc *param_desc) +{ + GUID duck_guid(calc_duck_guid(value_desc,transform_stack)^GUID::hasher(modifier)); + etl::handle duck=new Duck(); + + return duck; +} +*/ + +bool +Duckmatic::add_to_ducks(const synfigapp::ValueDesc& value_desc,etl::handle canvas_view, const synfig::TransformStack& transform_stack, synfig::ParamDesc *param_desc, int multiple) +{ + ValueBase::Type type=value_desc.get_value_type(); +#define REAL_COOKIE reinterpret_cast(28) + switch(type) + { + case ValueBase::TYPE_REAL: + + if(!param_desc || param_desc==REAL_COOKIE || !param_desc->get_origin().empty()) + { + etl::handle duck=new Duck(); + duck->set_transform_stack(transform_stack); + duck->set_radius(true); + duck->set_type(Duck::TYPE_RADIUS); + + duck->set_point(Point(value_desc.get_value(get_time()).get(Real()),0)); + duck->set_name(guid_string(value_desc)); + if(value_desc.is_value_node()) + { + // If the ValueNode can be directly manipulated, + // then set it as so. + duck->set_editable(synfigapp::is_editable(value_desc.get_value_node())); + } + else + { + duck->set_editable(true); + } + + if(param_desc && param_desc!=REAL_COOKIE) + { + if(!param_desc->get_origin().empty()) + { + synfigapp::ValueDesc value_desc_origin(value_desc.get_layer(),param_desc->get_origin()); + /* + duck->set_origin(value_desc_origin.get_value(get_time()).get(synfig::Point())); + */ + add_to_ducks(value_desc_origin,canvas_view, transform_stack); + duck->set_origin(last_duck()); + } + duck->set_scalar(param_desc->get_scalar()); + } + + duck->signal_edited().clear(); + duck->signal_edited().connect( + sigc::bind( + sigc::mem_fun( + *canvas_view, + &studio::CanvasView::on_duck_changed + ), + value_desc + ) + ); + duck->set_value_desc(value_desc); + + duck->signal_user_click(2).connect( + sigc::bind( + sigc::bind( + sigc::mem_fun( + *canvas_view, + &studio::CanvasView::popup_param_menu + ), + 0.0f + ), + value_desc + ) + ); + + duck->set_guid(calc_duck_guid(value_desc,transform_stack)^GUID::hasher(multiple)); + + add_duck(duck); + + return true; + } + break; + + case ValueBase::TYPE_ANGLE: + + if(!param_desc || param_desc==REAL_COOKIE || !param_desc->get_origin().empty()) + { + etl::handle duck=new Duck(); + duck->set_type(Duck::TYPE_ANGLE); + duck->set_transform_stack(transform_stack); + synfig::Angle angle; + + angle=value_desc.get_value(get_time()).get(Angle()); + duck->set_point(Point(Angle::cos(angle).get(),Angle::sin(angle).get())); + duck->set_name(guid_string(value_desc)); + if(value_desc.is_value_node()) + { + ValueNode::Handle value_node=value_desc.get_value_node(); + //duck->set_name(strprintf("%x",value_node.get())); + + // If the ValueNode can be directly manipulated, + // then set it as so. + duck->set_editable(synfigapp::is_editable(value_desc.get_value_node())); + } + else + { + //angle=(value_desc.get_value().get(Angle())); + //duck->set_point(Point(Angle::cos(angle).get(),Angle::sin(angle).get())); + //duck->set_name(strprintf("%x",value_desc.get_layer().get())+value_desc.get_param_name()); + duck->set_editable(true); + } + + if(param_desc && param_desc!=REAL_COOKIE) + { + if(!param_desc->get_origin().empty()) + { + synfigapp::ValueDesc value_desc_origin(value_desc.get_layer(),param_desc->get_origin()); + /* + duck->set_origin(value_desc_origin.get_value(get_time()).get(synfig::Point())); + */ + add_to_ducks(value_desc_origin,canvas_view, transform_stack); + duck->set_origin(last_duck()); + } + duck->set_scalar(param_desc->get_scalar()); + } + + duck->signal_edited().clear(); + duck->signal_edited().connect( + sigc::bind( + sigc::mem_fun( + *canvas_view, + &studio::CanvasView::on_duck_changed + ), + value_desc + ) + ); + duck->set_value_desc(value_desc); + + duck->signal_user_click(2).connect( + sigc::bind( + sigc::bind( + sigc::mem_fun( + *canvas_view, + &studio::CanvasView::popup_param_menu + ), + 0.0f + ), + value_desc + ) + ); + duck->set_guid(calc_duck_guid(value_desc,transform_stack)^GUID::hasher(multiple)); + + add_duck(duck); + + return true; + } + break; + + case ValueBase::TYPE_VECTOR: + { + etl::handle duck=new Duck(); + duck->set_transform_stack(transform_stack); + + duck->set_point(value_desc.get_value(get_time()).get(Point())); + duck->set_name(guid_string(value_desc)); + if(value_desc.is_value_node()) + { + //duck->set_name(strprintf("%x",value_desc.get_value_node().get())); + + // If the ValueNode can be directly manipulated, + // then set it as so. + duck->set_editable(synfigapp::is_editable(value_desc.get_value_node())); + } + else + { + //duck->set_point(value_desc.get_value().get(Point())); + //duck->set_name(strprintf("%x",value_desc.get_layer().get())+value_desc.get_param_name()); + duck->set_editable(true); + } + + // If we were passed a parameter description + if(param_desc) + { + if(!param_desc->get_connect().empty()) + { + synfigapp::ValueDesc value_desc_origin(value_desc.get_layer(),param_desc->get_connect()); + Duck::Handle connect_duck; + if(duck_map.find(calc_duck_guid(value_desc_origin,transform_stack)^GUID::hasher(0))!=duck_map.end()) + { + connect_duck=duck_map[calc_duck_guid(value_desc_origin,transform_stack)^GUID::hasher(0)]; + } + else + { + add_to_ducks(value_desc_origin,canvas_view, transform_stack); + connect_duck=last_duck(); + } + duck->set_connect_duck(connect_duck); + } + if(!param_desc->get_box().empty()) + { + synfigapp::ValueDesc value_desc_origin(value_desc.get_layer(),param_desc->get_box()); + add_to_ducks(value_desc_origin,canvas_view, transform_stack); + duck->set_box_duck(last_duck()); + } + + // If we have an origin + if(!param_desc->get_origin().empty()) + { + synfigapp::ValueDesc value_desc_origin(value_desc.get_layer(),param_desc->get_origin()); + /* + duck->set_origin(value_desc_origin.get_value(get_time()).get(synfig::Point())); + */ + add_to_ducks(value_desc_origin,canvas_view, transform_stack); + duck->set_origin(last_duck()); + duck->set_type(Duck::TYPE_VERTEX); + } + else + duck->set_type(Duck::TYPE_POSITION); + + duck->set_scalar(param_desc->get_scalar()); + } + else + duck->set_type(Duck::TYPE_POSITION); + + + duck->signal_edited().clear(); + duck->signal_edited().connect( + sigc::bind( + sigc::mem_fun( + *canvas_view, + &studio::CanvasView::on_duck_changed + ), + value_desc + ) + ); + duck->set_value_desc(value_desc); + + duck->signal_user_click(2).connect( + sigc::bind( + sigc::bind( + sigc::mem_fun( + *canvas_view, + &studio::CanvasView::popup_param_menu + ), + 1.0f + ), + value_desc + ) + ); + duck->set_guid(calc_duck_guid(value_desc,transform_stack)^GUID::hasher(multiple)); + add_duck(duck); + + return true; + } + break; +/* case ValueBase::TYPE_SEGMENT: + { + etl::handle bezier(new Bezier()); + ValueNode_Composite::Handle value_node; + + if(value_desc.is_value_node() && + (value_node=ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node())) + ) + { + if(!add_to_ducks(synfigapp::ValueDesc(value_node,0),canvas_view,transform_stack)) + return false; + bezier->p1=last_duck(); + bezier->p1->set_type(Duck::TYPE_VERTEX); + if(!add_to_ducks(synfigapp::ValueDesc(value_node,1),canvas_view,transform_stack)) + return false; + bezier->c1=last_duck(); + bezier->c1->set_type(Duck::TYPE_TANGENT); + bezier->c1->set_origin(bezier->p1); + bezier->c1->set_scalar(TANGENT_BEZIER_SCALE); + bezier->c1->set_tangent(true); + + + if(!add_to_ducks(synfigapp::ValueDesc(value_node,2),canvas_view,transform_stack)) + return false; + bezier->p2=last_duck(); + bezier->p2->set_type(Duck::TYPE_VERTEX); + if(!add_to_ducks(synfigapp::ValueDesc(value_node,3),canvas_view,transform_stack)) + return false; + bezier->c2=last_duck(); + bezier->c2->set_type(Duck::TYPE_TANGENT); + bezier->c2->set_origin(bezier->p2); + bezier->c2->set_scalar(-TANGENT_BEZIER_SCALE); + bezier->c2->set_tangent(true); + + bezier->signal_user_click(2).connect( + sigc::bind( + sigc::mem_fun( + *canvas_view, + &studio::CanvasView::popup_param_menu_bezier + ), + value_desc + ) + ); + + add_bezier(bezier); + } + else if(value_desc.get_value().is_valid()) + { + Segment segment=value_desc.get_value(); + etl::handle duck_p,duck_c; + synfig::String name; + if(param_desc) + { + name=param_desc->get_local_name(); + } + else + { + name=guid_string(value_desc); + } + + duck_p=new class Duck(segment.p1); + duck_p->set_name(name+".P1"); + duck_p->set_type(Duck::TYPE_VERTEX); + add_duck(duck_p); + + duck_c=new class Duck(segment.t1); + duck_c->set_name(name+".T1"); + duck_c->set_type(Duck::TYPE_TANGENT); + add_duck(duck_c); + duck_c->set_origin(duck_p); + duck_c->set_scalar(TANGENT_HANDLE_SCALE); + duck_c->set_tangent(true); + + bezier->p1=duck_p; + bezier->c1=duck_c; + + duck_p=new class Duck(segment.p2); + duck_p->set_name(name+".P2"); + duck_p->set_type(Duck::TYPE_VERTEX); + add_duck(duck_p); + + duck_c=new class Duck(segment.t2); + duck_c->set_type(Duck::TYPE_TANGENT); + duck_c->set_name(name+".T2"); + add_duck(duck_c); + duck_c->set_origin(duck_p); + duck_c->set_scalar(-TANGENT_HANDLE_SCALE); + duck_c->set_tangent(true); + + bezier->p2=duck_p; + bezier->c2=duck_c; + add_bezier(bezier); + } + + return true; + } + break; +*/ + case ValueBase::TYPE_BLINEPOINT: + { + + if(value_desc.is_value_node() && + ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()) + ) + { + ValueNode_Composite::Handle value_node; + value_node=ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()); + + + if(!add_to_ducks(synfigapp::ValueDesc(value_node,0),canvas_view,transform_stack)) + return false; + etl::handle vertex_duck(last_duck()); + vertex_duck->set_type(Duck::TYPE_VERTEX); + if(!add_to_ducks(synfigapp::ValueDesc(value_node,4),canvas_view,transform_stack)) + return false; + etl::handle t1_duck(last_duck()); + + t1_duck->set_origin(vertex_duck); + t1_duck->set_scalar(-TANGENT_HANDLE_SCALE); + t1_duck->set_tangent(true); + + etl::handle t2_duck; + + // If the tangents are split + if((*value_node->get_link("split"))(get_time()).get(bool())) + { + if(!add_to_ducks(synfigapp::ValueDesc(value_node,5),canvas_view,transform_stack)) + return false; + t2_duck=last_duck(); + t2_duck->set_origin(vertex_duck); + t2_duck->set_scalar(TANGENT_HANDLE_SCALE); + t2_duck->set_tangent(true); + } + else + { + if(!add_to_ducks(synfigapp::ValueDesc(value_node,4),canvas_view,transform_stack)) + return false; + t2_duck=last_duck(); + t2_duck->set_origin(vertex_duck); + t2_duck->set_scalar(TANGENT_HANDLE_SCALE); + t2_duck->set_tangent(true); + } + return true; + } + + } + break; + case ValueBase::TYPE_LIST: + { + // Check for BLine + if(value_desc.is_value_node() && + ValueNode_BLine::Handle::cast_dynamic(value_desc.get_value_node()) + ) + { + ValueNode_BLine::Handle value_node; + value_node=ValueNode_BLine::Handle::cast_dynamic(value_desc.get_value_node()); + + int i,first=-1; + + etl::handle bezier; + etl::handle first_duck; + etl::handle duck, tduck; + + for(i=0;ilink_count();i++) + { + float amount(value_node->list[i].amount_at_time(get_time())); + if(amount<0.9999f) + continue; + if(first==-1)first=i; + + BLinePoint bline_point((*value_node->get_link(i))(get_time())); + + ValueNode_Composite::Handle vertex_value_node( + ValueNode_Composite::Handle::cast_dynamic( + value_node->get_link(i) + ) + ); + + // Add the vertex duck + if(vertex_value_node) + { + if(add_to_ducks(synfigapp::ValueDesc(vertex_value_node,0),canvas_view,transform_stack)) + { + duck=last_duck(); + if(i==first) + first_duck=duck; + duck->set_type(Duck::TYPE_VERTEX); + + duck->signal_user_click(2).clear(); + duck->signal_user_click(2).connect( + sigc::bind( + sigc::bind( + sigc::mem_fun( + *canvas_view, + &studio::CanvasView::popup_param_menu + ), + 1.0f + ), + synfigapp::ValueDesc(value_node,i) + ) + ); + duck->set_value_desc(synfigapp::ValueDesc(value_node,i)); + + if(param_desc) + { + if(!param_desc->get_origin().empty()) + { + synfigapp::ValueDesc value_desc_origin(value_desc.get_layer(),param_desc->get_origin()); + add_to_ducks(value_desc_origin,canvas_view, transform_stack); + duck->set_origin(last_duck()); +/* + ValueBase value(synfigapp::ValueDesc(value_desc.get_layer(),param_desc->get_origin()).get_value(get_time())); + if(value.same_type_as(synfig::Point())) + duck->set_origin(value.get(synfig::Point())); +*/ + } + } + } + else + return false; + } + else + { + duck=new Duck(bline_point.get_vertex()); + if(i==first) + first_duck=duck; + duck->set_transform_stack(transform_stack); + duck->set_editable(false); + //duck->set_name(strprintf("%x-vertex",value_node->get_link(i).get())); + duck->set_name(guid_string(synfigapp::ValueDesc(value_node,i))+".v"); + + duck->set_type(Duck::TYPE_VERTEX); + if(param_desc) + { + if(!param_desc->get_origin().empty()) + { + synfigapp::ValueDesc value_desc_origin(value_desc.get_layer(),param_desc->get_origin()); + add_to_ducks(value_desc_origin,canvas_view, transform_stack); + duck->set_origin(last_duck()); +/* + ValueBase value(synfigapp::ValueDesc(value_desc.get_layer(),param_desc->get_origin()).get_value(get_time())); + if(value.same_type_as(synfig::Point())) + duck->set_origin(value.get(synfig::Point())); +*/ + } + } + duck->set_guid(calc_duck_guid(synfigapp::ValueDesc(value_node,i),transform_stack)^GUID::hasher(".v")); + duck=add_similar_duck(duck); +// add_duck(duck); + } + + // Add the width duck only if we have a hint of scale + if(param_desc && !param_desc->get_hint().empty()) + { + etl::handle width; + if(add_to_ducks(synfigapp::ValueDesc(vertex_value_node,1),canvas_view,transform_stack,REAL_COOKIE)) + { + width=last_duck(); + width->set_origin(duck); + width->set_type(Duck::TYPE_WIDTH); + width->set_name(guid_string(synfigapp::ValueDesc(value_node,i))+".w"); + { + ValueBase value(synfigapp::ValueDesc(value_desc.get_layer(),param_desc->get_hint()).get_value(get_time())); + if(value.same_type_as(synfig::Real())) + width->set_scalar(value.get(synfig::Real())*0.5f); + } + } + else + synfig::error("Unable to add width duck!"); + } + + if(bezier) + { + // Add the tangent1 duck + if(vertex_value_node) + { + if(!add_to_ducks(synfigapp::ValueDesc(vertex_value_node,4),canvas_view,transform_stack)) + return false; + tduck=last_duck(); + } + else + { + tduck=new Duck(bline_point.get_tangent1()); + tduck->set_transform_stack(transform_stack); + tduck->set_editable(false); + tduck->set_name(guid_string(synfigapp::ValueDesc(value_node,i))+".t1"); +// tduck->set_name(strprintf("%x-tangent1",value_node->get_link(i).get())); + tduck->set_guid(calc_duck_guid(synfigapp::ValueDesc(value_node,i),transform_stack)^GUID::hasher(".t1")); + tduck=add_similar_duck(tduck); +// add_duck(duck); + } + + tduck->set_origin(duck); + tduck->set_scalar(-TANGENT_BEZIER_SCALE); + tduck->set_tangent(true); + + bezier->p2=duck; + bezier->c2=tduck; + + bezier->signal_user_click(2).connect( + sigc::bind( + sigc::mem_fun( + *canvas_view, + &studio::CanvasView::popup_param_menu_bezier + ), + synfigapp::ValueDesc(value_node,i) + ) + ); + + duck->signal_user_click(2).clear(); + duck->signal_user_click(2).connect( + sigc::bind( + sigc::bind( + sigc::mem_fun( + *canvas_view, + &studio::CanvasView::popup_param_menu + ), + 1.0f + ), + synfigapp::ValueDesc(value_node,i) + ) + ); + duck->set_value_desc(synfigapp::ValueDesc(value_node,i)); + + add_bezier(bezier); + bezier=0; + } + + if(i+1>=value_node->link_count() && !value_node->get_loop()) + continue; + + bezier=new Bezier(); + + // Add the tangent2 duck + if(vertex_value_node) + { + int i=bline_point.get_split_tangent_flag()?5:4; + if(!add_to_ducks(synfigapp::ValueDesc(vertex_value_node,i),canvas_view,transform_stack,0,2)) + return false; + tduck=last_duck(); + } + else + { + if(bline_point.get_split_tangent_flag()) + { + tduck=new Duck(bline_point.get_tangent2()); + tduck->set_transform_stack(transform_stack); + //tduck->set_name(strprintf("%x-tangent2",value_node->get_link(i).get())); + tduck->set_name(guid_string(synfigapp::ValueDesc(value_node,i))+".t2"); + tduck->set_guid(calc_duck_guid(synfigapp::ValueDesc(value_node,i),transform_stack)^GUID::hasher(".t2")); + } + else + { + tduck=new Duck(bline_point.get_tangent1()); + tduck->set_transform_stack(transform_stack); + //tduck->set_name(strprintf("%x-tangent1",value_node->get_link(i).get())); + tduck->set_name(guid_string(synfigapp::ValueDesc(value_node,i))+".t1"); + tduck->set_guid(calc_duck_guid(synfigapp::ValueDesc(value_node,i),transform_stack)^GUID::hasher(".t1")); + } + tduck->set_editable(false); + tduck=add_similar_duck(tduck); +// add_duck(duck); + if(param_desc) + { + synfigapp::ValueDesc value_desc_origin(value_desc.get_layer(),param_desc->get_origin()); + add_to_ducks(value_desc_origin,canvas_view, transform_stack); + duck->set_origin(last_duck()); +/* + ValueBase value(synfigapp::ValueDesc(value_desc.get_layer(),param_desc->get_origin()).get_value(get_time())); + if(value.same_type_as(synfig::Point())) + duck->set_origin(value.get(synfig::Point())); +*/ +// if(!param_desc->get_origin().empty()) +// duck->set_origin(synfigapp::ValueDesc(value_desc.get_layer(),param_desc->get_origin()).get_value(get_time()).get(synfig::Point())); + } + duck->signal_user_click(2).clear(); + duck->signal_user_click(2).connect( + sigc::bind( + sigc::bind( + sigc::mem_fun( + *canvas_view, + &studio::CanvasView::popup_param_menu + ), + 1.0f + ), + synfigapp::ValueDesc(value_node,0) + ) + ); + duck->set_value_desc(synfigapp::ValueDesc(value_node,0)); + + } + + tduck->set_origin(duck); + tduck->set_scalar(TANGENT_BEZIER_SCALE); + tduck->set_tangent(true); + + bezier->p1=duck; + bezier->c1=tduck; + + } + // Loop if necessary + if(bezier && value_node->get_loop()) + { + BLinePoint bline_point((*value_node->get_link(first))(get_time())); + + ValueNode_Composite::Handle vertex_value_node( + ValueNode_Composite::Handle::cast_dynamic( + value_node->get_link(first) + ) + ); + + // Add the vertex duck + duck=first_duck; + /* + if(vertex_value_node) + { + if(!add_to_ducks(synfigapp::ValueDesc(vertex_value_node,0),canvas_view,transform_stack)) + return false; + duck=last_duck(); + if(param_desc) + { + if(!param_desc->get_origin().empty()) + duck->set_origin(value_desc.get_layer()->get_param(param_desc->get_origin()).get(synfig::Point())); + } + duck->set_type(Duck::TYPE_VERTEX); + } + else + { + duck=new Duck(bline_point.get_vertex()); + duck->set_transform_stack(transform_stack); + if(param_desc) + { + if(!param_desc->get_origin().empty()) + duck->set_origin(value_desc.get_layer()->get_param(param_desc->get_origin()).get(synfig::Point())); + } + duck->set_editable(false); + duck->set_name(strprintf("%x-vertex",value_node->get_link(first).get())); + duck->set_type(Duck::TYPE_VERTEX); + duck=add_similar_duck(duck); + } + */ + + // Add the tangent1 duck + if(vertex_value_node) + { + if(!add_to_ducks(synfigapp::ValueDesc(vertex_value_node,4),canvas_view,transform_stack)) + return false; + tduck=last_duck(); + } + else + { + tduck=new Duck(bline_point.get_tangent1()); + tduck->set_transform_stack(transform_stack); + tduck->set_editable(false); + tduck->set_name(guid_string(synfigapp::ValueDesc(value_node,first))+".t1"); + //tduck->set_name(strprintf("%x-tangent1",value_node->get_link(first).get())); + tduck=add_similar_duck(tduck); + tduck->set_guid(calc_duck_guid(synfigapp::ValueDesc(value_node,i),transform_stack)^GUID::hasher(".t1")); + //add_duck(duck); + } + + tduck->set_origin(duck); + tduck->set_scalar(-TANGENT_BEZIER_SCALE); + tduck->set_tangent(true); + + bezier->p2=duck; + bezier->c2=tduck; + bezier->signal_user_click(2).connect( + sigc::bind( + sigc::mem_fun( + *canvas_view, + &studio::CanvasView::popup_param_menu_bezier + ), + synfigapp::ValueDesc(value_node,first) + ) + ); + duck->signal_user_click(2).clear(); + duck->signal_user_click(2).connect( + sigc::bind( + sigc::bind( + sigc::mem_fun( + *canvas_view, + &studio::CanvasView::popup_param_menu + ), + 1.0f + ), + synfigapp::ValueDesc(value_node,first) + ) + ); + duck->set_value_desc(synfigapp::ValueDesc(value_node,first)); + + add_bezier(bezier); + bezier=0; + + } + return true; + } + else // Check for DynamicList + if(value_desc.is_value_node() && + ValueNode_DynamicList::Handle::cast_dynamic(value_desc.get_value_node()) + ) + { + ValueNode_DynamicList::Handle value_node; + value_node=ValueNode_DynamicList::Handle::cast_dynamic(value_desc.get_value_node()); + int i; + + if(value_node->get_contained_type()==ValueBase::TYPE_VECTOR) + { + Bezier bezier; + for(i=0;ilink_count();i++) + { + if(!value_node->list[i].status_at_time(get_time())) + continue; + if(!add_to_ducks(synfigapp::ValueDesc(value_node,i),canvas_view,transform_stack)) + return false; + etl::handle duck(last_duck()); + + if(param_desc) + { + synfigapp::ValueDesc value_desc_origin(value_desc.get_layer(),param_desc->get_origin()); + add_to_ducks(value_desc_origin,canvas_view, transform_stack); + duck->set_origin(last_duck()); +/* + ValueBase value(synfigapp::ValueDesc(value_desc.get_layer(),param_desc->get_origin()).get_value(get_time())); + if(value.same_type_as(synfig::Point())) + duck->set_origin(value.get(synfig::Point())); +*/ +// if(!param_desc->get_origin().empty()) +// last_duck()->set_origin(synfigapp::ValueDesc(value_desc.get_layer(),param_desc->get_origin()).get_value(get_time()).get(synfig::Point())); + } + duck->set_type(Duck::TYPE_VERTEX); + bezier.p1=bezier.p2;bezier.c1=bezier.c2; + bezier.p2=bezier.c2=duck; + + if(i>0) + { + handle bezier_(new Bezier()); + bezier_->p1=bezier.p1; + bezier_->c1=bezier.c1; + bezier_->p2=bezier.p2; + bezier_->c2=bezier.c2; + add_bezier(bezier_); + last_bezier()->signal_user_click(2).connect( + sigc::bind( + sigc::mem_fun( + *canvas_view, + &studio::CanvasView::popup_param_menu_bezier + ), + synfigapp::ValueDesc(value_node,i) + ) + ); + } + } + } + /*else if(value_node->get_contained_type()==ValueBase::TYPE_SEGMENT) + { + for(i=0;ilink_count();i++) + { + if(!value_node->list[i].status_at_time(get_time())) + continue; + if(!add_to_ducks(synfigapp::ValueDesc(value_node,i),canvas_view,transform_stack)) + return false; + } + } + */ + else + return false; + } + else + { + // WRITEME + } + + return true; + } + + + break; + default: + break; + } + return false; +}