Removed a bunch more DEBUGPOINT()s.
[synfig.git] / synfig-studio / trunk / src / gtkmm / cellrenderer_timetrack.cpp
index b3c9a66..c1759d9 100644 (file)
@@ -1,20 +1,22 @@
-/* === S I N F G =========================================================== */
+/* === S Y N F I G ========================================================= */
 /*!    \file cellrenderer_timetrack.cpp
 **     \brief Template Header
 **
-**     $Id: cellrenderer_timetrack.cpp,v 1.4 2005/01/13 20:23:01 darco Exp $
+**     $Id$
 **
 **     \legal
-**     Copyright (c) 2002 Robert B. Quattlebaum Jr.
+**     Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
+**     Copyright (c) 2007 Chris Moore
 **
-**     This software and associated documentation
-**     are CONFIDENTIAL and PROPRIETARY property of
-**     the above-mentioned copyright holder.
+**     This package is free software; you can redistribute it and/or
+**     modify it under the terms of the GNU General Public License as
+**     published by the Free Software Foundation; either version 2 of
+**     the License, or (at your option) any later version.
 **
-**     You may not copy, print, publish, or in any
-**     other way distribute this software without
-**     a prior written agreement with
-**     the copyright holder.
+**     This package is distributed in the hope that it will be useful,
+**     but WITHOUT ANY WARRANTY; without even the implied warranty of
+**     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+**     General Public License for more details.
 **     \endlegal
 */
 /* ========================================================================= */
 #include "widget_time.h"
 #include "widget_timeslider.h"
 
-#include <sinfgapp/canvasinterface.h>
+#include <synfigapp/canvasinterface.h>
 #include "instance.h"
 
-#include <sinfg/timepointcollect.h>
+#include <synfig/timepointcollect.h>
+
+#include "general.h"
 
 #endif
 
-using namespace sinfg;
+using namespace synfig;
 using namespace std;
 using namespace etl;
 using namespace studio;
@@ -76,19 +80,19 @@ CellRenderer_TimeTrack::CellRenderer_TimeTrack():
        Glib::ObjectBase        (typeid(CellRenderer_TimeTrack)),
        Gtk::CellRenderer       (),
        adjustment_                     (10,10,20,0,0,0),
-       
-       property_valuedesc_     (*this,"value_desc",sinfgapp::ValueDesc()),
-       property_canvas_        (*this,"canvas",sinfg::Canvas::Handle()),
+
+       property_valuedesc_     (*this,"value_desc",synfigapp::ValueDesc()),
+       property_canvas_        (*this,"canvas",synfig::Canvas::Handle()),
        property_adjustment_(*this,"adjustment",&adjustment_),
        property_enable_timing_info_(*this,"enable-timing-info", false)
 {
-               dragging=false;
+       dragging=false;
        selection=false;
 }
 
 CellRenderer_TimeTrack::~CellRenderer_TimeTrack()
 {
-       sinfg::info("CellRenderer_TimeTrack::~CellRenderer_TimeTrack(): deleted");
+       synfig::info("CellRenderer_TimeTrack::~CellRenderer_TimeTrack(): deleted");
 }
 
 void
@@ -98,7 +102,7 @@ CellRenderer_TimeTrack::set_adjustment(Gtk::Adjustment &x)
 //     x.signal_value_changed().connect(sigc::mem_fun(*this,&Gtk::Widget::queue_draw));
 }
 
-sinfg::Canvas::Handle
+synfig::Canvas::Handle
 CellRenderer_TimeTrack::get_canvas()const
 {
        return const_cast<CellRenderer_TimeTrack*>(this)->property_canvas().get_value();
@@ -122,26 +126,48 @@ CellRenderer_TimeTrack::is_selected(const Waypoint& waypoint)const
        return selected==waypoint;
 }
 
+const synfig::Time get_time_offset_from_vdesc(const synfigapp::ValueDesc &v)
+{
+#ifdef ADJUST_WAYPOINTS_FOR_TIME_OFFSET
+       if(v.get_value_type() != synfig::ValueBase::TYPE_CANVAS)
+               return synfig::Time::zero();
+
+       synfig::Canvas::Handle canvasparam = v.get_value().get(Canvas::Handle());
+       if(!canvasparam)
+               return synfig::Time::zero();
+
+       if (!v.parent_is_layer_param())
+               return synfig::Time::zero();
+
+       synfig::Layer::Handle layer = v.get_layer();
+
+       if (layer->get_name()!="PasteCanvas")
+               return synfig::Time::zero();
+
+       return layer->get_param("time_offset").get(Time());
+#else // ADJUST_WAYPOINTS_FOR_TIME_OFFSET
+       return synfig::Time::zero();
+#endif
+}
+
 //kind of a hack... pointer is ugly
-const sinfg::Node::time_set *get_times_from_vdesc(const sinfgapp::ValueDesc &v)
+const synfig::Node::time_set *get_times_from_vdesc(const synfigapp::ValueDesc &v)
 {
-       if(v.get_value_type() == sinfg::ValueBase::TYPE_CANVAS)
+       if(v.get_value_type() == synfig::ValueBase::TYPE_CANVAS)
        {
-               sinfg::Canvas::Handle canvasparam = v.get_value().get(Canvas::Handle());
-       
+               synfig::Canvas::Handle canvasparam = v.get_value().get(Canvas::Handle());
+
                if(canvasparam)
-               {
                        return &canvasparam->get_times();
-               }
        }
-       
+
        ValueNode *base_value = v.get_value_node().get();
-       
-       ValueNode_DynamicList *parent_value_node = 
+
+       ValueNode_DynamicList *parent_value_node =
                        v.parent_is_value_node() ?
                                dynamic_cast<ValueNode_DynamicList *>(v.get_parent_value_node().get()) :
                                0;
-       
+
        //we want a dynamic list entry to override the normal...
        if(parent_value_node)
        {
@@ -153,36 +179,44 @@ const sinfg::Node::time_set *get_times_from_vdesc(const sinfgapp::ValueDesc &v)
        return 0;
 }
 
-bool get_closest_time(const sinfg::Node::time_set &tset, const Time &t, const Time &range, Time &out)
+bool get_closest_time(const synfig::Node::time_set &tset, const Time &t, const Time &range, Time &out)
 {
        Node::time_set::const_iterator  i,j,end = tset.end();
-       
+
+       // stop the crash mentioned in bug #1689282
+       // doesn't solve the underlying problem though, I don't think
+       if (tset.size() == 0)
+       {
+               synfig::error(__FILE__":%d: tset.size() == 0",__LINE__);
+               return false;
+       }
+
        //TODO add in RangeGet so it's not so damn hard to click on points
-       
+
        i = tset.upper_bound(t); //where t is the lower bound, t < [first,i)
        j = i; --j;
-       
+
        double dist = Time::end();
        double closest = 0;
-       
+
        if(i != end)
        {
                closest = i->get_time();
                dist = abs(i->get_time() - t);
        }
-       
+
        if(j != end && (abs(j->get_time() - t) < dist) )
        {
                closest = j->get_time();
                dist = abs(j->get_time() - t);
        }
-       
+
        if( dist <= range/2 )
        {
                out = closest;
                return true;
        }
-       
+
        return false;
 }
 
@@ -190,19 +224,19 @@ void
 CellRenderer_TimeTrack::render_vfunc(
                const Glib::RefPtr<Gdk::Drawable>& window,
                Gtk::Widget& widget,
-               const Gdk::Rectangle& background_area,
+               const Gdk::Rectangle& /*background_area*/,
                const Gdk::Rectangle& area_,
-               const Gdk::Rectangle& expose_area,
-               Gtk::CellRendererState flags)
+               const Gdk::Rectangle& /*expose_area*/,
+               Gtk::CellRendererState /*flags*/)
 {
        if(!window)
                return;
-       
+
        Glib::RefPtr<Gdk::GC> gc(Gdk::GC::create(window));
        Glib::RefPtr<Gdk::GC> inactive_gc(Gdk::GC::create(window));
        Gtk::Adjustment *adjustment=get_adjustment();
-       Gtk::StateType state = Gtk::STATE_ACTIVE;
-       Gtk::ShadowType shadow;
+       // Gtk::StateType state = Gtk::STATE_ACTIVE;
+       // Gtk::ShadowType shadow;
 
        Gdk::Color
                curr_time_color("#0000ff"),
@@ -216,84 +250,84 @@ CellRenderer_TimeTrack::render_vfunc(
        inactive_gc->set_rgb_fg_color(inactive_color);
        inactive_gc->set_stipple(Gdk::Bitmap::create(stipple_xpm,2,2));
        inactive_gc->set_fill(Gdk::STIPPLED);
-       
-       sinfg::Canvas::Handle canvas(property_canvas().get_value());
-       
-       sinfgapp::ValueDesc value_desc = property_value_desc().get_value();
-       sinfg::ValueNode *base_value = value_desc.get_value_node().get();
-       sinfg::ValueNode_Animated *value_node=dynamic_cast<sinfg::ValueNode_Animated*>(base_value);
-
-       sinfg::ValueNode_DynamicList *parent_value_node(0);
+
+       synfig::Canvas::Handle canvas(property_canvas().get_value());
+
+       synfigapp::ValueDesc value_desc = property_value_desc().get_value();
+       synfig::ValueNode *base_value = value_desc.get_value_node().get();
+       // synfig::ValueNode_Animated *value_node=dynamic_cast<synfig::ValueNode_Animated*>(base_value);
+
+       synfig::ValueNode_DynamicList *parent_value_node(0);
        if(property_value_desc().get_value().parent_is_value_node())
-               parent_value_node=dynamic_cast<sinfg::ValueNode_DynamicList*>(property_value_desc().get_value().get_parent_value_node().get());
+               parent_value_node=dynamic_cast<synfig::ValueNode_DynamicList*>(property_value_desc().get_value().get_parent_value_node().get());
 
        // If the canvas is defined, then load up the keyframes
        if(canvas)
        {
-               const sinfg::KeyframeList& keyframe_list(canvas->keyframe_list());
-               sinfg::KeyframeList::const_iterator iter;
-               
+               const synfig::KeyframeList& keyframe_list(canvas->keyframe_list());
+               synfig::KeyframeList::const_iterator iter;
+
                for(iter=keyframe_list.begin();iter!=keyframe_list.end();++iter)
                {
                        if(!iter->get_time().is_valid())
                                continue;
-                       
+
                        const int x((int)((float)area_.get_width()/(adjustment->get_upper()-adjustment->get_lower())*(iter->get_time()-adjustment->get_lower())));
                        if(iter->get_time()>=adjustment->get_lower() && iter->get_time()<adjustment->get_upper())
                        {
                                gc->set_rgb_fg_color(keyframe_color);
                                window->draw_rectangle(gc, true, area_.get_x()+x, area_.get_y(), 1, area_.get_height()+1);
-                       }                       
+                       }
                }
        }
-       
+
        //render all the time points that exist
        {
-               const sinfg::Node::time_set *tset = get_times_from_vdesc(value_desc);
-               
+               const synfig::Node::time_set *tset = get_times_from_vdesc(value_desc);
+
                if(tset)
                {
-                       sinfg::Node::time_set::const_iterator   i = tset->begin(), end = tset->end();
-                       
+                       const synfig::Time time_offset = get_time_offset_from_vdesc(value_desc);
+                       synfig::Node::time_set::const_iterator  i = tset->begin(), end = tset->end();
+
                        float   lower = adjustment->get_lower(),
                                        upper = adjustment->get_upper();
-                       
+
                        Glib::RefPtr<Gdk::GC>   gc = Gdk::GC::create(widget.get_window());
-                       
+
                        Gdk::Rectangle area(area_);
                        gc->set_clip_rectangle(area);
                        gc->set_line_attributes(1,Gdk::LINE_SOLID,Gdk::CAP_BUTT,Gdk::JOIN_MITER);
-                       
+
                        bool valselected = sel_value.get_value_node() == base_value && !sel_times.empty();
-                       
+
                        float cfps = get_canvas()->rend_desc().get_frame_rate();
-                       
+
                        vector<Time>    drawredafter;
-                       
+
                        Time diff = actual_time - actual_dragtime;//selected_time-drag_time;
                        for(; i != end; ++i)
                        {
                                //find the coordinate in the drawable space...
-                               Time t = i->get_time();
-                               
-                               if(!t.is_valid())
-                                       continue;
-                               
-                               //if it found it... (might want to change comparison, and optimize 
+                               Time t_orig = i->get_time();
+                               if(!t_orig.is_valid()) continue;
+                               Time t = t_orig - time_offset;
+
+                               //if it found it... (might want to change comparison, and optimize
                                //                                       sel_times.find to not produce an overall nlogn solution)
-                               
+
                                bool selected=false;
                                //not dragging... just draw as per normal
                                //if move dragging draw offset
                                //if copy dragging draw both...
-                                                               
-                               if(valselected && sel_times.find(t) != sel_times.end())
+
+                               if(valselected && sel_times.find(t_orig) != sel_times.end())
                                {
                                        if(dragging) //skip if we're dragging because we'll render it later
                                        {
                                                if(mode & COPY_MASK) // draw both blue and red moved
                                                {
-                                                       drawredafter.push_back((t + diff).round(cfps));
+                                                       drawredafter.push_back(t + diff.round(cfps));
                                                        gc->set_rgb_fg_color(Gdk::Color("#00EEEE"));
                                                }else if(mode & DELETE_MASK) //it's just red...
                                                {
@@ -301,7 +335,7 @@ CellRenderer_TimeTrack::render_vfunc(
                                                        selected=true;
                                                }else //move - draw the red on top of the others...
                                                {
-                                                       drawredafter.push_back((t + diff).round(cfps));
+                                                       drawredafter.push_back(t + diff.round(cfps));
                                                        continue;
                                                }
                                        }else
@@ -313,10 +347,10 @@ CellRenderer_TimeTrack::render_vfunc(
                                {
                                        gc->set_rgb_fg_color(Gdk::Color("#00EEEE"));
                                }
-                               
-                               //sinfg::info("Displaying time: %.3f s",(float)t);
+
+                               //synfig::info("Displaying time: %.3f s",(float)t);
                                const int x = (int)((t-lower)*area.get_width()/(upper-lower));
-                               
+
                                //should draw me a grey filled circle...
                                Gdk::Rectangle area2(
                                        area.get_x() - area.get_height()/2 + x + 1,
@@ -324,13 +358,13 @@ CellRenderer_TimeTrack::render_vfunc(
                                        area.get_height()-2,
                                        area.get_height()-2
                                );
-                               render_time_point_to_window(window,area2,*i,selected);
-                               
+                               render_time_point_to_window(window,area2,*i - time_offset,selected);
+
                                /*window->draw_arc(gc,true,
                                area.get_x() + x - area.get_height()/4, area.get_y() + area.get_height()/8,
                                area.get_height()/2, area.get_height()*3/4,
                                0, 64*360);
-                               
+
                                gc->set_rgb_fg_color(Gdk::Color("#000000"));
                                window->draw_arc(gc,false,
                                area.get_x() + x - area.get_height()/4, area.get_y() + area.get_height()/8,
@@ -338,22 +372,22 @@ CellRenderer_TimeTrack::render_vfunc(
                                0, 64*360);
                                */
                        }
-                       
+
                        {
                                vector<Time>::iterator i = drawredafter.begin(), end = drawredafter.end();
                                for(; i != end; ++i)
                                {
                                        //find the coordinate in the drawable space...
                                        Time t = *i;
-                                       
+
                                        if(!t.is_valid())
                                                continue;
-                                                                                                               
-                                       //sinfg::info("Displaying time: %.3f s",(float)t);
+
+                                       //synfig::info("Displaying time: %.3f s",(float)t);
                                        const int x = (int)((t-lower)*area.get_width()/(upper-lower));
-                                       
+
                                        //should draw me a grey filled circle...
-                                       
+
                                        Gdk::Rectangle area2(
                                                area.get_x() - area.get_height()/2 + x + 1,
                                                area.get_y() + 1,
@@ -366,14 +400,14 @@ CellRenderer_TimeTrack::render_vfunc(
                                        area.get_x() + x - area.get_height()/4, area.get_y() + area.get_height()/8,
                                        area.get_height()/2, area.get_height()*3/4,
                                        0, 64*360);
-                                       
+
                                        gc->set_rgb_fg_color(Gdk::Color("#000000"));
                                        window->draw_arc(gc,false,
                                        area.get_x() + x - area.get_height()/4, area.get_y() + area.get_height()/8,
                                        area.get_height()/2, area.get_height()*3/4,
                                        0, 64*360);
 */
-                               }               
+                               }
                        }
                }
        }
@@ -381,9 +415,9 @@ CellRenderer_TimeTrack::render_vfunc(
        /* THIS IS NOW HANDLED ENTIRELY BY THE TIMEPOINT SYSTEM
        // This this is an animated value node, then render the waypoints
        if(value_node)
-       {                               
+       {
                //now render the actual waypoints
-               sinfg::ValueNode_Animated::WaypointList::iterator iter;
+               synfig::ValueNode_Animated::WaypointList::iterator iter;
                for(
                        iter=value_node->waypoint_list().begin();
                        iter!=value_node->waypoint_list().end();
@@ -412,8 +446,8 @@ CellRenderer_TimeTrack::render_vfunc(
                                shadow=Gtk::SHADOW_OUT;
                                selected=false;
                        }
-                       
-                       
+
+
                        widget.get_style()->paint_diamond(
                                Glib::RefPtr<Gdk::Window>::cast_static(window),
                                state,
@@ -435,31 +469,31 @@ CellRenderer_TimeTrack::render_vfunc(
        if(parent_value_node)
        {
                const int index(property_value_desc().get_value().get_index());
-               const sinfg::ValueNode_DynamicList::ListEntry& list_entry(parent_value_node->list[index]);
-               const sinfg::ValueNode_DynamicList::ListEntry::ActivepointList& activepoint_list(list_entry.timing_info);
-               sinfg::ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator iter,next;
+               const synfig::ValueNode_DynamicList::ListEntry& list_entry(parent_value_node->list[index]);
+               const synfig::ValueNode_DynamicList::ListEntry::ActivepointList& activepoint_list(list_entry.timing_info);
+               synfig::ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator iter,next;
 
                bool is_off(false);
                if(!activepoint_list.empty())
                        is_off=!activepoint_list.front().state;
-               
+
                int xstart(0);
-               
+
                int x=0,prevx=0;
                for(next=activepoint_list.begin(),iter=next++;iter!=activepoint_list.end();iter=next++)
                {
                        x=((int)((float)area.get_width()/(adjustment->get_upper()-adjustment->get_lower())*(iter->time-adjustment->get_lower())));
                        if(x<0)x=0;
                        if(x>area.get_width())x=area.get_width();
-                       
+
                        bool status_at_time=0;
                        if(next!=activepoint_list.end())
                        {
-                               status_at_time=!list_entry.status_at_time((iter->time+next->time)/2.0); 
+                               status_at_time=!list_entry.status_at_time((iter->time+next->time)/2.0);
                        }
                        else
-                               status_at_time=!list_entry.status_at_time(Time::end()); 
-                       
+                               status_at_time=!list_entry.status_at_time(Time::end());
+
                        if(!is_off && status_at_time)
                        {
                                xstart=x;
@@ -471,7 +505,7 @@ CellRenderer_TimeTrack::render_vfunc(
                                window->draw_rectangle(inactive_gc, true, area.get_x()+xstart, area.get_y(), x-xstart, area.get_height());
                                is_off=false;
                        }
-                       
+
                        /*
                        if(!is_off && iter!=activepoint_list.end() && next->state==false && iter->state==false)
                        {
@@ -489,9 +523,9 @@ CellRenderer_TimeTrack::render_vfunc(
                                is_off=false;
                        }
                        */
-                       
-                       
-                       
+
+
+
                        if(iter->time>=adjustment->get_lower() && iter->time<adjustment->get_upper())
                        {
                                int w(1);
@@ -506,8 +540,8 @@ CellRenderer_TimeTrack::render_vfunc(
                {
                        window->draw_rectangle(inactive_gc, true, area.get_x()+xstart, area.get_y(), area.get_width()-xstart, area.get_height());
                }
-       }               
-               
+       }
+
        // Render a line that defines the current tick in time
        {
                gc->set_rgb_fg_color(curr_time_color);
@@ -519,14 +553,14 @@ CellRenderer_TimeTrack::render_vfunc(
        }
 }
 
-sinfg::ValueNode_Animated::WaypointList::iterator
-CellRenderer_TimeTrack::find_waypoint(const sinfg::Time& t,const sinfg::Time& scope)
+synfig::ValueNode_Animated::WaypointList::iterator
+CellRenderer_TimeTrack::find_waypoint(const synfig::Time& /*t*/,const synfig::Time& scope)
 {
-       sinfg::ValueNode_Animated *value_node=dynamic_cast<sinfg::ValueNode_Animated*>(property_value_desc().get_value().get_value_node().get());
+       synfig::ValueNode_Animated *value_node=dynamic_cast<synfig::ValueNode_Animated*>(property_value_desc().get_value().get_value_node().get());
 
     Time nearest(Time::end());
 
-       sinfg::ValueNode_Animated::WaypointList::iterator iter,ret;
+       synfig::ValueNode_Animated::WaypointList::iterator iter,ret;
 
        if(value_node)
        {
@@ -555,24 +589,24 @@ CellRenderer_TimeTrack::find_waypoint(const sinfg::Time& t,const sinfg::Time& sc
 bool
 CellRenderer_TimeTrack::activate_vfunc(
        GdkEvent* event,
-       Gtk::Widget& widget,
+       Gtk::Widget& /*widget*/,
        const Glib::ustring& treepath,
-       const Gdk::Rectangle& background_area,
+       const Gdk::Rectangle& /*background_area*/,
        const Gdk::Rectangle& cell_area,
-       Gtk::CellRendererState flags)
+       Gtk::CellRendererState /*flags*/)
 {
        path=treepath;
-       sinfg::ValueNode_Animated::WaypointList::iterator iter;
+       synfig::ValueNode_Animated::WaypointList::iterator iter;
     Time nearest=1000000000;
        Gtk::Adjustment *adjustment=get_adjustment();
 
-       sinfg::ValueNode_Animated *value_node=dynamic_cast<sinfg::ValueNode_Animated*>(property_value_desc().get_value().get_value_node().get());
+       // synfig::ValueNode_Animated *value_node=dynamic_cast<synfig::ValueNode_Animated*>(property_value_desc().get_value().get_value_node().get());
 
-       sinfg::Canvas::Handle canvas(get_canvas());
+       synfig::Canvas::Handle canvas(get_canvas());
 
-       sinfg::ValueNode_DynamicList *parent_value_node(0);
+       synfig::ValueNode_DynamicList *parent_value_node(0);
        if(property_value_desc().get_value().parent_is_value_node())
-               parent_value_node=dynamic_cast<sinfg::ValueNode_DynamicList*>(property_value_desc().get_value().get_parent_value_node().get());
+               parent_value_node=dynamic_cast<synfig::ValueNode_DynamicList*>(property_value_desc().get_value().get_parent_value_node().get());
 
        Time deltatime = 0;
        Time curr_time;
@@ -580,9 +614,9 @@ CellRenderer_TimeTrack::activate_vfunc(
        {
        case GDK_MOTION_NOTIFY:
                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();
-               
-               mode = NONE;                    
-               {       
+
+               mode = NONE;
+               {
                        Gdk::ModifierType mod;
                        Gdk::Event(event).get_state(mod);
                        mode = mod;
@@ -592,20 +626,20 @@ CellRenderer_TimeTrack::activate_vfunc(
        case GDK_BUTTON_RELEASE:
        default:
                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();
-               {       
+               {
                        Gdk::ModifierType mod;
                        Gdk::Event(event).get_state(mod);
                        mode = mod;
                }
-               break;          
+               break;
        }
-       actual_time = curr_time;        
+       actual_time = curr_time;
        if(canvas)
                curr_time=curr_time.round(canvas->rend_desc().get_frame_rate());
        selected_time=curr_time;
 
     Time pixel_width((adjustment->get_upper()-adjustment->get_lower())/cell_area.get_width());
-       
+
     switch(event->type)
     {
        case GDK_BUTTON_PRESS:
@@ -615,26 +649,27 @@ CellRenderer_TimeTrack::activate_vfunc(
                if(/*!value_node && */event->button.button == 1)
                {
                        Time stime;
-                       
+
                        /*!     UI specification:
-                       
-                               When nothing is selected, clicking on a point in either normal mode order
-                                       addative mode will select the time point closest to the click. 
+
+                               When nothing is selected, clicking on a point in either normal mode or
+                                       additive mode will select the time point closest to the click.
                                        Subtractive click will do nothing
-                       
+
                                When things are already selected, clicking on a selected point does
                                        nothing (in both normal and add mode).  Add mode clicking on an unselected
                                        point adds it to the set.  Normal clicking on an unselected point will
                                        select only that one time point.  Subtractive clicking on any point
                                        will remove it from the the set if it is included.
                        */
-                                               
-                       sinfgapp::ValueDesc valdesc = property_value_desc().get_value();
+
+                       synfigapp::ValueDesc valdesc = property_value_desc().get_value();
                        const Node::time_set *tset = get_times_from_vdesc(valdesc);
-                       
-                       bool clickfound = tset && get_closest_time(*tset,actual_time,pixel_width*cell_area.get_height(),stime);
+                       const synfig::Time time_offset = get_time_offset_from_vdesc(valdesc);
+
+                       bool clickfound = tset && get_closest_time(*tset,actual_time+time_offset,pixel_width*cell_area.get_height(),stime);
                        bool selectmode = mode & SELECT_MASK;
-                                               
+
                        //NOTE LATER ON WE SHOULD MAKE IT SO MULTIPLE VALUENODES CAN BE SELECTED AT ONCE
                        //we want to jump to the value desc if we're not currently on it
                        //      but only if we want to add the point
@@ -643,42 +678,42 @@ CellRenderer_TimeTrack::activate_vfunc(
                                sel_value = valdesc;
                                sel_times.clear();
                        }
-                       
+
                        //now that we've made sure we're selecting the correct value, deal with the already selected points
                        set<Time>::iterator foundi = clickfound ? sel_times.find(stime) : sel_times.end();
                        bool found = foundi != sel_times.end();
-                       
+
                        //remove all other points from our list... (only select the one we need)
                        if(!selectmode && !found)
                        {
                                sel_times.clear();
                        }
-                       
+
                        if(found && selectmode) //remove a single already selected point
                        {
                                sel_times.erase(foundi);
                        }else if(clickfound) //otherwise look at adding it
                        {
                                //for replace the list was cleared earlier, and for add it wasn't so it works
-                               sel_times.insert(stime);                                
+                               sel_times.insert(stime);
                        }
                }
-               
+
                selection=false;
                try
                {
                        iter=find_waypoint(selected_time,pixel_width*cell_area.get_height()/2);
                        selected_waypoint=iter;
                        selected=*iter;
-                       
+
                        selection=true;
                }
                catch(int)
                {
                        selection=false;
-                       selected=sinfg::UniqueID::nil();
+                       selected=synfig::UniqueID::nil();
                }
-               
+
                if((!sel_times.empty() || selection) && event->button.button==1)
                {
                        dragging=true;
@@ -692,9 +727,9 @@ CellRenderer_TimeTrack::activate_vfunc(
                if(parent_value_node)
                {
                        const int index(property_value_desc().get_value().get_index());
-                       const sinfg::ValueNode_DynamicList::ListEntry::ActivepointList& activepoint_list(parent_value_node->list[index].timing_info);
-                       sinfg::ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator iter;
-       
+                       const synfig::ValueNode_DynamicList::ListEntry::ActivepointList& activepoint_list(parent_value_node->list[index].timing_info);
+                       synfig::ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator iter;
+
                        for(iter=activepoint_list.begin();iter!=activepoint_list.end();++iter)
                        {
                                Time val=abs(iter->time-selected_time);
@@ -705,18 +740,19 @@ CellRenderer_TimeTrack::activate_vfunc(
                                        selection=true;
                                }
                        }
-                       // Perhaps I sould signal if we selected this activepoint?
+                       // Perhaps I should signal if we selected this activepoint?
                }*/
-               
+
                        if(event->button.button==3)
                        {
                                Time stime;
-                               sinfgapp::ValueDesc valdesc = property_value_desc().get_value();
+                               synfigapp::ValueDesc valdesc = property_value_desc().get_value();
                                const Node::time_set *tset = get_times_from_vdesc(valdesc);
-                               
-                               bool clickfound = tset && get_closest_time(*tset,actual_time,pixel_width*cell_area.get_height(),stime);
-                               
-                               etl::handle<sinfg::Node> node;
+                               synfig::Time time_offset = get_time_offset_from_vdesc(valdesc);
+
+                               bool clickfound = tset && get_closest_time(*tset,actual_time+time_offset,pixel_width*cell_area.get_height(),stime);
+
+                               etl::handle<synfig::Node> node;
                                if(valdesc.get_value(stime).get_type()==ValueBase::TYPE_CANVAS)
                                {
                                        node=Canvas::Handle(valdesc.get_value(stime).get(Canvas::Handle()));
@@ -725,35 +761,32 @@ CellRenderer_TimeTrack::activate_vfunc(
                                {
                                        node=valdesc.get_value_node();
                                }
-                               
+
                                if(clickfound && node)
                                {
-                                       show_timepoint_menu(node, stime, actual_time<stime?SIDE_LEFT:SIDE_RIGHT);
+                                       show_timepoint_menu(node, stime, time_offset, actual_time+time_offset<stime?SIDE_LEFT:SIDE_RIGHT);
                                }
                        }
 
                break;
        case GDK_MOTION_NOTIFY:
-               //DEBUGPOINT();
                //if(selection && dragging)
                //      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();
                return true;
-               
+
                break;
        case GDK_BUTTON_RELEASE:
                {
-                       DEBUGPOINT();
-       
                        //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();
                        dragging=false;
-       
+
                        /*if(event->button.button==3 && selection)
                        {
                                signal_waypoint_clicked_(path,*selected_waypoint,event->button.button-1);
                                return true;
                        }
                        */
-                       
+
                        //Time point stuff...
                        if(event->button.button == 1)
                        {
@@ -761,31 +794,31 @@ CellRenderer_TimeTrack::activate_vfunc(
                                deltatime = actual_time - actual_dragtime;
                                if(sel_times.size() != 0 && (delmode || !deltatime.is_equal(Time(0))))
                                {
-                                       sinfgapp::Action::ParamList param_list;
+                                       synfigapp::Action::ParamList param_list;
                                        param_list.add("canvas",canvas_interface()->get_canvas());
                                        param_list.add("canvas_interface",canvas_interface());
-                                       
-                                       if(sel_value.get_value_type() == sinfg::ValueBase::TYPE_CANVAS)
+
+                                       if(sel_value.get_value_type() == synfig::ValueBase::TYPE_CANVAS)
                                        {
                                                param_list.add("addcanvas",sel_value.get_value().get(Canvas::Handle()));
                                        }else
                                        {
                                                param_list.add("addvaluedesc",sel_value);
                                        }
-                                       
+
                                        set<Time>       newset;
-                                       std::set<sinfg::Time>::iterator i = sel_times.begin(), end = sel_times.end();
+                                       std::set<synfig::Time>::iterator i = sel_times.begin(), end = sel_times.end();
                                        for(; i != end; ++i)
                                        {
                                                param_list.add("addtime",*i);
-                                               
+
                                                newset.insert((*i + deltatime).round(get_canvas()->rend_desc().get_frame_rate()));
                                        }
-                                                               
+
                                        if(!delmode)
                                                param_list.add("deltatime",deltatime);
                                //      param_list.add("time",canvas_interface()->get_time());
-                                       
+
                                        if(mode & COPY_MASK) //copy
                                        {
                                                etl::handle<studio::Instance>::cast_static(canvas_interface()->get_instance())
@@ -793,20 +826,20 @@ CellRenderer_TimeTrack::activate_vfunc(
                                        }else if(delmode) //DELETE
                                        {
                                                etl::handle<studio::Instance>::cast_static(canvas_interface()->get_instance())
-                                                       ->process_action("timepoint_delete", param_list);                                       
+                                                       ->process_action("timepoint_delete", param_list);
                                        }else //MOVE
                                        {
                                                etl::handle<studio::Instance>::cast_static(canvas_interface()->get_instance())
-                                                       ->process_action("timepoint_move", param_list);                                 
+                                                       ->process_action("timepoint_move", param_list);
                                        }
-                                       
+
                                        //now replace all the selected with the new selected
-                                       sel_times = newset;                     
+                                       sel_times = newset;
                                }
                        }
-                       
-                       
-                       
+
+
+
                        /*if(value_node && selection)
                        {
                                if(selected_time==drag_time && event->button.button!=3)
@@ -814,7 +847,7 @@ CellRenderer_TimeTrack::activate_vfunc(
                                else
                                if(event->button.button==1)
                                {
-                                       sinfg::Waypoint waypoint(*selected_waypoint);
+                                       synfig::Waypoint waypoint(*selected_waypoint);
                                        Time newtime((waypoint.get_time()+(selected_time-drag_time)).round(canvas->rend_desc().get_frame_rate()));
                                        if(waypoint.get_time()!=newtime)
                                        {
@@ -823,7 +856,7 @@ CellRenderer_TimeTrack::activate_vfunc(
                                        }
                                }
                        }*/
-                       
+
                        //if(selection)
                        //      selected_time=iter->time;
                        //selected_time=iter->get_time();
@@ -833,7 +866,7 @@ CellRenderer_TimeTrack::activate_vfunc(
                //std::cerr<<"unknown event type "<<event->type<<std::endl;
                return false;
                break;
-       }       
+       }
 
 
 
@@ -842,16 +875,20 @@ CellRenderer_TimeTrack::activate_vfunc(
 
 
 
-Glib::PropertyProxy<sinfgapp::ValueDesc>
+// The following three functions don't get documented correctly by
+// doxygen 1.5.[23] because of a bug with any function whose name
+// begins with 'property'.  Fixed in doxygen 1.5.4 apparently.  See
+// http://bugzilla.gnome.org/show_bug.cgi?id=471185 .
+Glib::PropertyProxy<synfigapp::ValueDesc>
 CellRenderer_TimeTrack::property_value_desc()
 {
-       return Glib::PropertyProxy<sinfgapp::ValueDesc>(this,"value_desc");
+       return Glib::PropertyProxy<synfigapp::ValueDesc>(this,"value_desc");
 }
 
-Glib::PropertyProxy<sinfg::Canvas::Handle>
+Glib::PropertyProxy<synfig::Canvas::Handle>
 CellRenderer_TimeTrack::property_canvas()
 {
-       return Glib::PropertyProxy<sinfg::Canvas::Handle>(this,"canvas");
+       return Glib::PropertyProxy<synfig::Canvas::Handle>(this,"canvas");
 }
 
 Glib::PropertyProxy<Gtk::Adjustment* >
@@ -861,27 +898,27 @@ CellRenderer_TimeTrack::property_adjustment()
 }
 
 void
-CellRenderer_TimeTrack::set_canvas_interface(etl::loose_handle<sinfgapp::CanvasInterface>      h)
+CellRenderer_TimeTrack::set_canvas_interface(etl::loose_handle<synfigapp::CanvasInterface>     h)
 {
        canvas_interface_ = h;
 }
 
 static void
-set_waypoint_model(std::set<sinfg::Waypoint, std::less<UniqueID> > waypoints, Waypoint::Model model, etl::loose_handle<sinfgapp::CanvasInterface> canvas_interface)
+set_waypoint_model(std::set<synfig::Waypoint, std::less<UniqueID> > waypoints, Waypoint::Model model, etl::loose_handle<synfigapp::CanvasInterface> canvas_interface)
 {
        // Create the action group
-       sinfgapp::Action::PassiveGrouper group(canvas_interface->get_instance().get(),_("Change Waypoint Group"));
+       synfigapp::Action::PassiveGrouper group(canvas_interface->get_instance().get(),_("Change Waypoint Group"));
 
-       std::set<sinfg::Waypoint, std::less<UniqueID> >::const_iterator iter;
+       std::set<synfig::Waypoint, std::less<UniqueID> >::const_iterator iter;
        for(iter=waypoints.begin();iter!=waypoints.end();++iter)
        {
                Waypoint waypoint(*iter);
                waypoint.apply_model(model);
-               
-               sinfgapp::Action::Handle action(sinfgapp::Action::create("waypoint_set"));
-               
+
+               synfigapp::Action::Handle action(synfigapp::Action::create("waypoint_set"));
+
                assert(action);
-               
+
                action->set_param("canvas",canvas_interface->get_canvas());
                action->set_param("canvas_interface",canvas_interface);
 
@@ -897,20 +934,31 @@ set_waypoint_model(std::set<sinfg::Waypoint, std::less<UniqueID> > waypoints, Wa
 }
 
 void
-CellRenderer_TimeTrack::show_timepoint_menu(const etl::handle<sinfg::Node>& node, const sinfg::Time& time, Side side)
+CellRenderer_TimeTrack::show_timepoint_menu(const etl::handle<synfig::Node>& node, const synfig::Time& time, const synfig::Time& time_offset, Side side)
 {
-       std::set<sinfg::Waypoint, std::less<UniqueID> > waypoint_set;
+       std::set<synfig::Waypoint, std::less<UniqueID> > waypoint_set;
        int n;
-       n=sinfg::waypoint_collect(waypoint_set,time,node);
+       n=synfig::waypoint_collect(waypoint_set,time,node);
 
        Gtk::Menu* menu(manage(new Gtk::Menu()));
+       menu->signal_hide().connect(sigc::bind(sigc::ptr_fun(&delete_widget), menu));
 
        // Create the interpolation method menu
        if(!waypoint_set.empty())
        {
                Gtk::Menu* interp_menu(manage(new Gtk::Menu()));
+               // no need to connect to signal_hide for this one - it will be deleted when its parent is deleted
                Waypoint::Model model;
-               
+
+               // note: each of the following 4 'if' blocks provokes these warnings:
+               //  /usr/include/sigc++-2.0/sigc++/adaptors/bound_argument.h:57: warning:
+               //  'model.synfig::Waypoint::Model::temporal_tension' is used uninitialized in this function
+               //      'model.synfig::Waypoint::Model::bias' is used uninitialized in this function
+               //      'model.synfig::Waypoint::Model::continuity' is used uninitialized in this function
+               //      'model.synfig::Waypoint::Model::tension' is used uninitialized in this function
+               //      'model.synfig::Waypoint::Model::priority' is used uninitialized in this function
+               // I don't know if that matters or not.
+
                if(side==SIDE_LEFT)model.set_before(INTERPOLATION_TCB);
                else model.set_after(INTERPOLATION_TCB);
                interp_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("TCB"),
@@ -954,8 +1002,8 @@ CellRenderer_TimeTrack::show_timepoint_menu(const etl::handle<sinfg::Node>& node
                                canvas_interface()
                        )
                ));
-               
-               
+
+
                menu->items().push_back(
                        Gtk::Menu_Helpers::MenuElem(
                                side==SIDE_LEFT?_("Change \"In\" Interp."):_("Change \"Out\" Interp."),
@@ -968,15 +1016,17 @@ CellRenderer_TimeTrack::show_timepoint_menu(const etl::handle<sinfg::Node>& node
                sigc::bind(
                        sigc::mem_fun(
                                *canvas_interface(),
-                               &sinfgapp::CanvasInterface::set_time
+                               &synfigapp::CanvasInterface::set_time
                        ),
-                       time
+                       time - time_offset
                )
        ));
 
        if(!waypoint_set.empty())
        {
-               if(waypoint_set.size()==1)
+               // attempting to locate the valuenode for the clicked waypoint doesn't work if this is a Canvas parameter,
+               // so act as if there were multiple waypoints in that case as a workaround
+               if(waypoint_set.size()==1 && !Canvas::Handle::cast_dynamic(node))
                {
                        delete menu;
                        menu=0;
@@ -984,10 +1034,10 @@ CellRenderer_TimeTrack::show_timepoint_menu(const etl::handle<sinfg::Node>& node
                        return;
                }
                else
-                       sinfg::info("Too many waypoints under me");
+                       synfig::info("Too many waypoints under me");
        }
        else
-               sinfg::info("ZERO waypoints under me");
+               synfig::info("ZERO waypoints under me");
 
        if(menu)menu->popup(3,gtk_get_current_event_time());
 }