1 /* === S Y N F I G ========================================================= */
2 /*! \file cellrenderer_timetrack.cpp
3 ** \brief Template Header
5 ** $Id: cellrenderer_timetrack.cpp,v 1.4 2005/01/13 20:23:01 darco Exp $
8 ** Copyright (c) 2002 Robert B. Quattlebaum Jr.
10 ** This software and associated documentation
11 ** are CONFIDENTIAL and PROPRIETARY property of
12 ** the above-mentioned copyright holder.
14 ** You may not copy, print, publish, or in any
15 ** other way distribute this software without
16 ** a prior written agreement with
17 ** the copyright holder.
20 /* ========================================================================= */
22 /* === H E A D E R S ======================================================= */
31 #include <gtkmm/label.h>
32 #include "cellrenderer_timetrack.h"
34 #include <gtkmm/spinbutton.h>
35 #include <gtkmm/combo.h>
36 #include <ETL/stringf>
37 #include "widget_value.h"
39 #include <gtkmm/menu.h>
40 #include <gtkmm/optionmenu.h>
41 #include "widget_time.h"
42 #include "widget_timeslider.h"
44 #include <synfigapp/canvasinterface.h>
47 #include <synfig/timepointcollect.h>
51 using namespace synfig;
54 using namespace studio;
56 /* === M A C R O S ========================================================= */
58 /* === G L O B A L S ======================================================= */
60 static char stipple_xpm[] = { 2, 0 };
62 //mode for modifier keys
66 SELECT_MASK = Gdk::CONTROL_MASK,
67 COPY_MASK = Gdk::SHIFT_MASK,
68 DELETE_MASK = Gdk::MOD1_MASK
71 /* === P R O C E D U R E S ================================================= */
73 /* === M E T H O D S ======================================================= */
75 CellRenderer_TimeTrack::CellRenderer_TimeTrack():
76 Glib::ObjectBase (typeid(CellRenderer_TimeTrack)),
78 adjustment_ (10,10,20,0,0,0),
80 property_valuedesc_ (*this,"value_desc",synfigapp::ValueDesc()),
81 property_canvas_ (*this,"canvas",synfig::Canvas::Handle()),
82 property_adjustment_(*this,"adjustment",&adjustment_),
83 property_enable_timing_info_(*this,"enable-timing-info", false)
89 CellRenderer_TimeTrack::~CellRenderer_TimeTrack()
91 synfig::info("CellRenderer_TimeTrack::~CellRenderer_TimeTrack(): deleted");
95 CellRenderer_TimeTrack::set_adjustment(Gtk::Adjustment &x)
97 property_adjustment_=&x;
98 // x.signal_value_changed().connect(sigc::mem_fun(*this,&Gtk::Widget::queue_draw));
101 synfig::Canvas::Handle
102 CellRenderer_TimeTrack::get_canvas()const
104 return const_cast<CellRenderer_TimeTrack*>(this)->property_canvas().get_value();
108 CellRenderer_TimeTrack::get_adjustment()
110 return (Gtk::Adjustment*)property_adjustment_;
113 const Gtk::Adjustment *
114 CellRenderer_TimeTrack::get_adjustment()const
116 return (const Gtk::Adjustment*)property_adjustment_;
120 CellRenderer_TimeTrack::is_selected(const Waypoint& waypoint)const
122 return selected==waypoint;
125 //kind of a hack... pointer is ugly
126 const synfig::Node::time_set *get_times_from_vdesc(const synfigapp::ValueDesc &v)
128 if(v.get_value_type() == synfig::ValueBase::TYPE_CANVAS)
130 synfig::Canvas::Handle canvasparam = v.get_value().get(Canvas::Handle());
134 return &canvasparam->get_times();
138 ValueNode *base_value = v.get_value_node().get();
140 ValueNode_DynamicList *parent_value_node =
141 v.parent_is_value_node() ?
142 dynamic_cast<ValueNode_DynamicList *>(v.get_parent_value_node().get()) :
145 //we want a dynamic list entry to override the normal...
146 if(parent_value_node)
148 return &parent_value_node->list[v.get_index()].get_times();
149 }else if(base_value) //don't render stuff if it's just animated...
151 return &base_value->get_times();
156 bool get_closest_time(const synfig::Node::time_set &tset, const Time &t, const Time &range, Time &out)
158 Node::time_set::const_iterator i,j,end = tset.end();
160 //TODO add in RangeGet so it's not so damn hard to click on points
162 i = tset.upper_bound(t); //where t is the lower bound, t < [first,i)
165 double dist = Time::end();
170 closest = i->get_time();
171 dist = abs(i->get_time() - t);
174 if(j != end && (abs(j->get_time() - t) < dist) )
176 closest = j->get_time();
177 dist = abs(j->get_time() - t);
180 if( dist <= range/2 )
190 CellRenderer_TimeTrack::render_vfunc(
191 const Glib::RefPtr<Gdk::Drawable>& window,
193 const Gdk::Rectangle& background_area,
194 const Gdk::Rectangle& area_,
195 const Gdk::Rectangle& expose_area,
196 Gtk::CellRendererState flags)
201 Glib::RefPtr<Gdk::GC> gc(Gdk::GC::create(window));
202 Glib::RefPtr<Gdk::GC> inactive_gc(Gdk::GC::create(window));
203 Gtk::Adjustment *adjustment=get_adjustment();
204 Gtk::StateType state = Gtk::STATE_ACTIVE;
205 Gtk::ShadowType shadow;
208 curr_time_color("#0000ff"),
209 inactive_color("#000000"),
210 keyframe_color("#a07f7f");
211 Gdk::Color activepoint_color[2];
213 activepoint_color[0]=Gdk::Color("#ff0000");
214 activepoint_color[1]=Gdk::Color("#00ff00");
216 inactive_gc->set_rgb_fg_color(inactive_color);
217 inactive_gc->set_stipple(Gdk::Bitmap::create(stipple_xpm,2,2));
218 inactive_gc->set_fill(Gdk::STIPPLED);
220 synfig::Canvas::Handle canvas(property_canvas().get_value());
222 synfigapp::ValueDesc value_desc = property_value_desc().get_value();
223 synfig::ValueNode *base_value = value_desc.get_value_node().get();
224 synfig::ValueNode_Animated *value_node=dynamic_cast<synfig::ValueNode_Animated*>(base_value);
226 synfig::ValueNode_DynamicList *parent_value_node(0);
227 if(property_value_desc().get_value().parent_is_value_node())
228 parent_value_node=dynamic_cast<synfig::ValueNode_DynamicList*>(property_value_desc().get_value().get_parent_value_node().get());
230 // If the canvas is defined, then load up the keyframes
233 const synfig::KeyframeList& keyframe_list(canvas->keyframe_list());
234 synfig::KeyframeList::const_iterator iter;
236 for(iter=keyframe_list.begin();iter!=keyframe_list.end();++iter)
238 if(!iter->get_time().is_valid())
241 const int x((int)((float)area_.get_width()/(adjustment->get_upper()-adjustment->get_lower())*(iter->get_time()-adjustment->get_lower())));
242 if(iter->get_time()>=adjustment->get_lower() && iter->get_time()<adjustment->get_upper())
244 gc->set_rgb_fg_color(keyframe_color);
245 window->draw_rectangle(gc, true, area_.get_x()+x, area_.get_y(), 1, area_.get_height()+1);
250 //render all the time points that exist
252 const synfig::Node::time_set *tset = get_times_from_vdesc(value_desc);
256 synfig::Node::time_set::const_iterator i = tset->begin(), end = tset->end();
258 float lower = adjustment->get_lower(),
259 upper = adjustment->get_upper();
261 Glib::RefPtr<Gdk::GC> gc = Gdk::GC::create(widget.get_window());
263 Gdk::Rectangle area(area_);
264 gc->set_clip_rectangle(area);
265 gc->set_line_attributes(1,Gdk::LINE_SOLID,Gdk::CAP_BUTT,Gdk::JOIN_MITER);
267 bool valselected = sel_value.get_value_node() == base_value && !sel_times.empty();
269 float cfps = get_canvas()->rend_desc().get_frame_rate();
271 vector<Time> drawredafter;
273 Time diff = actual_time - actual_dragtime;//selected_time-drag_time;
276 //find the coordinate in the drawable space...
277 Time t = i->get_time();
282 //if it found it... (might want to change comparison, and optimize
283 // sel_times.find to not produce an overall nlogn solution)
286 //not dragging... just draw as per normal
287 //if move dragging draw offset
288 //if copy dragging draw both...
290 if(valselected && sel_times.find(t) != sel_times.end())
292 if(dragging) //skip if we're dragging because we'll render it later
294 if(mode & COPY_MASK) // draw both blue and red moved
296 drawredafter.push_back((t + diff).round(cfps));
297 gc->set_rgb_fg_color(Gdk::Color("#00EEEE"));
298 }else if(mode & DELETE_MASK) //it's just red...
300 gc->set_rgb_fg_color(Gdk::Color("#EE0000"));
302 }else //move - draw the red on top of the others...
304 drawredafter.push_back((t + diff).round(cfps));
309 gc->set_rgb_fg_color(Gdk::Color("#EE0000"));
314 gc->set_rgb_fg_color(Gdk::Color("#00EEEE"));
317 //synfig::info("Displaying time: %.3f s",(float)t);
318 const int x = (int)((t-lower)*area.get_width()/(upper-lower));
320 //should draw me a grey filled circle...
321 Gdk::Rectangle area2(
322 area.get_x() - area.get_height()/2 + x + 1,
327 render_time_point_to_window(window,area2,*i,selected);
329 /*window->draw_arc(gc,true,
330 area.get_x() + x - area.get_height()/4, area.get_y() + area.get_height()/8,
331 area.get_height()/2, area.get_height()*3/4,
334 gc->set_rgb_fg_color(Gdk::Color("#000000"));
335 window->draw_arc(gc,false,
336 area.get_x() + x - area.get_height()/4, area.get_y() + area.get_height()/8,
337 area.get_height()/2, area.get_height()*3/4,
343 vector<Time>::iterator i = drawredafter.begin(), end = drawredafter.end();
346 //find the coordinate in the drawable space...
352 //synfig::info("Displaying time: %.3f s",(float)t);
353 const int x = (int)((t-lower)*area.get_width()/(upper-lower));
355 //should draw me a grey filled circle...
357 Gdk::Rectangle area2(
358 area.get_x() - area.get_height()/2 + x + 1,
363 render_time_point_to_window(window,area2,*i,true);
364 /* gc->set_rgb_fg_color(Gdk::Color("#EE0000"));
365 window->draw_arc(gc,true,
366 area.get_x() + x - area.get_height()/4, area.get_y() + area.get_height()/8,
367 area.get_height()/2, area.get_height()*3/4,
370 gc->set_rgb_fg_color(Gdk::Color("#000000"));
371 window->draw_arc(gc,false,
372 area.get_x() + x - area.get_height()/4, area.get_y() + area.get_height()/8,
373 area.get_height()/2, area.get_height()*3/4,
381 /* THIS IS NOW HANDLED ENTIRELY BY THE TIMEPOINT SYSTEM
382 // This this is an animated value node, then render the waypoints
385 //now render the actual waypoints
386 synfig::ValueNode_Animated::WaypointList::iterator iter;
388 iter=value_node->waypoint_list().begin();
389 iter!=value_node->waypoint_list().end();
393 if(!iter->get_time().is_valid())
397 if(is_selected(*iter))
399 Time t(iter->get_time());
403 t=(t+selected_time-drag_time).round(get_canvas()->rend_desc().get_frame_rate());
405 x=(int)((float)area.get_width()/(adjustment->get_upper()-adjustment->get_lower())*(t-adjustment->get_lower()));
406 shadow=Gtk::SHADOW_IN;
411 x=(int)((float)area.get_width()/(adjustment->get_upper()-adjustment->get_lower())*(iter->get_time()-adjustment->get_lower()));
412 shadow=Gtk::SHADOW_OUT;
417 widget.get_style()->paint_diamond(
418 Glib::RefPtr<Gdk::Window>::cast_static(window),
424 area.get_x()+x-area.get_height()/4,
425 area.get_y()+area.get_height()/4,
432 Gdk::Rectangle area(area_);
433 // If the parent of this value node is a dynamic list, then
434 // render the on and off times
435 if(parent_value_node)
437 const int index(property_value_desc().get_value().get_index());
438 const synfig::ValueNode_DynamicList::ListEntry& list_entry(parent_value_node->list[index]);
439 const synfig::ValueNode_DynamicList::ListEntry::ActivepointList& activepoint_list(list_entry.timing_info);
440 synfig::ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator iter,next;
443 if(!activepoint_list.empty())
444 is_off=!activepoint_list.front().state;
449 for(next=activepoint_list.begin(),iter=next++;iter!=activepoint_list.end();iter=next++)
451 x=((int)((float)area.get_width()/(adjustment->get_upper()-adjustment->get_lower())*(iter->time-adjustment->get_lower())));
453 if(x>area.get_width())x=area.get_width();
455 bool status_at_time=0;
456 if(next!=activepoint_list.end())
458 status_at_time=!list_entry.status_at_time((iter->time+next->time)/2.0);
461 status_at_time=!list_entry.status_at_time(Time::end());
463 if(!is_off && status_at_time)
469 if(is_off && !status_at_time)
471 window->draw_rectangle(inactive_gc, true, area.get_x()+xstart, area.get_y(), x-xstart, area.get_height());
476 if(!is_off && iter!=activepoint_list.end() && next->state==false && iter->state==false)
481 else if(is_off && next!=activepoint_list.end() && iter->state==false && next->state==true)
483 window->draw_rectangle(inactive_gc, true, area.get_x()+xstart, area.get_y(), x-xstart, area.get_height());
486 else if(is_off && iter!=activepoint_list.end() && iter->state==true)
488 window->draw_rectangle(inactive_gc, true, area.get_x()+xstart, area.get_y(), prevx-xstart, area.get_height());
495 if(iter->time>=adjustment->get_lower() && iter->time<adjustment->get_upper())
500 gc->set_rgb_fg_color(activepoint_color[iter->state]);
501 window->draw_rectangle(gc, true, area.get_x()+x-w/2, area.get_y(), w, area.get_height());
507 window->draw_rectangle(inactive_gc, true, area.get_x()+xstart, area.get_y(), area.get_width()-xstart, area.get_height());
511 // Render a line that defines the current tick in time
513 gc->set_rgb_fg_color(curr_time_color);
515 const int x((int)((float)area.get_width()/(adjustment->get_upper()-adjustment->get_lower())*(adjustment->get_value()-adjustment->get_lower())));
517 if(adjustment->get_value()>=adjustment->get_lower() && adjustment->get_value()<adjustment->get_upper())
518 window->draw_rectangle(gc, true, area.get_x()+x, area.get_y(), 1, area.get_height());
522 synfig::ValueNode_Animated::WaypointList::iterator
523 CellRenderer_TimeTrack::find_waypoint(const synfig::Time& t,const synfig::Time& scope)
525 synfig::ValueNode_Animated *value_node=dynamic_cast<synfig::ValueNode_Animated*>(property_value_desc().get_value().get_value_node().get());
527 Time nearest(Time::end());
529 synfig::ValueNode_Animated::WaypointList::iterator iter,ret;
534 iter=value_node->waypoint_list().begin();
535 iter!=value_node->waypoint_list().end();
539 Time val=abs(iter->get_time()-selected_time);
547 if(nearest!=Time::end() && nearest<scope)
556 CellRenderer_TimeTrack::activate_vfunc(
559 const Glib::ustring& treepath,
560 const Gdk::Rectangle& background_area,
561 const Gdk::Rectangle& cell_area,
562 Gtk::CellRendererState flags)
565 synfig::ValueNode_Animated::WaypointList::iterator iter;
566 Time nearest=1000000000;
567 Gtk::Adjustment *adjustment=get_adjustment();
569 synfig::ValueNode_Animated *value_node=dynamic_cast<synfig::ValueNode_Animated*>(property_value_desc().get_value().get_value_node().get());
571 synfig::Canvas::Handle canvas(get_canvas());
573 synfig::ValueNode_DynamicList *parent_value_node(0);
574 if(property_value_desc().get_value().parent_is_value_node())
575 parent_value_node=dynamic_cast<synfig::ValueNode_DynamicList*>(property_value_desc().get_value().get_parent_value_node().get());
581 case GDK_MOTION_NOTIFY:
582 curr_time=((float)event->motion.x-(float)cell_area.get_x())/(float)cell_area.get_width()*(adjustment->get_upper()-adjustment->get_lower())+adjustment->get_lower();
586 Gdk::ModifierType mod;
587 Gdk::Event(event).get_state(mod);
591 case GDK_BUTTON_PRESS:
592 case GDK_BUTTON_RELEASE:
594 curr_time=((float)event->button.x-(float)cell_area.get_x())/(float)cell_area.get_width()*(adjustment->get_upper()-adjustment->get_lower())+adjustment->get_lower();
596 Gdk::ModifierType mod;
597 Gdk::Event(event).get_state(mod);
602 actual_time = curr_time;
604 curr_time=curr_time.round(canvas->rend_desc().get_frame_rate());
605 selected_time=curr_time;
607 Time pixel_width((adjustment->get_upper()-adjustment->get_lower())/cell_area.get_width());
611 case GDK_BUTTON_PRESS:
612 //selected_time=((float)event->button.x-(float)cell_area.get_x())/(float)cell_area.get_width()*(adjustment->get_upper()-adjustment->get_lower())+adjustment->get_lower();
614 //Deal with time point selection, but only if they aren't involved in the insanity...
615 if(/*!value_node && */event->button.button == 1)
619 /*! UI specification:
621 When nothing is selected, clicking on a point in either normal mode order
622 addative mode will select the time point closest to the click.
623 Subtractive click will do nothing
625 When things are already selected, clicking on a selected point does
626 nothing (in both normal and add mode). Add mode clicking on an unselected
627 point adds it to the set. Normal clicking on an unselected point will
628 select only that one time point. Subtractive clicking on any point
629 will remove it from the the set if it is included.
632 synfigapp::ValueDesc valdesc = property_value_desc().get_value();
633 const Node::time_set *tset = get_times_from_vdesc(valdesc);
635 bool clickfound = tset && get_closest_time(*tset,actual_time,pixel_width*cell_area.get_height(),stime);
636 bool selectmode = mode & SELECT_MASK;
638 //NOTE LATER ON WE SHOULD MAKE IT SO MULTIPLE VALUENODES CAN BE SELECTED AT ONCE
639 //we want to jump to the value desc if we're not currently on it
640 // but only if we want to add the point
641 if(clickfound && !(sel_value == valdesc))
647 //now that we've made sure we're selecting the correct value, deal with the already selected points
648 set<Time>::iterator foundi = clickfound ? sel_times.find(stime) : sel_times.end();
649 bool found = foundi != sel_times.end();
651 //remove all other points from our list... (only select the one we need)
652 if(!selectmode && !found)
657 if(found && selectmode) //remove a single already selected point
659 sel_times.erase(foundi);
660 }else if(clickfound) //otherwise look at adding it
662 //for replace the list was cleared earlier, and for add it wasn't so it works
663 sel_times.insert(stime);
670 iter=find_waypoint(selected_time,pixel_width*cell_area.get_height()/2);
671 selected_waypoint=iter;
679 selected=synfig::UniqueID::nil();
682 if((!sel_times.empty() || selection) && event->button.button==1)
685 drag_time=selected_time;
686 actual_dragtime=actual_time;
688 //selected_time=iter->time;
691 // Activepoint Selection
692 if(parent_value_node)
694 const int index(property_value_desc().get_value().get_index());
695 const synfig::ValueNode_DynamicList::ListEntry::ActivepointList& activepoint_list(parent_value_node->list[index].timing_info);
696 synfig::ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator iter;
698 for(iter=activepoint_list.begin();iter!=activepoint_list.end();++iter)
700 Time val=abs(iter->time-selected_time);
708 // Perhaps I sould signal if we selected this activepoint?
711 if(event->button.button==3)
714 synfigapp::ValueDesc valdesc = property_value_desc().get_value();
715 const Node::time_set *tset = get_times_from_vdesc(valdesc);
717 bool clickfound = tset && get_closest_time(*tset,actual_time,pixel_width*cell_area.get_height(),stime);
719 etl::handle<synfig::Node> node;
720 if(valdesc.get_value(stime).get_type()==ValueBase::TYPE_CANVAS)
722 node=Canvas::Handle(valdesc.get_value(stime).get(Canvas::Handle()));
724 else //if(valdesc.is_value_node())
726 node=valdesc.get_value_node();
729 if(clickfound && node)
731 show_timepoint_menu(node, stime, actual_time<stime?SIDE_LEFT:SIDE_RIGHT);
736 case GDK_MOTION_NOTIFY:
738 //if(selection && dragging)
739 // selected_time=((float)event->motion.x-(float)cell_area.get_x())/(float)cell_area.get_width()*(adjustment->get_upper()-adjustment->get_lower())+adjustment->get_lower();
743 case GDK_BUTTON_RELEASE:
747 //selected_time=((float)event->button.x-(float)cell_area.get_x())/(float)cell_area.get_width()*(adjustment->get_upper()-adjustment->get_lower())+adjustment->get_lower();
750 /*if(event->button.button==3 && selection)
752 signal_waypoint_clicked_(path,*selected_waypoint,event->button.button-1);
757 //Time point stuff...
758 if(event->button.button == 1)
760 bool delmode = (mode & DELETE_MASK) && !(mode & COPY_MASK);
761 deltatime = actual_time - actual_dragtime;
762 if(sel_times.size() != 0 && (delmode || !deltatime.is_equal(Time(0))))
764 synfigapp::Action::ParamList param_list;
765 param_list.add("canvas",canvas_interface()->get_canvas());
766 param_list.add("canvas_interface",canvas_interface());
768 if(sel_value.get_value_type() == synfig::ValueBase::TYPE_CANVAS)
770 param_list.add("addcanvas",sel_value.get_value().get(Canvas::Handle()));
773 param_list.add("addvaluedesc",sel_value);
777 std::set<synfig::Time>::iterator i = sel_times.begin(), end = sel_times.end();
780 param_list.add("addtime",*i);
782 newset.insert((*i + deltatime).round(get_canvas()->rend_desc().get_frame_rate()));
786 param_list.add("deltatime",deltatime);
787 // param_list.add("time",canvas_interface()->get_time());
789 if(mode & COPY_MASK) //copy
791 etl::handle<studio::Instance>::cast_static(canvas_interface()->get_instance())
792 ->process_action("timepoint_copy", param_list);
793 }else if(delmode) //DELETE
795 etl::handle<studio::Instance>::cast_static(canvas_interface()->get_instance())
796 ->process_action("timepoint_delete", param_list);
799 etl::handle<studio::Instance>::cast_static(canvas_interface()->get_instance())
800 ->process_action("timepoint_move", param_list);
803 //now replace all the selected with the new selected
810 /*if(value_node && selection)
812 if(selected_time==drag_time && event->button.button!=3)
813 signal_waypoint_clicked_(path,*selected_waypoint,event->button.button-1);
815 if(event->button.button==1)
817 synfig::Waypoint waypoint(*selected_waypoint);
818 Time newtime((waypoint.get_time()+(selected_time-drag_time)).round(canvas->rend_desc().get_frame_rate()));
819 if(waypoint.get_time()!=newtime)
821 waypoint.set_time(newtime);
822 signal_waypoint_changed_(waypoint,value_node);
828 // selected_time=iter->time;
829 //selected_time=iter->get_time();
833 //std::cerr<<"unknown event type "<<event->type<<std::endl;
845 Glib::PropertyProxy<synfigapp::ValueDesc>
846 CellRenderer_TimeTrack::property_value_desc()
848 return Glib::PropertyProxy<synfigapp::ValueDesc>(this,"value_desc");
851 Glib::PropertyProxy<synfig::Canvas::Handle>
852 CellRenderer_TimeTrack::property_canvas()
854 return Glib::PropertyProxy<synfig::Canvas::Handle>(this,"canvas");
857 Glib::PropertyProxy<Gtk::Adjustment* >
858 CellRenderer_TimeTrack::property_adjustment()
860 return Glib::PropertyProxy<Gtk::Adjustment* >(this,"adjustment");
864 CellRenderer_TimeTrack::set_canvas_interface(etl::loose_handle<synfigapp::CanvasInterface> h)
866 canvas_interface_ = h;
870 set_waypoint_model(std::set<synfig::Waypoint, std::less<UniqueID> > waypoints, Waypoint::Model model, etl::loose_handle<synfigapp::CanvasInterface> canvas_interface)
872 // Create the action group
873 synfigapp::Action::PassiveGrouper group(canvas_interface->get_instance().get(),_("Change Waypoint Group"));
875 std::set<synfig::Waypoint, std::less<UniqueID> >::const_iterator iter;
876 for(iter=waypoints.begin();iter!=waypoints.end();++iter)
878 Waypoint waypoint(*iter);
879 waypoint.apply_model(model);
881 synfigapp::Action::Handle action(synfigapp::Action::create("waypoint_set"));
885 action->set_param("canvas",canvas_interface->get_canvas());
886 action->set_param("canvas_interface",canvas_interface);
888 action->set_param("waypoint",waypoint);
889 action->set_param("value_node",waypoint.get_parent_value_node());
891 if(!canvas_interface->get_instance()->perform_action(action))
900 CellRenderer_TimeTrack::show_timepoint_menu(const etl::handle<synfig::Node>& node, const synfig::Time& time, Side side)
902 std::set<synfig::Waypoint, std::less<UniqueID> > waypoint_set;
904 n=synfig::waypoint_collect(waypoint_set,time,node);
906 Gtk::Menu* menu(manage(new Gtk::Menu()));
908 // Create the interpolation method menu
909 if(!waypoint_set.empty())
911 Gtk::Menu* interp_menu(manage(new Gtk::Menu()));
912 Waypoint::Model model;
914 if(side==SIDE_LEFT)model.set_before(INTERPOLATION_TCB);
915 else model.set_after(INTERPOLATION_TCB);
916 interp_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("TCB"),
918 sigc::ptr_fun(set_waypoint_model),
925 if(side==SIDE_LEFT)model.set_before(INTERPOLATION_LINEAR);
926 else model.set_after(INTERPOLATION_LINEAR);
927 interp_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("Linear"),
929 sigc::ptr_fun(set_waypoint_model),
936 if(side==SIDE_LEFT)model.set_before(INTERPOLATION_HALT);
937 else model.set_after(INTERPOLATION_HALT);
938 interp_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("Ease"),
940 sigc::ptr_fun(set_waypoint_model),
947 if(side==SIDE_LEFT)model.set_before(INTERPOLATION_CONSTANT);
948 else model.set_after(INTERPOLATION_CONSTANT);
949 interp_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("Constant"),
951 sigc::ptr_fun(set_waypoint_model),
959 menu->items().push_back(
960 Gtk::Menu_Helpers::MenuElem(
961 side==SIDE_LEFT?_("Change \"In\" Interp."):_("Change \"Out\" Interp."),
967 menu->items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::StockID("gtk-jump-to"),
971 &synfigapp::CanvasInterface::set_time
977 if(!waypoint_set.empty())
979 if(waypoint_set.size()==1)
983 signal_waypoint_clicked_(" ",*waypoint_set.begin(),2);
987 synfig::info("Too many waypoints under me");
990 synfig::info("ZERO waypoints under me");
992 if(menu)menu->popup(3,gtk_get_current_event_time());