Added copyright lines for files I've edited this year.
[synfig.git] / synfig-studio / trunk / src / gtkmm / canvasview.cpp
index 561549f..ad2ab6b 100644 (file)
@@ -6,7 +6,7 @@
 **
 **     \legal
 **     Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
-**     Copyright (c) 2007 Chris Moore
+**     Copyright (c) 2007, 2008 Chris Moore
 **
 **     This package is free software; you can redistribute it and/or
 **     modify it under the terms of the GNU General Public License as
@@ -912,11 +912,22 @@ CanvasView::~CanvasView()
        // this was causing a crash before
        canvas_interface()->signal_dirty_preview().clear();
 
-       synfig::info("CanvasView:~CanvasView(): Destructor Finished");
+       if (getenv("SYNFIG_DEBUG_DESTRUCTORS"))
+               synfig::info("CanvasView::~CanvasView(): Deleted");
 }
 
 
 
+std::list<int>&
+CanvasView::get_pixel_sizes()
+{
+       // prime factors of 120 are 2, 2, 2, 3, 5 - see TILE_SIZE in synfig-core/trunk/src/synfig/target_tile.h
+       static int pixel_size_array[] = {2,3,4,5,6,8,10,12,15,20,24,30,40,60,120};
+       static list<int> pixel_sizes = list<int>(pixel_size_array, pixel_size_array + sizeof(pixel_size_array) / sizeof(int));
+
+       return pixel_sizes;
+}
+
 Gtk::Widget *
 CanvasView::create_time_bar()
 {
@@ -1046,109 +1057,117 @@ void
 CanvasView::on_current_time_widget_changed()
 {
        set_time(current_time_widget->get_value());
-}
-
-Gtk::Widget*
-CanvasView::create_children_tree()
-{
-       // Create the layer tree
-       children_tree=manage(new class ChildrenTree());
-
-       // Set up the layer tree
-       //children_tree->set_model(children_tree_store());
-       if(children_tree)children_tree->set_time_adjustment(time_adjustment());
-       if(children_tree)children_tree->show();
-
-       // Connect Signals
-       if(children_tree)children_tree->signal_edited_value().connect(sigc::mem_fun(*this, &studio::CanvasView::on_edited_value));
-       if(children_tree)children_tree->signal_user_click().connect(sigc::mem_fun(*this, &studio::CanvasView::on_children_user_click));
-       if(children_tree)children_tree->signal_waypoint_clicked().connect(sigc::mem_fun(*this, &studio::CanvasView::on_waypoint_clicked));
-       if(children_tree)children_tree->get_selection()->signal_changed().connect(SLOT_EVENT(EVENT_REFRESH_DUCKS));
-
-       return children_tree;
-}
-
-Gtk::Widget*
-CanvasView::create_keyframe_tree()
-{
-       keyframe_tree=manage(new KeyframeTree());
-
-       //keyframe_tree->get_selection()->set_mode(Gtk::SELECTION_MULTIPLE);
-       //keyframe_tree->show();
-       //keyframe_tree->set_model(keyframe_tree_store());
-       keyframe_tree->set_editable(true);
-       //keyframe_tree->signal_edited().connect(sigc::hide_return(sigc::mem_fun(*canvas_interface(), &synfigapp::CanvasInterface::update_keyframe)));
-
-       keyframe_tree->signal_event().connect(sigc::mem_fun(*this, &studio::CanvasView::on_keyframe_tree_event));
-
-       Gtk::ScrolledWindow *scroll_layer_tree = manage(new class Gtk::ScrolledWindow());
-       scroll_layer_tree->set_flags(Gtk::CAN_FOCUS);
-       scroll_layer_tree->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
-       scroll_layer_tree->add(*keyframe_tree);
-       scroll_layer_tree->set_shadow_type(Gtk::SHADOW_ETCHED_IN);
-       //scroll_layer_tree->show();
-
-
-       Gtk::Table *layout_table= manage(new Gtk::Table(1, 2, false));
-       layout_table->attach(*scroll_layer_tree, 0, 1, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
-
-       Gtk::Image *icon;
-       Gtk::IconSize iconsize(Gtk::IconSize::from_name("synfig-small_icon"));
 
-       NEW_SMALL_BUTTON(button_add,"gtk-add",_("New Keyframe"));
-       NEW_SMALL_BUTTON(button_duplicate,"synfig-duplicate",_("Duplicate Keyframe"));
-       NEW_SMALL_BUTTON(button_delete,"gtk-delete",_("Delete Keyframe"));
-
-       Gtk::HBox *hbox(manage(new Gtk::HBox()));
-       layout_table->attach(*hbox, 0, 1, 1, 2, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK, 0, 0);
-
-       hbox->pack_start(*button_add,Gtk::PACK_SHRINK);
-       hbox->pack_start(*button_duplicate,Gtk::PACK_SHRINK);
-       hbox->pack_start(*button_delete,Gtk::PACK_SHRINK);
-
-       /*
-       button_raise->set_relief(Gtk::RELIEF_HALF);
-       button_lower->set_relief(Gtk::RELIEF_HALF);
-       button_duplicate->set_relief(Gtk::RELIEF_HALF);
-       button_delete->set_relief(Gtk::RELIEF_HALF);
-       */
-
-       button_add->signal_clicked().connect(sigc::mem_fun(*this, &studio::CanvasView::on_keyframe_add_pressed));
-       button_duplicate->signal_clicked().connect(sigc::mem_fun(*this, &studio::CanvasView::on_keyframe_duplicate_pressed));
-       button_delete->signal_clicked().connect(sigc::mem_fun(*this, &studio::CanvasView::on_keyframe_remove_pressed));
-
-       //layout_table->show_all();
-
-       keyframe_tab_child=layout_table;
-
-
-       layout_table->hide();
-
-       return layout_table;
+       // show the value being used - it will have been rounded to nearest frame
+       // this was already being done elsewhere, but only if the time was really changed;
+       // if the current time was 6f and the user edited it to 6.1f, then the 6.1f would
+       // be left in the display without the following line to fix it
+       current_time_widget->set_value(get_time());
+       current_time_widget->set_position(-1); // leave the cursor at the end
 }
 
-Gtk::Widget*
-CanvasView::create_layer_tree()
-{
-       // Create the layer tree
-       layer_tree=manage(new class LayerTree());
-
-       // Set up the layer tree
-       //layer_tree->set_model(layer_tree_store());
-       layer_tree->set_time_adjustment(time_adjustment());
-       layer_tree->show();
+//     Gtk::Widget*
+//     CanvasView::create_children_tree()
+//     {
+//             // Create the layer tree
+//             children_tree=manage(new class ChildrenTree());
+//
+//             // Set up the layer tree
+//             //children_tree->set_model(children_tree_store());
+//             if(children_tree)children_tree->set_time_adjustment(time_adjustment());
+//             if(children_tree)children_tree->show();
+//
+//             // Connect Signals
+//             if(children_tree)children_tree->signal_edited_value().connect(sigc::mem_fun(*this, &studio::CanvasView::on_edited_value));
+//             if(children_tree)children_tree->signal_user_click().connect(sigc::mem_fun(*this, &studio::CanvasView::on_children_user_click));
+//             if(children_tree)children_tree->signal_waypoint_clicked_childrentree().connect(sigc::mem_fun(*this, &studio::CanvasView::on_waypoint_clicked_canvasview));
+//             if(children_tree)children_tree->get_selection()->signal_changed().connect(SLOT_EVENT(EVENT_REFRESH_DUCKS));
+//
+//             return children_tree;
+//     }
 
-       // Connect Signals
-       layer_tree->signal_layer_toggle().connect(sigc::mem_fun(*this, &studio::CanvasView::on_layer_toggle));
-       layer_tree->signal_edited_value().connect(sigc::mem_fun(*this, &studio::CanvasView::on_edited_value));
-       layer_tree->signal_layer_user_click().connect(sigc::mem_fun(*this, &studio::CanvasView::on_layer_user_click));
-       layer_tree->signal_param_user_click().connect(sigc::mem_fun(*this, &studio::CanvasView::on_children_user_click));
-       layer_tree->signal_waypoint_clicked().connect(sigc::mem_fun(*this, &studio::CanvasView::on_waypoint_clicked));
-       layer_tree->get_selection()->signal_changed().connect(SLOT_EVENT(EVENT_REFRESH_DUCKS));
+//     Gtk::Widget*
+//     CanvasView::create_keyframe_tree()
+//     {
+//             keyframe_tree=manage(new KeyframeTree());
+//
+//             //keyframe_tree->get_selection()->set_mode(Gtk::SELECTION_MULTIPLE);
+//             //keyframe_tree->show();
+//             //keyframe_tree->set_model(keyframe_tree_store());
+//             keyframe_tree->set_editable(true);
+//             //keyframe_tree->signal_edited().connect(sigc::hide_return(sigc::mem_fun(*canvas_interface(), &synfigapp::CanvasInterface::update_keyframe)));
+//
+//             keyframe_tree->signal_event().connect(sigc::mem_fun(*this, &studio::CanvasView::on_keyframe_tree_event));
+//
+//             Gtk::ScrolledWindow *scroll_layer_tree = manage(new class Gtk::ScrolledWindow());
+//             scroll_layer_tree->set_flags(Gtk::CAN_FOCUS);
+//             scroll_layer_tree->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
+//             scroll_layer_tree->add(*keyframe_tree);
+//             scroll_layer_tree->set_shadow_type(Gtk::SHADOW_ETCHED_IN);
+//             //scroll_layer_tree->show();
+//
+//
+//             Gtk::Table *layout_table= manage(new Gtk::Table(1, 2, false));
+//             layout_table->attach(*scroll_layer_tree, 0, 1, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
+//
+//             Gtk::Image *icon;
+//             Gtk::IconSize iconsize(Gtk::IconSize::from_name("synfig-small_icon"));
+//
+//             NEW_SMALL_BUTTON(button_add,"gtk-add",_("New Keyframe"));
+//             NEW_SMALL_BUTTON(button_duplicate,"synfig-duplicate",_("Duplicate Keyframe"));
+//             NEW_SMALL_BUTTON(button_delete,"gtk-delete",_("Delete Keyframe"));
+//
+//             Gtk::HBox *hbox(manage(new Gtk::HBox()));
+//             layout_table->attach(*hbox, 0, 1, 1, 2, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK, 0, 0);
+//
+//             hbox->pack_start(*button_add,Gtk::PACK_SHRINK);
+//             hbox->pack_start(*button_duplicate,Gtk::PACK_SHRINK);
+//             hbox->pack_start(*button_delete,Gtk::PACK_SHRINK);
+//
+//             /*
+//             button_raise->set_relief(Gtk::RELIEF_HALF);
+//             button_lower->set_relief(Gtk::RELIEF_HALF);
+//             button_duplicate->set_relief(Gtk::RELIEF_HALF);
+//             button_delete->set_relief(Gtk::RELIEF_HALF);
+//             */
+//
+//             button_add->signal_clicked().connect(sigc::mem_fun(*this, &studio::CanvasView::on_keyframe_add_pressed));
+//             button_duplicate->signal_clicked().connect(sigc::mem_fun(*this, &studio::CanvasView::on_keyframe_duplicate_pressed));
+//             button_delete->signal_clicked().connect(sigc::mem_fun(*this, &studio::CanvasView::on_keyframe_remove_pressed));
+//
+//             //layout_table->show_all();
+//
+//             keyframe_tab_child=layout_table;
+//
+//
+//             layout_table->hide();
+//
+//             return layout_table;
+//     }
 
-       layer_tree->hide();
-       return layer_tree;
-}
+//     Gtk::Widget*
+//     CanvasView::create_layer_tree()
+//     {
+//             // Create the layer tree
+//             printf("CanvasView::create_layer_tree()\n");
+//             layer_tree=manage(new class LayerTree());
+//
+//             // Set up the layer tree
+//             //layer_tree->set_model(layer_tree_store());
+//             layer_tree->set_time_adjustment(time_adjustment());
+//             layer_tree->show();
+//
+//             // Connect Signals
+//             layer_tree->signal_layer_toggle().connect(sigc::mem_fun(*this, &studio::CanvasView::on_layer_toggle));
+//             layer_tree->signal_edited_value().connect(sigc::mem_fun(*this, &studio::CanvasView::on_edited_value));
+//             layer_tree->signal_layer_user_click().connect(sigc::mem_fun(*this, &studio::CanvasView::on_layer_user_click));
+//             layer_tree->signal_param_user_click().connect(sigc::mem_fun(*this, &studio::CanvasView::on_children_user_click));
+//             layer_tree->signal_waypoint_clicked_layertree().connect(sigc::mem_fun(*this, &studio::CanvasView::on_waypoint_clicked_canvasview));
+//             layer_tree->get_selection()->signal_changed().connect(SLOT_EVENT(EVENT_REFRESH_DUCKS));
+//
+//             layer_tree->hide();
+//             return layer_tree;
+//     }
 
 void
 CanvasView::init_menus()
@@ -1276,7 +1295,7 @@ CanvasView::init_menus()
                        if (i == 10) note = _(" (fastest)");
                        Glib::RefPtr<Gtk::RadioAction> action(Gtk::RadioAction::create(quality_group,strprintf("quality-%02d",i),
                                                                                                                                                   strprintf(_("Set Quality to %d"),i) + note));
-                       if(i==9)                        // default quality
+                       if (i==8)                       // default quality
                        {
                                action->set_active();
                                work_area->set_quality(i);
@@ -1290,6 +1309,37 @@ CanvasView::init_menus()
                }
        }
 
+       // Low-Res Quality Menu
+       {
+               int i;
+               for(list<int>::iterator iter = CanvasView::get_pixel_sizes().begin(); iter != CanvasView::get_pixel_sizes().end(); iter++)
+               {
+                       i = *iter;
+                       Glib::RefPtr<Gtk::RadioAction> action(Gtk::RadioAction::create(low_res_pixel_size_group,strprintf("lowres-pixel-%d",i),
+                                                                                                                                                  strprintf(_("Set Low-Res pixel size to %d"),i)));
+                       if(i==2)                        // default pixel size
+                       {
+                               action->set_active();
+                               work_area->set_low_res_pixel_size(i);
+                       }
+                       action_group->add( action,
+                               sigc::bind(
+                                       sigc::mem_fun(*work_area, &studio::WorkArea::set_low_res_pixel_size),
+                                       i
+                               )
+                       );
+               }
+
+               Glib::RefPtr<Gtk::Action> action;
+
+               action=Gtk::Action::create("decrease-low-res-pixel-size", _("Decrease Low-Res Pixel Size"));
+               action_group->add( action,sigc::mem_fun(this, &studio::CanvasView::decrease_low_res_pixel_size));
+
+               action=Gtk::Action::create("increase-low-res-pixel-size",  _("Increase Low-Res Pixel Size"));
+               action_group->add( action, sigc::mem_fun(this, &studio::CanvasView::increase_low_res_pixel_size));
+
+       }
+
        action_group->add( Gtk::Action::create("play", Gtk::Stock::MEDIA_PLAY),
                sigc::mem_fun(*this, &studio::CanvasView::play)
        );
@@ -1329,7 +1379,6 @@ CanvasView::init_menus()
                sigc::mem_fun(*work_area, &studio::WorkArea::zoom_norm)
        );
 
-
        {
                Glib::RefPtr<Gtk::Action> action;
 
@@ -2395,7 +2444,12 @@ CanvasView::on_time_changed()
 void
 CanvasView::time_zoom_in()
 {
+       float frame_rate = get_canvas()->rend_desc().get_frame_rate();
+       Time min_page_size = 2/frame_rate;
+
        time_window_adjustment().set_page_size(time_window_adjustment().get_page_size()*0.75);
+       if (time_window_adjustment().get_page_size() < min_page_size)
+               time_window_adjustment().set_page_size(min_page_size);
        time_window_adjustment().changed();
 
        refresh_time_window();
@@ -2404,7 +2458,12 @@ CanvasView::time_zoom_in()
 void
 CanvasView::time_zoom_out()
 {
+       Time length = (get_canvas()->rend_desc().get_time_end() -
+                                  get_canvas()->rend_desc().get_time_start());
+
        time_window_adjustment().set_page_size(time_window_adjustment().get_page_size()/0.75);
+       if (time_window_adjustment().get_page_size() > length)
+               time_window_adjustment().set_page_size(length);
        time_window_adjustment().changed();
 
        refresh_time_window();
@@ -2827,6 +2886,55 @@ CanvasView::rebuild_ducks()
 }
 
 void
+CanvasView::decrease_low_res_pixel_size()
+{
+       list<int> sizes = CanvasView::get_pixel_sizes();
+       int pixel_size = work_area->get_low_res_pixel_size();
+
+       for (list<int>::iterator iter = sizes.begin(); iter != sizes.end(); iter++)
+               if (*iter == pixel_size)
+               {
+                       if (iter == sizes.begin())
+                               // we already have the smallest low-res pixels possible - turn off low-res instead
+                               work_area->set_low_resolution_flag(false);
+                       else
+                       {
+                               iter--;
+                               Glib::RefPtr<Gtk::Action> action = action_group->get_action(strprintf("lowres-pixel-%d", *iter));
+                               action->activate(); // to make sure the radiobutton in the menu is updated too
+                               work_area->set_low_resolution_flag(true);
+                       }
+                       break;
+               }
+}
+
+void
+CanvasView::increase_low_res_pixel_size()
+{
+       list<int> sizes = CanvasView::get_pixel_sizes();
+       int pixel_size = work_area->get_low_res_pixel_size();
+
+       if (!work_area->get_low_resolution_flag())
+       {
+               work_area->set_low_resolution_flag(true);
+               return;
+       }
+
+       for (list<int>::iterator iter = sizes.begin(); iter != sizes.end(); iter++)
+               if (*iter == pixel_size)
+               {
+                       iter++;
+                       if (iter != sizes.end())
+                       {
+                               Glib::RefPtr<Gtk::Action> action = action_group->get_action(strprintf("lowres-pixel-%d", *iter));
+                               action->activate(); // to make sure the radiobutton in the menu is updated too
+                               work_area->set_low_resolution_flag(true);
+                       }
+                       break;
+               }
+}
+
+void
 CanvasView::on_dirty_preview()
 {
        if(!is_playing_)
@@ -2999,66 +3107,160 @@ CanvasView::set_sensitive_timebar(bool sensitive)
 }
 
 
+static void
+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
+       synfigapp::Action::PassiveGrouper group(canvas_interface->get_instance().get(),_("Change Waypoint Group"));
+
+       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);
+
+               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);
+
+               action->set_param("waypoint",waypoint);
+               action->set_param("value_node",waypoint.get_parent_value_node());
+
+               if(!canvas_interface->get_instance()->perform_action(action))
+               {
+                       group.cancel();
+                       return;
+               }
+       }
+}
+
+static void
+duplicate_waypoints(std::set<synfig::Waypoint, std::less<UniqueID> > waypoints,
+                                       etl::loose_handle<synfigapp::CanvasInterface> canvas_interface)
+{
+       // Create the action group
+       synfigapp::Action::PassiveGrouper group(canvas_interface->get_instance().get(),_("Duplicate Waypoints"));
+
+       std::set<synfig::Waypoint, std::less<UniqueID> >::const_iterator iter;
+       for (iter = waypoints.begin(); iter != waypoints.end(); iter++)
+       {
+               Waypoint waypoint(*iter);
+               ValueNode::Handle value_node(iter->get_parent_value_node());
+               canvas_interface->waypoint_duplicate(value_node, waypoint);
+       }
+}
+
+static void
+remove_waypoints(std::set<synfig::Waypoint, std::less<UniqueID> > waypoints,
+                                etl::loose_handle<synfigapp::CanvasInterface> canvas_interface)
+{
+       // Create the action group
+       synfigapp::Action::PassiveGrouper group(canvas_interface->get_instance().get(),_("Remove Waypoints"));
+
+       std::set<synfig::Waypoint, std::less<UniqueID> >::const_iterator iter;
+       for (iter = waypoints.begin(); iter != waypoints.end(); iter++)
+       {
+               Waypoint waypoint(*iter);
+               ValueNode::Handle value_node(iter->get_parent_value_node());
+               canvas_interface->waypoint_remove(value_node, waypoint);
+       }
+}
+
 void
-CanvasView::on_waypoint_clicked(synfigapp::ValueDesc value_desc,synfig::Waypoint waypoint,int button)
+CanvasView::on_waypoint_clicked_canvasview(synfigapp::ValueDesc value_desc,
+                                                                                  std::set<synfig::Waypoint, std::less<UniqueID> > waypoint_set,
+                                                                                  int button,
+                                                                                  synfig::Waypoint::Side side)
 {
-       waypoint_dialog.set_value_desc(value_desc);
-       waypoint_dialog.set_waypoint(waypoint);
+       int size = waypoint_set.size();
+       Waypoint waypoint(*(waypoint_set.begin()));
+       Time time(waypoint.get_time());
+
+       if (size == 1)
+       {
+               waypoint_dialog.set_value_desc(value_desc);
+               waypoint_dialog.set_waypoint(waypoint);
+       }
 
        switch(button)
        {
        case -1:
-               waypoint_dialog.show();
+               if (size == 1)
+                       waypoint_dialog.show();
                break;
        case 2:
-               {
-                       Gtk::Menu* waypoint_menu(manage(new Gtk::Menu()));
-                       waypoint_menu->signal_hide().connect(sigc::bind(sigc::ptr_fun(&delete_widget), waypoint_menu));
+       {
+               Gtk::Menu* waypoint_menu(manage(new Gtk::Menu()));
+               waypoint_menu->signal_hide().connect(sigc::bind(sigc::ptr_fun(&delete_widget), waypoint_menu));
 
-                       waypoint_menu->items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::StockID("gtk-jump-to"),
-                               sigc::bind(
-                                       sigc::mem_fun(
-                                               *canvas_interface(),
-                                               &synfigapp::CanvasInterface::set_time
-                                       ),
-                                       waypoint.get_time()
-                               )
-                       ));
+               Waypoint::Model model;
+               String side_string(String(" ") + (side==Waypoint::SIDE_LEFT ? _("In") : _("Out")));
 
-                       waypoint_menu->items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::StockID(_("Edit Waypoint")),
-                               sigc::mem_fun(
-                                       waypoint_dialog,
-                                       &Gtk::Widget::show
-                               )
-                       ));
+               // ------------------------------------------------------------------------
+               if(side==Waypoint::SIDE_LEFT)   model.set_before(INTERPOLATION_TCB);
+               else                                                    model.set_after(INTERPOLATION_TCB);
+               waypoint_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("_TCB") + side_string,
+                       sigc::bind(sigc::ptr_fun(set_waypoint_model), waypoint_set, model, canvas_interface())));
+
+               if(side==Waypoint::SIDE_LEFT)   model.set_before(INTERPOLATION_LINEAR);
+               else                                                    model.set_after(INTERPOLATION_LINEAR);
+               waypoint_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("_Linear") + side_string,
+                       sigc::bind(sigc::ptr_fun(set_waypoint_model), waypoint_set, model, canvas_interface())));
+
+               if(side==Waypoint::SIDE_LEFT)   model.set_before(INTERPOLATION_HALT);
+               else                                                    model.set_after(INTERPOLATION_HALT);
+               waypoint_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("_Ease") + side_string,
+                       sigc::bind(sigc::ptr_fun(set_waypoint_model), waypoint_set, model, canvas_interface())));
+
+               if(side==Waypoint::SIDE_LEFT)   model.set_before(INTERPOLATION_CONSTANT);
+               else                                                    model.set_after(INTERPOLATION_CONSTANT);
+               waypoint_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("_Constant") + side_string,
+                       sigc::bind(sigc::ptr_fun(set_waypoint_model), waypoint_set, model, canvas_interface())));
+
+               // ------------------------------------------------------------------------
+               waypoint_menu->items().push_back(Gtk::Menu_Helpers::SeparatorElem());
+
+               model.set_after(INTERPOLATION_TCB); model.set_before(INTERPOLATION_TCB);
+               waypoint_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("TC_B Both"),
+                       sigc::bind(sigc::ptr_fun(set_waypoint_model), waypoint_set, model, canvas_interface())));
+
+               model.set_after(INTERPOLATION_LINEAR); model.set_before(INTERPOLATION_LINEAR);
+               waypoint_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("Li_near Both"),
+                       sigc::bind(sigc::ptr_fun(set_waypoint_model), waypoint_set, model, canvas_interface())));
+
+               model.set_after(INTERPOLATION_HALT); model.set_before(INTERPOLATION_HALT);
+               waypoint_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("Ea_se Both"),
+                       sigc::bind(sigc::ptr_fun(set_waypoint_model), waypoint_set, model, canvas_interface())));
+
+               model.set_after(INTERPOLATION_CONSTANT); model.set_before(INTERPOLATION_CONSTANT);
+               waypoint_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("C_onstant Both"),
+                       sigc::bind(sigc::ptr_fun(set_waypoint_model), waypoint_set, model, canvas_interface())));
+
+               // ------------------------------------------------------------------------
+               waypoint_menu->items().push_back(Gtk::Menu_Helpers::SeparatorElem());
+
+               waypoint_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("_Jump To"),
+                       sigc::bind(sigc::mem_fun(*canvas_interface(), &synfigapp::CanvasInterface::set_time), time)));
+
+               waypoint_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("_Duplicate"),
+                        sigc::bind(sigc::ptr_fun(duplicate_waypoints), waypoint_set, canvas_interface())));
+
+               waypoint_menu->items().push_back(Gtk::Menu_Helpers::MenuElem((size == 1) ? _("_Remove") : strprintf(_("_Remove %d Waypoints"), size),
+                        sigc::bind(sigc::ptr_fun(remove_waypoints), waypoint_set, canvas_interface())));
+
+               if (size == 1 && value_desc.is_valid())
+                       waypoint_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("_Properties"),
+                               sigc::mem_fun(waypoint_dialog,&Gtk::Widget::show)));
+
+               waypoint_menu->popup(button+1,gtk_get_current_event_time());
+       }
+       break;
 
-                       waypoint_menu->items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::StockID("synfig-duplicate"),
-                               sigc::bind(
-                                       sigc::bind(
-                                               sigc::mem_fun(
-                                                       *canvas_interface(),
-                                                       &synfigapp::CanvasInterface::waypoint_duplicate
-                                               ),
-                                               waypoint
-                                       ),
-                                       value_desc
-                               )
-                       ));
-                       waypoint_menu->items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::StockID("gtk-delete"),
-                               sigc::bind(
-                                       sigc::bind(
-                                               sigc::mem_fun(
-                                                       *canvas_interface(),
-                                                       &synfigapp::CanvasInterface::waypoint_remove
-                                               ),
-                                               waypoint
-                                       ),
-                                       value_desc
-                               )
-                       ));
-                       waypoint_menu->popup(button+1,gtk_get_current_event_time());
-               }
-               break;
        default:
                break;
        }
@@ -3567,13 +3769,13 @@ CanvasView::set_ext_widget(const synfig::String& x, Gtk::Widget* y)
                layer_tree->get_selection()->signal_changed().connect(SLOT_EVENT(EVENT_REFRESH_DUCKS));
                layer_tree->signal_layer_user_click().connect(sigc::mem_fun(*this, &studio::CanvasView::on_layer_user_click));
                layer_tree->signal_param_user_click().connect(sigc::mem_fun(*this, &studio::CanvasView::on_children_user_click));
-               layer_tree->signal_waypoint_clicked().connect(sigc::mem_fun(*this, &studio::CanvasView::on_waypoint_clicked));
+               layer_tree->signal_waypoint_clicked_layertree().connect(sigc::mem_fun(*this, &studio::CanvasView::on_waypoint_clicked_canvasview));
        }
        if(x=="children")
        {
                children_tree=dynamic_cast<ChildrenTree*>(y);
                if(children_tree)children_tree->signal_user_click().connect(sigc::mem_fun(*this, &studio::CanvasView::on_children_user_click));
-               if(children_tree)children_tree->signal_waypoint_clicked().connect(sigc::mem_fun(*this, &studio::CanvasView::on_waypoint_clicked));
+               if(children_tree)children_tree->signal_waypoint_clicked_childrentree().connect(sigc::mem_fun(*this, &studio::CanvasView::on_waypoint_clicked_canvasview));
                if(children_tree)children_tree->get_selection()->signal_changed().connect(SLOT_EVENT(EVENT_REFRESH_DUCKS));
        }
        if(x=="keyframes")
@@ -3581,7 +3783,7 @@ CanvasView::set_ext_widget(const synfig::String& x, Gtk::Widget* y)
 }
 
 bool
-CanvasView::on_delete_event(GdkEventAny* event)
+CanvasView::on_delete_event(GdkEventAny* event __attribute__ ((unused)))
 {
        close_view();