1 /* === S Y N F I G ========================================================= */
2 /*! \file state_normal.cpp
3 ** \brief Template File
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007, 2008 Chris Moore
10 ** Copyright (c) 2009 Nikita Kitaev
12 ** This package is free software; you can redistribute it and/or
13 ** modify it under the terms of the GNU General Public License as
14 ** published by the Free Software Foundation; either version 2 of
15 ** the License, or (at your option) any later version.
17 ** This package is distributed in the hope that it will be useful,
18 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 ** General Public License for more details.
23 /* ========================================================================= */
25 /* === H E A D E R S ======================================================= */
34 #include <gtkmm/dialog.h>
35 #include <gtkmm/entry.h>
37 #include <synfig/valuenode_animated.h>
38 #include <synfig/valuenode_blinecalcvertex.h>
39 #include <synfig/valuenode_composite.h>
40 #include <synfig/valuenode_const.h>
41 #include <synfig/valuenode_dynamiclist.h>
42 #include <synfigapp/action_system.h>
44 #include "state_normal.h"
45 #include "canvasview.h"
49 #include <synfigapp/action.h>
50 #include "event_mouse.h"
51 #include "event_layerclick.h"
53 #include "dialog_tooloptions.h"
54 #include <gtkmm/optionmenu.h>
56 #include <synfig/angle.h>
57 #include <synfigapp/main.h>
62 /* === U S I N G =========================================================== */
66 using namespace synfig;
67 using namespace studio;
69 /* === M A C R O S ========================================================= */
72 #define EPSILON 0.0000001
75 /* === G L O B A L S ======================================================= */
77 StateNormal studio::state_normal;
79 /* === C L A S S E S & S T R U C T S ======================================= */
81 class DuckDrag_Combo : public DuckDrag_Base
83 synfig::Vector last_move;
84 synfig::Vector drag_offset;
85 synfig::Vector center;
88 synfig::Angle original_angle;
89 synfig::Real original_mag;
91 std::vector<synfig::Vector> last_;
92 std::vector<synfig::Vector> positions;
99 CanvasView* canvas_view_;
104 void begin_duck_drag(Duckmatic* duckmatic, const synfig::Vector& begin);
105 bool end_duck_drag(Duckmatic* duckmatic);
106 void duck_drag(Duckmatic* duckmatic, const synfig::Vector& vector);
108 etl::handle<synfigapp::CanvasInterface> get_canvas_interface()const{return canvas_view_->canvas_interface();}
112 class studio::StateNormal_Context : public sigc::trackable
114 CanvasView* canvas_view_;
116 synfigapp::Settings& settings;
118 etl::handle<DuckDrag_Combo> duck_dragger_;
120 Gtk::Table options_table;
124 bool get_rotate_flag()const { if(duck_dragger_) return duck_dragger_->rotate; else return false; }
125 void set_rotate_flag(bool x) { if(duck_dragger_ && x!=duck_dragger_->rotate) duck_dragger_->rotate=x; }
127 bool get_scale_flag()const { if(duck_dragger_) return duck_dragger_->scale; else return false; }
128 void set_scale_flag(bool x) { if(duck_dragger_ && x!=duck_dragger_->scale) duck_dragger_->scale=x; }
130 bool get_constrain_flag()const { if(duck_dragger_) return duck_dragger_->constrain; else return false; }
131 void set_constrain_flag(bool x) { if(duck_dragger_ && x!=duck_dragger_->constrain) duck_dragger_->constrain=x; }
133 void refresh_cursor();
135 StateNormal_Context(CanvasView* canvas_view);
137 ~StateNormal_Context();
139 CanvasView* get_canvas_view()const{return canvas_view_;}
140 etl::handle<synfigapp::CanvasInterface> get_canvas_interface()const{return canvas_view_->canvas_interface();}
141 synfig::Canvas::Handle get_canvas()const{return canvas_view_->get_canvas();}
142 WorkArea * get_work_area()const{return canvas_view_->get_work_area();}
144 void load_settings();
145 void save_settings();
147 Smach::event_result event_stop_handler(const Smach::event& x);
148 Smach::event_result event_refresh_handler(const Smach::event& x);
149 Smach::event_result event_refresh_ducks_handler(const Smach::event& x);
150 Smach::event_result event_undo_handler(const Smach::event& x);
151 Smach::event_result event_redo_handler(const Smach::event& x);
152 Smach::event_result event_mouse_button_down_handler(const Smach::event& x);
153 Smach::event_result event_multiple_ducks_clicked_handler(const Smach::event& x);
154 Smach::event_result event_mouse_motion_handler(const Smach::event& x);
155 Smach::event_result event_refresh_tool_options(const Smach::event& x);
156 void refresh_tool_options();
157 Smach::event_result event_layer_click(const Smach::event& x);
160 }; // END of class StateNormal_Context
162 /* === M E T H O D S ======================================================= */
164 StateNormal::StateNormal():
165 Smach::state<StateNormal_Context>("normal")
167 insert(event_def(EVENT_STOP,&StateNormal_Context::event_stop_handler));
168 insert(event_def(EVENT_REFRESH,&StateNormal_Context::event_refresh_handler));
169 insert(event_def(EVENT_REFRESH_DUCKS,&StateNormal_Context::event_refresh_ducks_handler));
170 insert(event_def(EVENT_UNDO,&StateNormal_Context::event_undo_handler));
171 insert(event_def(EVENT_REDO,&StateNormal_Context::event_redo_handler));
172 insert(event_def(EVENT_WORKAREA_MOUSE_BUTTON_DOWN,&StateNormal_Context::event_mouse_button_down_handler));
173 insert(event_def(EVENT_WORKAREA_MULTIPLE_DUCKS_CLICKED,&StateNormal_Context::event_multiple_ducks_clicked_handler));
174 insert(event_def(EVENT_REFRESH_TOOL_OPTIONS,&StateNormal_Context::event_refresh_tool_options));
175 insert(event_def(EVENT_WORKAREA_MOUSE_MOTION, &StateNormal_Context::event_mouse_motion_handler));
176 insert(event_def(EVENT_WORKAREA_MOUSE_BUTTON_DRAG, &StateNormal_Context::event_mouse_motion_handler));
177 insert(event_def(EVENT_WORKAREA_LAYER_CLICKED,&StateNormal_Context::event_layer_click));
181 StateNormal::~StateNormal()
185 void StateNormal_Context::refresh_cursor()
187 // Check the current state and return when applicable
188 synfig::String sname;
189 sname=get_canvas_view()->get_smach().get_state_name();
190 if (sname=="smooth_move"||sname=="zoom"||sname=="width" ||
191 sname=="text"||sname=="stroke"||sname=="star"||sname=="sketch"||
192 sname=="scale"||sname=="zoom"||sname=="rotate"||sname=="rectangle"||
193 sname=="polygon"||sname=="gradient"||sname=="fill"||sname=="draw"||
197 // Change the cursor based on key flags
198 if(get_rotate_flag() && !get_scale_flag())
200 get_work_area()->set_cursor(Gdk::EXCHANGE);
203 if(!get_rotate_flag() && get_scale_flag())
205 get_work_area()->set_cursor(Gdk::SIZING);
208 if(get_rotate_flag() && get_scale_flag())
210 get_work_area()->set_cursor(Gdk::CROSSHAIR);
213 // If we are in BLine state and there is not key pressed return to
217 get_work_area()->set_cursor(Gdk::CROSSHAIR);
220 // Default cursor for Transform tool
221 get_work_area()->set_cursor(Gdk::ARROW);
226 StateNormal_Context::load_settings()
230 if(settings.get_value("normal.rotate",value) && value=="1")
231 set_rotate_flag(true);
233 set_rotate_flag(false);
235 if(settings.get_value("normal.scale",value) && value=="1")
236 set_scale_flag(true);
238 set_scale_flag(false);
240 if(settings.get_value("normal.constrain",value) && value=="1")
241 set_constrain_flag(true);
243 set_constrain_flag(false);
248 StateNormal_Context::save_settings()
250 settings.set_value("normal.rotate",get_rotate_flag()?"1":"0");
251 settings.set_value("normal.scale",get_scale_flag()?"1":"0");
252 settings.set_value("normal.constrain",get_constrain_flag()?"1":"0");
255 StateNormal_Context::StateNormal_Context(CanvasView* canvas_view):
256 canvas_view_(canvas_view),
257 settings(synfigapp::Main::get_selected_input_device()->settings()),
258 duck_dragger_(new DuckDrag_Combo())
260 duck_dragger_->canvas_view_=get_canvas_view();
262 // Set up the tool options dialog
263 options_table.attach(*manage(new Gtk::Label(_("Transform Tool"))), 0, 2, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
264 options_table.attach(*manage(new Gtk::Label(_("Ctrl to rotate"), Gtk::ALIGN_LEFT)), 0, 2, 1, 2, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
265 options_table.attach(*manage(new Gtk::Label(_("Alt to scale"), Gtk::ALIGN_LEFT)), 0, 2, 2, 3, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
266 options_table.attach(*manage(new Gtk::Label(_("Shift to constrain"), Gtk::ALIGN_LEFT)), 0, 2, 3, 4, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
268 options_table.show_all();
269 refresh_tool_options();
270 //App::dialog_tool_options->set_widget(options_table);
271 //App::dialog_tool_options->present();
273 get_work_area()->set_allow_layer_clicks(true);
274 get_work_area()->set_duck_dragger(duck_dragger_);
276 //these will segfault
277 // get_work_area()->set_cursor(Gdk::CROSSHAIR);
278 // get_work_area()->reset_cursor();
280 App::toolbox->refresh();
286 StateNormal_Context::refresh_tool_options()
288 App::dialog_tool_options->clear();
289 App::dialog_tool_options->set_widget(options_table);
290 App::dialog_tool_options->set_local_name(_("Transform Tool"));
291 App::dialog_tool_options->set_name("normal");
296 StateNormal_Context::~StateNormal_Context()
300 get_work_area()->clear_duck_dragger();
301 get_work_area()->reset_cursor();
303 App::dialog_tool_options->clear();
305 App::toolbox->refresh();
308 DuckDrag_Combo::DuckDrag_Combo():
311 constrain(false) // Lock aspect for scale; smooth move for translate
316 DuckDrag_Combo::begin_duck_drag(Duckmatic* duckmatic, const synfig::Vector& offset)
318 last_move=Vector(1,1);
320 const DuckList selected_ducks(duckmatic->get_selected_ducks());
321 DuckList::const_iterator iter;
325 drag_offset=duckmatic->find_duck(offset)->get_trans_point();
327 //snap=drag_offset-duckmatic->snap_point_to_grid(drag_offset);
328 //snap=offset-drag_offset_;
332 Point vmin(100000000,100000000);
333 Point vmax(-100000000,-100000000);
334 //std::set<etl::handle<Duck> >::iterator iter;
337 for(i=0,iter=selected_ducks.begin();iter!=selected_ducks.end();++iter,i++)
339 Point p((*iter)->get_trans_point());
340 vmin[0]=min(vmin[0],p[0]);
341 vmin[1]=min(vmin[1],p[1]);
342 vmax[0]=max(vmax[0],p[0]);
343 vmax[1]=max(vmax[1],p[1]);
344 positions.push_back(p);
346 center=(vmin+vmax)*0.5;
347 if((vmin-vmax).mag()<=EPSILON)
353 synfig::Vector vect(offset-center);
354 original_angle=Angle::tan(vect[1],vect[0]);
355 original_mag=vect.mag();
360 DuckDrag_Combo::duck_drag(Duckmatic* duckmatic, const synfig::Vector& vector)
362 if (!duckmatic) return;
367 //Override axis lock set in workarea when holding down the shift key
368 if (!move_only && (scale || rotate))
369 duckmatic->set_axis_lock(false);
372 if (move_only || (!scale && !rotate))
373 vect= duckmatic->snap_point_to_grid(vector)-drag_offset+snap;
375 vect= duckmatic->snap_point_to_grid(vector)-center+snap;
379 const DuckList selected_ducks(duckmatic->get_selected_ducks());
380 DuckList::const_iterator iter;
382 Time time(duckmatic->get_time());
385 if( move_only || (!scale && !rotate) )
387 for(i=0,iter=selected_ducks.begin();iter!=selected_ducks.end();++iter,i++)
389 if((*iter)->get_type()==Duck::TYPE_VERTEX || (*iter)->get_type()==Duck::TYPE_POSITION)
390 (*iter)->set_trans_point(positions[i]+vect, time);
392 for(i=0,iter=selected_ducks.begin();iter!=selected_ducks.end();++iter,i++)
394 if((*iter)->get_type()!=Duck::TYPE_VERTEX&&(*iter)->get_type()!=Duck::TYPE_POSITION)
395 (*iter)->set_trans_point(positions[i]+vect, time);
401 Angle::deg angle(Angle::tan(vect[1],vect[0]));
402 angle=original_angle-angle;
405 float degrees = angle.get()/15;
406 angle= Angle::deg (degrees>0?std::floor(degrees)*15:std::ceil(degrees)*15);
408 Real mag(vect.mag()/original_mag);
409 Real sine(Angle::sin(angle).get());
410 Real cosine(Angle::cos(angle).get());
412 for(i=0,iter=selected_ducks.begin();iter!=selected_ducks.end();++iter,i++)
414 if((*iter)->get_type()!=Duck::TYPE_VERTEX&&(*iter)->get_type()!=Duck::TYPE_POSITION)continue;
416 Vector x(positions[i]-center),p;
418 p[0]=cosine*x[0]+sine*x[1];
419 p[1]=-sine*x[0]+cosine*x[1];
422 (*iter)->set_trans_point(p, time);
424 for(i=0,iter=selected_ducks.begin();iter!=selected_ducks.end();++iter,i++)
426 if(!((*iter)->get_type()!=Duck::TYPE_VERTEX&&(*iter)->get_type()!=Duck::TYPE_POSITION))continue;
428 Vector x(positions[i]-center),p;
430 p[0]=cosine*x[0]+sine*x[1];
431 p[1]=-sine*x[0]+cosine*x[1];
434 (*iter)->set_trans_point(p, time);
440 if(abs(drag_offset[0]-center[0])>EPSILON)
441 vect[0]/=drag_offset[0]-center[0];
444 if(abs(drag_offset[1]-center[1])>EPSILON)
445 vect[1]/=drag_offset[1]-center[1];
451 //vect[0]=vect[1]=vect.mag()*0.707106781;
452 Real amount(vect.mag()/(drag_offset-center).mag());
453 vect[0]=vect[1]=amount;
456 if(vect[0]<EPSILON && vect[0]>-EPSILON)
458 if(vect[1]<EPSILON && vect[1]>-EPSILON)
461 for(i=0,iter=selected_ducks.begin();iter!=selected_ducks.end();++iter,i++)
463 if(((*iter)->get_type()!=Duck::TYPE_VERTEX&&(*iter)->get_type()!=Duck::TYPE_POSITION))continue;
465 Vector p(positions[i]-center);
470 (*iter)->set_trans_point(p, time);
472 for(i=0,iter=selected_ducks.begin();iter!=selected_ducks.end();++iter,i++)
474 if(!((*iter)->get_type()!=Duck::TYPE_VERTEX&&(*iter)->get_type()!=Duck::TYPE_POSITION))continue;
476 Vector p(positions[i]-center);
481 (*iter)->set_trans_point(p, time);
485 // then patch up the tangents for the vertices we've moved
486 duckmatic->update_ducks();
492 DuckDrag_Combo::end_duck_drag(Duckmatic* duckmatic)
494 if(bad_drag)return false;
496 //synfigapp::Action::PassiveGrouper group(get_canvas_interface()->get_instance().get(),_("Rotate Ducks"));
498 if((last_move-Vector(1,1)).mag()>0.0001)
500 duckmatic->signal_edited_selected_ducks();
505 duckmatic->signal_user_click_selected_ducks(0);
511 StateNormal_Context::event_refresh_tool_options(const Smach::event& /*x*/)
513 refresh_tool_options();
514 return Smach::RESULT_ACCEPT;
518 StateNormal_Context::event_stop_handler(const Smach::event& /*x*/)
520 // synfig::info("STATE NORMAL: Received Stop Event");
521 canvas_view_->stop();
522 return Smach::RESULT_ACCEPT;
526 StateNormal_Context::event_refresh_handler(const Smach::event& /*x*/)
528 // synfig::info("STATE NORMAL: Received Refresh Event");
529 canvas_view_->rebuild_tables();
530 canvas_view_->work_area->queue_render_preview();
531 return Smach::RESULT_ACCEPT;
535 StateNormal_Context::event_refresh_ducks_handler(const Smach::event& /*x*/)
537 // synfig::info("STATE NORMAL: Received Refresh Ducks");
538 canvas_view_->queue_rebuild_ducks();
539 return Smach::RESULT_ACCEPT;
543 StateNormal_Context::event_undo_handler(const Smach::event& /*x*/)
545 // synfig::info("STATE NORMAL: Received Undo Event");
546 canvas_view_->get_instance()->undo();
547 return Smach::RESULT_ACCEPT;
551 StateNormal_Context::event_redo_handler(const Smach::event& /*x*/)
553 // synfig::info("STATE NORMAL: Received Redo Event");
554 canvas_view_->get_instance()->redo();
555 return Smach::RESULT_ACCEPT;
559 StateNormal_Context::event_mouse_button_down_handler(const Smach::event& x)
561 // synfig::info("STATE NORMAL: Received mouse button down Event");
563 const EventMouse& event(*reinterpret_cast<const EventMouse*>(&x));
568 canvas_view_->popup_main_menu();
569 return Smach::RESULT_ACCEPT;
571 return Smach::RESULT_OK;
576 StateNormal_Context::event_mouse_motion_handler(const Smach::event& x)
578 // synfig::info("STATE NORMAL: Received mouse button down Event");
580 const EventMouse& event(*reinterpret_cast<const EventMouse*>(&x));
582 set_rotate_flag(event.modifier&GDK_CONTROL_MASK);
583 set_scale_flag(event.modifier&GDK_MOD1_MASK);
584 set_constrain_flag(event.modifier&GDK_SHIFT_MASK);
586 return Smach::RESULT_OK;
590 StateNormal_Context::event_layer_click(const Smach::event& x)
592 const EventLayerClick& event(*reinterpret_cast<const EventLayerClick*>(&x));
596 // synfig::info("STATE NORMAL: Received layer click Event, \"%s\"",event.layer->get_name().c_str());
600 // synfig::info("STATE NORMAL: Received layer click Event with an empty layer.");
606 if(!(event.modifier&Gdk::CONTROL_MASK))
607 canvas_view_->get_selection_manager()->clear_selected_layers();
610 std::list<Layer::Handle> layer_list(canvas_view_->get_selection_manager()->get_selected_layers());
611 std::set<Layer::Handle> layers(layer_list.begin(),layer_list.end());
612 if(layers.count(event.layer))
614 layers.erase(event.layer);
615 layer_list=std::list<Layer::Handle>(layers.begin(),layers.end());
616 canvas_view_->get_selection_manager()->clear_selected_layers();
617 canvas_view_->get_selection_manager()->set_selected_layers(layer_list);
621 canvas_view_->get_selection_manager()->set_selected_layer(event.layer);
624 return Smach::RESULT_ACCEPT;
626 canvas_view_->popup_layer_menu(event.layer);
627 return Smach::RESULT_ACCEPT;
629 return Smach::RESULT_OK;
635 StateNormal_Context::edit_several_waypoints(std::list<synfigapp::ValueDesc> value_desc_list)
638 "Edit Multiple Waypoints", // Title
640 true // use_separator
643 Widget_WaypointModel widget_waypoint_model;
644 widget_waypoint_model.show();
646 dialog.get_vbox()->pack_start(widget_waypoint_model);
649 dialog.add_button(Gtk::StockID("gtk-apply"),1);
650 dialog.add_button(Gtk::StockID("gtk-cancel"),0);
655 synfigapp::Action::PassiveGrouper group(get_canvas_interface()->get_instance().get(),_("Set Waypoints"));
657 std::list<synfigapp::ValueDesc>::iterator iter;
658 for(iter=value_desc_list.begin();iter!=value_desc_list.end();++iter)
660 synfigapp::ValueDesc value_desc(*iter);
662 if(!value_desc.is_valid())
665 ValueNode_Animated::Handle value_node;
667 // If this value isn't a ValueNode_Animated, but
668 // it is somewhat constant, then go ahead and convert
669 // it to a ValueNode_Animated.
670 if(!value_desc.is_value_node() || ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
673 if(value_desc.is_value_node())
674 value=ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node())->get_value();
676 value=value_desc.get_value();
678 value_node=ValueNode_Animated::create(value,get_canvas()->get_time());
680 synfigapp::Action::Handle action;
682 if(!value_desc.is_value_node())
684 action=synfigapp::Action::create("ValueDescConnect");
685 action->set_param("dest",value_desc);
686 action->set_param("src",ValueNode::Handle(value_node));
690 action=synfigapp::Action::create("ValueNodeReplace");
691 action->set_param("dest",value_desc.get_value_node());
692 action->set_param("src",ValueNode::Handle(value_node));
695 action->set_param("canvas",get_canvas());
696 action->set_param("canvas_interface",get_canvas_interface());
699 if(!get_canvas_interface()->get_instance()->perform_action(action))
701 get_canvas_view()->get_ui_interface()->error(_("Unable to convert to animated waypoint"));
708 if(value_desc.is_value_node())
709 value_node=ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node());
716 synfigapp::Action::Handle action(synfigapp::Action::create("WaypointSetSmart"));
720 get_canvas_view()->get_ui_interface()->error(_("Unable to find WaypointSetSmart action"));
726 action->set_param("canvas",get_canvas());
727 action->set_param("canvas_interface",get_canvas_interface());
728 action->set_param("value_node",ValueNode::Handle(value_node));
729 action->set_param("time",get_canvas()->get_time());
730 action->set_param("model",widget_waypoint_model.get_waypoint_model());
732 if(!get_canvas_interface()->get_instance()->perform_action(action))
734 get_canvas_view()->get_ui_interface()->error(_("Unable to set a specific waypoint"));
741 //get_canvas_view()->get_ui_interface()->error(_("Unable to animate a specific valuedesc"));
751 StateNormal_Context::event_multiple_ducks_clicked_handler(const Smach::event& /*x*/)
753 // synfig::info("STATE NORMAL: Received multiple duck click event");
755 //const EventMouse& event(*reinterpret_cast<const EventMouse*>(&x));
757 std::list<synfigapp::ValueDesc> value_desc_list;
759 // Create a list of value_descs associated with selection
760 const DuckList selected_ducks(get_work_area()->get_selected_ducks());
761 DuckList::const_iterator iter;
762 for(iter=selected_ducks.begin();iter!=selected_ducks.end();++iter)
764 synfigapp::ValueDesc value_desc((*iter)->get_value_desc());
766 if(!value_desc.is_valid())
769 if(value_desc.get_value_type()==ValueBase::TYPE_BLINEPOINT && value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
771 value_desc_list.push_back(
772 synfigapp::ValueDesc(
773 ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node())
774 ,ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node())
775 ->get_link_index_from_name("point")
780 value_desc_list.push_back(value_desc);
783 Gtk::Menu *menu=manage(new Gtk::Menu());
784 menu->signal_hide().connect(sigc::bind(sigc::ptr_fun(&delete_widget), menu));
786 canvas_view_->get_instance()->make_param_menu(menu,canvas_view_->get_canvas(),value_desc_list);
789 synfigapp::Action::ParamList param_list;
790 param_list=get_canvas_interface()->generate_param_list(value_desc_list);
792 canvas_view_->add_actions_to_menu(menu, param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
794 menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoints"),
798 &studio::StateNormal_Context::edit_several_waypoints
804 menu->popup(3,gtk_get_current_event_time());
806 return Smach::RESULT_ACCEPT;