add mixbus profile which removes the tearoffs
[ardour.git] / gtk2_ardour / editor.cc
1 /*
2     Copyright (C) 2000-2009 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 /* Note: public Editor methods are documented in public_editor.h */
21
22 #include <stdint.h>
23 #include <unistd.h>
24 #include <cstdlib>
25 #include <cmath>
26 #include <string>
27 #include <algorithm>
28 #include <map>
29
30 #include "ardour_ui.h"
31 /*
32  * ardour_ui.h include was moved to the top of the list
33  * due to a conflicting definition of 'Style' between
34  * Apple's MacTypes.h and BarController.
35  */
36
37 #include <boost/none.hpp>
38
39 #include <sigc++/bind.h>
40
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
49
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
55
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
58
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include "gtkmm2ext/tearoff.h"
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
67
68 #include "ardour/audio_track.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/audioregion.h"
71 #include "ardour/location.h"
72 #include "ardour/profile.h"
73 #include "ardour/route_group.h"
74 #include "ardour/session_playlists.h"
75 #include "ardour/tempo.h"
76 #include "ardour/utils.h"
77
78 #include "canvas/debug.h"
79 #include "canvas/text.h"
80
81 #include "control_protocol/control_protocol.h"
82
83 #include "actions.h"
84 #include "actions.h"
85 #include "analysis_window.h"
86 #include "audio_clock.h"
87 #include "audio_region_view.h"
88 #include "audio_streamview.h"
89 #include "audio_time_axis.h"
90 #include "automation_time_axis.h"
91 #include "bundle_manager.h"
92 #include "crossfade_edit.h"
93 #include "debug.h"
94 #include "editing.h"
95 #include "editor.h"
96 #include "editor_cursors.h"
97 #include "editor_drag.h"
98 #include "editor_group_tabs.h"
99 #include "editor_locations.h"
100 #include "editor_regions.h"
101 #include "editor_route_groups.h"
102 #include "editor_routes.h"
103 #include "editor_snapshots.h"
104 #include "editor_summary.h"
105 #include "global_port_matrix.h"
106 #include "gui_object.h"
107 #include "gui_thread.h"
108 #include "keyboard.h"
109 #include "marker.h"
110 #include "midi_time_axis.h"
111 #include "mixer_strip.h"
112 #include "mixer_ui.h"
113 #include "mouse_cursors.h"
114 #include "playlist_selector.h"
115 #include "public_editor.h"
116 #include "region_layering_order_editor.h"
117 #include "rgb_macros.h"
118 #include "rhythm_ferret.h"
119 #include "selection.h"
120 #include "sfdb_ui.h"
121 #include "tempo_lines.h"
122 #include "time_axis_view.h"
123 #include "utils.h"
124 #include "verbose_cursor.h"
125
126 #include "i18n.h"
127
128 using namespace std;
129 using namespace ARDOUR;
130 using namespace ARDOUR_UI_UTILS;
131 using namespace PBD;
132 using namespace Gtk;
133 using namespace Glib;
134 using namespace Gtkmm2ext;
135 using namespace Editing;
136
137 using PBD::internationalize;
138 using PBD::atoi;
139 using Gtkmm2ext::Keyboard;
140
141 const double Editor::timebar_height = 15.0;
142
143 static const gchar *_snap_type_strings[] = {
144         N_("CD Frames"),
145         N_("TC Frames"),
146         N_("TC Seconds"),
147         N_("TC Minutes"),
148         N_("Seconds"),
149         N_("Minutes"),
150         N_("Beats/128"),
151         N_("Beats/64"),
152         N_("Beats/32"),
153         N_("Beats/28"),
154         N_("Beats/24"),
155         N_("Beats/20"),
156         N_("Beats/16"),
157         N_("Beats/14"),
158         N_("Beats/12"),
159         N_("Beats/10"),
160         N_("Beats/8"),
161         N_("Beats/7"),
162         N_("Beats/6"),
163         N_("Beats/5"),
164         N_("Beats/4"),
165         N_("Beats/3"),
166         N_("Beats/2"),
167         N_("Beats"),
168         N_("Bars"),
169         N_("Marks"),
170         N_("Region starts"),
171         N_("Region ends"),
172         N_("Region syncs"),
173         N_("Region bounds"),
174         0
175 };
176
177 static const gchar *_snap_mode_strings[] = {
178         N_("No Grid"),
179         N_("Grid"),
180         N_("Magnetic"),
181         0
182 };
183
184 static const gchar *_edit_point_strings[] = {
185         N_("Playhead"),
186         N_("Marker"),
187         N_("Mouse"),
188         0
189 };
190
191 static const gchar *_zoom_focus_strings[] = {
192         N_("Left"),
193         N_("Right"),
194         N_("Center"),
195         N_("Playhead"),
196         N_("Mouse"),
197         N_("Edit point"),
198         0
199 };
200
201 #ifdef USE_RUBBERBAND
202 static const gchar *_rb_opt_strings[] = {
203         N_("Mushy"),
204         N_("Smooth"),
205         N_("Balanced multitimbral mixture"),
206         N_("Unpitched percussion with stable notes"),
207         N_("Crisp monophonic instrumental"),
208         N_("Unpitched solo percussion"),
209         N_("Resample without preserving pitch"),
210         0
211 };
212 #endif
213
214 static void
215 pane_size_watcher (Paned* pane)
216 {
217         /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
218            it is:
219
220               X: hard to access
221               Quartz: impossible to access
222               
223            so stop that by preventing it from ever getting too narrow. 35
224            pixels is basically a rough guess at the tab width.
225
226            ugh.
227         */
228
229         int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
230
231         gint pos = pane->get_position ();
232
233         if (pos > max_width_of_lhs) {
234                 pane->set_position (max_width_of_lhs);
235         }
236 }
237
238 Editor::Editor ()
239         : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
240
241           /* time display buttons */
242         , minsec_label (_("Mins:Secs"))
243         , bbt_label (_("Bars:Beats"))
244         , timecode_label (_("Timecode"))
245         , samples_label (_("Samples"))
246         , tempo_label (_("Tempo"))
247         , meter_label (_("Meter"))
248         , mark_label (_("Location Markers"))
249         , range_mark_label (_("Range Markers"))
250         , transport_mark_label (_("Loop/Punch Ranges"))
251         , cd_mark_label (_("CD Markers"))
252         , videotl_label (_("Video Timeline"))
253         , edit_packer (4, 4, true)
254
255           /* the values here don't matter: layout widgets
256              reset them as needed.
257           */
258
259         , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
260         , horizontal_adjustment (0.0, 0.0, 1e16)
261         , unused_adjustment (0.0, 0.0, 10.0, 400.0)
262
263         , controls_layout (unused_adjustment, vertical_adjustment)
264
265           /* tool bar related */
266
267         , toolbar_selection_clock_table (2,3)
268         , _mouse_mode_tearoff (0)
269         , automation_mode_button (_("mode"))
270         , _zoom_tearoff (0)
271         , _tools_tearoff (0)
272
273         , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
274
275           /* nudge */
276
277         , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
278         , meters_running(false)
279         , _pending_locate_request (false)
280         , _pending_initial_locate (false)
281         , _last_cut_copy_source_track (0)
282
283         , _region_selection_change_updates_region_list (true)
284         , _following_mixer_selection (false)
285         , _control_point_toggled_on_press (false)
286         , _stepping_axis_view (0)
287 {
288         constructed = false;
289
290         /* we are a singleton */
291
292         PublicEditor::_instance = this;
293
294         _have_idled = false;
295         
296         selection = new Selection (this);
297         cut_buffer = new Selection (this);
298
299         clicked_regionview = 0;
300         clicked_axisview = 0;
301         clicked_routeview = 0;
302         clicked_control_point = 0;
303         last_update_frame = 0;
304         pre_press_cursor = 0;
305         _drags = new DragManager (this);
306         lock_dialog = 0;
307         ruler_dialog = 0;
308         current_mixer_strip = 0;
309         tempo_lines = 0;
310
311         snap_type_strings =  I18N (_snap_type_strings);
312         snap_mode_strings =  I18N (_snap_mode_strings);
313         zoom_focus_strings = I18N (_zoom_focus_strings);
314         edit_point_strings = I18N (_edit_point_strings);
315 #ifdef USE_RUBBERBAND
316         rb_opt_strings = I18N (_rb_opt_strings);
317         rb_current_opt = 4;
318 #endif
319
320         build_edit_mode_menu();
321         build_zoom_focus_menu();
322         build_track_count_menu();
323         build_snap_mode_menu();
324         build_snap_type_menu();
325         build_edit_point_menu();
326
327         snap_threshold = 5.0;
328         bbt_beat_subdivision = 4;
329         _visible_canvas_width = 0;
330         _visible_canvas_height = 0;
331         autoscroll_horizontal_allowed = false;
332         autoscroll_vertical_allowed = false;
333         logo_item = 0;
334
335         analysis_window = 0;
336
337         current_interthread_info = 0;
338         _show_measures = true;
339         _maximised = false;
340         show_gain_after_trim = false;
341
342         have_pending_keyboard_selection = false;
343         _follow_playhead = true;
344         _stationary_playhead = false;
345         editor_ruler_menu = 0;
346         no_ruler_shown_update = false;
347         marker_menu = 0;
348         range_marker_menu = 0;
349         marker_menu_item = 0;
350         tempo_or_meter_marker_menu = 0;
351         transport_marker_menu = 0;
352         new_transport_marker_menu = 0;
353         editor_mixer_strip_width = Wide;
354         show_editor_mixer_when_tracks_arrive = false;
355         region_edit_menu_split_multichannel_item = 0;
356         region_edit_menu_split_item = 0;
357         temp_location = 0;
358         leftmost_frame = 0;
359         current_stepping_trackview = 0;
360         entered_track = 0;
361         entered_regionview = 0;
362         entered_marker = 0;
363         clear_entered_track = false;
364         current_timefx = 0;
365         playhead_cursor = 0;
366         button_release_can_deselect = true;
367         _dragging_playhead = false;
368         _dragging_edit_point = false;
369         select_new_marker = false;
370         rhythm_ferret = 0;
371         layering_order_editor = 0;
372         no_save_visual = false;
373         resize_idle_id = -1;
374         within_track_canvas = false;
375
376         scrubbing_direction = 0;
377
378         sfbrowser = 0;
379
380         location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
381         location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
382         location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
383         location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
384         location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
385
386         zoom_focus = ZoomFocusLeft;
387         _edit_point = EditAtMouse;
388         _internal_editing = false;
389         current_canvas_cursor = 0;
390         _visible_track_count = 16;
391
392         samples_per_pixel = 2048; /* too early to use reset_zoom () */
393
394         _scroll_callbacks = 0;
395
396         bbt_label.set_name ("EditorRulerLabel");
397         bbt_label.set_size_request (-1, (int)timebar_height);
398         bbt_label.set_alignment (1.0, 0.5);
399         bbt_label.set_padding (5,0);
400         bbt_label.hide ();
401         bbt_label.set_no_show_all();
402         minsec_label.set_name ("EditorRulerLabel");
403         minsec_label.set_size_request (-1, (int)timebar_height);
404         minsec_label.set_alignment (1.0, 0.5);
405         minsec_label.set_padding (5,0);
406         minsec_label.hide ();
407         minsec_label.set_no_show_all();
408         timecode_label.set_name ("EditorRulerLabel");
409         timecode_label.set_size_request (-1, (int)timebar_height);
410         timecode_label.set_alignment (1.0, 0.5);
411         timecode_label.set_padding (5,0);
412         timecode_label.hide ();
413         timecode_label.set_no_show_all();
414         samples_label.set_name ("EditorRulerLabel");
415         samples_label.set_size_request (-1, (int)timebar_height);
416         samples_label.set_alignment (1.0, 0.5);
417         samples_label.set_padding (5,0);
418         samples_label.hide ();
419         samples_label.set_no_show_all();
420
421         tempo_label.set_name ("EditorRulerLabel");
422         tempo_label.set_size_request (-1, (int)timebar_height);
423         tempo_label.set_alignment (1.0, 0.5);
424         tempo_label.set_padding (5,0);
425         tempo_label.hide();
426         tempo_label.set_no_show_all();
427
428         meter_label.set_name ("EditorRulerLabel");
429         meter_label.set_size_request (-1, (int)timebar_height);
430         meter_label.set_alignment (1.0, 0.5);
431         meter_label.set_padding (5,0);
432         meter_label.hide();
433         meter_label.set_no_show_all();
434
435         if (Profile->get_trx()) {
436                 mark_label.set_text (_("Markers"));
437         }
438         mark_label.set_name ("EditorRulerLabel");
439         mark_label.set_size_request (-1, (int)timebar_height);
440         mark_label.set_alignment (1.0, 0.5);
441         mark_label.set_padding (5,0);
442         mark_label.hide();
443         mark_label.set_no_show_all();
444
445         cd_mark_label.set_name ("EditorRulerLabel");
446         cd_mark_label.set_size_request (-1, (int)timebar_height);
447         cd_mark_label.set_alignment (1.0, 0.5);
448         cd_mark_label.set_padding (5,0);
449         cd_mark_label.hide();
450         cd_mark_label.set_no_show_all();
451
452         videotl_bar_height = 4;
453         videotl_label.set_name ("EditorRulerLabel");
454         videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
455         videotl_label.set_alignment (1.0, 0.5);
456         videotl_label.set_padding (5,0);
457         videotl_label.hide();
458         videotl_label.set_no_show_all();
459
460         range_mark_label.set_name ("EditorRulerLabel");
461         range_mark_label.set_size_request (-1, (int)timebar_height);
462         range_mark_label.set_alignment (1.0, 0.5);
463         range_mark_label.set_padding (5,0);
464         range_mark_label.hide();
465         range_mark_label.set_no_show_all();
466
467         transport_mark_label.set_name ("EditorRulerLabel");
468         transport_mark_label.set_size_request (-1, (int)timebar_height);
469         transport_mark_label.set_alignment (1.0, 0.5);
470         transport_mark_label.set_padding (5,0);
471         transport_mark_label.hide();
472         transport_mark_label.set_no_show_all();
473
474         initialize_canvas ();
475
476         _summary = new EditorSummary (this);
477
478         selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
479         selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
480
481         editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
482
483         selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
484         selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
485
486         edit_controls_vbox.set_spacing (0);
487         vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
488         _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
489
490         HBox* h = manage (new HBox);
491         _group_tabs = new EditorGroupTabs (this);
492         if (!ARDOUR::Profile->get_trx()) {
493                 h->pack_start (*_group_tabs, PACK_SHRINK);
494         }
495         h->pack_start (edit_controls_vbox);
496         controls_layout.add (*h);
497
498         controls_layout.set_name ("EditControlsBase");
499         controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
500         controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
501         controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
502
503         _cursors = new MouseCursors;
504         _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
505         cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
506
507         ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
508
509         ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
510         pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
511         pad_line_1->set_outline_color (0xFF0000FF);
512         pad_line_1->show();
513
514         // CAIROCANVAS
515         time_pad->show();
516
517         edit_packer.set_col_spacings (0);
518         edit_packer.set_row_spacings (0);
519         edit_packer.set_homogeneous (false);
520         edit_packer.set_border_width (0);
521         edit_packer.set_name ("EditorWindow");
522
523         time_bars_event_box.add (time_bars_vbox);
524         time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
525         time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
526
527         /* labels for the time bars */
528         edit_packer.attach (time_bars_event_box,     0, 1, 0, 1,    FILL,        SHRINK, 0, 0);
529         /* track controls */
530         edit_packer.attach (controls_layout,         0, 1, 1, 2,    FILL,        FILL|EXPAND, 0, 0);
531         /* canvas */
532         edit_packer.attach (*_track_canvas_viewport,  1, 2, 0, 2,    FILL|EXPAND, FILL|EXPAND, 0, 0);
533
534         bottom_hbox.set_border_width (2);
535         bottom_hbox.set_spacing (3);
536
537         _route_groups = new EditorRouteGroups (this);
538         _routes = new EditorRoutes (this);
539         _regions = new EditorRegions (this);
540         _snapshots = new EditorSnapshots (this);
541         _locations = new EditorLocations (this);
542
543         add_notebook_page (_("Regions"), _regions->widget ());
544         add_notebook_page (_("Tracks & Busses"), _routes->widget ());
545         add_notebook_page (_("Snapshots"), _snapshots->widget ());
546         add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
547         add_notebook_page (_("Ranges & Marks"), _locations->widget ());
548
549         _the_notebook.set_show_tabs (true);
550         _the_notebook.set_scrollable (true);
551         _the_notebook.popup_disable ();
552         _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
553         _the_notebook.show_all ();
554
555         _notebook_shrunk = false;
556
557         editor_summary_pane.pack1(edit_packer);
558
559         Button* summary_arrows_left_left = manage (new Button);
560         summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
561         summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
562         summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
563
564         Button* summary_arrows_left_right = manage (new Button);
565         summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
566         summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
567         summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
568
569         VBox* summary_arrows_left = manage (new VBox);
570         summary_arrows_left->pack_start (*summary_arrows_left_left);
571         summary_arrows_left->pack_start (*summary_arrows_left_right);
572
573         Button* summary_arrows_right_up = manage (new Button);
574         summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
575         summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
576         summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
577
578         Button* summary_arrows_right_down = manage (new Button);
579         summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
580         summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
581         summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
582
583         VBox* summary_arrows_right = manage (new VBox);
584         summary_arrows_right->pack_start (*summary_arrows_right_up);
585         summary_arrows_right->pack_start (*summary_arrows_right_down);
586
587         Frame* summary_frame = manage (new Frame);
588         summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
589
590         summary_frame->add (*_summary);
591         summary_frame->show ();
592
593         _summary_hbox.pack_start (*summary_arrows_left, false, false);
594         _summary_hbox.pack_start (*summary_frame, true, true);
595         _summary_hbox.pack_start (*summary_arrows_right, false, false);
596
597         if (!ARDOUR::Profile->get_trx()) {
598                 editor_summary_pane.pack2 (_summary_hbox);
599         }
600
601         edit_pane.pack1 (editor_summary_pane, true, true);
602         if (!ARDOUR::Profile->get_trx()) {
603                 edit_pane.pack2 (_the_notebook, false, true);
604         }
605
606         editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
607
608         /* XXX: editor_summary_pane might need similar to the edit_pane */
609
610         edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
611
612         Glib::PropertyProxy<int> proxy = edit_pane.property_position();
613         proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
614
615         top_hbox.pack_start (toolbar_frame);
616
617         HBox *hbox = manage (new HBox);
618         hbox->pack_start (edit_pane, true, true);
619
620         global_vpacker.pack_start (top_hbox, false, false);
621         global_vpacker.pack_start (*hbox, true, true);
622
623         global_hpacker.pack_start (global_vpacker, true, true);
624
625         set_name ("EditorWindow");
626         add_accel_group (ActionManager::ui_manager->get_accel_group());
627
628         status_bar_hpacker.show ();
629
630         vpacker.pack_end (status_bar_hpacker, false, false);
631         vpacker.pack_end (global_hpacker, true, true);
632
633         /* register actions now so that set_state() can find them and set toggles/checks etc */
634
635         register_actions ();
636         /* when we start using our own keybinding system for the editor, this
637          * will be uncommented
638          */
639         // load_bindings ();
640
641         setup_toolbar ();
642
643         set_zoom_focus (zoom_focus);
644         set_visible_track_count (_visible_track_count);
645         _snap_type = SnapToBeat;
646         set_snap_to (_snap_type);
647         _snap_mode = SnapOff;
648         set_snap_mode (_snap_mode);
649         set_mouse_mode (MouseObject, true);
650         pre_internal_mouse_mode = MouseObject;
651         pre_internal_snap_type = _snap_type;
652         pre_internal_snap_mode = _snap_mode;
653         internal_snap_type = _snap_type;
654         internal_snap_mode = _snap_mode;
655         set_edit_point_preference (EditAtMouse, true);
656
657         _playlist_selector = new PlaylistSelector();
658         _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
659
660         RegionView::RegionViewGoingAway.connect (*this, invalidator (*this),  boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
661
662         /* nudge stuff */
663
664         nudge_forward_button.set_name ("nudge button");
665 //      nudge_forward_button.add_elements (ArdourButton::Inset);
666         nudge_forward_button.set_image(::get_icon("nudge_right"));
667
668         nudge_backward_button.set_name ("nudge button");
669 //      nudge_backward_button.add_elements (ArdourButton::Inset);
670         nudge_backward_button.set_image(::get_icon("nudge_left"));
671
672         fade_context_menu.set_name ("ArdourContextMenu");
673
674         /* icons, titles, WM stuff */
675
676         list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
677         Glib::RefPtr<Gdk::Pixbuf> icon;
678
679         if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
680                 window_icons.push_back (icon);
681         }
682         if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
683                 window_icons.push_back (icon);
684         }
685         if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
686                 window_icons.push_back (icon);
687         }
688         if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
689                 window_icons.push_back (icon);
690         }
691         if (!window_icons.empty()) {
692                 // set_icon_list (window_icons);
693                 set_default_icon_list (window_icons);
694         }
695
696         WindowTitle title(Glib::get_application_name());
697         title += _("Editor");
698         set_title (title.get_string());
699         set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
700
701         add (vpacker);
702         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
703
704         signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
705         signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
706
707         Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
708         
709         /* allow external control surfaces/protocols to do various things */
710
711         ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
712         ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
713         ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
714         ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
715         ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
716         ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
717         ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
718         ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
719         ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
720         ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
721         ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
722         ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
723         ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
724         ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
725
726         ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
727         ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
728         ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
729         ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
730         ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
731
732         BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
733
734         /* problematic: has to return a value and thus cannot be x-thread */
735
736         Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
737
738         Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
739         ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
740
741         TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
742
743         _ignore_region_action = false;
744         _last_region_menu_was_main = false;
745         _popup_region_menu_item = 0;
746
747         _ignore_follow_edits = false;
748
749         _show_marker_lines = false;
750
751         /* Button bindings */
752
753         button_bindings = new Bindings;
754
755         XMLNode* node = button_settings();
756         if (node) {
757                 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
758                         button_bindings->load (**i);
759                 }
760         }
761
762         constructed = true;
763
764         /* grab current parameter state */
765         boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
766         ARDOUR_UI::config()->map_parameters (pc);
767
768         setup_fade_images ();
769
770         instant_save ();
771 }
772
773 Editor::~Editor()
774 {
775         delete button_bindings;
776         delete _routes;
777         delete _route_groups;
778         delete _track_canvas_viewport;
779         delete _drags;
780 }
781
782 XMLNode*
783 Editor::button_settings () const
784 {
785         XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
786         XMLNode* node = find_named_node (*settings, X_("Buttons"));
787
788         if (!node) {
789                 node = new XMLNode (X_("Buttons"));
790         }
791
792         return node;
793 }
794
795 void
796 Editor::add_toplevel_controls (Container& cont)
797 {
798         vpacker.pack_start (cont, false, false);
799         cont.show_all ();
800 }
801
802 bool
803 Editor::get_smart_mode () const
804 {
805         return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
806 }
807
808 void
809 Editor::catch_vanishing_regionview (RegionView *rv)
810 {
811         /* note: the selection will take care of the vanishing
812            audioregionview by itself.
813         */
814
815         if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
816                 _drags->abort ();
817         }
818
819         if (clicked_regionview == rv) {
820                 clicked_regionview = 0;
821         }
822
823         if (entered_regionview == rv) {
824                 set_entered_regionview (0);
825         }
826
827         if (!_all_region_actions_sensitized) {
828                 sensitize_all_region_actions (true);
829         }
830 }
831
832 void
833 Editor::set_entered_regionview (RegionView* rv)
834 {
835         if (rv == entered_regionview) {
836                 return;
837         }
838
839         if (entered_regionview) {
840                 entered_regionview->exited ();
841         }
842
843         entered_regionview = rv;
844
845         if (entered_regionview  != 0) {
846                 entered_regionview->entered (internal_editing ());
847         }
848
849         if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
850                 /* This RegionView entry might have changed what region actions
851                    are allowed, so sensitize them all in case a key is pressed.
852                 */
853                 sensitize_all_region_actions (true);
854         }
855 }
856
857 void
858 Editor::set_entered_track (TimeAxisView* tav)
859 {
860         if (entered_track) {
861                 entered_track->exited ();
862         }
863
864         entered_track = tav;
865
866         if (entered_track) {
867                 entered_track->entered ();
868         }
869 }
870
871 void
872 Editor::show_window ()
873 {
874         if (!is_visible ()) {
875                 show_all ();
876
877                 /* XXX: this is a bit unfortunate; it would probably
878                    be nicer if we could just call show () above rather
879                    than needing the show_all ()
880                 */
881
882                 /* re-hide stuff if necessary */
883                 editor_list_button_toggled ();
884                 parameter_changed ("show-summary");
885                 parameter_changed ("show-group-tabs");
886                 parameter_changed ("show-zoom-tools");
887
888                 /* now reset all audio_time_axis heights, because widgets might need
889                    to be re-hidden
890                 */
891
892                 TimeAxisView *tv;
893
894                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
895                         tv = (static_cast<TimeAxisView*>(*i));
896                         tv->reset_height ();
897                 }
898
899                 if (current_mixer_strip) {
900                         current_mixer_strip->hide_things ();
901                         current_mixer_strip->parameter_changed ("mixer-strip-visibility");
902                 }
903         }
904
905         present ();
906 }
907
908 void
909 Editor::instant_save ()
910 {
911         if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
912                 return;
913         }
914
915         if (_session) {
916                 _session->add_instant_xml(get_state());
917         } else {
918                 Config->add_instant_xml(get_state());
919         }
920 }
921
922 void
923 Editor::control_vertical_zoom_in_all ()
924 {
925         tav_zoom_smooth (false, true);
926 }
927
928 void
929 Editor::control_vertical_zoom_out_all ()
930 {
931         tav_zoom_smooth (true, true);
932 }
933
934 void
935 Editor::control_vertical_zoom_in_selected ()
936 {
937         tav_zoom_smooth (false, false);
938 }
939
940 void
941 Editor::control_vertical_zoom_out_selected ()
942 {
943         tav_zoom_smooth (true, false);
944 }
945
946 void
947 Editor::control_view (uint32_t view)
948 {
949         goto_visual_state (view);
950 }
951
952 void
953 Editor::control_unselect ()
954 {
955         selection->clear_tracks ();
956 }
957
958 void
959 Editor::control_select (uint32_t rid, Selection::Operation op) 
960 {
961         /* handles the (static) signal from the ControlProtocol class that
962          * requests setting the selected track to a given RID
963          */
964          
965         if (!_session) {
966                 return;
967         }
968
969         boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
970
971         if (!r) {
972                 return;
973         }
974
975         TimeAxisView* tav = axis_view_from_route (r);
976
977         if (tav) {
978                 switch (op) {
979                 case Selection::Add:
980                         selection->add (tav);
981                         break;
982                 case Selection::Toggle:
983                         selection->toggle (tav);
984                         break;
985                 case Selection::Extend:
986                         break;
987                 case Selection::Set:
988                         selection->set (tav);
989                         break;
990                 }
991         } else {
992                 selection->clear_tracks ();
993         }
994 }
995
996 void
997 Editor::control_step_tracks_up ()
998 {
999         scroll_tracks_up_line ();
1000 }
1001
1002 void
1003 Editor::control_step_tracks_down ()
1004 {
1005         scroll_tracks_down_line ();
1006 }
1007
1008 void
1009 Editor::control_scroll (float fraction)
1010 {
1011         ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1012
1013         if (!_session) {
1014                 return;
1015         }
1016
1017         double step = fraction * current_page_samples();
1018
1019         /*
1020                 _control_scroll_target is an optional<T>
1021
1022                 it acts like a pointer to an framepos_t, with
1023                 a operator conversion to boolean to check
1024                 that it has a value could possibly use
1025                 playhead_cursor->current_frame to store the
1026                 value and a boolean in the class to know
1027                 when it's out of date
1028         */
1029
1030         if (!_control_scroll_target) {
1031                 _control_scroll_target = _session->transport_frame();
1032                 _dragging_playhead = true;
1033         }
1034
1035         if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1036                 *_control_scroll_target = 0;
1037         } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1038                 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1039         } else {
1040                 *_control_scroll_target += (framepos_t) floor (step);
1041         }
1042
1043         /* move visuals, we'll catch up with it later */
1044
1045         playhead_cursor->set_position (*_control_scroll_target);
1046         UpdateAllTransportClocks (*_control_scroll_target);
1047
1048         if (*_control_scroll_target > (current_page_samples() / 2)) {
1049                 /* try to center PH in window */
1050                 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1051         } else {
1052                 reset_x_origin (0);
1053         }
1054
1055         /*
1056                 Now we do a timeout to actually bring the session to the right place
1057                 according to the playhead. This is to avoid reading disk buffers on every
1058                 call to control_scroll, which is driven by ScrollTimeline and therefore
1059                 probably by a control surface wheel which can generate lots of events.
1060         */
1061         /* cancel the existing timeout */
1062
1063         control_scroll_connection.disconnect ();
1064
1065         /* add the next timeout */
1066
1067         control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1068 }
1069
1070 bool
1071 Editor::deferred_control_scroll (framepos_t /*target*/)
1072 {
1073         _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1074         // reset for next stream
1075         _control_scroll_target = boost::none;
1076         _dragging_playhead = false;
1077         return false;
1078 }
1079
1080 void
1081 Editor::access_action (std::string action_group, std::string action_item)
1082 {
1083         if (!_session) {
1084                 return;
1085         }
1086
1087         ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1088
1089         RefPtr<Action> act;
1090         act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1091
1092         if (act) {
1093                 act->activate();
1094         }
1095 }
1096
1097 void
1098 Editor::on_realize ()
1099 {
1100         Window::on_realize ();
1101         Realized ();
1102
1103         if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1104                 start_lock_event_timing ();
1105         }
1106
1107         signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1108 }
1109
1110 void
1111 Editor::start_lock_event_timing ()
1112 {
1113         /* check if we should lock the GUI every 30 seconds */
1114
1115         Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1116 }
1117
1118 bool
1119 Editor::generic_event_handler (GdkEvent* ev)
1120 {
1121         switch (ev->type) {
1122         case GDK_BUTTON_PRESS:
1123         case GDK_BUTTON_RELEASE:
1124         case GDK_MOTION_NOTIFY:
1125         case GDK_KEY_PRESS:
1126         case GDK_KEY_RELEASE:
1127                 gettimeofday (&last_event_time, 0);
1128                 break;
1129         default:
1130                 break;
1131         }
1132         return false;
1133 }
1134
1135 bool
1136 Editor::lock_timeout_callback ()
1137 {
1138         struct timeval now, delta;
1139
1140         gettimeofday (&now, 0);
1141
1142         timersub (&now, &last_event_time, &delta);
1143
1144         if (delta.tv_sec > ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1145                 lock ();
1146                 /* don't call again. Returning false will effectively
1147                    disconnect us from the timer callback.
1148
1149                    unlock() will call start_lock_event_timing() to get things
1150                    started again.
1151                 */
1152                 return false;
1153         }
1154
1155         return true;
1156 }
1157
1158 void
1159 Editor::map_position_change (framepos_t frame)
1160 {
1161         ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1162
1163         if (_session == 0) {
1164                 return;
1165         }
1166
1167         if (_follow_playhead) {
1168                 center_screen (frame);
1169         }
1170
1171         playhead_cursor->set_position (frame);
1172 }
1173
1174 void
1175 Editor::center_screen (framepos_t frame)
1176 {
1177         framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1178
1179         /* if we're off the page, then scroll.
1180          */
1181
1182         if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1183                 center_screen_internal (frame, page);
1184         }
1185 }
1186
1187 void
1188 Editor::center_screen_internal (framepos_t frame, float page)
1189 {
1190         page /= 2;
1191
1192         if (frame > page) {
1193                 frame -= (framepos_t) page;
1194         } else {
1195                 frame = 0;
1196         }
1197
1198         reset_x_origin (frame);
1199 }
1200
1201
1202 void
1203 Editor::update_title ()
1204 {
1205         ENSURE_GUI_THREAD (*this, &Editor::update_title)
1206
1207         if (_session) {
1208                 bool dirty = _session->dirty();
1209
1210                 string session_name;
1211
1212                 if (_session->snap_name() != _session->name()) {
1213                         session_name = _session->snap_name();
1214                 } else {
1215                         session_name = _session->name();
1216                 }
1217
1218                 if (dirty) {
1219                         session_name = "*" + session_name;
1220                 }
1221
1222                 WindowTitle title(session_name);
1223                 title += Glib::get_application_name();
1224                 set_title (title.get_string());
1225         } else {
1226                 /* ::session_going_away() will have taken care of it */
1227         }
1228 }
1229
1230 void
1231 Editor::set_session (Session *t)
1232 {
1233         SessionHandlePtr::set_session (t);
1234
1235         if (!_session) {
1236                 return;
1237         }
1238
1239         _playlist_selector->set_session (_session);
1240         nudge_clock->set_session (_session);
1241         _summary->set_session (_session);
1242         _group_tabs->set_session (_session);
1243         _route_groups->set_session (_session);
1244         _regions->set_session (_session);
1245         _snapshots->set_session (_session);
1246         _routes->set_session (_session);
1247         _locations->set_session (_session);
1248
1249         if (rhythm_ferret) {
1250                 rhythm_ferret->set_session (_session);
1251         }
1252
1253         if (analysis_window) {
1254                 analysis_window->set_session (_session);
1255         }
1256
1257         if (sfbrowser) {
1258                 sfbrowser->set_session (_session);
1259         }
1260
1261         compute_fixed_ruler_scale ();
1262
1263         /* Make sure we have auto loop and auto punch ranges */
1264
1265         Location* loc = _session->locations()->auto_loop_location();
1266         if (loc != 0) {
1267                 loc->set_name (_("Loop"));
1268         }
1269
1270         loc = _session->locations()->auto_punch_location();
1271         if (loc != 0) {
1272                 // force name
1273                 loc->set_name (_("Punch"));
1274         }
1275
1276         refresh_location_display ();
1277
1278         /* This must happen after refresh_location_display(), as (amongst other things) we restore
1279            the selected Marker; this needs the LocationMarker list to be available.
1280         */
1281         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1282         set_state (*node, Stateful::loading_state_version);
1283
1284         /* catch up with the playhead */
1285
1286         _session->request_locate (playhead_cursor->current_frame ());
1287         _pending_initial_locate = true;
1288
1289         update_title ();
1290
1291         /* These signals can all be emitted by a non-GUI thread. Therefore the
1292            handlers for them must not attempt to directly interact with the GUI,
1293            but use PBD::Signal<T>::connect() which accepts an event loop
1294            ("context") where the handler will be asked to run.
1295         */
1296
1297         _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1298         _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1299         _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1300         _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1301         _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1302         _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1303         _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1304         _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1305         _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1306         _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1307         _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1308         _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1309         _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1310         _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1311
1312         playhead_cursor->show ();
1313
1314         boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1315         Config->map_parameters (pc);
1316         _session->config.map_parameters (pc);
1317
1318         restore_ruler_visibility ();
1319         //tempo_map_changed (PropertyChange (0));
1320         _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1321
1322         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1323                 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1324         }
1325
1326         super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1327                 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1328                 );
1329
1330         switch (_snap_type) {
1331         case SnapToRegionStart:
1332         case SnapToRegionEnd:
1333         case SnapToRegionSync:
1334         case SnapToRegionBoundary:
1335                 build_region_boundary_cache ();
1336                 break;
1337
1338         default:
1339                 break;
1340         }
1341
1342         /* register for undo history */
1343         _session->register_with_memento_command_factory(id(), this);
1344
1345         ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1346
1347         start_updating_meters ();
1348 }
1349
1350 void
1351 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1352 {
1353         if (a->get_name() == "RegionMenu") {
1354                 /* When the main menu's region menu is opened, we setup the actions so that they look right
1355                    in the menu.  I can't find a way of getting a signal when this menu is subsequently closed,
1356                    so we resensitize all region actions when the entered regionview or the region selection
1357                    changes.  HOWEVER we can't always resensitize on entered_regionview change because that
1358                    happens after the region context menu is opened.  So we set a flag here, too.
1359
1360                    What a carry on :(
1361                 */
1362                 sensitize_the_right_region_actions ();
1363                 _last_region_menu_was_main = true;
1364         }
1365 }
1366
1367 void
1368 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1369 {
1370         using namespace Menu_Helpers;
1371
1372         void (Editor::*emf)(FadeShape);
1373         std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1374
1375         if (start) {
1376                 images = &_xfade_in_images;
1377                 emf = &Editor::set_fade_in_shape;
1378         } else {
1379                 images = &_xfade_out_images;
1380                 emf = &Editor::set_fade_out_shape;
1381         }
1382
1383         items.push_back (
1384                 ImageMenuElem (
1385                         _("Linear (for highly correlated material)"),
1386                         *(*images)[FadeLinear],
1387                         sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1388                         )
1389                 );
1390         
1391         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1392         
1393         items.push_back (
1394                 ImageMenuElem (
1395                         _("Constant power"),
1396                         *(*images)[FadeConstantPower],
1397                         sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1398                         ));
1399         
1400         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1401         
1402         items.push_back (
1403                 ImageMenuElem (
1404                         _("Symmetric"),
1405                         *(*images)[FadeSymmetric],
1406                         sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1407                         )
1408                 );
1409         
1410         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1411         
1412         items.push_back (
1413                 ImageMenuElem (
1414                         _("Slow"),
1415                         *(*images)[FadeSlow],
1416                         sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1417                         ));
1418         
1419         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1420         
1421         items.push_back (
1422                 ImageMenuElem (
1423                         _("Fast"),
1424                         *(*images)[FadeFast],
1425                         sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1426                         ));
1427         
1428         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1429 }
1430
1431 /** Pop up a context menu for when the user clicks on a start crossfade */
1432 void
1433 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1434 {
1435         using namespace Menu_Helpers;
1436         AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1437         assert(arv);
1438
1439         MenuList& items (xfade_in_context_menu.items());
1440         items.clear ();
1441
1442         if (arv->audio_region()->fade_in_active()) {
1443                 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1444         } else {
1445                 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1446         }
1447
1448         items.push_back (SeparatorElem());
1449         fill_xfade_menu (items, true);
1450
1451         xfade_in_context_menu.popup (button, time);
1452 }
1453
1454 /** Pop up a context menu for when the user clicks on an end crossfade */
1455 void
1456 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1457 {
1458         using namespace Menu_Helpers;
1459         AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1460         assert(arv);
1461
1462         MenuList& items (xfade_out_context_menu.items());
1463         items.clear ();
1464
1465         if (arv->audio_region()->fade_out_active()) {
1466                 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1467         } else {
1468                 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1469         }
1470
1471         items.push_back (SeparatorElem());
1472         fill_xfade_menu (items, false);
1473
1474         xfade_out_context_menu.popup (button, time);
1475 }
1476
1477 void
1478 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1479 {
1480         using namespace Menu_Helpers;
1481         Menu* (Editor::*build_menu_function)();
1482         Menu *menu;
1483
1484         switch (item_type) {
1485         case RegionItem:
1486         case RegionViewName:
1487         case RegionViewNameHighlight:
1488         case LeftFrameHandle:
1489         case RightFrameHandle:
1490                 if (with_selection) {
1491                         build_menu_function = &Editor::build_track_selection_context_menu;
1492                 } else {
1493                         build_menu_function = &Editor::build_track_region_context_menu;
1494                 }
1495                 break;
1496
1497         case SelectionItem:
1498                 if (with_selection) {
1499                         build_menu_function = &Editor::build_track_selection_context_menu;
1500                 } else {
1501                         build_menu_function = &Editor::build_track_context_menu;
1502                 }
1503                 break;
1504
1505         case StreamItem:
1506                 if (clicked_routeview->track()) {
1507                         build_menu_function = &Editor::build_track_context_menu;
1508                 } else {
1509                         build_menu_function = &Editor::build_track_bus_context_menu;
1510                 }
1511                 break;
1512
1513         default:
1514                 /* probably shouldn't happen but if it does, we don't care */
1515                 return;
1516         }
1517
1518         menu = (this->*build_menu_function)();
1519         menu->set_name ("ArdourContextMenu");
1520
1521         /* now handle specific situations */
1522
1523         switch (item_type) {
1524         case RegionItem:
1525         case RegionViewName:
1526         case RegionViewNameHighlight:
1527         case LeftFrameHandle:
1528         case RightFrameHandle:
1529                 if (!with_selection) {
1530                         if (region_edit_menu_split_item) {
1531                                 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1532                                         ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1533                                 } else {
1534                                         ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1535                                 }
1536                         }
1537                         if (region_edit_menu_split_multichannel_item) {
1538                                 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1539                                         region_edit_menu_split_multichannel_item->set_sensitive (true);
1540                                 } else {
1541                                         region_edit_menu_split_multichannel_item->set_sensitive (false);
1542                                 }
1543                         }
1544                 }
1545                 break;
1546
1547         case SelectionItem:
1548                 break;
1549
1550         case StreamItem:
1551                 break;
1552
1553         default:
1554                 /* probably shouldn't happen but if it does, we don't care */
1555                 return;
1556         }
1557
1558         if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1559
1560                 /* Bounce to disk */
1561
1562                 using namespace Menu_Helpers;
1563                 MenuList& edit_items  = menu->items();
1564
1565                 edit_items.push_back (SeparatorElem());
1566
1567                 switch (clicked_routeview->audio_track()->freeze_state()) {
1568                 case AudioTrack::NoFreeze:
1569                         edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1570                         break;
1571
1572                 case AudioTrack::Frozen:
1573                         edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1574                         break;
1575
1576                 case AudioTrack::UnFrozen:
1577                         edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1578                         break;
1579                 }
1580
1581         }
1582
1583         if (item_type == StreamItem && clicked_routeview) {
1584                 clicked_routeview->build_underlay_menu(menu);
1585         }
1586
1587         /* When the region menu is opened, we setup the actions so that they look right
1588            in the menu.
1589         */
1590         sensitize_the_right_region_actions ();
1591         _last_region_menu_was_main = false;
1592
1593         menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1594         menu->popup (button, time);
1595 }
1596
1597 Menu*
1598 Editor::build_track_context_menu ()
1599 {
1600         using namespace Menu_Helpers;
1601
1602         MenuList& edit_items = track_context_menu.items();
1603         edit_items.clear();
1604
1605         add_dstream_context_items (edit_items);
1606         return &track_context_menu;
1607 }
1608
1609 Menu*
1610 Editor::build_track_bus_context_menu ()
1611 {
1612         using namespace Menu_Helpers;
1613
1614         MenuList& edit_items = track_context_menu.items();
1615         edit_items.clear();
1616
1617         add_bus_context_items (edit_items);
1618         return &track_context_menu;
1619 }
1620
1621 Menu*
1622 Editor::build_track_region_context_menu ()
1623 {
1624         using namespace Menu_Helpers;
1625         MenuList& edit_items  = track_region_context_menu.items();
1626         edit_items.clear();
1627
1628         /* we've just cleared the track region context menu, so the menu that these
1629            two items were on will have disappeared; stop them dangling.
1630         */
1631         region_edit_menu_split_item = 0;
1632         region_edit_menu_split_multichannel_item = 0;
1633
1634         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1635
1636         if (rtv) {
1637                 boost::shared_ptr<Track> tr;
1638                 boost::shared_ptr<Playlist> pl;
1639
1640                 if ((tr = rtv->track())) {
1641                         add_region_context_items (edit_items, tr);
1642                 }
1643         }
1644
1645         add_dstream_context_items (edit_items);
1646
1647         return &track_region_context_menu;
1648 }
1649
1650 void
1651 Editor::analyze_region_selection ()
1652 {
1653         if (analysis_window == 0) {
1654                 analysis_window = new AnalysisWindow();
1655
1656                 if (_session != 0)
1657                         analysis_window->set_session(_session);
1658
1659                 analysis_window->show_all();
1660         }
1661
1662         analysis_window->set_regionmode();
1663         analysis_window->analyze();
1664
1665         analysis_window->present();
1666 }
1667
1668 void
1669 Editor::analyze_range_selection()
1670 {
1671         if (analysis_window == 0) {
1672                 analysis_window = new AnalysisWindow();
1673
1674                 if (_session != 0)
1675                         analysis_window->set_session(_session);
1676
1677                 analysis_window->show_all();
1678         }
1679
1680         analysis_window->set_rangemode();
1681         analysis_window->analyze();
1682
1683         analysis_window->present();
1684 }
1685
1686 Menu*
1687 Editor::build_track_selection_context_menu ()
1688 {
1689         using namespace Menu_Helpers;
1690         MenuList& edit_items  = track_selection_context_menu.items();
1691         edit_items.clear ();
1692
1693         add_selection_context_items (edit_items);
1694         // edit_items.push_back (SeparatorElem());
1695         // add_dstream_context_items (edit_items);
1696
1697         return &track_selection_context_menu;
1698 }
1699
1700 void
1701 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1702 {
1703         using namespace Menu_Helpers;
1704
1705         /* OK, stick the region submenu at the top of the list, and then add
1706            the standard items.
1707         */
1708
1709         RegionSelection rs = get_regions_from_selection_and_entered ();
1710
1711         string::size_type pos = 0;
1712         string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1713
1714         /* we have to hack up the region name because "_" has a special
1715            meaning for menu titles.
1716         */
1717
1718         while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1719                 menu_item_name.replace (pos, 1, "__");
1720                 pos += 2;
1721         }
1722
1723         if (_popup_region_menu_item == 0) {
1724                 _popup_region_menu_item = new MenuItem (menu_item_name);
1725                 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1726                 _popup_region_menu_item->show ();
1727         } else {
1728                 _popup_region_menu_item->set_label (menu_item_name);
1729         }
1730
1731         const framepos_t position = get_preferred_edit_position (false, true);
1732
1733         edit_items.push_back (*_popup_region_menu_item);
1734         if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1735                 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1736         }
1737         edit_items.push_back (SeparatorElem());
1738 }
1739
1740 /** Add context menu items relevant to selection ranges.
1741  * @param edit_items List to add the items to.
1742  */
1743 void
1744 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1745 {
1746         using namespace Menu_Helpers;
1747
1748         edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1749         edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1750
1751         edit_items.push_back (SeparatorElem());
1752         edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1753
1754         edit_items.push_back (SeparatorElem());
1755
1756         edit_items.push_back (
1757                 MenuElem (
1758                         _("Move Range Start to Previous Region Boundary"),
1759                         sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1760                         )
1761                 );
1762
1763         edit_items.push_back (
1764                 MenuElem (
1765                         _("Move Range Start to Next Region Boundary"),
1766                         sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1767                         )
1768                 );
1769
1770         edit_items.push_back (
1771                 MenuElem (
1772                         _("Move Range End to Previous Region Boundary"),
1773                         sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1774                         )
1775                 );
1776
1777         edit_items.push_back (
1778                 MenuElem (
1779                         _("Move Range End to Next Region Boundary"),
1780                         sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1781                         )
1782                 );
1783
1784         edit_items.push_back (SeparatorElem());
1785         edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1786         edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1787
1788         edit_items.push_back (SeparatorElem());
1789         edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1790
1791         edit_items.push_back (SeparatorElem());
1792         edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1793         edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1794
1795         edit_items.push_back (SeparatorElem());
1796         edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1797
1798         edit_items.push_back (SeparatorElem());
1799         edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1800         edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1801         edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1802
1803         edit_items.push_back (SeparatorElem());
1804         edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1805         edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1806         edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1807         edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1808         edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1809         if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1810                 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1811         }
1812 }
1813
1814
1815 void
1816 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1817 {
1818         using namespace Menu_Helpers;
1819
1820         /* Playback */
1821
1822         Menu *play_menu = manage (new Menu);
1823         MenuList& play_items = play_menu->items();
1824         play_menu->set_name ("ArdourContextMenu");
1825
1826         play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1827         play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1828         play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1829         play_items.push_back (SeparatorElem());
1830         play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1831
1832         edit_items.push_back (MenuElem (_("Play"), *play_menu));
1833
1834         /* Selection */
1835
1836         Menu *select_menu = manage (new Menu);
1837         MenuList& select_items = select_menu->items();
1838         select_menu->set_name ("ArdourContextMenu");
1839
1840         select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1841         select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1842         select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1843         select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1844         select_items.push_back (SeparatorElem());
1845         select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1846         select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1847         select_items.push_back (SeparatorElem());
1848         select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1849         select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1850         select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1851         select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1852         select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1853         select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1854         select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1855
1856         edit_items.push_back (MenuElem (_("Select"), *select_menu));
1857
1858         /* Cut-n-Paste */
1859
1860         Menu *cutnpaste_menu = manage (new Menu);
1861         MenuList& cutnpaste_items = cutnpaste_menu->items();
1862         cutnpaste_menu->set_name ("ArdourContextMenu");
1863
1864         cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1865         cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1866         cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1867
1868         cutnpaste_items.push_back (SeparatorElem());
1869
1870         cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1871         cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1872
1873         edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1874
1875         /* Adding new material */
1876
1877         edit_items.push_back (SeparatorElem());
1878         edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1879         edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1880
1881         /* Nudge track */
1882
1883         Menu *nudge_menu = manage (new Menu());
1884         MenuList& nudge_items = nudge_menu->items();
1885         nudge_menu->set_name ("ArdourContextMenu");
1886
1887         edit_items.push_back (SeparatorElem());
1888         nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1889         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1890         nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1891         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1892
1893         edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1894 }
1895
1896 void
1897 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1898 {
1899         using namespace Menu_Helpers;
1900
1901         /* Playback */
1902
1903         Menu *play_menu = manage (new Menu);
1904         MenuList& play_items = play_menu->items();
1905         play_menu->set_name ("ArdourContextMenu");
1906
1907         play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1908         play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1909         edit_items.push_back (MenuElem (_("Play"), *play_menu));
1910
1911         /* Selection */
1912
1913         Menu *select_menu = manage (new Menu);
1914         MenuList& select_items = select_menu->items();
1915         select_menu->set_name ("ArdourContextMenu");
1916
1917         select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1918         select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1919         select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1920         select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1921         select_items.push_back (SeparatorElem());
1922         select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1923         select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1924         select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1925         select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1926
1927         edit_items.push_back (MenuElem (_("Select"), *select_menu));
1928
1929         /* Cut-n-Paste */
1930
1931         Menu *cutnpaste_menu = manage (new Menu);
1932         MenuList& cutnpaste_items = cutnpaste_menu->items();
1933         cutnpaste_menu->set_name ("ArdourContextMenu");
1934
1935         cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1936         cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1937         cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1938
1939         Menu *nudge_menu = manage (new Menu());
1940         MenuList& nudge_items = nudge_menu->items();
1941         nudge_menu->set_name ("ArdourContextMenu");
1942
1943         edit_items.push_back (SeparatorElem());
1944         nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1945         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1946         nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1947         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1948
1949         edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1950 }
1951
1952 SnapType
1953 Editor::snap_type() const
1954 {
1955         return _snap_type;
1956 }
1957
1958 SnapMode
1959 Editor::snap_mode() const
1960 {
1961         return _snap_mode;
1962 }
1963
1964 void
1965 Editor::set_snap_to (SnapType st)
1966 {
1967         unsigned int snap_ind = (unsigned int)st;
1968
1969         _snap_type = st;
1970
1971         if (snap_ind > snap_type_strings.size() - 1) {
1972                 snap_ind = 0;
1973                 _snap_type = (SnapType)snap_ind;
1974         }
1975
1976         string str = snap_type_strings[snap_ind];
1977
1978         if (str != snap_type_selector.get_text()) {
1979                 snap_type_selector.set_text (str);
1980         }
1981
1982         instant_save ();
1983
1984         switch (_snap_type) {
1985         case SnapToBeatDiv128:
1986         case SnapToBeatDiv64:
1987         case SnapToBeatDiv32:
1988         case SnapToBeatDiv28:
1989         case SnapToBeatDiv24:
1990         case SnapToBeatDiv20:
1991         case SnapToBeatDiv16:
1992         case SnapToBeatDiv14:
1993         case SnapToBeatDiv12:
1994         case SnapToBeatDiv10:
1995         case SnapToBeatDiv8:
1996         case SnapToBeatDiv7:
1997         case SnapToBeatDiv6:
1998         case SnapToBeatDiv5:
1999         case SnapToBeatDiv4:
2000         case SnapToBeatDiv3:
2001         case SnapToBeatDiv2: {
2002                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2003                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2004                 
2005                 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2006                                             current_bbt_points_begin, current_bbt_points_end);
2007                 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2008                                          current_bbt_points_begin, current_bbt_points_end);
2009                 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2010                 break;
2011         }
2012
2013         case SnapToRegionStart:
2014         case SnapToRegionEnd:
2015         case SnapToRegionSync:
2016         case SnapToRegionBoundary:
2017                 build_region_boundary_cache ();
2018                 break;
2019
2020         default:
2021                 /* relax */
2022                 break;
2023         }
2024
2025         SnapChanged (); /* EMIT SIGNAL */
2026 }
2027
2028 void
2029 Editor::set_snap_mode (SnapMode mode)
2030 {
2031         string str = snap_mode_strings[(int)mode];
2032
2033         if (_internal_editing) {
2034                 internal_snap_mode = mode;
2035         } else {
2036                 pre_internal_snap_mode = mode;
2037         }
2038
2039         _snap_mode = mode;
2040
2041         if (str != snap_mode_selector.get_text ()) {
2042                 snap_mode_selector.set_text (str);
2043         }
2044
2045         instant_save ();
2046 }
2047 void
2048 Editor::set_edit_point_preference (EditPoint ep, bool force)
2049 {
2050         bool changed = (_edit_point != ep);
2051
2052         _edit_point = ep;
2053         string str = edit_point_strings[(int)ep];
2054
2055         if (str != edit_point_selector.get_text ()) {
2056                 edit_point_selector.set_text (str);
2057         }
2058
2059         reset_canvas_cursor ();
2060
2061         if (!force && !changed) {
2062                 return;
2063         }
2064
2065         const char* action=NULL;
2066
2067         switch (_edit_point) {
2068         case EditAtPlayhead:
2069                 action = "edit-at-playhead";
2070                 break;
2071         case EditAtSelectedMarker:
2072                 action = "edit-at-marker";
2073                 break;
2074         case EditAtMouse:
2075                 action = "edit-at-mouse";
2076                 break;
2077         }
2078
2079         Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2080         if (act) {
2081                 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2082         }
2083
2084         framepos_t foo;
2085         bool in_track_canvas;
2086
2087         if (!mouse_frame (foo, in_track_canvas)) {
2088                 in_track_canvas = false;
2089         }
2090
2091         reset_canvas_action_sensitivity (in_track_canvas);
2092
2093         instant_save ();
2094 }
2095
2096 int
2097 Editor::set_state (const XMLNode& node, int /*version*/)
2098 {
2099         const XMLProperty* prop;
2100         XMLNode* geometry;
2101         int x, y;
2102         Gdk::Geometry g;
2103
2104         set_id (node);
2105
2106         g.base_width = default_width;
2107         g.base_height = default_height;
2108         x = 1;
2109         y = 1;
2110
2111         if ((geometry = find_named_node (node, "geometry")) != 0) {
2112
2113                 XMLProperty* prop;
2114
2115                 if ((prop = geometry->property("x_size")) == 0) {
2116                         prop = geometry->property ("x-size");
2117                 }
2118                 if (prop) {
2119                         g.base_width = atoi(prop->value());
2120                 }
2121                 if ((prop = geometry->property("y_size")) == 0) {
2122                         prop = geometry->property ("y-size");
2123                 }
2124                 if (prop) {
2125                         g.base_height = atoi(prop->value());
2126                 }
2127
2128                 if ((prop = geometry->property ("x_pos")) == 0) {
2129                         prop = geometry->property ("x-pos");
2130                 }
2131                 if (prop) {
2132                         x = atoi (prop->value());
2133
2134                 }
2135                 if ((prop = geometry->property ("y_pos")) == 0) {
2136                         prop = geometry->property ("y-pos");
2137                 }
2138                 if (prop) {
2139                         y = atoi (prop->value());
2140                 }
2141         }
2142
2143         set_default_size (g.base_width, g.base_height);
2144         move (x, y);
2145
2146         if (_session && (prop = node.property ("playhead"))) {
2147                 framepos_t pos;
2148                 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2149                 playhead_cursor->set_position (pos);
2150         } else {
2151                 playhead_cursor->set_position (0);
2152         }
2153
2154         if ((prop = node.property ("mixer-width"))) {
2155                 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2156         }
2157
2158         if ((prop = node.property ("zoom-focus"))) {
2159                 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2160         }
2161
2162         if ((prop = node.property ("zoom"))) {
2163                 /* older versions of ardour used floating point samples_per_pixel */
2164                 double f = PBD::atof (prop->value());
2165                 reset_zoom (llrintf (f));
2166         } else {
2167                 reset_zoom (samples_per_pixel);
2168         }
2169
2170         if ((prop = node.property ("visible-track-count"))) {
2171                 set_visible_track_count (PBD::atoi (prop->value()));
2172         }
2173
2174         if ((prop = node.property ("snap-to"))) {
2175                 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2176         }
2177
2178         if ((prop = node.property ("snap-mode"))) {
2179                 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2180         }
2181
2182         if ((prop = node.property ("internal-snap-to"))) {
2183                 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2184         }
2185
2186         if ((prop = node.property ("internal-snap-mode"))) {
2187                 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2188         }
2189
2190         if ((prop = node.property ("pre-internal-snap-to"))) {
2191                 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2192         }
2193
2194
2195         if ((prop = node.property ("pre-internal-snap-mode"))) {
2196                 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2197         }
2198
2199         if ((prop = node.property ("mouse-mode"))) {
2200                 MouseMode m = str2mousemode(prop->value());
2201                 set_mouse_mode (m, true);
2202         } else {
2203                 set_mouse_mode (MouseObject, true);
2204         }
2205
2206         if ((prop = node.property ("left-frame")) != 0) {
2207                 framepos_t pos;
2208                 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2209                         if (pos < 0) {
2210                                 pos = 0;
2211                         }
2212                         reset_x_origin (pos);
2213                 }
2214         }
2215
2216         if ((prop = node.property ("y-origin")) != 0) {
2217                 reset_y_origin (atof (prop->value ()));
2218         }
2219
2220         if ((prop = node.property ("internal-edit"))) {
2221                 bool yn = string_is_affirmative (prop->value());
2222                 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2223                 if (act) {
2224                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2225                         tact->set_active (!yn);
2226                         tact->set_active (yn);
2227                 }
2228         }
2229
2230         if ((prop = node.property ("join-object-range"))) {
2231                 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2232                 bool yn = string_is_affirmative (prop->value());
2233                 if (act) {
2234                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2235                         tact->set_active (!yn);
2236                         tact->set_active (yn);
2237                 }
2238                 set_mouse_mode(mouse_mode, true);
2239         }
2240
2241         if ((prop = node.property ("edit-point"))) {
2242                 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2243         }
2244
2245         if ((prop = node.property ("show-measures"))) {
2246                 bool yn = string_is_affirmative (prop->value());
2247                 _show_measures = yn;
2248                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2249                 if (act) {
2250                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2251                         /* do it twice to force the change */
2252                         tact->set_active (!yn);
2253                         tact->set_active (yn);
2254                 }
2255         }
2256
2257         if ((prop = node.property ("follow-playhead"))) {
2258                 bool yn = string_is_affirmative (prop->value());
2259                 set_follow_playhead (yn);
2260                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2261                 if (act) {
2262                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2263                         if (tact->get_active() != yn) {
2264                                 tact->set_active (yn);
2265                         }
2266                 }
2267         }
2268
2269         if ((prop = node.property ("stationary-playhead"))) {
2270                 bool yn = string_is_affirmative (prop->value());
2271                 set_stationary_playhead (yn);
2272                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2273                 if (act) {
2274                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2275                         if (tact->get_active() != yn) {
2276                                 tact->set_active (yn);
2277                         }
2278                 }
2279         }
2280
2281         if ((prop = node.property ("region-list-sort-type"))) {
2282                 RegionListSortType st;
2283                 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2284         }
2285
2286         if ((prop = node.property ("show-editor-mixer"))) {
2287
2288                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2289                 assert (act);
2290
2291                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2292                 bool yn = string_is_affirmative (prop->value());
2293
2294                 /* do it twice to force the change */
2295
2296                 tact->set_active (!yn);
2297                 tact->set_active (yn);
2298         }
2299
2300         if ((prop = node.property ("show-editor-list"))) {
2301
2302                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2303                 assert (act);
2304
2305                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2306                 bool yn = string_is_affirmative (prop->value());
2307
2308                 /* do it twice to force the change */
2309
2310                 tact->set_active (!yn);
2311                 tact->set_active (yn);
2312         }
2313
2314         if ((prop = node.property (X_("editor-list-page")))) {
2315                 _the_notebook.set_current_page (atoi (prop->value ()));
2316         }
2317
2318         if ((prop = node.property (X_("show-marker-lines")))) {
2319                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2320                 assert (act);
2321                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2322                 bool yn = string_is_affirmative (prop->value ());
2323
2324                 tact->set_active (!yn);
2325                 tact->set_active (yn);
2326         }
2327
2328         XMLNodeList children = node.children ();
2329         for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2330                 selection->set_state (**i, Stateful::current_state_version);
2331                 _regions->set_state (**i);
2332         }
2333
2334         if ((prop = node.property ("maximised"))) {
2335                 bool yn = string_is_affirmative (prop->value());
2336                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2337                 assert (act);
2338                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2339                 bool fs = tact && tact->get_active();
2340                 if (yn ^ fs) {
2341                         ActionManager::do_action ("Common", "ToggleMaximalEditor");
2342                 }
2343         }
2344
2345         if ((prop = node.property ("nudge-clock-value"))) {
2346                 framepos_t f;
2347                 sscanf (prop->value().c_str(), "%" PRId64, &f);
2348                 nudge_clock->set (f);
2349         } else {
2350                 nudge_clock->set_mode (AudioClock::Timecode);
2351                 nudge_clock->set (_session->frame_rate() * 5, true);
2352         }
2353
2354         return 0;
2355 }
2356
2357 XMLNode&
2358 Editor::get_state ()
2359 {
2360         XMLNode* node = new XMLNode ("Editor");
2361         char buf[32];
2362
2363         id().print (buf, sizeof (buf));
2364         node->add_property ("id", buf);
2365
2366         if (is_realized()) {
2367                 Glib::RefPtr<Gdk::Window> win = get_window();
2368
2369                 int x, y, width, height;
2370                 win->get_root_origin(x, y);
2371                 win->get_size(width, height);
2372
2373                 XMLNode* geometry = new XMLNode ("geometry");
2374
2375                 snprintf(buf, sizeof(buf), "%d", width);
2376                 geometry->add_property("x-size", string(buf));
2377                 snprintf(buf, sizeof(buf), "%d", height);
2378                 geometry->add_property("y-size", string(buf));
2379                 snprintf(buf, sizeof(buf), "%d", x);
2380                 geometry->add_property("x-pos", string(buf));
2381                 snprintf(buf, sizeof(buf), "%d", y);
2382                 geometry->add_property("y-pos", string(buf));
2383                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2384                 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2385                 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2386                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2387                 geometry->add_property("edit-vertical-pane-pos", string(buf));
2388
2389                 node->add_child_nocopy (*geometry);
2390         }
2391
2392         maybe_add_mixer_strip_width (*node);
2393
2394         node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2395
2396         snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2397         node->add_property ("zoom", buf);
2398         node->add_property ("snap-to", enum_2_string (_snap_type));
2399         node->add_property ("snap-mode", enum_2_string (_snap_mode));
2400         node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2401         node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2402         node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2403         node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2404         node->add_property ("edit-point", enum_2_string (_edit_point));
2405         snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2406         node->add_property ("visible-track-count", buf);
2407
2408         snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2409         node->add_property ("playhead", buf);
2410         snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2411         node->add_property ("left-frame", buf);
2412         snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2413         node->add_property ("y-origin", buf);
2414
2415         node->add_property ("show-measures", _show_measures ? "yes" : "no");
2416         node->add_property ("maximised", _maximised ? "yes" : "no");
2417         node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2418         node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2419         node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2420         node->add_property ("mouse-mode", enum2str(mouse_mode));
2421         node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2422         node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2423
2424         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2425         if (act) {
2426                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2427                 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2428         }
2429
2430         act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2431         if (act) {
2432                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2433                 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2434         }
2435
2436         snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2437         node->add_property (X_("editor-list-page"), buf);
2438
2439         if (button_bindings) {
2440                 XMLNode* bb = new XMLNode (X_("Buttons"));
2441                 button_bindings->save (*bb);
2442                 node->add_child_nocopy (*bb);
2443         }
2444
2445         node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2446
2447         node->add_child_nocopy (selection->get_state ());
2448         node->add_child_nocopy (_regions->get_state ());
2449
2450         snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2451         node->add_property ("nudge-clock-value", buf);
2452
2453         return *node;
2454 }
2455
2456 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2457  *  if @param trackview_relative_offset is false, @param y y is a global canvas *  coordinate, in pixel units
2458  *
2459  *  @return pair: TimeAxisView that y is over, layer index.
2460  *
2461  *  TimeAxisView may be 0.  Layer index is the layer number if the TimeAxisView is valid and is
2462  *  in stacked or expanded region display mode, otherwise 0.
2463  */
2464 std::pair<TimeAxisView *, double>
2465 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2466 {
2467         if (!trackview_relative_offset) {
2468                 y -= _trackview_group->canvas_origin().y;
2469         }
2470
2471         if (y < 0) {
2472                 return std::make_pair ( (TimeAxisView *) 0, 0);
2473         }
2474
2475         for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2476                         
2477                 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2478                         
2479                 if (r.first) {
2480                         return r;
2481                 }
2482         }
2483
2484         return std::make_pair ( (TimeAxisView *) 0, 0);
2485 }
2486
2487 /** Snap a position to the grid, if appropriate, taking into account current
2488  *  grid settings and also the state of any snap modifier keys that may be pressed.
2489  *  @param start Position to snap.
2490  *  @param event Event to get current key modifier information from, or 0.
2491  */
2492 void
2493 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2494 {
2495         if (!_session || !event) {
2496                 return;
2497         }
2498
2499         if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2500                 if (_snap_mode == SnapOff) {
2501                         snap_to_internal (start, direction, for_mark);
2502                 }
2503         } else {
2504                 if (_snap_mode != SnapOff) {
2505                         snap_to_internal (start, direction, for_mark);
2506                 }
2507         }
2508 }
2509
2510 void
2511 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2512 {
2513         if (!_session || _snap_mode == SnapOff) {
2514                 return;
2515         }
2516
2517         snap_to_internal (start, direction, for_mark);
2518 }
2519
2520 void
2521 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2522 {
2523         const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2524         framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2525
2526         switch (_snap_type) {
2527         case SnapToTimecodeFrame:
2528                 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2529                         start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2530                 } else {
2531                         start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) *  _session->frames_per_timecode_frame());
2532                 }
2533                 break;
2534
2535         case SnapToTimecodeSeconds:
2536                 if (_session->config.get_timecode_offset_negative()) {
2537                         start += _session->config.get_timecode_offset ();
2538                 } else {
2539                         start -= _session->config.get_timecode_offset ();
2540                 }
2541                 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2542                         start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2543                 } else {
2544                         start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2545                 }
2546
2547                 if (_session->config.get_timecode_offset_negative()) {
2548                         start -= _session->config.get_timecode_offset ();
2549                 } else {
2550                         start += _session->config.get_timecode_offset ();
2551                 }
2552                 break;
2553
2554         case SnapToTimecodeMinutes:
2555                 if (_session->config.get_timecode_offset_negative()) {
2556                         start += _session->config.get_timecode_offset ();
2557                 } else {
2558                         start -= _session->config.get_timecode_offset ();
2559                 }
2560                 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2561                         start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2562                 } else {
2563                         start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2564                 }
2565                 if (_session->config.get_timecode_offset_negative()) {
2566                         start -= _session->config.get_timecode_offset ();
2567                 } else {
2568                         start += _session->config.get_timecode_offset ();
2569                 }
2570                 break;
2571         default:
2572                 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2573                 /*NOTREACHED*/
2574         }
2575 }
2576
2577 void
2578 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2579 {
2580         const framepos_t one_second = _session->frame_rate();
2581         const framepos_t one_minute = _session->frame_rate() * 60;
2582         framepos_t presnap = start;
2583         framepos_t before;
2584         framepos_t after;
2585
2586         switch (_snap_type) {
2587         case SnapToTimecodeFrame:
2588         case SnapToTimecodeSeconds:
2589         case SnapToTimecodeMinutes:
2590                 return timecode_snap_to_internal (start, direction, for_mark);
2591
2592         case SnapToCDFrame:
2593                 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2594                         start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2595                 } else {
2596                         start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2597                 }
2598                 break;
2599
2600         case SnapToSeconds:
2601                 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2602                         start = (framepos_t) ceil ((double) start / one_second) * one_second;
2603                 } else {
2604                         start = (framepos_t) floor ((double) start / one_second) * one_second;
2605                 }
2606                 break;
2607
2608         case SnapToMinutes:
2609                 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2610                         start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2611                 } else {
2612                         start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2613                 }
2614                 break;
2615
2616         case SnapToBar:
2617                 start = _session->tempo_map().round_to_bar (start, direction);
2618                 break;
2619
2620         case SnapToBeat:
2621                 start = _session->tempo_map().round_to_beat (start, direction);
2622                 break;
2623
2624         case SnapToBeatDiv128:
2625                 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2626                 break;
2627         case SnapToBeatDiv64:
2628                 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2629                 break;
2630         case SnapToBeatDiv32:
2631                 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2632                 break;
2633         case SnapToBeatDiv28:
2634                 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2635                 break;
2636         case SnapToBeatDiv24:
2637                 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2638                 break;
2639         case SnapToBeatDiv20:
2640                 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2641                 break;
2642         case SnapToBeatDiv16:
2643                 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2644                 break;
2645         case SnapToBeatDiv14:
2646                 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2647                 break;
2648         case SnapToBeatDiv12:
2649                 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2650                 break;
2651         case SnapToBeatDiv10:
2652                 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2653                 break;
2654         case SnapToBeatDiv8:
2655                 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2656                 break;
2657         case SnapToBeatDiv7:
2658                 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2659                 break;
2660         case SnapToBeatDiv6:
2661                 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2662                 break;
2663         case SnapToBeatDiv5:
2664                 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2665                 break;
2666         case SnapToBeatDiv4:
2667                 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2668                 break;
2669         case SnapToBeatDiv3:
2670                 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2671                 break;
2672         case SnapToBeatDiv2:
2673                 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2674                 break;
2675
2676         case SnapToMark:
2677                 if (for_mark) {
2678                         return;
2679                 }
2680
2681                 _session->locations()->marks_either_side (start, before, after);
2682
2683                 if (before == max_framepos && after == max_framepos) {
2684                         /* No marks to snap to, so just don't snap */
2685                         return;
2686                 } else if (before == max_framepos) {
2687                         start = after;
2688                 } else if (after == max_framepos) {
2689                         start = before;
2690                 } else if (before != max_framepos && after != max_framepos) {
2691                         /* have before and after */
2692                         if ((start - before) < (after - start)) {
2693                                 start = before;
2694                         } else {
2695                                 start = after;
2696                         }
2697                 }
2698
2699                 break;
2700
2701         case SnapToRegionStart:
2702         case SnapToRegionEnd:
2703         case SnapToRegionSync:
2704         case SnapToRegionBoundary:
2705                 if (!region_boundary_cache.empty()) {
2706
2707                         vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2708                         vector<framepos_t>::iterator next = region_boundary_cache.end ();
2709
2710                         if (direction > 0) {
2711                                 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2712                         } else {
2713                                 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2714                         }
2715
2716                         if (next != region_boundary_cache.begin ()) {
2717                                 prev = next;
2718                                 prev--;
2719                         }
2720
2721                         framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2722                         framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2723
2724                         if (start > (p + n) / 2) {
2725                                 start = n;
2726                         } else {
2727                                 start = p;
2728                         }
2729                 }
2730                 break;
2731         }
2732
2733         switch (_snap_mode) {
2734         case SnapNormal:
2735                 return;
2736
2737         case SnapMagnetic:
2738
2739                 if (presnap > start) {
2740                         if (presnap > (start + pixel_to_sample(snap_threshold))) {
2741                                 start = presnap;
2742                         }
2743
2744                 } else if (presnap < start) {
2745                         if (presnap < (start - pixel_to_sample(snap_threshold))) {
2746                                 start = presnap;
2747                         }
2748                 }
2749
2750         default:
2751                 /* handled at entry */
2752                 return;
2753
2754         }
2755 }
2756
2757
2758 void
2759 Editor::setup_toolbar ()
2760 {
2761         HBox* mode_box = manage(new HBox);
2762         mode_box->set_border_width (2);
2763         mode_box->set_spacing(2);
2764
2765         HBox* mouse_mode_box = manage (new HBox);
2766         HBox* mouse_mode_hbox = manage (new HBox);
2767         VBox* mouse_mode_vbox = manage (new VBox);
2768         Alignment* mouse_mode_align = manage (new Alignment);
2769
2770         Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2771         //mouse_mode_size_group->add_widget (smart_mode_button);
2772         mouse_mode_size_group->add_widget (mouse_move_button);
2773         mouse_mode_size_group->add_widget (mouse_cut_button);
2774         mouse_mode_size_group->add_widget (mouse_select_button);
2775         mouse_mode_size_group->add_widget (mouse_zoom_button);
2776         mouse_mode_size_group->add_widget (mouse_gain_button);
2777         mouse_mode_size_group->add_widget (mouse_timefx_button);
2778         mouse_mode_size_group->add_widget (mouse_audition_button);
2779         mouse_mode_size_group->add_widget (mouse_draw_button);
2780         mouse_mode_size_group->add_widget (internal_edit_button);
2781
2782         if (!ARDOUR::Profile->get_small_screen()) {
2783                 /* make them just a bit bigger */
2784                 mouse_move_button.set_size_request (24, 30);
2785         } else {
2786                 /* make them just a bit taller */
2787                 mouse_move_button.set_size_request (-1, 30);
2788         }
2789         mouse_mode_hbox->set_spacing (2);
2790
2791         if (!ARDOUR::Profile->get_trx()) {
2792                 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2793         }
2794
2795         mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2796         mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2797         mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2798         mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2799
2800         if (!ARDOUR::Profile->get_trx()) {
2801                 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2802                 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2803                 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2804                 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2805                 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 4);
2806         }
2807
2808         mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2809
2810         mouse_mode_align->add (*mouse_mode_vbox);
2811         mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2812
2813         mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2814
2815         edit_mode_selector.set_name ("mouse mode button");
2816         set_size_request_to_display_given_text (edit_mode_selector, _("Ripple"), 30, 2);
2817         edit_mode_selector.add_elements (ArdourButton::Inset);
2818
2819         if (!ARDOUR::Profile->get_trx()) {
2820                 mode_box->pack_start (edit_mode_selector, false, false);
2821         }
2822         mode_box->pack_start (*mouse_mode_box, false, false);
2823
2824         _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2825         _mouse_mode_tearoff->set_name ("MouseModeBase");
2826         _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2827
2828         if (Profile->get_sae() || Profile->get_mixbus() ) {
2829                 _mouse_mode_tearoff->set_can_be_torn_off (false);
2830         }
2831
2832         _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2833                                                          &_mouse_mode_tearoff->tearoff_window()));
2834         _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2835                                                          &_mouse_mode_tearoff->tearoff_window(), 1));
2836         _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2837                                                          &_mouse_mode_tearoff->tearoff_window()));
2838         _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2839                                                           &_mouse_mode_tearoff->tearoff_window(), 1));
2840
2841         /* Zoom */
2842
2843         _zoom_box.set_spacing (2);
2844         _zoom_box.set_border_width (2);
2845
2846         RefPtr<Action> act;
2847
2848         zoom_in_button.set_name ("zoom button");
2849 //      zoom_in_button.add_elements ( ArdourButton::Inset );
2850         zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2851         zoom_in_button.set_image(::get_icon ("zoom_in"));
2852         act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2853         zoom_in_button.set_related_action (act);
2854
2855         zoom_out_button.set_name ("zoom button");
2856 //      zoom_out_button.add_elements ( ArdourButton::Inset );
2857         zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2858         zoom_out_button.set_image(::get_icon ("zoom_out"));
2859         act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2860         zoom_out_button.set_related_action (act);
2861
2862         zoom_out_full_button.set_name ("zoom button");
2863 //      zoom_out_full_button.add_elements ( ArdourButton::Inset );
2864         zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2865         zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2866         act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2867         zoom_out_full_button.set_related_action (act);
2868
2869         zoom_focus_selector.set_name ("zoom button");
2870         set_size_request_to_display_given_text (zoom_focus_selector, _("Edit Point"), 30, 2);
2871 //      zoom_focus_selector.add_elements (ArdourButton::Inset);
2872
2873         if (ARDOUR::Profile->get_mixbus()) {
2874                 _zoom_box.pack_start (zoom_out_button, false, false);
2875                 _zoom_box.pack_start (zoom_in_button, false, false);
2876                 _zoom_box.pack_start (zoom_out_full_button, false, false);
2877         } else if (ARDOUR::Profile->get_trx()) {
2878                 mode_box->pack_start (zoom_out_button, false, false);
2879                 mode_box->pack_start (zoom_in_button, false, false);
2880         } else {
2881                 _zoom_box.pack_start (zoom_out_button, false, false);
2882                 _zoom_box.pack_start (zoom_in_button, false, false);
2883                 _zoom_box.pack_start (zoom_out_full_button, false, false);
2884                 _zoom_box.pack_start (zoom_focus_selector, false, false);
2885         }
2886
2887         /* Track zoom buttons */
2888         visible_tracks_selector.set_name ("zoom button");
2889 //      visible_tracks_selector.add_elements ( ArdourButton::Inset );
2890         set_size_request_to_display_given_text (visible_tracks_selector, _("all"), 40, 2);
2891
2892         tav_expand_button.set_name ("zoom button");
2893 //      tav_expand_button.add_elements ( ArdourButton::FlatFace );
2894         tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2895         tav_expand_button.set_size_request (-1, 20);
2896         tav_expand_button.set_image(::get_icon ("tav_exp"));
2897         act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2898         tav_expand_button.set_related_action (act);
2899
2900         tav_shrink_button.set_name ("zoom button");
2901 //      tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2902         tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2903         tav_shrink_button.set_size_request (-1, 20);
2904         tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2905         act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2906         tav_shrink_button.set_related_action (act);
2907
2908         if (!ARDOUR::Profile->get_trx()) {
2909                 _zoom_box.pack_start (visible_tracks_selector);
2910         }
2911         _zoom_box.pack_start (tav_shrink_button);
2912         _zoom_box.pack_start (tav_expand_button);
2913
2914         if (!ARDOUR::Profile->get_trx()) {
2915                 _zoom_tearoff = manage (new TearOff (_zoom_box));
2916                 
2917                 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2918                                                            &_zoom_tearoff->tearoff_window()));
2919                 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2920                                                            &_zoom_tearoff->tearoff_window(), 0));
2921                 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2922                                                            &_zoom_tearoff->tearoff_window()));
2923                 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2924                                                             &_zoom_tearoff->tearoff_window(), 0));
2925         } 
2926
2927         if (Profile->get_sae() || Profile->get_mixbus() ) {
2928                 _zoom_tearoff->set_can_be_torn_off (false);
2929         }
2930
2931         snap_box.set_spacing (2);
2932         snap_box.set_border_width (2);
2933
2934         snap_type_selector.set_name ("mouse mode button");
2935         snap_type_selector.add_elements (ArdourButton::Inset);
2936         set_size_request_to_display_given_text (snap_type_selector, _("Region starts"), 34, 2);
2937
2938         snap_mode_selector.set_name ("mouse mode button");
2939         snap_mode_selector.add_elements (ArdourButton::Inset);
2940         set_size_request_to_display_given_text (snap_mode_selector, _("Magnetic"), 34, 2);
2941
2942         edit_point_selector.set_name ("mouse mode button");
2943         edit_point_selector.add_elements (ArdourButton::Inset);
2944         set_size_request_to_display_given_text (edit_point_selector, _("Playhead"), 34, 2);
2945
2946         snap_box.pack_start (snap_mode_selector, false, false);
2947         snap_box.pack_start (snap_type_selector, false, false);
2948         snap_box.pack_start (edit_point_selector, false, false);
2949
2950         /* Nudge */
2951
2952         HBox *nudge_box = manage (new HBox);
2953         nudge_box->set_spacing (2);
2954         nudge_box->set_border_width (2);
2955
2956         nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2957         nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2958
2959         nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2960         nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2961
2962         nudge_box->pack_start (nudge_backward_button, false, false);
2963         nudge_box->pack_start (nudge_forward_button, false, false);
2964         nudge_box->pack_start (*nudge_clock, false, false);
2965
2966
2967         /* Pack everything in... */
2968
2969         HBox* hbox = manage (new HBox);
2970         hbox->set_spacing(2);
2971
2972         _tools_tearoff = manage (new TearOff (*hbox));
2973         _tools_tearoff->set_name ("MouseModeBase");
2974         _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2975
2976         if (Profile->get_sae() || Profile->get_mixbus()) {
2977                 _tools_tearoff->set_can_be_torn_off (false);
2978         }
2979
2980         _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2981                                                     &_tools_tearoff->tearoff_window()));
2982         _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2983                                                     &_tools_tearoff->tearoff_window(), 0));
2984         _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2985                                                     &_tools_tearoff->tearoff_window()));
2986         _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2987                                                      &_tools_tearoff->tearoff_window(), 0));
2988
2989         toolbar_hbox.set_spacing (2);
2990         toolbar_hbox.set_border_width (1);
2991
2992         toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2993         if (!ARDOUR::Profile->get_trx()) {
2994                 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
2995                 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
2996         }
2997
2998         if (!ARDOUR::Profile->get_trx()) {
2999                 hbox->pack_start (snap_box, false, false);
3000                 if (!Profile->get_small_screen()) {
3001                         hbox->pack_start (*nudge_box, false, false);
3002                 } else {
3003                         ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3004                 }
3005         }
3006         hbox->pack_start (panic_box, false, false);
3007
3008         hbox->show_all ();
3009
3010         toolbar_base.set_name ("ToolBarBase");
3011         toolbar_base.add (toolbar_hbox);
3012
3013         _toolbar_viewport.add (toolbar_base);
3014         /* stick to the required height but allow width to vary if there's not enough room */
3015         _toolbar_viewport.set_size_request (1, -1);
3016
3017         toolbar_frame.set_shadow_type (SHADOW_OUT);
3018         toolbar_frame.set_name ("BaseFrame");
3019         toolbar_frame.add (_toolbar_viewport);
3020 }
3021
3022 void
3023 Editor::build_edit_point_menu ()
3024 {
3025         using namespace Menu_Helpers;
3026
3027         edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3028         edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3029         edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3030 }
3031
3032 void
3033 Editor::build_edit_mode_menu ()
3034 {
3035         using namespace Menu_Helpers;
3036
3037         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Slide), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3038 //      edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Splice), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3039         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Ripple), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3040         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Lock), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode)  Lock)));
3041 }
3042
3043 void
3044 Editor::build_snap_mode_menu ()
3045 {
3046         using namespace Menu_Helpers;
3047
3048         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3049         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3050         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3051 }
3052
3053 void
3054 Editor::build_snap_type_menu ()
3055 {
3056         using namespace Menu_Helpers;
3057
3058         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3059         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3060         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3061         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3062         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3063         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3064         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3065         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3066         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3067         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3068         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3069         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3070         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3071         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3072         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3073         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3074         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3075         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3076         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3077         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3078         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3079         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3080         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3081         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3082         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3083         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3084         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3085         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3086         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3087         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3088 }
3089
3090 void
3091 Editor::setup_tooltips ()
3092 {
3093         ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3094         ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3095         ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3096         ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3097         ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3098         ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3099         ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3100         ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3101         ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3102         ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3103         ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3104         ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3105         ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3106         ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3107         ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3108         ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3109         ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3110         ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3111         ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3112         ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3113         ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3114         ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3115         ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3116         ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3117         ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3118 }
3119
3120 int
3121 Editor::convert_drop_to_paths (
3122                 vector<string>&                paths,
3123                 const RefPtr<Gdk::DragContext>& /*context*/,
3124                 gint                            /*x*/,
3125                 gint                            /*y*/,
3126                 const SelectionData&            data,
3127                 guint                           /*info*/,
3128                 guint                           /*time*/)
3129 {
3130         if (_session == 0) {
3131                 return -1;
3132         }
3133
3134         vector<string> uris = data.get_uris();
3135
3136         if (uris.empty()) {
3137
3138                 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3139                    are actually URI lists. So do it by hand.
3140                 */
3141
3142                 if (data.get_target() != "text/plain") {
3143                         return -1;
3144                 }
3145
3146                 /* Parse the "uri-list" format that Nautilus provides,
3147                    where each pathname is delimited by \r\n.
3148
3149                    THERE MAY BE NO NULL TERMINATING CHAR!!!
3150                 */
3151
3152                 string txt = data.get_text();
3153                 char* p;
3154                 const char* q;
3155
3156                 p = (char *) malloc (txt.length() + 1);
3157                 txt.copy (p, txt.length(), 0);
3158                 p[txt.length()] = '\0';
3159
3160                 while (p)
3161                 {
3162                         if (*p != '#')
3163                         {
3164                                 while (g_ascii_isspace (*p))
3165                                         p++;
3166
3167                                 q = p;
3168                                 while (*q && (*q != '\n') && (*q != '\r')) {
3169                                         q++;
3170                                 }
3171
3172                                 if (q > p)
3173                                 {
3174                                         q--;
3175                                         while (q > p && g_ascii_isspace (*q))
3176                                                 q--;
3177
3178                                         if (q > p)
3179                                         {
3180                                                 uris.push_back (string (p, q - p + 1));
3181                                         }
3182                                 }
3183                         }
3184                         p = strchr (p, '\n');
3185                         if (p)
3186                                 p++;
3187                 }
3188
3189                 free ((void*)p);
3190
3191                 if (uris.empty()) {
3192                         return -1;
3193                 }
3194         }
3195
3196         for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3197                 if ((*i).substr (0,7) == "file://") {
3198                         paths.push_back (Glib::filename_from_uri (*i));
3199                 }
3200         }
3201
3202         return 0;
3203 }
3204
3205 void
3206 Editor::new_tempo_section ()
3207 {
3208 }
3209
3210 void
3211 Editor::map_transport_state ()
3212 {
3213         ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3214
3215         if (_session && _session->transport_stopped()) {
3216                 have_pending_keyboard_selection = false;
3217         }
3218
3219         update_loop_range_view ();
3220 }
3221
3222 /* UNDO/REDO */
3223
3224 void
3225 Editor::begin_reversible_command (string name)
3226 {
3227         if (_session) {
3228                 _session->begin_reversible_command (name);
3229         }
3230 }
3231
3232 void
3233 Editor::begin_reversible_command (GQuark q)
3234 {
3235         if (_session) {
3236                 _session->begin_reversible_command (q);
3237         }
3238 }
3239
3240 void
3241 Editor::commit_reversible_command ()
3242 {
3243         if (_session) {
3244                 _session->commit_reversible_command ();
3245         }
3246 }
3247
3248 void
3249 Editor::history_changed ()
3250 {
3251         string label;
3252
3253         if (undo_action && _session) {
3254                 if (_session->undo_depth() == 0) {
3255                         label = S_("Command|Undo");
3256                 } else {
3257                         label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3258                 }
3259                 undo_action->property_label() = label;
3260         }
3261
3262         if (redo_action && _session) {
3263                 if (_session->redo_depth() == 0) {
3264                         label = _("Redo");
3265                 } else {
3266                         label = string_compose(_("Redo (%1)"), _session->next_redo());
3267                 }
3268                 redo_action->property_label() = label;
3269         }
3270 }
3271
3272 void
3273 Editor::duplicate_range (bool with_dialog)
3274 {
3275         float times = 1.0f;
3276
3277         RegionSelection rs = get_regions_from_selection_and_entered ();
3278
3279         if ( selection->time.length() == 0 && rs.empty()) {
3280                 return;
3281         }
3282
3283         if (with_dialog) {
3284
3285                 ArdourDialog win (_("Duplicate"));
3286                 Label label (_("Number of duplications:"));
3287                 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3288                 SpinButton spinner (adjustment, 0.0, 1);
3289                 HBox hbox;
3290
3291                 win.get_vbox()->set_spacing (12);
3292                 win.get_vbox()->pack_start (hbox);
3293                 hbox.set_border_width (6);
3294                 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3295
3296                 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3297                    place, visually. so do this by hand.
3298                 */
3299
3300                 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3301                 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3302                 spinner.grab_focus();
3303
3304                 hbox.show ();
3305                 label.show ();
3306                 spinner.show ();
3307
3308                 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3309                 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3310                 win.set_default_response (RESPONSE_ACCEPT);
3311
3312                 spinner.grab_focus ();
3313
3314                 switch (win.run ()) {
3315                 case RESPONSE_ACCEPT:
3316                         break;
3317                 default:
3318                         return;
3319                 }
3320
3321                 times = adjustment.get_value();
3322         }
3323
3324         if ((current_mouse_mode() == Editing::MouseRange)) {
3325                 if (selection->time.length()) {
3326                         duplicate_selection (times);
3327                 }
3328         } else if (get_smart_mode()) {
3329                 if (selection->time.length()) {
3330                         duplicate_selection (times);
3331                 } else 
3332                         duplicate_some_regions (rs, times);
3333         } else {
3334                 duplicate_some_regions (rs, times);
3335         }
3336 }
3337
3338 void
3339 Editor::set_edit_mode (EditMode m)
3340 {
3341         Config->set_edit_mode (m);
3342 }
3343
3344 void
3345 Editor::cycle_edit_mode ()
3346 {
3347         switch (Config->get_edit_mode()) {
3348         case Slide:
3349                 if (Profile->get_sae()) {
3350                         Config->set_edit_mode (Lock);
3351                 } else {
3352                         Config->set_edit_mode (Ripple);
3353                 }
3354                 break;
3355         case Splice:
3356         case Ripple:
3357                 Config->set_edit_mode (Lock);
3358                 break;
3359         case Lock:
3360                 Config->set_edit_mode (Slide);
3361                 break;
3362         }
3363 }
3364
3365 void
3366 Editor::edit_mode_selection_done ( EditMode m )
3367 {
3368         Config->set_edit_mode ( m );
3369 }
3370
3371 void
3372 Editor::snap_type_selection_done (SnapType snaptype)
3373 {
3374         RefPtr<RadioAction> ract = snap_type_action (snaptype);
3375         if (ract) {
3376                 ract->set_active ();
3377         }
3378 }
3379
3380 void
3381 Editor::snap_mode_selection_done (SnapMode mode)
3382 {
3383         RefPtr<RadioAction> ract = snap_mode_action (mode);
3384
3385         if (ract) {
3386                 ract->set_active (true);
3387         }
3388 }
3389
3390 void
3391 Editor::cycle_edit_point (bool with_marker)
3392 {
3393         switch (_edit_point) {
3394         case EditAtMouse:
3395                 set_edit_point_preference (EditAtPlayhead);
3396                 break;
3397         case EditAtPlayhead:
3398                 if (with_marker) {
3399                         set_edit_point_preference (EditAtSelectedMarker);
3400                 } else {
3401                         set_edit_point_preference (EditAtMouse);
3402                 }
3403                 break;
3404         case EditAtSelectedMarker:
3405                 set_edit_point_preference (EditAtMouse);
3406                 break;
3407         }
3408 }
3409
3410 void
3411 Editor::edit_point_selection_done (EditPoint ep)
3412 {
3413         set_edit_point_preference ( ep );
3414 }
3415
3416 void
3417 Editor::build_zoom_focus_menu ()
3418 {
3419         using namespace Menu_Helpers;
3420
3421         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3422         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3423         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3424         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3425         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3426         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3427 }
3428
3429 void
3430 Editor::zoom_focus_selection_done ( ZoomFocus f )
3431 {
3432         RefPtr<RadioAction> ract = zoom_focus_action (f);
3433         if (ract) {
3434                 ract->set_active ();
3435         }
3436 }
3437
3438 void
3439 Editor::build_track_count_menu ()
3440 {
3441         using namespace Menu_Helpers;
3442
3443         visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3444         visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3445         visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3446         visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3447         visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3448         visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3449         visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3450         visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3451         visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3452         visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3453         visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3454         visible_tracks_selector.AddMenuElem (MenuElem (_("all"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3455 }
3456
3457 void
3458 Editor::set_visible_track_count (int32_t n)
3459 {
3460         _visible_track_count = n;
3461
3462         /* if the canvas hasn't really been allocated any size yet, just
3463            record the desired number of visible tracks and return. when canvas
3464            allocation happens, we will get called again and then we can do the
3465            real work.
3466         */
3467         
3468         if (_visible_canvas_height <= 1) {
3469                 return;
3470         }
3471
3472         int h;
3473         string str;
3474
3475         if (_visible_track_count > 0) {
3476                 h = _visible_canvas_height / _visible_track_count;
3477                 std::ostringstream s;
3478                 s << _visible_track_count;
3479                 str = s.str();
3480         } else if (_visible_track_count == 0) {
3481                 h = _visible_canvas_height / track_views.size();
3482                 str = _("all");
3483         } else {
3484                 /* negative value means that the visible track count has 
3485                    been overridden by explicit track height changes.
3486                 */
3487                 visible_tracks_selector.set_text (X_("*"));
3488                 return;
3489         }
3490
3491         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3492                 (*i)->set_height (h);
3493         }
3494         
3495         if (str != visible_tracks_selector.get_text()) {
3496                 visible_tracks_selector.set_text (str);
3497         }
3498 }
3499
3500 void
3501 Editor::override_visible_track_count ()
3502 {
3503         _visible_track_count = -_visible_track_count;
3504 }
3505
3506 bool
3507 Editor::edit_controls_button_release (GdkEventButton* ev)
3508 {
3509         if (Keyboard::is_context_menu_event (ev)) {
3510                 ARDOUR_UI::instance()->add_route (this);
3511         } else if (ev->button == 1) {
3512                 selection->clear_tracks ();
3513         }
3514
3515         return true;
3516 }
3517
3518 bool
3519 Editor::mouse_select_button_release (GdkEventButton* ev)
3520 {
3521         /* this handles just right-clicks */
3522
3523         if (ev->button != 3) {
3524                 return false;
3525         }
3526
3527         return true;
3528 }
3529
3530 void
3531 Editor::set_zoom_focus (ZoomFocus f)
3532 {
3533         string str = zoom_focus_strings[(int)f];
3534
3535         if (str != zoom_focus_selector.get_text()) {
3536                 zoom_focus_selector.set_text (str);
3537         }
3538
3539         if (zoom_focus != f) {
3540                 zoom_focus = f;
3541                 instant_save ();
3542         }
3543 }
3544
3545 void
3546 Editor::cycle_zoom_focus ()
3547 {
3548         switch (zoom_focus) {
3549         case ZoomFocusLeft:
3550                 set_zoom_focus (ZoomFocusRight);
3551                 break;
3552         case ZoomFocusRight:
3553                 set_zoom_focus (ZoomFocusCenter);
3554                 break;
3555         case ZoomFocusCenter:
3556                 set_zoom_focus (ZoomFocusPlayhead);
3557                 break;
3558         case ZoomFocusPlayhead:
3559                 set_zoom_focus (ZoomFocusMouse);
3560                 break;
3561         case ZoomFocusMouse:
3562                 set_zoom_focus (ZoomFocusEdit);
3563                 break;
3564         case ZoomFocusEdit:
3565                 set_zoom_focus (ZoomFocusLeft);
3566                 break;
3567         }
3568 }
3569
3570 void
3571 Editor::ensure_float (Window& win)
3572 {
3573         win.set_transient_for (*this);
3574 }
3575
3576 void
3577 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3578 {
3579         /* recover or initialize pane positions. do this here rather than earlier because
3580            we don't want the positions to change the child allocations, which they seem to do.
3581          */
3582
3583         int pos;
3584         XMLProperty* prop;
3585         char buf[32];
3586         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3587
3588         enum Pane {
3589                 Horizontal = 0x1,
3590                 Vertical = 0x2
3591         };
3592
3593         static Pane done;
3594
3595         XMLNode* geometry = find_named_node (*node, "geometry");
3596
3597         if (which == static_cast<Paned*> (&edit_pane)) {
3598
3599                 if (done & Horizontal) {
3600                         return;
3601                 }
3602
3603                 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3604                         _notebook_shrunk = string_is_affirmative (prop->value ());
3605                 }
3606
3607                 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3608                         /* initial allocation is 90% to canvas, 10% to notebook */
3609                         pos = (int) floor (alloc.get_width() * 0.90f);
3610                         snprintf (buf, sizeof(buf), "%d", pos);
3611                 } else {
3612                         pos = atoi (prop->value());
3613                 }
3614
3615                 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3616                         edit_pane.set_position (pos);
3617                 }
3618
3619                 done = (Pane) (done | Horizontal);
3620
3621         } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3622
3623                 if (done & Vertical) {
3624                         return;
3625                 }
3626
3627                 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3628                         /* initial allocation is 90% to canvas, 10% to summary */
3629                         pos = (int) floor (alloc.get_height() * 0.90f);
3630                         snprintf (buf, sizeof(buf), "%d", pos);
3631                 } else {
3632
3633                         pos = atoi (prop->value());
3634                 }
3635
3636                 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3637                         editor_summary_pane.set_position (pos);
3638                 }
3639
3640                 done = (Pane) (done | Vertical);
3641         }
3642 }
3643
3644 void
3645 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3646 {
3647         if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) && 
3648             (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) && 
3649             (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3650                 top_hbox.remove (toolbar_frame);
3651         }
3652 }
3653
3654 void
3655 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3656 {
3657         if (toolbar_frame.get_parent() == 0) {
3658                 top_hbox.pack_end (toolbar_frame);
3659         }
3660 }
3661
3662 void
3663 Editor::set_show_measures (bool yn)
3664 {
3665         if (_show_measures != yn) {
3666                 hide_measures ();
3667
3668                 if ((_show_measures = yn) == true) {
3669                         if (tempo_lines) {
3670                                 tempo_lines->show();
3671                         }
3672
3673                         ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3674                         ARDOUR::TempoMap::BBTPointList::const_iterator end;
3675                         
3676                         compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3677                         draw_measures (begin, end);
3678                 } 
3679
3680                 instant_save ();
3681         }
3682 }
3683
3684 void
3685 Editor::toggle_follow_playhead ()
3686 {
3687         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3688         if (act) {
3689                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3690                 set_follow_playhead (tact->get_active());
3691         }
3692 }
3693
3694 /** @param yn true to follow playhead, otherwise false.
3695  *  @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3696  */
3697 void
3698 Editor::set_follow_playhead (bool yn, bool catch_up)
3699 {
3700         if (_follow_playhead != yn) {
3701                 if ((_follow_playhead = yn) == true && catch_up) {
3702                         /* catch up */
3703                         reset_x_origin_to_follow_playhead ();
3704                 }
3705                 instant_save ();
3706         }
3707 }
3708
3709 void
3710 Editor::toggle_stationary_playhead ()
3711 {
3712         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3713         if (act) {
3714                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3715                 set_stationary_playhead (tact->get_active());
3716         }
3717 }
3718
3719 void
3720 Editor::set_stationary_playhead (bool yn)
3721 {
3722         if (_stationary_playhead != yn) {
3723                 if ((_stationary_playhead = yn) == true) {
3724                         /* catch up */
3725                         // FIXME need a 3.0 equivalent of this 2.X call
3726                         // update_current_screen ();
3727                 }
3728                 instant_save ();
3729         }
3730 }
3731
3732 PlaylistSelector&
3733 Editor::playlist_selector () const
3734 {
3735         return *_playlist_selector;
3736 }
3737
3738 Evoral::MusicalTime
3739 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3740 {
3741         success = true;
3742
3743         switch (_snap_type) {
3744         case SnapToBeat:
3745                 return 1.0;
3746                 break;
3747
3748         case SnapToBeatDiv128:
3749                 return 1.0/128.0;
3750                 break;
3751         case SnapToBeatDiv64:
3752                 return 1.0/64.0;
3753                 break;
3754         case SnapToBeatDiv32:
3755                 return 1.0/32.0;
3756                 break;
3757         case SnapToBeatDiv28:
3758                 return 1.0/28.0;
3759                 break;
3760         case SnapToBeatDiv24:
3761                 return 1.0/24.0;
3762                 break;
3763         case SnapToBeatDiv20:
3764                 return 1.0/20.0;
3765                 break;
3766         case SnapToBeatDiv16:
3767                 return 1.0/16.0;
3768                 break;
3769         case SnapToBeatDiv14:
3770                 return 1.0/14.0;
3771                 break;
3772         case SnapToBeatDiv12:
3773                 return 1.0/12.0;
3774                 break;
3775         case SnapToBeatDiv10:
3776                 return 1.0/10.0;
3777                 break;
3778         case SnapToBeatDiv8:
3779                 return 1.0/8.0;
3780                 break;
3781         case SnapToBeatDiv7:
3782                 return 1.0/7.0;
3783                 break;
3784         case SnapToBeatDiv6:
3785                 return 1.0/6.0;
3786                 break;
3787         case SnapToBeatDiv5:
3788                 return 1.0/5.0;
3789                 break;
3790         case SnapToBeatDiv4:
3791                 return 1.0/4.0;
3792                 break;
3793         case SnapToBeatDiv3:
3794                 return 1.0/3.0;
3795                 break;
3796         case SnapToBeatDiv2:
3797                 return 1.0/2.0;
3798                 break;
3799
3800         case SnapToBar:
3801                 if (_session) {
3802                         return _session->tempo_map().meter_at (position).divisions_per_bar();
3803                 }
3804                 break;
3805
3806         case SnapToCDFrame:
3807         case SnapToTimecodeFrame:
3808         case SnapToTimecodeSeconds:
3809         case SnapToTimecodeMinutes:
3810         case SnapToSeconds:
3811         case SnapToMinutes:
3812         case SnapToRegionStart:
3813         case SnapToRegionEnd:
3814         case SnapToRegionSync:
3815         case SnapToRegionBoundary:
3816         default:
3817                 success = false;
3818                 break;
3819         }
3820
3821         return 0.0;
3822 }
3823
3824 framecnt_t
3825 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3826 {
3827         framecnt_t ret;
3828
3829         ret = nudge_clock->current_duration (pos);
3830         next = ret + 1; /* XXXX fix me */
3831
3832         return ret;
3833 }
3834
3835 int
3836 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3837 {
3838         ArdourDialog dialog (_("Playlist Deletion"));
3839         Label  label (string_compose (_("Playlist %1 is currently unused.\n"
3840                                         "If it is kept, its audio files will not be cleaned.\n"
3841                                         "If it is deleted, audio files used by it alone will be cleaned."),
3842                                       pl->name()));
3843
3844         dialog.set_position (WIN_POS_CENTER);
3845         dialog.get_vbox()->pack_start (label);
3846
3847         label.show ();
3848
3849         dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3850         dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3851         dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3852
3853         switch (dialog.run ()) {
3854         case RESPONSE_ACCEPT:
3855                 /* delete the playlist */
3856                 return 0;
3857                 break;
3858
3859         case RESPONSE_REJECT:
3860                 /* keep the playlist */
3861                 return 1;
3862                 break;
3863
3864         default:
3865                 break;
3866         }
3867
3868         return -1;
3869 }
3870
3871 bool
3872 Editor::audio_region_selection_covers (framepos_t where)
3873 {
3874         for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3875                 if ((*a)->region()->covers (where)) {
3876                         return true;
3877                 }
3878         }
3879
3880         return false;
3881 }
3882
3883 void
3884 Editor::prepare_for_cleanup ()
3885 {
3886         cut_buffer->clear_regions ();
3887         cut_buffer->clear_playlists ();
3888
3889         selection->clear_regions ();
3890         selection->clear_playlists ();
3891
3892         _regions->suspend_redisplay ();
3893 }
3894
3895 void
3896 Editor::finish_cleanup ()
3897 {
3898         _regions->resume_redisplay ();
3899 }
3900
3901 Location*
3902 Editor::transport_loop_location()
3903 {
3904         if (_session) {
3905                 return _session->locations()->auto_loop_location();
3906         } else {
3907                 return 0;
3908         }
3909 }
3910
3911 Location*
3912 Editor::transport_punch_location()
3913 {
3914         if (_session) {
3915                 return _session->locations()->auto_punch_location();
3916         } else {
3917                 return 0;
3918         }
3919 }
3920
3921 bool
3922 Editor::control_layout_scroll (GdkEventScroll* ev)
3923 {
3924         /* Just forward to the normal canvas scroll method. The coordinate
3925            systems are different but since the canvas is always larger than the
3926            track headers, and aligned with the trackview area, this will work.
3927
3928            In the not too distant future this layout is going away anyway and
3929            headers will be on the canvas.
3930         */
3931         return canvas_scroll_event (ev, false);
3932 }
3933
3934 void
3935 Editor::session_state_saved (string)
3936 {
3937         update_title ();
3938         _snapshots->redisplay ();
3939 }
3940
3941 void
3942 Editor::update_tearoff_visibility()
3943 {
3944         bool visible = Config->get_keep_tearoffs();
3945         _mouse_mode_tearoff->set_visible (visible);
3946         _tools_tearoff->set_visible (visible);
3947         if (_zoom_tearoff) {
3948                 _zoom_tearoff->set_visible (visible);
3949         }
3950 }
3951
3952 void
3953 Editor::maximise_editing_space ()
3954 {
3955         if (_maximised) {
3956                 return;
3957         }
3958
3959         fullscreen ();
3960
3961         _maximised = true;
3962 }
3963
3964 void
3965 Editor::restore_editing_space ()
3966 {
3967         if (!_maximised) {
3968                 return;
3969         }
3970
3971         unfullscreen();
3972
3973         _maximised = false;
3974 }
3975
3976 /**
3977  *  Make new playlists for a given track and also any others that belong
3978  *  to the same active route group with the `select' property.
3979  *  @param v Track.
3980  */
3981
3982 void
3983 Editor::new_playlists (TimeAxisView* v)
3984 {
3985         begin_reversible_command (_("new playlists"));
3986         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3987         _session->playlists->get (playlists);
3988         mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
3989         commit_reversible_command ();
3990 }
3991
3992 /**
3993  *  Use a copy of the current playlist for a given track and also any others that belong
3994  *  to the same active route group with the `select' property.
3995  *  @param v Track.
3996  */
3997
3998 void
3999 Editor::copy_playlists (TimeAxisView* v)
4000 {
4001         begin_reversible_command (_("copy playlists"));
4002         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4003         _session->playlists->get (playlists);
4004         mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4005         commit_reversible_command ();
4006 }
4007
4008 /** Clear the current playlist for a given track and also any others that belong
4009  *  to the same active route group with the `select' property.
4010  *  @param v Track.
4011  */
4012
4013 void
4014 Editor::clear_playlists (TimeAxisView* v)
4015 {
4016         begin_reversible_command (_("clear playlists"));
4017         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4018         _session->playlists->get (playlists);
4019         mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4020         commit_reversible_command ();
4021 }
4022
4023 void
4024 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4025 {
4026         atv.use_new_playlist (sz > 1 ? false : true, playlists);
4027 }
4028
4029 void
4030 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4031 {
4032         atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4033 }
4034
4035 void
4036 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4037 {
4038         atv.clear_playlist ();
4039 }
4040
4041 bool
4042 Editor::on_key_press_event (GdkEventKey* ev)
4043 {
4044         return key_press_focus_accelerator_handler (*this, ev);
4045 }
4046
4047 bool
4048 Editor::on_key_release_event (GdkEventKey* ev)
4049 {
4050         return Gtk::Window::on_key_release_event (ev);
4051         // return key_press_focus_accelerator_handler (*this, ev);
4052 }
4053
4054 /** Queue up a change to the viewport x origin.
4055  *  @param frame New x origin.
4056  */
4057 void
4058 Editor::reset_x_origin (framepos_t frame)
4059 {
4060         pending_visual_change.add (VisualChange::TimeOrigin);
4061         pending_visual_change.time_origin = frame;
4062         ensure_visual_change_idle_handler ();
4063 }
4064
4065 void
4066 Editor::reset_y_origin (double y)
4067 {
4068         pending_visual_change.add (VisualChange::YOrigin);
4069         pending_visual_change.y_origin = y;
4070         ensure_visual_change_idle_handler ();
4071 }
4072
4073 void
4074 Editor::reset_zoom (framecnt_t spp)
4075 {
4076         if (spp == samples_per_pixel) {
4077                 return;
4078         }
4079
4080         pending_visual_change.add (VisualChange::ZoomLevel);
4081         pending_visual_change.samples_per_pixel = spp;
4082         ensure_visual_change_idle_handler ();
4083 }
4084
4085 void
4086 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4087 {
4088         reset_x_origin (frame);
4089         reset_zoom (fpu);
4090
4091         if (!no_save_visual) {
4092                 undo_visual_stack.push_back (current_visual_state(false));
4093         }
4094 }
4095
4096 Editor::VisualState::VisualState (bool with_tracks)
4097         : gui_state (with_tracks ? new GUIObjectState : 0)
4098 {
4099 }
4100
4101 Editor::VisualState::~VisualState ()
4102 {
4103         delete gui_state;
4104 }
4105
4106 Editor::VisualState*
4107 Editor::current_visual_state (bool with_tracks)
4108 {
4109         VisualState* vs = new VisualState (with_tracks);
4110         vs->y_position = vertical_adjustment.get_value();
4111         vs->samples_per_pixel = samples_per_pixel;
4112         vs->leftmost_frame = leftmost_frame;
4113         vs->zoom_focus = zoom_focus;
4114
4115         if (with_tracks) {      
4116                 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4117         }
4118
4119         return vs;
4120 }
4121
4122 void
4123 Editor::undo_visual_state ()
4124 {
4125         if (undo_visual_stack.empty()) {
4126                 return;
4127         }
4128
4129         VisualState* vs = undo_visual_stack.back();
4130         undo_visual_stack.pop_back();
4131
4132
4133         redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4134
4135         use_visual_state (*vs);
4136 }
4137
4138 void
4139 Editor::redo_visual_state ()
4140 {
4141         if (redo_visual_stack.empty()) {
4142                 return;
4143         }
4144
4145         VisualState* vs = redo_visual_stack.back();
4146         redo_visual_stack.pop_back();
4147
4148         undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4149
4150         use_visual_state (*vs);
4151 }
4152
4153 void
4154 Editor::swap_visual_state ()
4155 {
4156         if (undo_visual_stack.empty()) {
4157                 redo_visual_state ();
4158         } else {
4159                 undo_visual_state ();
4160         }
4161 }
4162
4163 void
4164 Editor::use_visual_state (VisualState& vs)
4165 {
4166         PBD::Unwinder<bool> nsv (no_save_visual, true);
4167         DisplaySuspender ds;
4168
4169         vertical_adjustment.set_value (vs.y_position);
4170
4171         set_zoom_focus (vs.zoom_focus);
4172         reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4173         
4174         if (vs.gui_state) {
4175                 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4176                 
4177                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {    
4178                         (*i)->reset_visual_state ();
4179                 }
4180         }
4181
4182         _routes->update_visibility ();
4183 }
4184
4185 /** This is the core function that controls the zoom level of the canvas. It is called
4186  *  whenever one or more calls are made to reset_zoom().  It executes in an idle handler.
4187  *  @param spp new number of samples per pixel
4188  */
4189 void
4190 Editor::set_samples_per_pixel (framecnt_t spp)
4191 {
4192         if (spp < 1) {
4193                 return;
4194         }
4195
4196         const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4197         const framecnt_t lots_of_pixels = 4000;
4198
4199         /* if the zoom level is greater than what you'd get trying to display 3
4200          * days of audio on a really big screen, then it's too big.
4201          */
4202
4203         if (spp * lots_of_pixels > three_days) {
4204                 return;
4205         }
4206
4207         samples_per_pixel = spp;
4208
4209         if (tempo_lines) {
4210                 tempo_lines->tempo_map_changed();
4211         }
4212
4213         bool const showing_time_selection = selection->time.length() > 0;
4214
4215         if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4216                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4217                         (*i)->reshow_selection (selection->time);
4218                 }
4219         }
4220
4221         ZoomChanged (); /* EMIT_SIGNAL */
4222
4223         ArdourCanvas::GtkCanvasViewport* c;
4224
4225         c = get_track_canvas();
4226         if (c) {
4227                 c->canvas()->zoomed ();
4228         }
4229
4230         if (playhead_cursor) {
4231                 playhead_cursor->set_position (playhead_cursor->current_frame ());
4232         }
4233
4234         refresh_location_display();
4235         _summary->set_overlays_dirty ();
4236
4237         update_marker_labels ();
4238
4239         instant_save ();
4240 }
4241
4242 void
4243 Editor::queue_visual_videotimeline_update ()
4244 {
4245         /* TODO:
4246          * pending_visual_change.add (VisualChange::VideoTimeline);
4247          * or maybe even more specific: which videotimeline-image
4248          * currently it calls update_video_timeline() to update
4249          * _all outdated_ images on the video-timeline.
4250          * see 'exposeimg()' in video_image_frame.cc
4251          */
4252         ensure_visual_change_idle_handler ();
4253 }
4254
4255 void
4256 Editor::ensure_visual_change_idle_handler ()
4257 {
4258         if (pending_visual_change.idle_handler_id < 0) {
4259                 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4260                 pending_visual_change.being_handled = false;
4261         }
4262 }
4263
4264 int
4265 Editor::_idle_visual_changer (void* arg)
4266 {
4267         return static_cast<Editor*>(arg)->idle_visual_changer ();
4268 }
4269
4270 int
4271 Editor::idle_visual_changer ()
4272 {
4273         /* set_horizontal_position() below (and maybe other calls) call
4274            gtk_main_iteration(), so it's possible that a signal will be handled
4275            half-way through this method.  If this signal wants an
4276            idle_visual_changer we must schedule another one after this one, so
4277            mark the idle_handler_id as -1 here to allow that.  Also make a note
4278            that we are doing the visual change, so that changes in response to
4279            super-rapid-screen-update can be dropped if we are still processing
4280            the last one.
4281         */
4282
4283         pending_visual_change.idle_handler_id = -1;
4284         pending_visual_change.being_handled = true;
4285         
4286         VisualChange vc = pending_visual_change;
4287
4288         pending_visual_change.pending = (VisualChange::Type) 0;
4289
4290         visual_changer (vc);
4291
4292         pending_visual_change.being_handled = false;
4293
4294         return 0; /* this is always a one-shot call */
4295 }
4296
4297 void
4298 Editor::visual_changer (const VisualChange& vc)
4299 {
4300         double const last_time_origin = horizontal_position ();
4301
4302         if (vc.pending & VisualChange::ZoomLevel) {
4303                 set_samples_per_pixel (vc.samples_per_pixel);
4304
4305                 compute_fixed_ruler_scale ();
4306
4307                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4308                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4309                 
4310                 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4311                                             current_bbt_points_begin, current_bbt_points_end);
4312                 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4313                                          current_bbt_points_begin, current_bbt_points_end);
4314                 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4315
4316                 update_video_timeline();
4317         }
4318
4319         if (vc.pending & VisualChange::TimeOrigin) {
4320                 set_horizontal_position (vc.time_origin / samples_per_pixel);
4321         }
4322
4323         if (vc.pending & VisualChange::YOrigin) {
4324                 vertical_adjustment.set_value (vc.y_origin);
4325         }
4326
4327         if (last_time_origin == horizontal_position ()) {
4328                 /* changed signal not emitted */
4329                 update_fixed_rulers ();
4330                 redisplay_tempo (true);
4331         }
4332
4333         if (!(vc.pending & VisualChange::ZoomLevel)) {
4334                 update_video_timeline();
4335         }
4336
4337         _summary->set_overlays_dirty ();
4338 }
4339
4340 struct EditorOrderTimeAxisSorter {
4341     bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4342             return a->order () < b->order ();
4343     }
4344 };
4345
4346 void
4347 Editor::sort_track_selection (TrackViewList& sel)
4348 {
4349         EditorOrderTimeAxisSorter cmp;
4350         sel.sort (cmp);
4351 }
4352
4353 framepos_t
4354 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4355 {
4356         bool ignored;
4357         framepos_t where = 0;
4358         EditPoint ep = _edit_point;
4359
4360         if (from_context_menu && (ep == EditAtMouse)) {
4361                 return  canvas_event_sample (&context_click_event, 0, 0);
4362         }
4363
4364         if (entered_marker) {
4365                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4366                 return entered_marker->position();
4367         }
4368
4369         if (ignore_playhead && ep == EditAtPlayhead) {
4370                 ep = EditAtSelectedMarker;
4371         }
4372
4373         switch (ep) {
4374         case EditAtPlayhead:
4375                 where = _session->audible_frame();
4376                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4377                 break;
4378
4379         case EditAtSelectedMarker:
4380                 if (!selection->markers.empty()) {
4381                         bool is_start;
4382                         Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4383                         if (loc) {
4384                                 if (is_start) {
4385                                         where =  loc->start();
4386                                 } else {
4387                                         where = loc->end();
4388                                 }
4389                                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4390                                 break;
4391                         }
4392                 }
4393                 /* fallthru */
4394
4395         default:
4396         case EditAtMouse:
4397                 if (!mouse_frame (where, ignored)) {
4398                         /* XXX not right but what can we do ? */
4399                         return 0;
4400                 }
4401                 snap_to (where);
4402                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4403                 break;
4404         }
4405
4406         return where;
4407 }
4408
4409 void
4410 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4411 {
4412         if (!_session) return;
4413
4414         begin_reversible_command (cmd);
4415
4416         Location* tll;
4417
4418         if ((tll = transport_loop_location()) == 0) {
4419                 Location* loc = new Location (*_session, start, end, _("Loop"),  Location::IsAutoLoop);
4420                 XMLNode &before = _session->locations()->get_state();
4421                 _session->locations()->add (loc, true);
4422                 _session->set_auto_loop_location (loc);
4423                 XMLNode &after = _session->locations()->get_state();
4424                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4425         } else {
4426                 XMLNode &before = tll->get_state();
4427                 tll->set_hidden (false, this);
4428                 tll->set (start, end);
4429                 XMLNode &after = tll->get_state();
4430                 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4431         }
4432
4433         commit_reversible_command ();
4434 }
4435
4436 void
4437 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4438 {
4439         if (!_session) return;
4440
4441         begin_reversible_command (cmd);
4442
4443         Location* tpl;
4444
4445         if ((tpl = transport_punch_location()) == 0) {
4446                 Location* loc = new Location (*_session, start, end, _("Punch"),  Location::IsAutoPunch);
4447                 XMLNode &before = _session->locations()->get_state();
4448                 _session->locations()->add (loc, true);
4449                 _session->set_auto_punch_location (loc);
4450                 XMLNode &after = _session->locations()->get_state();
4451                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4452         }
4453         else {
4454                 XMLNode &before = tpl->get_state();
4455                 tpl->set_hidden (false, this);
4456                 tpl->set (start, end);
4457                 XMLNode &after = tpl->get_state();
4458                 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4459         }
4460
4461         commit_reversible_command ();
4462 }
4463
4464 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4465  *  @param rs List to which found regions are added.
4466  *  @param where Time to look at.
4467  *  @param ts Tracks to look on; if this is empty, all tracks are examined.
4468  */
4469 void
4470 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4471 {
4472         const TrackViewList* tracks;
4473
4474         if (ts.empty()) {
4475                 tracks = &track_views;
4476         } else {
4477                 tracks = &ts;
4478         }
4479
4480         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4481
4482                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4483
4484                 if (rtv) {
4485                         boost::shared_ptr<Track> tr;
4486                         boost::shared_ptr<Playlist> pl;
4487
4488                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4489
4490                                 boost::shared_ptr<RegionList> regions = pl->regions_at (
4491                                                 (framepos_t) floor ( (double) where * tr->speed()));
4492
4493                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4494                                         RegionView* rv = rtv->view()->find_view (*i);
4495                                         if (rv) {
4496                                                 rs.add (rv);
4497                                         }
4498                                 }
4499                         }
4500                 }
4501         }
4502 }
4503
4504 void
4505 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4506 {
4507         const TrackViewList* tracks;
4508
4509         if (ts.empty()) {
4510                 tracks = &track_views;
4511         } else {
4512                 tracks = &ts;
4513         }
4514
4515         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4516                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4517                 if (rtv) {
4518                         boost::shared_ptr<Track> tr;
4519                         boost::shared_ptr<Playlist> pl;
4520
4521                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4522
4523                                 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4524                                         (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4525
4526                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4527
4528                                         RegionView* rv = rtv->view()->find_view (*i);
4529
4530                                         if (rv) {
4531                                                 rs.add (rv);
4532                                         }
4533                                 }
4534                         }
4535                 }
4536         }
4537 }
4538
4539 /** Get regions using the following method:
4540  *
4541  *  Make a region list using:
4542  *   (a) any selected regions
4543  *   (b) the intersection of any selected tracks and the edit point(*)
4544  *   (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4545  *
4546  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4547  *
4548  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4549  */
4550
4551 RegionSelection
4552 Editor::get_regions_from_selection_and_edit_point ()
4553 {
4554         RegionSelection regions;
4555
4556         if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4557                 regions.add (entered_regionview);
4558         } else {
4559                 regions = selection->regions;
4560         }
4561
4562         if ( regions.empty() ) {
4563                 TrackViewList tracks = selection->tracks;
4564
4565                 if (!tracks.empty()) {
4566                         /* no region selected or entered, but some selected tracks:
4567                          * act on all regions on the selected tracks at the edit point
4568                          */ 
4569                         framepos_t const where = get_preferred_edit_position ();
4570                         get_regions_at(regions, where, tracks);
4571                 }
4572         }
4573
4574         return regions;
4575 }
4576
4577 /** Get regions using the following method:
4578  *
4579  *  Make a region list using:
4580  *   (a) any selected regions
4581  *   (b) the intersection of any selected tracks and the edit point(*)
4582  *   (c) if neither exists, then whatever region is under the mouse
4583  *
4584  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4585  *
4586  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4587  */
4588 RegionSelection
4589 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4590 {
4591         RegionSelection regions;
4592
4593         if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4594                 regions.add (entered_regionview);
4595         } else {
4596                 regions = selection->regions;
4597         }
4598
4599         if ( regions.empty() ) {
4600                 TrackViewList tracks = selection->tracks;
4601
4602                 if (!tracks.empty()) {
4603                         /* no region selected or entered, but some selected tracks:
4604                          * act on all regions on the selected tracks at the edit point
4605                          */ 
4606                         get_regions_at(regions, pos, tracks);
4607                 }
4608         }
4609
4610         return regions;
4611 }
4612
4613 /** Start with regions that are selected, or the entered regionview if none are selected.
4614  *  Then add equivalent regions on tracks in the same active edit-enabled route group as any
4615  *  of the regions that we started with.
4616  */
4617
4618 RegionSelection
4619 Editor::get_regions_from_selection_and_entered ()
4620 {
4621         RegionSelection regions = selection->regions;
4622
4623         if (regions.empty() && entered_regionview) {
4624                 regions.add (entered_regionview);
4625         }
4626
4627         return regions;
4628 }
4629
4630 void
4631 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4632 {
4633         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4634
4635                 RouteTimeAxisView* tatv;
4636
4637                 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4638
4639                         boost::shared_ptr<Playlist> pl;
4640                         vector<boost::shared_ptr<Region> > results;
4641                         RegionView* marv;
4642                         boost::shared_ptr<Track> tr;
4643
4644                         if ((tr = tatv->track()) == 0) {
4645                                 /* bus */
4646                                 continue;
4647                         }
4648
4649                         if ((pl = (tr->playlist())) != 0) {
4650                                 if (src_comparison) {
4651                                         pl->get_source_equivalent_regions (region, results);
4652                                 } else {
4653                                         pl->get_region_list_equivalent_regions (region, results);
4654                                 }
4655                         }
4656
4657                         for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4658                                 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4659                                         regions.push_back (marv);
4660                                 }
4661                         }
4662
4663                 }
4664         }
4665 }
4666
4667 void
4668 Editor::show_rhythm_ferret ()
4669 {
4670         if (rhythm_ferret == 0) {
4671                 rhythm_ferret = new RhythmFerret(*this);
4672         }
4673
4674         rhythm_ferret->set_session (_session);
4675         rhythm_ferret->show ();
4676         rhythm_ferret->present ();
4677 }
4678
4679 void
4680 Editor::first_idle ()
4681 {
4682         MessageDialog* dialog = 0;
4683         
4684         if (track_views.size() > 1) {
4685                 dialog = new MessageDialog (
4686                         *this,
4687                         string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4688                         true
4689                         );
4690                 dialog->present ();
4691                 ARDOUR_UI::instance()->flush_pending ();
4692         }
4693
4694         for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4695                 (*t)->first_idle();
4696         }
4697
4698         // first idle adds route children (automation tracks), so we need to redisplay here
4699         _routes->redisplay ();
4700
4701         delete dialog;
4702         _have_idled = true;
4703 }
4704
4705 gboolean
4706 Editor::_idle_resize (gpointer arg)
4707 {
4708         return ((Editor*)arg)->idle_resize ();
4709 }
4710
4711 void
4712 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4713 {
4714         if (resize_idle_id < 0) {
4715                 resize_idle_id = g_idle_add (_idle_resize, this);
4716                 _pending_resize_amount = 0;
4717         }
4718
4719         /* make a note of the smallest resulting height, so that we can clamp the
4720            lower limit at TimeAxisView::hSmall */
4721
4722         int32_t min_resulting = INT32_MAX;
4723
4724         _pending_resize_amount += h;
4725         _pending_resize_view = view;
4726
4727         min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4728
4729         if (selection->tracks.contains (_pending_resize_view)) {
4730                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4731                         min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4732                 }
4733         }
4734
4735         if (min_resulting < 0) {
4736                 min_resulting = 0;
4737         }
4738
4739         /* clamp */
4740         if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4741                 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4742         }
4743 }
4744
4745 /** Handle pending resizing of tracks */
4746 bool
4747 Editor::idle_resize ()
4748 {
4749         _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4750
4751         if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4752             selection->tracks.contains (_pending_resize_view)) {
4753
4754                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4755                         if (*i != _pending_resize_view) {
4756                                 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4757                         }
4758                 }
4759         }
4760
4761         _pending_resize_amount = 0;
4762         _group_tabs->set_dirty ();
4763         resize_idle_id = -1;
4764
4765         return false;
4766 }
4767
4768 void
4769 Editor::located ()
4770 {
4771         ENSURE_GUI_THREAD (*this, &Editor::located);
4772
4773         if (_session) {
4774                 playhead_cursor->set_position (_session->audible_frame ());
4775                 if (_follow_playhead && !_pending_initial_locate) {
4776                         reset_x_origin_to_follow_playhead ();
4777                 }
4778         }
4779
4780         _pending_locate_request = false;
4781         _pending_initial_locate = false;
4782 }
4783
4784 void
4785 Editor::region_view_added (RegionView *)
4786 {
4787         _summary->set_background_dirty ();
4788 }
4789
4790 void
4791 Editor::region_view_removed ()
4792 {
4793         _summary->set_background_dirty ();
4794 }
4795
4796 RouteTimeAxisView*
4797 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4798 {
4799         TrackViewList::const_iterator j = track_views.begin ();
4800         while (j != track_views.end()) {
4801                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4802                 if (rtv && rtv->route() == r) {
4803                         return rtv;
4804                 }
4805                 ++j;
4806         }
4807
4808         return 0;
4809 }
4810
4811
4812 TrackViewList
4813 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4814 {
4815         TrackViewList t;
4816
4817         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4818                 TimeAxisView* tv = axis_view_from_route (*i);
4819                 if (tv) {
4820                         t.push_back (tv);
4821                 }
4822         }
4823
4824         return t;
4825 }
4826
4827 void
4828 Editor::suspend_route_redisplay ()
4829 {
4830         if (_routes) {
4831                 _routes->suspend_redisplay();
4832         }
4833 }
4834
4835 void
4836 Editor::resume_route_redisplay ()
4837 {
4838         if (_routes) {
4839                 _routes->resume_redisplay();
4840         }
4841 }
4842
4843 void
4844 Editor::add_routes (RouteList& routes)
4845 {
4846         ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4847
4848         RouteTimeAxisView *rtv;
4849         list<RouteTimeAxisView*> new_views;
4850
4851         for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4852                 boost::shared_ptr<Route> route = (*x);
4853
4854                 if (route->is_auditioner() || route->is_monitor()) {
4855                         continue;
4856                 }
4857
4858                 DataType dt = route->input()->default_type();
4859
4860                 if (dt == ARDOUR::DataType::AUDIO) {
4861                         rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4862                         rtv->set_route (route);
4863                 } else if (dt == ARDOUR::DataType::MIDI) {
4864                         rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4865                         rtv->set_route (route);
4866                 } else {
4867                         throw unknown_type();
4868                 }
4869
4870                 new_views.push_back (rtv);
4871                 track_views.push_back (rtv);
4872
4873                 rtv->effective_gain_display ();
4874
4875                 if (internal_editing()) {
4876                         rtv->enter_internal_edit_mode ();
4877                 } else {
4878                         rtv->leave_internal_edit_mode ();
4879                 }
4880
4881                 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4882                 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4883         }
4884
4885         if (new_views.size() > 0) {
4886                 _routes->routes_added (new_views);
4887                 _summary->routes_added (new_views);
4888         }
4889
4890         if (show_editor_mixer_when_tracks_arrive) {
4891                 show_editor_mixer (true);
4892         }
4893
4894         editor_list_button.set_sensitive (true);
4895 }
4896
4897 void
4898 Editor::timeaxisview_deleted (TimeAxisView *tv)
4899 {
4900         if (tv == entered_track) {
4901                 entered_track = 0;
4902         }
4903
4904         if (_session && _session->deletion_in_progress()) {
4905                 /* the situation is under control */
4906                 return;
4907         }
4908
4909         ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4910
4911         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4912
4913         _routes->route_removed (tv);
4914
4915         TimeAxisView::Children c = tv->get_child_list ();
4916         for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4917                 if (entered_track == i->get()) {
4918                         entered_track = 0;
4919                 }
4920         }
4921
4922         /* remove it from the list of track views */
4923
4924         TrackViewList::iterator i;
4925
4926         if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4927                 i = track_views.erase (i);
4928         }
4929
4930         /* update whatever the current mixer strip is displaying, if revelant */
4931
4932         boost::shared_ptr<Route> route;
4933
4934         if (rtav) {
4935                 route = rtav->route ();
4936         }
4937
4938         if (current_mixer_strip && current_mixer_strip->route() == route) {
4939
4940                 TimeAxisView* next_tv;
4941
4942                 if (track_views.empty()) {
4943                         next_tv = 0;
4944                 } else if (i == track_views.end()) {
4945                         next_tv = track_views.front();
4946                 } else {
4947                         next_tv = (*i);
4948                 }
4949
4950
4951                 if (next_tv) {
4952                         set_selected_mixer_strip (*next_tv);
4953                 } else {
4954                         /* make the editor mixer strip go away setting the
4955                          * button to inactive (which also unticks the menu option)
4956                          */
4957
4958                         ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4959                 }
4960         }
4961 }
4962
4963 void
4964 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4965 {
4966         if (apply_to_selection) {
4967                 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4968
4969                         TrackSelection::iterator j = i;
4970                         ++j;
4971
4972                         hide_track_in_display (*i, false);
4973
4974                         i = j;
4975                 }
4976         } else {
4977                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4978
4979                 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4980                         // this will hide the mixer strip
4981                         set_selected_mixer_strip (*tv);
4982                 }
4983
4984                 _routes->hide_track_in_display (*tv);
4985         }
4986 }
4987
4988 bool
4989 Editor::sync_track_view_list_and_routes ()
4990 {
4991         track_views = TrackViewList (_routes->views ());
4992
4993         _summary->set_dirty ();
4994         _group_tabs->set_dirty ();
4995
4996         return false; // do not call again (until needed)
4997 }
4998
4999 void
5000 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5001 {
5002         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5003                 theslot (**i);
5004         }
5005 }
5006
5007 /** Find a RouteTimeAxisView by the ID of its route */
5008 RouteTimeAxisView*
5009 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5010 {
5011         RouteTimeAxisView* v;
5012
5013         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5014                 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5015                         if(v->route()->id() == id) {
5016                                 return v;
5017                         }
5018                 }
5019         }
5020
5021         return 0;
5022 }
5023
5024 void
5025 Editor::fit_route_group (RouteGroup *g)
5026 {
5027         TrackViewList ts = axis_views_from_routes (g->route_list ());
5028         fit_tracks (ts);
5029 }
5030
5031 void
5032 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5033 {
5034         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5035
5036         if (r == 0) {
5037                 _session->cancel_audition ();
5038                 return;
5039         }
5040
5041         if (_session->is_auditioning()) {
5042                 _session->cancel_audition ();
5043                 if (r == last_audition_region) {
5044                         return;
5045                 }
5046         }
5047
5048         _session->audition_region (r);
5049         last_audition_region = r;
5050 }
5051
5052
5053 void
5054 Editor::hide_a_region (boost::shared_ptr<Region> r)
5055 {
5056         r->set_hidden (true);
5057 }
5058
5059 void
5060 Editor::show_a_region (boost::shared_ptr<Region> r)
5061 {
5062         r->set_hidden (false);
5063 }
5064
5065 void
5066 Editor::audition_region_from_region_list ()
5067 {
5068         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5069 }
5070
5071 void
5072 Editor::hide_region_from_region_list ()
5073 {
5074         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5075 }
5076
5077 void
5078 Editor::show_region_in_region_list ()
5079 {
5080         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5081 }
5082
5083 void
5084 Editor::step_edit_status_change (bool yn)
5085 {
5086         if (yn) {
5087                 start_step_editing ();
5088         } else {
5089                 stop_step_editing ();
5090         }
5091 }
5092
5093 void
5094 Editor::start_step_editing ()
5095 {
5096         step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5097 }
5098
5099 void
5100 Editor::stop_step_editing ()
5101 {
5102         step_edit_connection.disconnect ();
5103 }
5104
5105 bool
5106 Editor::check_step_edit ()
5107 {
5108         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5109                 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5110                 if (mtv) {
5111                         mtv->check_step_edit ();
5112                 }
5113         }
5114
5115         return true; // do it again, till we stop
5116 }
5117
5118 bool
5119 Editor::scroll_press (Direction dir)
5120 {
5121         ++_scroll_callbacks;
5122
5123         if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5124                 /* delay the first auto-repeat */
5125                 return true;
5126         }
5127
5128         switch (dir) {
5129         case LEFT:
5130                 scroll_backward (1);
5131                 break;
5132
5133         case RIGHT:
5134                 scroll_forward (1);
5135                 break;
5136
5137         case UP:
5138                 scroll_tracks_up_line ();
5139                 break;
5140
5141         case DOWN:
5142                 scroll_tracks_down_line ();
5143                 break;
5144         }
5145
5146         /* do hacky auto-repeat */
5147         if (!_scroll_connection.connected ()) {
5148
5149                 _scroll_connection = Glib::signal_timeout().connect (
5150                         sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5151                         );
5152
5153                 _scroll_callbacks = 0;
5154         }
5155
5156         return true;
5157 }
5158
5159 void
5160 Editor::scroll_release ()
5161 {
5162         _scroll_connection.disconnect ();
5163 }
5164
5165 /** Queue a change for the Editor viewport x origin to follow the playhead */
5166 void
5167 Editor::reset_x_origin_to_follow_playhead ()
5168 {
5169         framepos_t const frame = playhead_cursor->current_frame ();
5170
5171         if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5172
5173                 if (_session->transport_speed() < 0) {
5174
5175                         if (frame > (current_page_samples() / 2)) {
5176                                 center_screen (frame-(current_page_samples()/2));
5177                         } else {
5178                                 center_screen (current_page_samples()/2);
5179                         }
5180
5181                 } else {
5182
5183                         framepos_t l = 0;
5184                         
5185                         if (frame < leftmost_frame) {
5186                                 /* moving left */
5187                                 if (_session->transport_rolling()) {
5188                                         /* rolling; end up with the playhead at the right of the page */
5189                                         l = frame - current_page_samples ();
5190                                 } else {
5191                                         /* not rolling: end up with the playhead 1/4 of the way along the page */
5192                                         l = frame - current_page_samples() / 4;
5193                                 }
5194                         } else {
5195                                 /* moving right */
5196                                 if (_session->transport_rolling()) {
5197                                         /* rolling: end up with the playhead on the left of the page */
5198                                         l = frame;
5199                                 } else {
5200                                         /* not rolling: end up with the playhead 3/4 of the way along the page */
5201                                         l = frame - 3 * current_page_samples() / 4;
5202                                 }
5203                         }
5204
5205                         if (l < 0) {
5206                                 l = 0;
5207                         }
5208                         
5209                         center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5210                 }
5211         }
5212 }
5213
5214 void
5215 Editor::super_rapid_screen_update ()
5216 {
5217         if (!_session || !_session->engine().running()) {
5218                 return;
5219         }
5220
5221         /* METERING / MIXER STRIPS */
5222
5223         /* update track meters, if required */
5224         if (is_mapped() && meters_running) {
5225                 RouteTimeAxisView* rtv;
5226                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5227                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5228                                 rtv->fast_update ();
5229                         }
5230                 }
5231         }
5232
5233         /* and any current mixer strip */
5234         if (current_mixer_strip) {
5235                 current_mixer_strip->fast_update ();
5236         }
5237
5238         /* PLAYHEAD AND VIEWPORT */
5239
5240         framepos_t const frame = _session->audible_frame();
5241
5242         /* There are a few reasons why we might not update the playhead / viewport stuff:
5243          *
5244          * 1.  we don't update things when there's a pending locate request, otherwise
5245          *     when the editor requests a locate there is a chance that this method
5246          *     will move the playhead before the locate request is processed, causing
5247          *     a visual glitch.
5248          * 2.  if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5249          * 3.  if we're still at the same frame that we were last time, there's nothing to do.
5250          */
5251
5252         if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5253
5254                 last_update_frame = frame;
5255
5256                 if (!_dragging_playhead) {
5257                         playhead_cursor->set_position (frame);
5258                 }
5259
5260                 if (!_stationary_playhead) {
5261
5262                         if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5263                                 /* We only do this if we aren't already
5264                                    handling a visual change (ie if
5265                                    pending_visual_change.being_handled is
5266                                    false) so that these requests don't stack
5267                                    up there are too many of them to handle in
5268                                    time.
5269                                 */
5270                                 reset_x_origin_to_follow_playhead ();
5271                         }
5272
5273                 } else {
5274
5275                         /* don't do continuous scroll till the new position is in the rightmost quarter of the
5276                            editor canvas
5277                         */
5278 #if 0
5279                         // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5280                         double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5281                         if (target <= 0.0) {
5282                                 target = 0.0;
5283                         }
5284                         if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5285                                 target = (target * 0.15) + (current * 0.85);
5286                         } else {
5287                                 /* relax */
5288                         }
5289
5290                         current = target;
5291                         set_horizontal_position (current);
5292 #endif
5293                 }
5294
5295         }
5296 }
5297
5298
5299 void
5300 Editor::session_going_away ()
5301 {
5302         _have_idled = false;
5303
5304         _session_connections.drop_connections ();
5305
5306         super_rapid_screen_update_connection.disconnect ();
5307
5308         selection->clear ();
5309         cut_buffer->clear ();
5310
5311         clicked_regionview = 0;
5312         clicked_axisview = 0;
5313         clicked_routeview = 0;
5314         entered_regionview = 0;
5315         entered_track = 0;
5316         last_update_frame = 0;
5317         _drags->abort ();
5318
5319         playhead_cursor->hide ();
5320
5321         /* rip everything out of the list displays */
5322
5323         _regions->clear ();
5324         _routes->clear ();
5325         _route_groups->clear ();
5326
5327         /* do this first so that deleting a track doesn't reset cms to null
5328            and thus cause a leak.
5329         */
5330
5331         if (current_mixer_strip) {
5332                 if (current_mixer_strip->get_parent() != 0) {
5333                         global_hpacker.remove (*current_mixer_strip);
5334                 }
5335                 delete current_mixer_strip;
5336                 current_mixer_strip = 0;
5337         }
5338
5339         /* delete all trackviews */
5340
5341         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5342                 delete *i;
5343         }
5344         track_views.clear ();
5345
5346         nudge_clock->set_session (0);
5347
5348         editor_list_button.set_active(false);
5349         editor_list_button.set_sensitive(false);
5350
5351         /* clear tempo/meter rulers */
5352         remove_metric_marks ();
5353         hide_measures ();
5354         clear_marker_display ();
5355
5356         stop_step_editing ();
5357         
5358         /* get rid of any existing editor mixer strip */
5359
5360         WindowTitle title(Glib::get_application_name());
5361         title += _("Editor");
5362
5363         set_title (title.get_string());
5364
5365         SessionHandlePtr::session_going_away ();
5366 }
5367
5368
5369 void
5370 Editor::show_editor_list (bool yn)
5371 {
5372         if (yn) {
5373                 _the_notebook.show ();
5374         } else {
5375                 _the_notebook.hide ();
5376         }
5377 }
5378
5379 void
5380 Editor::change_region_layering_order (bool from_context_menu)
5381 {
5382         const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5383
5384         if (!clicked_routeview) {
5385                 if (layering_order_editor) {
5386                         layering_order_editor->hide ();
5387                 }
5388                 return;
5389         }
5390
5391         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5392
5393         if (!track) {
5394                 return;
5395         }
5396
5397         boost::shared_ptr<Playlist> pl = track->playlist();
5398
5399         if (!pl) {
5400                 return;
5401         }
5402
5403         if (layering_order_editor == 0) {
5404                 layering_order_editor = new RegionLayeringOrderEditor (*this);
5405         }
5406
5407         layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5408         layering_order_editor->maybe_present ();
5409 }
5410
5411 void
5412 Editor::update_region_layering_order_editor ()
5413 {
5414         if (layering_order_editor && layering_order_editor->is_visible ()) {
5415                 change_region_layering_order (true);
5416         }
5417 }
5418
5419 void
5420 Editor::setup_fade_images ()
5421 {
5422         _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5423         _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5424         _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5425         _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5426         _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5427
5428         _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5429         _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5430         _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5431         _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5432         _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5433         
5434         _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5435         _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5436         _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5437         _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5438         _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5439
5440         _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5441         _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5442         _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5443         _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5444         _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5445
5446 }
5447
5448 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5449 Gtk::MenuItem&
5450 Editor::action_menu_item (std::string const & name)
5451 {
5452         Glib::RefPtr<Action> a = editor_actions->get_action (name);
5453         assert (a);
5454
5455         return *manage (a->create_menu_item ());
5456 }
5457
5458 void
5459 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5460 {
5461         EventBox* b = manage (new EventBox);
5462         b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5463         Label* l = manage (new Label (name));
5464         l->set_angle (-90);
5465         b->add (*l);
5466         b->show_all ();
5467         _the_notebook.append_page (widget, *b);
5468 }
5469
5470 bool
5471 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5472 {
5473         if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5474                 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5475         }
5476
5477         if (ev->type == GDK_2BUTTON_PRESS) {
5478
5479                 /* double-click on a notebook tab shrinks or expands the notebook */
5480
5481                 if (_notebook_shrunk) {
5482                         if (pre_notebook_shrink_pane_width) {
5483                                 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5484                         }
5485                         _notebook_shrunk = false;
5486                 } else {
5487                         pre_notebook_shrink_pane_width = edit_pane.get_position();
5488
5489                         /* this expands the LHS of the edit pane to cover the notebook
5490                            PAGE but leaves the tabs visible.
5491                          */
5492                         edit_pane.set_position (edit_pane.get_position() + page->get_width());
5493                         _notebook_shrunk = true;
5494                 }
5495         }
5496
5497         return true;
5498 }
5499
5500 void
5501 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5502 {
5503         using namespace Menu_Helpers;
5504         
5505         MenuList& items = _control_point_context_menu.items ();
5506         items.clear ();
5507         
5508         items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5509         items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5510         if (!can_remove_control_point (item)) {
5511                 items.back().set_sensitive (false);
5512         }
5513
5514         _control_point_context_menu.popup (event->button.button, event->button.time);
5515 }
5516
5517 void
5518 Editor::zoom_vertical_modifier_released()
5519 {
5520         _stepping_axis_view = 0;
5521 }
5522
5523 void
5524 Editor::ui_parameter_changed (string parameter)
5525 {
5526         if (parameter == "icon-set") {
5527                 while (!_cursor_stack.empty()) {
5528                         _cursor_stack.pop();
5529                 }
5530                 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5531         } else if (parameter == "draggable-playhead") {
5532                 if (_verbose_cursor) {
5533                         playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());
5534                 }
5535         }
5536 }