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