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