1 /* === S Y N F I G ========================================================= */
2 /*! \file cellrenderer_timetrack.cpp
3 ** \brief Template Header
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007, 2008 Chris Moore
11 ** This package is free software; you can redistribute it and/or
12 ** modify it under the terms of the GNU General Public License as
13 ** published by the Free Software Foundation; either version 2 of
14 ** the License, or (at your option) any later version.
16 ** This package is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ** General Public License for more details.
22 /* ========================================================================= */
24 /* === H E A D E R S ======================================================= */
33 #include <gtkmm/label.h>
34 #include "cellrenderer_timetrack.h"
36 #include <gtkmm/spinbutton.h>
37 #include <gtkmm/combo.h>
38 #include <ETL/stringf>
39 #include "widget_value.h"
41 #include <gtkmm/menu.h>
42 #include <gtkmm/optionmenu.h>
43 #include "widget_time.h"
44 #include "widget_timeslider.h"
46 #include <synfigapp/canvasinterface.h>
53 using namespace synfig;
56 using namespace studio;
58 /* === M A C R O S ========================================================= */
60 /* === G L O B A L S ======================================================= */
62 static char stipple_xpm[] = { 2, 0 };
64 //mode for modifier keys
68 SELECT_MASK = Gdk::CONTROL_MASK,
69 COPY_MASK = Gdk::SHIFT_MASK,
70 DELETE_MASK = Gdk::MOD1_MASK
73 /* === P R O C E D U R E S ================================================= */
75 /* === M E T H O D S ======================================================= */
77 CellRenderer_TimeTrack::CellRenderer_TimeTrack():
78 Glib::ObjectBase (typeid(CellRenderer_TimeTrack)),
80 adjustment_ (10,10,20,0,0,0),
82 property_valuedesc_ (*this,"value_desc",synfigapp::ValueDesc()),
83 property_canvas_ (*this,"canvas",synfig::Canvas::Handle()),
84 property_adjustment_(*this,"adjustment",&adjustment_),
85 property_enable_timing_info_(*this,"enable-timing-info", false)
91 CellRenderer_TimeTrack::~CellRenderer_TimeTrack()
93 if (getenv("SYNFIG_DEBUG_DESTRUCTORS"))
94 synfig::info("CellRenderer_TimeTrack::~CellRenderer_TimeTrack(): Deleted");
98 CellRenderer_TimeTrack::set_adjustment(Gtk::Adjustment &x)
100 property_adjustment_=&x;
101 // x.signal_value_changed().connect(sigc::mem_fun(*this,&Gtk::Widget::queue_draw));
104 synfig::Canvas::Handle
105 CellRenderer_TimeTrack::get_canvas()const
107 return const_cast<CellRenderer_TimeTrack*>(this)->property_canvas().get_value();
111 CellRenderer_TimeTrack::get_adjustment()
113 return (Gtk::Adjustment*)property_adjustment_;
116 const Gtk::Adjustment *
117 CellRenderer_TimeTrack::get_adjustment()const
119 return (const Gtk::Adjustment*)property_adjustment_;
123 CellRenderer_TimeTrack::is_selected(const Waypoint& waypoint)const
125 return selected==waypoint;
128 const synfig::Time get_time_offset_from_vdesc(const synfigapp::ValueDesc &v)
130 #ifdef ADJUST_WAYPOINTS_FOR_TIME_OFFSET
131 if(getenv("SYNFIG_SHOW_CANVAS_PARAM_WAYPOINTS") ||
132 v.get_value_type() != synfig::ValueBase::TYPE_CANVAS)
133 return synfig::Time::zero();
135 synfig::Canvas::Handle canvasparam = v.get_value().get(Canvas::Handle());
137 return synfig::Time::zero();
139 if (!v.parent_is_layer_param())
140 return synfig::Time::zero();
142 synfig::Layer::Handle layer = v.get_layer();
144 if (layer->get_name()!="PasteCanvas")
145 return synfig::Time::zero();
147 return layer->get_param("time_offset").get(Time());
148 #else // ADJUST_WAYPOINTS_FOR_TIME_OFFSET
149 return synfig::Time::zero();
153 //kind of a hack... pointer is ugly
154 const synfig::Node::time_set *get_times_from_vdesc(const synfigapp::ValueDesc &v)
156 if(!getenv("SYNFIG_SHOW_CANVAS_PARAM_WAYPOINTS") &&
157 v.get_value_type() == synfig::ValueBase::TYPE_CANVAS)
159 synfig::Canvas::Handle canvasparam = v.get_value().get(Canvas::Handle());
162 return &canvasparam->get_times();
165 ValueNode *base_value = v.get_value_node().get();
167 ValueNode_DynamicList *parent_value_node =
168 v.parent_is_value_node() ?
169 dynamic_cast<ValueNode_DynamicList *>(v.get_parent_value_node().get()) :
172 //we want a dynamic list entry to override the normal...
173 if(parent_value_node)
175 return &parent_value_node->list[v.get_index()].get_times();
176 }else if(base_value) //don't render stuff if it's just animated...
178 return &base_value->get_times();
183 bool get_closest_time(const synfig::Node::time_set &tset, const Time &t, const Time &range, Time &out)
185 Node::time_set::const_iterator i,j,end = tset.end();
187 // stop the crash mentioned in bug #1689282
188 // doesn't solve the underlying problem though, I don't think
189 if (tset.size() == 0)
191 synfig::error(__FILE__":%d: tset.size() == 0",__LINE__);
195 //TODO add in RangeGet so it's not so damn hard to click on points
197 i = tset.upper_bound(t); //where t is the lower bound, t < [first,i)
200 double dist = Time::end();
205 closest = i->get_time();
206 dist = abs(i->get_time() - t);
209 if(j != end && (abs(j->get_time() - t) < dist) )
211 closest = j->get_time();
212 dist = abs(j->get_time() - t);
215 if( dist <= range/2 )
225 CellRenderer_TimeTrack::render_vfunc(
226 const Glib::RefPtr<Gdk::Drawable>& window,
228 const Gdk::Rectangle& /*background_area*/,
229 const Gdk::Rectangle& area_,
230 const Gdk::Rectangle& /*expose_area*/,
231 Gtk::CellRendererState /*flags*/)
236 Glib::RefPtr<Gdk::GC> gc(Gdk::GC::create(window));
237 Glib::RefPtr<Gdk::GC> inactive_gc(Gdk::GC::create(window));
238 Gtk::Adjustment *adjustment=get_adjustment();
239 // Gtk::StateType state = Gtk::STATE_ACTIVE;
240 // Gtk::ShadowType shadow;
243 curr_time_color("#0000ff"),
244 inactive_color("#000000"),
245 keyframe_color("#a07f7f");
246 Gdk::Color activepoint_color[2];
248 activepoint_color[0]=Gdk::Color("#ff0000");
249 activepoint_color[1]=Gdk::Color("#00ff00");
251 inactive_gc->set_rgb_fg_color(inactive_color);
252 inactive_gc->set_stipple(Gdk::Bitmap::create(stipple_xpm,2,2));
253 inactive_gc->set_fill(Gdk::STIPPLED);
255 synfig::Canvas::Handle canvas(property_canvas().get_value());
257 synfigapp::ValueDesc value_desc = property_value_desc().get_value();
258 synfig::ValueNode *base_value = value_desc.get_value_node().get();
259 // synfig::ValueNode_Animated *value_node=dynamic_cast<synfig::ValueNode_Animated*>(base_value);
261 synfig::ValueNode_DynamicList *parent_value_node(0);
262 if(property_value_desc().get_value().parent_is_value_node())
263 parent_value_node=dynamic_cast<synfig::ValueNode_DynamicList*>(property_value_desc().get_value().get_parent_value_node().get());
265 // If the canvas is defined, then load up the keyframes
268 const synfig::KeyframeList& keyframe_list(canvas->keyframe_list());
269 synfig::KeyframeList::const_iterator iter;
271 for(iter=keyframe_list.begin();iter!=keyframe_list.end();++iter)
273 if(!iter->get_time().is_valid())
276 const int x((int)((float)area_.get_width()/(adjustment->get_upper()-adjustment->get_lower())*(iter->get_time()-adjustment->get_lower())));
277 if(iter->get_time()>=adjustment->get_lower() && iter->get_time()<adjustment->get_upper())
279 gc->set_rgb_fg_color(keyframe_color);
280 window->draw_rectangle(gc, true, area_.get_x()+x, area_.get_y(), 1, area_.get_height()+1);
285 //render all the time points that exist
287 const synfig::Node::time_set *tset = get_times_from_vdesc(value_desc);
291 const synfig::Time time_offset = get_time_offset_from_vdesc(value_desc);
292 synfig::Node::time_set::const_iterator i = tset->begin(), end = tset->end();
294 float lower = adjustment->get_lower(),
295 upper = adjustment->get_upper();
297 Glib::RefPtr<Gdk::GC> gc = Gdk::GC::create(widget.get_window());
299 Gdk::Rectangle area(area_);
300 gc->set_clip_rectangle(area);
301 gc->set_line_attributes(1,Gdk::LINE_SOLID,Gdk::CAP_BUTT,Gdk::JOIN_MITER);
303 bool valselected = sel_value.get_value_node() == base_value && !sel_times.empty();
305 float cfps = get_canvas()->rend_desc().get_frame_rate();
307 vector<Time> drawredafter;
309 Time diff = actual_time - actual_dragtime;//selected_time-drag_time;
312 //find the coordinate in the drawable space...
313 Time t_orig = i->get_time();
314 if(!t_orig.is_valid()) continue;
315 Time t = t_orig - time_offset;
317 //if it found it... (might want to change comparison, and optimize
318 // sel_times.find to not produce an overall nlogn solution)
321 //not dragging... just draw as per normal
322 //if move dragging draw offset
323 //if copy dragging draw both...
325 if(valselected && sel_times.find(t_orig) != sel_times.end())
327 if(dragging) //skip if we're dragging because we'll render it later
329 if(mode & COPY_MASK) // draw both blue and red moved
331 drawredafter.push_back(t + diff.round(cfps));
332 gc->set_rgb_fg_color(Gdk::Color("#00EEEE"));
333 }else if(mode & DELETE_MASK) //it's just red...
335 gc->set_rgb_fg_color(Gdk::Color("#EE0000"));
337 }else //move - draw the red on top of the others...
339 drawredafter.push_back(t + diff.round(cfps));
344 gc->set_rgb_fg_color(Gdk::Color("#EE0000"));
349 gc->set_rgb_fg_color(Gdk::Color("#00EEEE"));
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...
356 Gdk::Rectangle area2(
357 area.get_x() - area.get_height()/2 + x + 1,
362 render_time_point_to_window(window,area2,*i - time_offset,selected);
364 /*window->draw_arc(gc,true,
365 area.get_x() + x - area.get_height()/4, area.get_y() + area.get_height()/8,
366 area.get_height()/2, area.get_height()*3/4,
369 gc->set_rgb_fg_color(Gdk::Color("#000000"));
370 window->draw_arc(gc,false,
371 area.get_x() + x - area.get_height()/4, area.get_y() + area.get_height()/8,
372 area.get_height()/2, area.get_height()*3/4,
378 vector<Time>::iterator i = drawredafter.begin(), end = drawredafter.end();
381 //find the coordinate in the drawable space...
387 //synfig::info("Displaying time: %.3f s",(float)t);
388 const int x = (int)((t-lower)*area.get_width()/(upper-lower));
390 //should draw me a grey filled circle...
392 Gdk::Rectangle area2(
393 area.get_x() - area.get_height()/2 + x + 1,
398 render_time_point_to_window(window,area2,*i,true);
399 /* gc->set_rgb_fg_color(Gdk::Color("#EE0000"));
400 window->draw_arc(gc,true,
401 area.get_x() + x - area.get_height()/4, area.get_y() + area.get_height()/8,
402 area.get_height()/2, area.get_height()*3/4,
405 gc->set_rgb_fg_color(Gdk::Color("#000000"));
406 window->draw_arc(gc,false,
407 area.get_x() + x - area.get_height()/4, area.get_y() + area.get_height()/8,
408 area.get_height()/2, area.get_height()*3/4,
416 /* THIS IS NOW HANDLED ENTIRELY BY THE TIMEPOINT SYSTEM
417 // This this is an animated value node, then render the waypoints
420 //now render the actual waypoints
421 synfig::ValueNode_Animated::WaypointList::iterator iter;
423 iter=value_node->waypoint_list().begin();
424 iter!=value_node->waypoint_list().end();
428 if(!iter->get_time().is_valid())
432 if(is_selected(*iter))
434 Time t(iter->get_time());
438 t=(t+selected_time-drag_time).round(get_canvas()->rend_desc().get_frame_rate());
440 x=(int)((float)area.get_width()/(adjustment->get_upper()-adjustment->get_lower())*(t-adjustment->get_lower()));
441 shadow=Gtk::SHADOW_IN;
446 x=(int)((float)area.get_width()/(adjustment->get_upper()-adjustment->get_lower())*(iter->get_time()-adjustment->get_lower()));
447 shadow=Gtk::SHADOW_OUT;
452 widget.get_style()->paint_diamond(
453 Glib::RefPtr<Gdk::Window>::cast_static(window),
459 area.get_x()+x-area.get_height()/4,
460 area.get_y()+area.get_height()/4,
467 Gdk::Rectangle area(area_);
468 // If the parent of this value node is a dynamic list, then
469 // render the on and off times
470 if(parent_value_node)
472 const int index(property_value_desc().get_value().get_index());
473 const synfig::ValueNode_DynamicList::ListEntry& list_entry(parent_value_node->list[index]);
474 const synfig::ValueNode_DynamicList::ListEntry::ActivepointList& activepoint_list(list_entry.timing_info);
475 synfig::ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator iter,next;
478 if(!activepoint_list.empty())
479 is_off=!activepoint_list.front().state;
484 for(next=activepoint_list.begin(),iter=next++;iter!=activepoint_list.end();iter=next++)
486 x=((int)((float)area.get_width()/(adjustment->get_upper()-adjustment->get_lower())*(iter->time-adjustment->get_lower())));
488 if(x>area.get_width())x=area.get_width();
490 bool status_at_time=0;
491 if(next!=activepoint_list.end())
493 status_at_time=!list_entry.status_at_time((iter->time+next->time)/2.0);
496 status_at_time=!list_entry.status_at_time(Time::end());
498 if(!is_off && status_at_time)
504 if(is_off && !status_at_time)
506 window->draw_rectangle(inactive_gc, true, area.get_x()+xstart, area.get_y(), x-xstart, area.get_height());
511 if(!is_off && iter!=activepoint_list.end() && next->state==false && iter->state==false)
516 else if(is_off && next!=activepoint_list.end() && iter->state==false && next->state==true)
518 window->draw_rectangle(inactive_gc, true, area.get_x()+xstart, area.get_y(), x-xstart, area.get_height());
521 else if(is_off && iter!=activepoint_list.end() && iter->state==true)
523 window->draw_rectangle(inactive_gc, true, area.get_x()+xstart, area.get_y(), prevx-xstart, area.get_height());
530 if(iter->time>=adjustment->get_lower() && iter->time<adjustment->get_upper())
535 gc->set_rgb_fg_color(activepoint_color[iter->state]);
536 window->draw_rectangle(gc, true, area.get_x()+x-w/2, area.get_y(), w, area.get_height());
542 window->draw_rectangle(inactive_gc, true, area.get_x()+xstart, area.get_y(), area.get_width()-xstart, area.get_height());
546 // Render a line that defines the current tick in time
548 gc->set_rgb_fg_color(curr_time_color);
550 const int x((int)((float)area.get_width()/(adjustment->get_upper()-adjustment->get_lower())*(adjustment->get_value()-adjustment->get_lower())));
552 if(adjustment->get_value()>=adjustment->get_lower() && adjustment->get_value()<adjustment->get_upper())
553 window->draw_rectangle(gc, true, area.get_x()+x, area.get_y(), 1, area.get_height());
557 synfig::ValueNode_Animated::WaypointList::iterator
558 CellRenderer_TimeTrack::find_waypoint(const synfig::Time& /*t*/,const synfig::Time& scope)
560 synfig::ValueNode_Animated *value_node=dynamic_cast<synfig::ValueNode_Animated*>(property_value_desc().get_value().get_value_node().get());
562 Time nearest(Time::end());
564 synfig::ValueNode_Animated::WaypointList::iterator iter,ret;
569 iter=value_node->waypoint_list().begin();
570 iter!=value_node->waypoint_list().end();
574 Time val=abs(iter->get_time()-selected_time);
582 if(nearest!=Time::end() && nearest<scope)
591 CellRenderer_TimeTrack::activate_vfunc(
593 Gtk::Widget& /*widget*/,
594 const Glib::ustring& treepath,
595 const Gdk::Rectangle& /*background_area*/,
596 const Gdk::Rectangle& cell_area,
597 Gtk::CellRendererState /*flags*/)
600 synfig::ValueNode_Animated::WaypointList::iterator iter;
601 Time nearest=1000000000;
602 Gtk::Adjustment *adjustment=get_adjustment();
604 // synfig::ValueNode_Animated *value_node=dynamic_cast<synfig::ValueNode_Animated*>(property_value_desc().get_value().get_value_node().get());
606 synfig::Canvas::Handle canvas(get_canvas());
608 synfig::ValueNode_DynamicList *parent_value_node(0);
609 if(property_value_desc().get_value().parent_is_value_node())
610 parent_value_node=dynamic_cast<synfig::ValueNode_DynamicList*>(property_value_desc().get_value().get_parent_value_node().get());
616 case GDK_MOTION_NOTIFY:
617 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();
621 Gdk::ModifierType mod;
622 Gdk::Event(event).get_state(mod);
626 case GDK_BUTTON_PRESS:
627 case GDK_BUTTON_RELEASE:
629 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();
631 Gdk::ModifierType mod;
632 Gdk::Event(event).get_state(mod);
637 actual_time = curr_time;
639 curr_time=curr_time.round(canvas->rend_desc().get_frame_rate());
640 selected_time=curr_time;
642 Time pixel_width((adjustment->get_upper()-adjustment->get_lower())/cell_area.get_width());
646 case GDK_BUTTON_PRESS:
647 //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();
649 //Deal with time point selection, but only if they aren't involved in the insanity...
650 if(/*!value_node && */event->button.button == 1)
654 /*! UI specification:
656 When nothing is selected, clicking on a point in either normal mode or
657 additive mode will select the time point closest to the click.
658 Subtractive click will do nothing
660 When things are already selected, clicking on a selected point does
661 nothing (in both normal and add mode). Add mode clicking on an unselected
662 point adds it to the set. Normal clicking on an unselected point will
663 select only that one time point. Subtractive clicking on any point
664 will remove it from the the set if it is included.
667 synfigapp::ValueDesc valdesc = property_value_desc().get_value();
668 const Node::time_set *tset = get_times_from_vdesc(valdesc);
669 const synfig::Time time_offset = get_time_offset_from_vdesc(valdesc);
671 bool clickfound = tset && get_closest_time(*tset,actual_time+time_offset,pixel_width*cell_area.get_height(),stime);
672 bool selectmode = mode & SELECT_MASK;
674 //NOTE LATER ON WE SHOULD MAKE IT SO MULTIPLE VALUENODES CAN BE SELECTED AT ONCE
675 //we want to jump to the value desc if we're not currently on it
676 // but only if we want to add the point
677 if(clickfound && !(sel_value == valdesc))
683 //now that we've made sure we're selecting the correct value, deal with the already selected points
684 set<Time>::iterator foundi = clickfound ? sel_times.find(stime) : sel_times.end();
685 bool found = foundi != sel_times.end();
687 //remove all other points from our list... (only select the one we need)
688 if(!selectmode && !found)
693 if(found && selectmode) //remove a single already selected point
695 sel_times.erase(foundi);
696 }else if(clickfound) //otherwise look at adding it
698 //for replace the list was cleared earlier, and for add it wasn't so it works
699 sel_times.insert(stime);
706 iter=find_waypoint(selected_time,pixel_width*cell_area.get_height()/2);
707 selected_waypoint=iter;
715 selected=synfig::UniqueID::nil();
718 if((!sel_times.empty() || selection) && event->button.button==1)
721 drag_time=selected_time;
722 actual_dragtime=actual_time;
724 //selected_time=iter->time;
727 // Activepoint Selection
728 if(parent_value_node)
730 const int index(property_value_desc().get_value().get_index());
731 const synfig::ValueNode_DynamicList::ListEntry::ActivepointList& activepoint_list(parent_value_node->list[index].timing_info);
732 synfig::ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator iter;
734 for(iter=activepoint_list.begin();iter!=activepoint_list.end();++iter)
736 Time val=abs(iter->time-selected_time);
744 // Perhaps I should signal if we selected this activepoint?
747 if(event->button.button==3)
750 synfigapp::ValueDesc valdesc = property_value_desc().get_value();
751 const Node::time_set *tset = get_times_from_vdesc(valdesc);
752 synfig::Time time_offset = get_time_offset_from_vdesc(valdesc);
754 bool clickfound = tset && get_closest_time(*tset,actual_time+time_offset,pixel_width*cell_area.get_height(),stime);
756 etl::handle<synfig::Node> node;
757 if(!getenv("SYNFIG_SHOW_CANVAS_PARAM_WAYPOINTS") &&
758 valdesc.get_value(stime).get_type()==ValueBase::TYPE_CANVAS)
760 node=Canvas::Handle(valdesc.get_value(stime).get(Canvas::Handle()));
762 else //if(valdesc.is_value_node())
764 node=valdesc.get_value_node();
767 if(clickfound && node)
768 signal_waypoint_clicked_cellrenderer()(node, stime, time_offset, 2);
772 case GDK_MOTION_NOTIFY:
773 //if(selection && dragging)
774 // 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();
778 case GDK_BUTTON_RELEASE:
780 //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();
783 /*if(event->button.button==3 && selection)
785 signal_waypoint_clicked_cellrenderer()(path,*selected_waypoint,event->button.button-1);
790 //Time point stuff...
791 if(event->button.button == 1)
793 bool delmode = (mode & DELETE_MASK) && !(mode & COPY_MASK);
794 deltatime = actual_time - actual_dragtime;
795 if(sel_times.size() != 0 && (delmode || !deltatime.is_equal(Time(0))))
797 synfigapp::Action::ParamList param_list;
798 param_list.add("canvas",canvas_interface()->get_canvas());
799 param_list.add("canvas_interface",canvas_interface());
801 if(!getenv("SYNFIG_SHOW_CANVAS_PARAM_WAYPOINTS") &&
802 sel_value.get_value_type() == synfig::ValueBase::TYPE_CANVAS)
804 param_list.add("addcanvas",sel_value.get_value().get(Canvas::Handle()));
807 param_list.add("addvaluedesc",sel_value);
811 std::set<synfig::Time>::iterator i = sel_times.begin(), end = sel_times.end();
814 param_list.add("addtime",*i);
816 newset.insert((*i + deltatime).round(get_canvas()->rend_desc().get_frame_rate()));
820 param_list.add("deltatime",deltatime);
821 // param_list.add("time",canvas_interface()->get_time());
823 if(mode & COPY_MASK) //copy
825 etl::handle<studio::Instance>::cast_static(canvas_interface()->get_instance())
826 ->process_action("timepoint_copy", param_list);
827 }else if(delmode) //DELETE
829 etl::handle<studio::Instance>::cast_static(canvas_interface()->get_instance())
830 ->process_action("timepoint_delete", param_list);
833 etl::handle<studio::Instance>::cast_static(canvas_interface()->get_instance())
834 ->process_action("timepoint_move", param_list);
837 //now replace all the selected with the new selected
844 /*if(value_node && selection)
846 if(selected_time==drag_time && event->button.button!=3)
847 signal_waypoint_clicked_cellrenderer()(path,*selected_waypoint,event->button.button-1);
849 if(event->button.button==1)
851 synfig::Waypoint waypoint(*selected_waypoint);
852 Time newtime((waypoint.get_time()+(selected_time-drag_time)).round(canvas->rend_desc().get_frame_rate()));
853 if(waypoint.get_time()!=newtime)
855 waypoint.set_time(newtime);
856 signal_waypoint_changed_(waypoint,value_node);
862 // selected_time=iter->time;
863 //selected_time=iter->get_time();
867 //std::cerr<<"unknown event type "<<event->type<<std::endl;
879 // The following three functions don't get documented correctly by
880 // doxygen 1.5.[23] because of a bug with any function whose name
881 // begins with 'property'. Fixed in doxygen 1.5.4 apparently. See
882 // http://bugzilla.gnome.org/show_bug.cgi?id=471185 .
883 Glib::PropertyProxy<synfigapp::ValueDesc>
884 CellRenderer_TimeTrack::property_value_desc()
886 return Glib::PropertyProxy<synfigapp::ValueDesc>(this,"value_desc");
889 Glib::PropertyProxy<synfig::Canvas::Handle>
890 CellRenderer_TimeTrack::property_canvas()
892 return Glib::PropertyProxy<synfig::Canvas::Handle>(this,"canvas");
895 Glib::PropertyProxy<Gtk::Adjustment* >
896 CellRenderer_TimeTrack::property_adjustment()
898 return Glib::PropertyProxy<Gtk::Adjustment* >(this,"adjustment");
902 CellRenderer_TimeTrack::set_canvas_interface(etl::loose_handle<synfigapp::CanvasInterface> h)
904 canvas_interface_ = h;