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"
35 #include <gtkmm/spinbutton.h>
36 #include <gtkmm/combo.h>
37 #include <ETL/stringf>
38 #include "widget_value.h"
40 #include <gtkmm/menu.h>
41 #include <gtkmm/optionmenu.h>
42 #include "widget_time.h"
43 #include "widget_timeslider.h"
45 #include <synfigapp/canvasinterface.h>
52 using namespace synfig;
55 using namespace studio;
57 /* === M A C R O S ========================================================= */
59 /* === G L O B A L S ======================================================= */
61 static char stipple_xpm[] = { 2, 0 };
63 //mode for modifier keys
67 SELECT_MASK = Gdk::CONTROL_MASK,
68 COPY_MASK = Gdk::SHIFT_MASK,
69 DELETE_MASK = Gdk::MOD1_MASK
72 /* === P R O C E D U R E S ================================================= */
74 /* === M E T H O D S ======================================================= */
76 CellRenderer_TimeTrack::CellRenderer_TimeTrack():
77 Glib::ObjectBase (typeid(CellRenderer_TimeTrack)),
79 adjustment_ (10,10,20,0,0,0),
81 property_valuedesc_ (*this,"value_desc",synfigapp::ValueDesc()),
82 property_canvas_ (*this,"canvas",synfig::Canvas::Handle()),
83 property_adjustment_(*this,"adjustment",&adjustment_),
84 property_enable_timing_info_(*this,"enable-timing-info", false)
90 CellRenderer_TimeTrack::~CellRenderer_TimeTrack()
92 if (getenv("SYNFIG_DEBUG_DESTRUCTORS"))
93 synfig::info("CellRenderer_TimeTrack::~CellRenderer_TimeTrack(): Deleted");
97 CellRenderer_TimeTrack::set_adjustment(Gtk::Adjustment &x)
99 property_adjustment_=&x;
100 // x.signal_value_changed().connect(sigc::mem_fun(*this,&Gtk::Widget::queue_draw));
103 synfig::Canvas::Handle
104 CellRenderer_TimeTrack::get_canvas()const
106 return const_cast<CellRenderer_TimeTrack*>(this)->property_canvas().get_value();
110 CellRenderer_TimeTrack::get_adjustment()
112 return (Gtk::Adjustment*)property_adjustment_;
115 const Gtk::Adjustment *
116 CellRenderer_TimeTrack::get_adjustment()const
118 return (const Gtk::Adjustment*)property_adjustment_;
122 CellRenderer_TimeTrack::is_selected(const Waypoint& waypoint)const
124 return selected==waypoint;
127 const synfig::Time get_time_offset_from_vdesc(const synfigapp::ValueDesc &v)
129 #ifdef ADJUST_WAYPOINTS_FOR_TIME_OFFSET
130 if(getenv("SYNFIG_SHOW_CANVAS_PARAM_WAYPOINTS") ||
131 v.get_value_type() != synfig::ValueBase::TYPE_CANVAS)
132 return synfig::Time::zero();
134 synfig::Canvas::Handle canvasparam = v.get_value().get(Canvas::Handle());
136 return synfig::Time::zero();
138 if (!v.parent_is_layer_param())
139 return synfig::Time::zero();
141 synfig::Layer::Handle layer = v.get_layer();
143 if (layer->get_name()!="PasteCanvas")
144 return synfig::Time::zero();
146 return layer->get_param("time_offset").get(Time());
147 #else // ADJUST_WAYPOINTS_FOR_TIME_OFFSET
148 return synfig::Time::zero();
152 //kind of a hack... pointer is ugly
153 const synfig::Node::time_set *get_times_from_vdesc(const synfigapp::ValueDesc &v)
155 if(!getenv("SYNFIG_SHOW_CANVAS_PARAM_WAYPOINTS") &&
156 v.get_value_type() == synfig::ValueBase::TYPE_CANVAS)
158 synfig::Canvas::Handle canvasparam = v.get_value().get(Canvas::Handle());
161 return &canvasparam->get_times();
164 ValueNode *base_value = v.get_value_node().get();
166 ValueNode_DynamicList *parent_value_node =
167 v.parent_is_value_node() ?
168 dynamic_cast<ValueNode_DynamicList *>(v.get_parent_value_node().get()) :
171 //we want a dynamic list entry to override the normal...
172 if(parent_value_node)
174 return &parent_value_node->list[v.get_index()].get_times();
175 }else if(base_value) //don't render stuff if it's just animated...
177 return &base_value->get_times();
182 bool get_closest_time(const synfig::Node::time_set &tset, const Time &t, const Time &range, Time &out)
184 Node::time_set::const_iterator i,j,end = tset.end();
186 // stop the crash mentioned in bug #1689282
187 // doesn't solve the underlying problem though, I don't think
188 if (tset.size() == 0)
190 synfig::error(__FILE__":%d: tset.size() == 0",__LINE__);
194 //TODO add in RangeGet so it's not so damn hard to click on points
196 i = tset.upper_bound(t); //where t is the lower bound, t < [first,i)
199 double dist = Time::end();
204 closest = i->get_time();
205 dist = abs(i->get_time() - t);
208 if(j != end && (abs(j->get_time() - t) < dist) )
210 closest = j->get_time();
211 dist = abs(j->get_time() - t);
214 if( dist <= range/2 )
224 CellRenderer_TimeTrack::render_vfunc(
225 const Glib::RefPtr<Gdk::Drawable>& window,
227 const Gdk::Rectangle& /*background_area*/,
228 const Gdk::Rectangle& area_,
229 const Gdk::Rectangle& /*expose_area*/,
230 Gtk::CellRendererState /*flags*/)
235 Glib::RefPtr<Gdk::GC> gc(Gdk::GC::create(window));
236 Glib::RefPtr<Gdk::GC> inactive_gc(Gdk::GC::create(window));
237 Gtk::Adjustment *adjustment=get_adjustment();
238 // Gtk::StateType state = Gtk::STATE_ACTIVE;
239 // Gtk::ShadowType shadow;
242 curr_time_color("#0000ff"),
243 inactive_color("#000000"),
244 keyframe_color("#a07f7f");
245 Gdk::Color activepoint_color[2];
247 activepoint_color[0]=Gdk::Color("#ff0000");
248 activepoint_color[1]=Gdk::Color("#00ff00");
250 inactive_gc->set_rgb_fg_color(inactive_color);
251 inactive_gc->set_stipple(Gdk::Bitmap::create(stipple_xpm,2,2));
252 inactive_gc->set_fill(Gdk::STIPPLED);
254 synfig::Canvas::Handle canvas(property_canvas().get_value());
256 synfigapp::ValueDesc value_desc = property_value_desc().get_value();
257 synfig::ValueNode *base_value = value_desc.get_value_node().get();
258 // synfig::ValueNode_Animated *value_node=dynamic_cast<synfig::ValueNode_Animated*>(base_value);
260 synfig::ValueNode_DynamicList *parent_value_node(0);
261 if(property_value_desc().get_value().parent_is_value_node())
262 parent_value_node=dynamic_cast<synfig::ValueNode_DynamicList*>(property_value_desc().get_value().get_parent_value_node().get());
264 // If the canvas is defined, then load up the keyframes
267 const synfig::KeyframeList& keyframe_list(canvas->keyframe_list());
268 synfig::KeyframeList::const_iterator iter;
270 for(iter=keyframe_list.begin();iter!=keyframe_list.end();++iter)
272 if(!iter->get_time().is_valid())
275 const int x((int)((float)area_.get_width()/(adjustment->get_upper()-adjustment->get_lower())*(iter->get_time()-adjustment->get_lower())));
276 if(iter->get_time()>=adjustment->get_lower() && iter->get_time()<adjustment->get_upper())
278 gc->set_rgb_fg_color(keyframe_color);
279 window->draw_rectangle(gc, true, area_.get_x()+x, area_.get_y(), 1, area_.get_height()+1);
284 //render all the time points that exist
286 const synfig::Node::time_set *tset = get_times_from_vdesc(value_desc);
290 const synfig::Time time_offset = get_time_offset_from_vdesc(value_desc);
291 synfig::Node::time_set::const_iterator i = tset->begin(), end = tset->end();
293 float lower = adjustment->get_lower(),
294 upper = adjustment->get_upper();
296 Glib::RefPtr<Gdk::GC> gc = Gdk::GC::create(widget.get_window());
298 Gdk::Rectangle area(area_);
299 gc->set_clip_rectangle(area);
300 gc->set_line_attributes(1,Gdk::LINE_SOLID,Gdk::CAP_BUTT,Gdk::JOIN_MITER);
302 bool valselected = sel_value.get_value_node() == base_value && !sel_times.empty();
304 float cfps = get_canvas()->rend_desc().get_frame_rate();
306 vector<Time> drawredafter;
308 Time diff = actual_time - actual_dragtime;//selected_time-drag_time;
311 //find the coordinate in the drawable space...
312 Time t_orig = i->get_time();
313 if(!t_orig.is_valid()) continue;
314 Time t = t_orig - time_offset;
315 if(t<adjustment->get_lower() || t>adjustment->get_upper()) continue;
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("TimepointsCopy", param_list);
827 }else if(delmode) //DELETE
829 etl::handle<studio::Instance>::cast_static(canvas_interface()->get_instance())
830 ->process_action("TimepointsDelete", param_list);
833 etl::handle<studio::Instance>::cast_static(canvas_interface()->get_instance())
834 ->process_action("TimepointsMove", 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;