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