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