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