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