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 "widgets/widget_value.h"
41 #include <gtkmm/menu.h>
42 #include <gtkmm/optionmenu.h>
43 #include "widgets/widget_time.h"
44 #include "widgets/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;
316 if(t<adjustment->get_lower() || t>adjustment->get_upper()) continue;
318 //if it found it... (might want to change comparison, and optimize
319 // sel_times.find to not produce an overall nlogn solution)
322 //not dragging... just draw as per normal
323 //if move dragging draw offset
324 //if copy dragging draw both...
326 if(valselected && sel_times.find(t_orig) != sel_times.end())
328 if(dragging) //skip if we're dragging because we'll render it later
330 if(mode & COPY_MASK) // draw both blue and red moved
332 drawredafter.push_back(t + diff.round(cfps));
333 gc->set_rgb_fg_color(Gdk::Color("#00EEEE"));
334 }else if(mode & DELETE_MASK) //it's just red...
336 gc->set_rgb_fg_color(Gdk::Color("#EE0000"));
338 }else //move - draw the red on top of the others...
340 drawredafter.push_back(t + diff.round(cfps));
345 gc->set_rgb_fg_color(Gdk::Color("#EE0000"));
350 gc->set_rgb_fg_color(Gdk::Color("#00EEEE"));
353 //synfig::info("Displaying time: %.3f s",(float)t);
354 const int x = (int)((t-lower)*area.get_width()/(upper-lower));
356 //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 - time_offset,selected);
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,
379 vector<Time>::iterator i = drawredafter.begin(), end = drawredafter.end();
382 //find the coordinate in the drawable space...
388 //synfig::info("Displaying time: %.3f s",(float)t);
389 const int x = (int)((t-lower)*area.get_width()/(upper-lower));
391 //should draw me a grey filled circle...
393 Gdk::Rectangle area2(
394 area.get_x() - area.get_height()/2 + x + 1,
399 render_time_point_to_window(window,area2,*i,true);
400 /* gc->set_rgb_fg_color(Gdk::Color("#EE0000"));
401 window->draw_arc(gc,true,
402 area.get_x() + x - area.get_height()/4, area.get_y() + area.get_height()/8,
403 area.get_height()/2, area.get_height()*3/4,
406 gc->set_rgb_fg_color(Gdk::Color("#000000"));
407 window->draw_arc(gc,false,
408 area.get_x() + x - area.get_height()/4, area.get_y() + area.get_height()/8,
409 area.get_height()/2, area.get_height()*3/4,
417 /* THIS IS NOW HANDLED ENTIRELY BY THE TIMEPOINT SYSTEM
418 // This this is an animated value node, then render the waypoints
421 //now render the actual waypoints
422 synfig::ValueNode_Animated::WaypointList::iterator iter;
424 iter=value_node->waypoint_list().begin();
425 iter!=value_node->waypoint_list().end();
429 if(!iter->get_time().is_valid())
433 if(is_selected(*iter))
435 Time t(iter->get_time());
439 t=(t+selected_time-drag_time).round(get_canvas()->rend_desc().get_frame_rate());
441 x=(int)((float)area.get_width()/(adjustment->get_upper()-adjustment->get_lower())*(t-adjustment->get_lower()));
442 shadow=Gtk::SHADOW_IN;
447 x=(int)((float)area.get_width()/(adjustment->get_upper()-adjustment->get_lower())*(iter->get_time()-adjustment->get_lower()));
448 shadow=Gtk::SHADOW_OUT;
453 widget.get_style()->paint_diamond(
454 Glib::RefPtr<Gdk::Window>::cast_static(window),
460 area.get_x()+x-area.get_height()/4,
461 area.get_y()+area.get_height()/4,
468 Gdk::Rectangle area(area_);
469 // If the parent of this value node is a dynamic list, then
470 // render the on and off times
471 if(parent_value_node)
473 const int index(property_value_desc().get_value().get_index());
474 const synfig::ValueNode_DynamicList::ListEntry& list_entry(parent_value_node->list[index]);
475 const synfig::ValueNode_DynamicList::ListEntry::ActivepointList& activepoint_list(list_entry.timing_info);
476 synfig::ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator iter,next;
479 if(!activepoint_list.empty())
480 is_off=!activepoint_list.front().state;
485 for(next=activepoint_list.begin(),iter=next++;iter!=activepoint_list.end();iter=next++)
487 x=((int)((float)area.get_width()/(adjustment->get_upper()-adjustment->get_lower())*(iter->time-adjustment->get_lower())));
489 if(x>area.get_width())x=area.get_width();
491 bool status_at_time=0;
492 if(next!=activepoint_list.end())
494 status_at_time=!list_entry.status_at_time((iter->time+next->time)/2.0);
497 status_at_time=!list_entry.status_at_time(Time::end());
499 if(!is_off && status_at_time)
505 if(is_off && !status_at_time)
507 window->draw_rectangle(inactive_gc, true, area.get_x()+xstart, area.get_y(), x-xstart, area.get_height());
512 if(!is_off && iter!=activepoint_list.end() && next->state==false && iter->state==false)
517 else if(is_off && next!=activepoint_list.end() && iter->state==false && next->state==true)
519 window->draw_rectangle(inactive_gc, true, area.get_x()+xstart, area.get_y(), x-xstart, area.get_height());
522 else if(is_off && iter!=activepoint_list.end() && iter->state==true)
524 window->draw_rectangle(inactive_gc, true, area.get_x()+xstart, area.get_y(), prevx-xstart, area.get_height());
531 if(iter->time>=adjustment->get_lower() && iter->time<adjustment->get_upper())
536 gc->set_rgb_fg_color(activepoint_color[iter->state]);
537 window->draw_rectangle(gc, true, area.get_x()+x-w/2, area.get_y(), w, area.get_height());
543 window->draw_rectangle(inactive_gc, true, area.get_x()+xstart, area.get_y(), area.get_width()-xstart, area.get_height());
547 // Render a line that defines the current tick in time
549 gc->set_rgb_fg_color(curr_time_color);
551 const int x((int)((float)area.get_width()/(adjustment->get_upper()-adjustment->get_lower())*(adjustment->get_value()-adjustment->get_lower())));
553 if(adjustment->get_value()>=adjustment->get_lower() && adjustment->get_value()<adjustment->get_upper())
554 window->draw_rectangle(gc, true, area.get_x()+x, area.get_y(), 1, area.get_height());
558 synfig::ValueNode_Animated::WaypointList::iterator
559 CellRenderer_TimeTrack::find_waypoint(const synfig::Time& /*t*/,const synfig::Time& scope)
561 synfig::ValueNode_Animated *value_node=dynamic_cast<synfig::ValueNode_Animated*>(property_value_desc().get_value().get_value_node().get());
563 Time nearest(Time::end());
565 synfig::ValueNode_Animated::WaypointList::iterator iter,ret;
570 iter=value_node->waypoint_list().begin();
571 iter!=value_node->waypoint_list().end();
575 Time val=abs(iter->get_time()-selected_time);
583 if(nearest!=Time::end() && nearest<scope)
592 CellRenderer_TimeTrack::activate_vfunc(
594 Gtk::Widget& /*widget*/,
595 const Glib::ustring& treepath,
596 const Gdk::Rectangle& /*background_area*/,
597 const Gdk::Rectangle& cell_area,
598 Gtk::CellRendererState /*flags*/)
601 synfig::ValueNode_Animated::WaypointList::iterator iter;
602 Time nearest=1000000000;
603 Gtk::Adjustment *adjustment=get_adjustment();
605 // synfig::ValueNode_Animated *value_node=dynamic_cast<synfig::ValueNode_Animated*>(property_value_desc().get_value().get_value_node().get());
607 synfig::Canvas::Handle canvas(get_canvas());
609 synfig::ValueNode_DynamicList *parent_value_node(0);
610 if(property_value_desc().get_value().parent_is_value_node())
611 parent_value_node=dynamic_cast<synfig::ValueNode_DynamicList*>(property_value_desc().get_value().get_parent_value_node().get());
617 case GDK_MOTION_NOTIFY:
618 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();
622 Gdk::ModifierType mod;
623 Gdk::Event(event).get_state(mod);
627 case GDK_BUTTON_PRESS:
628 case GDK_BUTTON_RELEASE:
630 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();
632 Gdk::ModifierType mod;
633 Gdk::Event(event).get_state(mod);
638 actual_time = curr_time;
640 curr_time=curr_time.round(canvas->rend_desc().get_frame_rate());
641 selected_time=curr_time;
643 Time pixel_width((adjustment->get_upper()-adjustment->get_lower())/cell_area.get_width());
647 case GDK_BUTTON_PRESS:
648 //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();
650 //Deal with time point selection, but only if they aren't involved in the insanity...
651 if(/*!value_node && */event->button.button == 1)
655 /*! UI specification:
657 When nothing is selected, clicking on a point in either normal mode or
658 additive mode will select the time point closest to the click.
659 Subtractive click will do nothing
661 When things are already selected, clicking on a selected point does
662 nothing (in both normal and add mode). Add mode clicking on an unselected
663 point adds it to the set. Normal clicking on an unselected point will
664 select only that one time point. Subtractive clicking on any point
665 will remove it from the the set if it is included.
668 synfigapp::ValueDesc valdesc = property_value_desc().get_value();
669 const Node::time_set *tset = get_times_from_vdesc(valdesc);
670 const synfig::Time time_offset = get_time_offset_from_vdesc(valdesc);
672 bool clickfound = tset && get_closest_time(*tset,actual_time+time_offset,pixel_width*cell_area.get_height(),stime);
673 bool selectmode = mode & SELECT_MASK;
675 //NOTE LATER ON WE SHOULD MAKE IT SO MULTIPLE VALUENODES CAN BE SELECTED AT ONCE
676 //we want to jump to the value desc if we're not currently on it
677 // but only if we want to add the point
678 if(clickfound && !(sel_value == valdesc))
684 //now that we've made sure we're selecting the correct value, deal with the already selected points
685 set<Time>::iterator foundi = clickfound ? sel_times.find(stime) : sel_times.end();
686 bool found = foundi != sel_times.end();
688 //remove all other points from our list... (only select the one we need)
689 if(!selectmode && !found)
694 if(found && selectmode) //remove a single already selected point
696 sel_times.erase(foundi);
697 }else if(clickfound) //otherwise look at adding it
699 //for replace the list was cleared earlier, and for add it wasn't so it works
700 sel_times.insert(stime);
707 iter=find_waypoint(selected_time,pixel_width*cell_area.get_height()/2);
708 selected_waypoint=iter;
716 selected=synfig::UniqueID::nil();
719 if((!sel_times.empty() || selection) && event->button.button==1)
722 drag_time=selected_time;
723 actual_dragtime=actual_time;
725 //selected_time=iter->time;
728 // Activepoint Selection
729 if(parent_value_node)
731 const int index(property_value_desc().get_value().get_index());
732 const synfig::ValueNode_DynamicList::ListEntry::ActivepointList& activepoint_list(parent_value_node->list[index].timing_info);
733 synfig::ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator iter;
735 for(iter=activepoint_list.begin();iter!=activepoint_list.end();++iter)
737 Time val=abs(iter->time-selected_time);
745 // Perhaps I should signal if we selected this activepoint?
748 if(event->button.button==3)
751 synfigapp::ValueDesc valdesc = property_value_desc().get_value();
752 const Node::time_set *tset = get_times_from_vdesc(valdesc);
753 synfig::Time time_offset = get_time_offset_from_vdesc(valdesc);
755 bool clickfound = tset && get_closest_time(*tset,actual_time+time_offset,pixel_width*cell_area.get_height(),stime);
757 etl::handle<synfig::Node> node;
758 if(!getenv("SYNFIG_SHOW_CANVAS_PARAM_WAYPOINTS") &&
759 valdesc.get_value(stime).get_type()==ValueBase::TYPE_CANVAS)
761 node=Canvas::Handle(valdesc.get_value(stime).get(Canvas::Handle()));
763 else //if(valdesc.is_value_node())
765 node=valdesc.get_value_node();
768 if(clickfound && node)
769 signal_waypoint_clicked_cellrenderer()(node, stime, time_offset, 2);
773 case GDK_MOTION_NOTIFY:
774 //if(selection && dragging)
775 // 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();
779 case GDK_BUTTON_RELEASE:
781 //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();
784 /*if(event->button.button==3 && selection)
786 signal_waypoint_clicked_cellrenderer()(path,*selected_waypoint,event->button.button-1);
791 //Time point stuff...
792 if(event->button.button == 1)
794 bool delmode = (mode & DELETE_MASK) && !(mode & COPY_MASK);
795 deltatime = actual_time - actual_dragtime;
796 if(sel_times.size() != 0 && (delmode || !deltatime.is_equal(Time(0))))
798 synfigapp::Action::ParamList param_list;
799 param_list.add("canvas",canvas_interface()->get_canvas());
800 param_list.add("canvas_interface",canvas_interface());
802 if(!getenv("SYNFIG_SHOW_CANVAS_PARAM_WAYPOINTS") &&
803 sel_value.get_value_type() == synfig::ValueBase::TYPE_CANVAS)
805 param_list.add("addcanvas",sel_value.get_value().get(Canvas::Handle()));
808 param_list.add("addvaluedesc",sel_value);
812 std::set<synfig::Time>::iterator i = sel_times.begin(), end = sel_times.end();
815 param_list.add("addtime",*i);
817 newset.insert((*i + deltatime).round(get_canvas()->rend_desc().get_frame_rate()));
821 param_list.add("deltatime",deltatime);
822 // param_list.add("time",canvas_interface()->get_time());
824 if(mode & COPY_MASK) //copy
826 etl::handle<studio::Instance>::cast_static(canvas_interface()->get_instance())
827 ->process_action("TimepointsCopy", param_list);
828 }else if(delmode) //DELETE
830 etl::handle<studio::Instance>::cast_static(canvas_interface()->get_instance())
831 ->process_action("TimepointsDelete", param_list);
834 etl::handle<studio::Instance>::cast_static(canvas_interface()->get_instance())
835 ->process_action("TimepointsMove", param_list);
838 //now replace all the selected with the new selected
845 /*if(value_node && selection)
847 if(selected_time==drag_time && event->button.button!=3)
848 signal_waypoint_clicked_cellrenderer()(path,*selected_waypoint,event->button.button-1);
850 if(event->button.button==1)
852 synfig::Waypoint waypoint(*selected_waypoint);
853 Time newtime((waypoint.get_time()+(selected_time-drag_time)).round(canvas->rend_desc().get_frame_rate()));
854 if(waypoint.get_time()!=newtime)
856 waypoint.set_time(newtime);
857 signal_waypoint_changed_(waypoint,value_node);
863 // selected_time=iter->time;
864 //selected_time=iter->get_time();
868 //std::cerr<<"unknown event type "<<event->type<<std::endl;
880 // The following three functions don't get documented correctly by
881 // doxygen 1.5.[23] because of a bug with any function whose name
882 // begins with 'property'. Fixed in doxygen 1.5.4 apparently. See
883 // http://bugzilla.gnome.org/show_bug.cgi?id=471185 .
884 Glib::PropertyProxy<synfigapp::ValueDesc>
885 CellRenderer_TimeTrack::property_value_desc()
887 return Glib::PropertyProxy<synfigapp::ValueDesc>(this,"value_desc");
890 Glib::PropertyProxy<synfig::Canvas::Handle>
891 CellRenderer_TimeTrack::property_canvas()
893 return Glib::PropertyProxy<synfig::Canvas::Handle>(this,"canvas");
896 Glib::PropertyProxy<Gtk::Adjustment* >
897 CellRenderer_TimeTrack::property_adjustment()
899 return Glib::PropertyProxy<Gtk::Adjustment* >(this,"adjustment");
903 CellRenderer_TimeTrack::set_canvas_interface(etl::loose_handle<synfigapp::CanvasInterface> h)
905 canvas_interface_ = h;