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