Simplify spacer code
[ardour.git] / gtk2_ardour / editor.cc
1 /*
2     Copyright (C) 2000-2009 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 /* Note: public Editor methods are documented in public_editor.h */
21
22 #include <stdint.h>
23 #include <unistd.h>
24 #include <cstdlib>
25 #include <cmath>
26 #include <string>
27 #include <algorithm>
28 #include <map>
29
30 #include "ardour_ui.h"
31 /*
32  * ardour_ui.h include was moved to the top of the list
33  * due to a conflicting definition of 'Style' between
34  * Apple's MacTypes.h and BarController.
35  */
36
37 #include <boost/none.hpp>
38
39 #include <sigc++/bind.h>
40
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
49
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
55
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
58
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include <gtkmm2ext/keyboard.h>
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
67
68 #include "ardour/analysis_graph.h"
69 #include "ardour/audio_track.h"
70 #include "ardour/audioengine.h"
71 #include "ardour/audioregion.h"
72 #include "ardour/lmath.h"
73 #include "ardour/location.h"
74 #include "ardour/profile.h"
75 #include "ardour/route.h"
76 #include "ardour/route_group.h"
77 #include "ardour/session_playlists.h"
78 #include "ardour/tempo.h"
79 #include "ardour/utils.h"
80 #include "ardour/vca_manager.h"
81 #include "ardour/vca.h"
82
83 #include "canvas/debug.h"
84 #include "canvas/text.h"
85
86 #include "control_protocol/control_protocol.h"
87
88 #include "actions.h"
89 #include "analysis_window.h"
90 #include "ardour_spacer.h"
91 #include "audio_clock.h"
92 #include "audio_region_view.h"
93 #include "audio_streamview.h"
94 #include "audio_time_axis.h"
95 #include "automation_time_axis.h"
96 #include "bundle_manager.h"
97 #include "crossfade_edit.h"
98 #include "debug.h"
99 #include "editing.h"
100 #include "editor.h"
101 #include "editor_cursors.h"
102 #include "editor_drag.h"
103 #include "editor_group_tabs.h"
104 #include "editor_locations.h"
105 #include "editor_regions.h"
106 #include "editor_route_groups.h"
107 #include "editor_routes.h"
108 #include "editor_snapshots.h"
109 #include "editor_summary.h"
110 #include "export_report.h"
111 #include "global_port_matrix.h"
112 #include "gui_object.h"
113 #include "gui_thread.h"
114 #include "keyboard.h"
115 #include "keyeditor.h"
116 #include "luainstance.h"
117 #include "marker.h"
118 #include "midi_region_view.h"
119 #include "midi_time_axis.h"
120 #include "mixer_strip.h"
121 #include "mixer_ui.h"
122 #include "mouse_cursors.h"
123 #include "note_base.h"
124 #include "playlist_selector.h"
125 #include "public_editor.h"
126 #include "quantize_dialog.h"
127 #include "region_layering_order_editor.h"
128 #include "rgb_macros.h"
129 #include "rhythm_ferret.h"
130 #include "route_sorter.h"
131 #include "selection.h"
132 #include "simple_progress_dialog.h"
133 #include "sfdb_ui.h"
134 #include "tempo_lines.h"
135 #include "time_axis_view.h"
136 #include "time_info_box.h"
137 #include "timers.h"
138 #include "tooltips.h"
139 #include "ui_config.h"
140 #include "utils.h"
141 #include "vca_time_axis.h"
142 #include "verbose_cursor.h"
143
144 #include "pbd/i18n.h"
145
146 using namespace std;
147 using namespace ARDOUR;
148 using namespace ARDOUR_UI_UTILS;
149 using namespace PBD;
150 using namespace Gtk;
151 using namespace Glib;
152 using namespace Gtkmm2ext;
153 using namespace Editing;
154
155 using PBD::internationalize;
156 using PBD::atoi;
157 using Gtkmm2ext::Keyboard;
158
159 double Editor::timebar_height = 15.0;
160
161 static const gchar *_snap_type_strings[] = {
162         N_("CD Frames"),
163         N_("TC Frames"),
164         N_("TC Seconds"),
165         N_("TC Minutes"),
166         N_("Seconds"),
167         N_("Minutes"),
168         N_("Beats/128"),
169         N_("Beats/64"),
170         N_("Beats/32"),
171         N_("Beats/28"),
172         N_("Beats/24"),
173         N_("Beats/20"),
174         N_("Beats/16"),
175         N_("Beats/14"),
176         N_("Beats/12"),
177         N_("Beats/10"),
178         N_("Beats/8"),
179         N_("Beats/7"),
180         N_("Beats/6"),
181         N_("Beats/5"),
182         N_("Beats/4"),
183         N_("Beats/3"),
184         N_("Beats/2"),
185         N_("Beats"),
186         N_("Bars"),
187         N_("Marks"),
188         N_("Region starts"),
189         N_("Region ends"),
190         N_("Region syncs"),
191         N_("Region bounds"),
192         0
193 };
194
195 static const gchar *_snap_mode_strings[] = {
196         N_("No Grid"),
197         N_("Grid"),
198         N_("Magnetic"),
199         0
200 };
201
202 static const gchar *_edit_point_strings[] = {
203         N_("Playhead"),
204         N_("Marker"),
205         N_("Mouse"),
206         0
207 };
208
209 static const gchar *_edit_mode_strings[] = {
210         N_("Slide"),
211         N_("Splice"),
212         N_("Ripple"),
213         N_("Lock"),
214         0
215 };
216
217 static const gchar *_zoom_focus_strings[] = {
218         N_("Left"),
219         N_("Right"),
220         N_("Center"),
221         N_("Playhead"),
222         N_("Mouse"),
223         N_("Edit point"),
224         0
225 };
226
227 #ifdef USE_RUBBERBAND
228 static const gchar *_rb_opt_strings[] = {
229         N_("Mushy"),
230         N_("Smooth"),
231         N_("Balanced multitimbral mixture"),
232         N_("Unpitched percussion with stable notes"),
233         N_("Crisp monophonic instrumental"),
234         N_("Unpitched solo percussion"),
235         N_("Resample without preserving pitch"),
236         0
237 };
238 #endif
239
240 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
241
242 Editor::Editor ()
243         : PublicEditor (global_hpacker)
244         , editor_mixer_strip_width (Wide)
245         , constructed (false)
246         , _playlist_selector (0)
247         , _time_info_box (0)
248         , no_save_visual (false)
249         , leftmost_frame (0)
250         , samples_per_pixel (2048)
251         , zoom_focus (ZoomFocusPlayhead)
252         , mouse_mode (MouseObject)
253         , pre_internal_snap_type (SnapToBeat)
254         , pre_internal_snap_mode (SnapOff)
255         , internal_snap_type (SnapToBeat)
256         , internal_snap_mode (SnapOff)
257         , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
258         , _notebook_shrunk (false)
259         , location_marker_color (0)
260         , location_range_color (0)
261         , location_loop_color (0)
262         , location_punch_color (0)
263         , location_cd_marker_color (0)
264         , entered_marker (0)
265         , _show_marker_lines (false)
266         , clicked_axisview (0)
267         , clicked_routeview (0)
268         , clicked_regionview (0)
269         , clicked_selection (0)
270         , clicked_control_point (0)
271         , button_release_can_deselect (true)
272         , _mouse_changed_selection (false)
273         , region_edit_menu_split_item (0)
274         , region_edit_menu_split_multichannel_item (0)
275         , track_region_edit_playlist_menu (0)
276         , track_edit_playlist_submenu (0)
277         , track_selection_edit_playlist_submenu (0)
278         , _popup_region_menu_item (0)
279         , _track_canvas (0)
280         , _track_canvas_viewport (0)
281         , within_track_canvas (false)
282         , _verbose_cursor (0)
283         , tempo_group (0)
284         , meter_group (0)
285         , marker_group (0)
286         , range_marker_group (0)
287         , transport_marker_group (0)
288         , cd_marker_group (0)
289         , _time_markers_group (0)
290         , hv_scroll_group (0)
291         , h_scroll_group (0)
292         , cursor_scroll_group (0)
293         , no_scroll_group (0)
294         , _trackview_group (0)
295         , _drag_motion_group (0)
296         , _canvas_drop_zone (0)
297         , no_ruler_shown_update (false)
298         ,  ruler_grabbed_widget (0)
299         , ruler_dialog (0)
300         , minsec_mark_interval (0)
301         , minsec_mark_modulo (0)
302         , minsec_nmarks (0)
303         , timecode_mark_modulo (0)
304         , timecode_nmarks (0)
305         , _samples_ruler_interval (0)
306         , bbt_bars (0)
307         , bbt_nmarks (0)
308         , bbt_bar_helper_on (0)
309         , bbt_accent_modulo (0)
310         , timecode_ruler (0)
311         , bbt_ruler (0)
312         , samples_ruler (0)
313         , minsec_ruler (0)
314         , visible_timebars (0)
315         , editor_ruler_menu (0)
316         , tempo_bar (0)
317         , meter_bar (0)
318         , marker_bar (0)
319         , range_marker_bar (0)
320         , transport_marker_bar (0)
321         , cd_marker_bar (0)
322         , minsec_label (_("Mins:Secs"))
323         , bbt_label (_("Bars:Beats"))
324         , timecode_label (_("Timecode"))
325         , samples_label (_("Samples"))
326         , tempo_label (_("Tempo"))
327         , meter_label (_("Meter"))
328         , mark_label (_("Location Markers"))
329         , range_mark_label (_("Range Markers"))
330         , transport_mark_label (_("Loop/Punch Ranges"))
331         , cd_mark_label (_("CD Markers"))
332         , videotl_label (_("Video Timeline"))
333         , videotl_group (0)
334         , playhead_cursor (0)
335         , edit_packer (4, 4, true)
336         , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
337         , horizontal_adjustment (0.0, 0.0, 1e16)
338         , unused_adjustment (0.0, 0.0, 10.0, 400.0)
339         , controls_layout (unused_adjustment, vertical_adjustment)
340         , _scroll_callbacks (0)
341         , _visible_canvas_width (0)
342         , _visible_canvas_height (0)
343         , _full_canvas_height (0)
344         , edit_controls_left_menu (0)
345         , edit_controls_right_menu (0)
346         , last_update_frame (0)
347         , cut_buffer_start (0)
348         , cut_buffer_length (0)
349         , button_bindings (0)
350         , last_paste_pos (0)
351         , paste_count (0)
352         , sfbrowser (0)
353         , current_interthread_info (0)
354         , analysis_window (0)
355         , select_new_marker (false)
356         , last_scrub_x (0)
357         , scrubbing_direction (0)
358         , scrub_reversals (0)
359         , scrub_reverse_distance (0)
360         , have_pending_keyboard_selection (false)
361         , pending_keyboard_selection_start (0)
362         , _snap_type (SnapToBeat)
363         , _snap_mode (SnapOff)
364         , snap_threshold (5.0)
365         , ignore_gui_changes (false)
366         , _drags (new DragManager (this))
367         , lock_dialog (0)
368           /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
369         , _dragging_playhead (false)
370         , _dragging_edit_point (false)
371         , _show_measures (true)
372         , _follow_playhead (true)
373         , _stationary_playhead (false)
374         , _maximised (false)
375         , tempo_lines (0)
376         , global_rect_group (0)
377         , time_line_group (0)
378         , tempo_marker_menu (0)
379         , meter_marker_menu (0)
380         , marker_menu (0)
381         , range_marker_menu (0)
382         , transport_marker_menu (0)
383         , new_transport_marker_menu (0)
384         , cd_marker_menu (0)
385         , marker_menu_item (0)
386         , bbt_beat_subdivision (4)
387         , _visible_track_count (-1)
388         ,  toolbar_selection_clock_table (2,3)
389         ,  automation_mode_button (_("mode"))
390         , selection (new Selection (this))
391         , cut_buffer (new Selection (this))
392         , _selection_memento (new SelectionMemento())
393         , _all_region_actions_sensitized (false)
394         , _ignore_region_action (false)
395         , _last_region_menu_was_main (false)
396         , _ignore_follow_edits (false)
397         , cd_marker_bar_drag_rect (0)
398         , range_bar_drag_rect (0)
399         , transport_bar_drag_rect (0)
400         , transport_bar_range_rect (0)
401         , transport_bar_preroll_rect (0)
402         , transport_bar_postroll_rect (0)
403         , transport_loop_range_rect (0)
404         , transport_punch_range_rect (0)
405         , transport_punchin_line (0)
406         , transport_punchout_line (0)
407         , transport_preroll_rect (0)
408         , transport_postroll_rect (0)
409         , temp_location (0)
410         , rubberband_rect (0)
411         , _route_groups (0)
412         , _routes (0)
413         , _regions (0)
414         , _snapshots (0)
415         , _locations (0)
416         , autoscroll_horizontal_allowed (false)
417         , autoscroll_vertical_allowed (false)
418         , autoscroll_cnt (0)
419         , autoscroll_widget (0)
420         , show_gain_after_trim (false)
421         , selection_op_cmd_depth (0)
422         , selection_op_history_it (0)
423         , no_save_instant (false)
424         , current_timefx (0)
425         , current_mixer_strip (0)
426         , show_editor_mixer_when_tracks_arrive (false)
427         ,  nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
428         , current_stepping_trackview (0)
429         , last_track_height_step_timestamp (0)
430         , entered_track (0)
431         , entered_regionview (0)
432         , clear_entered_track (false)
433         , _edit_point (EditAtMouse)
434         , meters_running (false)
435         , rhythm_ferret (0)
436         , _have_idled (false)
437         , resize_idle_id (-1)
438         , _pending_resize_amount (0)
439         , _pending_resize_view (0)
440         , _pending_locate_request (false)
441         , _pending_initial_locate (false)
442         , _summary (0)
443         , _group_tabs (0)
444         , _last_motion_y (0)
445         , layering_order_editor (0)
446         , _last_cut_copy_source_track (0)
447         , _region_selection_change_updates_region_list (true)
448         , _cursors (0)
449         , _following_mixer_selection (false)
450         , _control_point_toggled_on_press (false)
451         , _stepping_axis_view (0)
452         , quantize_dialog (0)
453         , _main_menu_disabler (0)
454         , myactions (X_("editor"))
455 {
456         /* we are a singleton */
457
458         PublicEditor::_instance = this;
459
460         _have_idled = false;
461
462         last_event_time.tv_sec = 0;
463         last_event_time.tv_usec = 0;
464
465         selection_op_history.clear();
466         before.clear();
467
468         snap_type_strings =  I18N (_snap_type_strings);
469         snap_mode_strings =  I18N (_snap_mode_strings);
470         zoom_focus_strings = I18N (_zoom_focus_strings);
471         edit_mode_strings = I18N (_edit_mode_strings);
472         edit_point_strings = I18N (_edit_point_strings);
473 #ifdef USE_RUBBERBAND
474         rb_opt_strings = I18N (_rb_opt_strings);
475         rb_current_opt = 4;
476 #endif
477
478         build_edit_mode_menu();
479         build_zoom_focus_menu();
480         build_track_count_menu();
481         build_snap_mode_menu();
482         build_snap_type_menu();
483         build_edit_point_menu();
484
485         location_marker_color = UIConfiguration::instance().color ("location marker");
486         location_range_color = UIConfiguration::instance().color ("location range");
487         location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
488         location_loop_color = UIConfiguration::instance().color ("location loop");
489         location_punch_color = UIConfiguration::instance().color ("location punch");
490
491         timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
492
493         TimeAxisView::setup_sizes ();
494         ArdourMarker::setup_sizes (timebar_height);
495         TempoCurve::setup_sizes (timebar_height);
496
497         bbt_label.set_name ("EditorRulerLabel");
498         bbt_label.set_size_request (-1, (int)timebar_height);
499         bbt_label.set_alignment (1.0, 0.5);
500         bbt_label.set_padding (5,0);
501         bbt_label.hide ();
502         bbt_label.set_no_show_all();
503         minsec_label.set_name ("EditorRulerLabel");
504         minsec_label.set_size_request (-1, (int)timebar_height);
505         minsec_label.set_alignment (1.0, 0.5);
506         minsec_label.set_padding (5,0);
507         minsec_label.hide ();
508         minsec_label.set_no_show_all();
509         timecode_label.set_name ("EditorRulerLabel");
510         timecode_label.set_size_request (-1, (int)timebar_height);
511         timecode_label.set_alignment (1.0, 0.5);
512         timecode_label.set_padding (5,0);
513         timecode_label.hide ();
514         timecode_label.set_no_show_all();
515         samples_label.set_name ("EditorRulerLabel");
516         samples_label.set_size_request (-1, (int)timebar_height);
517         samples_label.set_alignment (1.0, 0.5);
518         samples_label.set_padding (5,0);
519         samples_label.hide ();
520         samples_label.set_no_show_all();
521
522         tempo_label.set_name ("EditorRulerLabel");
523         tempo_label.set_size_request (-1, (int)timebar_height);
524         tempo_label.set_alignment (1.0, 0.5);
525         tempo_label.set_padding (5,0);
526         tempo_label.hide();
527         tempo_label.set_no_show_all();
528
529         meter_label.set_name ("EditorRulerLabel");
530         meter_label.set_size_request (-1, (int)timebar_height);
531         meter_label.set_alignment (1.0, 0.5);
532         meter_label.set_padding (5,0);
533         meter_label.hide();
534         meter_label.set_no_show_all();
535
536         if (Profile->get_trx()) {
537                 mark_label.set_text (_("Markers"));
538         }
539         mark_label.set_name ("EditorRulerLabel");
540         mark_label.set_size_request (-1, (int)timebar_height);
541         mark_label.set_alignment (1.0, 0.5);
542         mark_label.set_padding (5,0);
543         mark_label.hide();
544         mark_label.set_no_show_all();
545
546         cd_mark_label.set_name ("EditorRulerLabel");
547         cd_mark_label.set_size_request (-1, (int)timebar_height);
548         cd_mark_label.set_alignment (1.0, 0.5);
549         cd_mark_label.set_padding (5,0);
550         cd_mark_label.hide();
551         cd_mark_label.set_no_show_all();
552
553         videotl_bar_height = 4;
554         videotl_label.set_name ("EditorRulerLabel");
555         videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
556         videotl_label.set_alignment (1.0, 0.5);
557         videotl_label.set_padding (5,0);
558         videotl_label.hide();
559         videotl_label.set_no_show_all();
560
561         range_mark_label.set_name ("EditorRulerLabel");
562         range_mark_label.set_size_request (-1, (int)timebar_height);
563         range_mark_label.set_alignment (1.0, 0.5);
564         range_mark_label.set_padding (5,0);
565         range_mark_label.hide();
566         range_mark_label.set_no_show_all();
567
568         transport_mark_label.set_name ("EditorRulerLabel");
569         transport_mark_label.set_size_request (-1, (int)timebar_height);
570         transport_mark_label.set_alignment (1.0, 0.5);
571         transport_mark_label.set_padding (5,0);
572         transport_mark_label.hide();
573         transport_mark_label.set_no_show_all();
574
575         initialize_canvas ();
576
577         CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
578
579         _summary = new EditorSummary (this);
580
581         selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
582         selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
583
584         editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
585
586         selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
587         selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
588
589         edit_controls_vbox.set_spacing (0);
590         vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
591         _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
592
593         HBox* h = manage (new HBox);
594         _group_tabs = new EditorGroupTabs (this);
595         if (!ARDOUR::Profile->get_trx()) {
596                 h->pack_start (*_group_tabs, PACK_SHRINK);
597         }
598         h->pack_start (edit_controls_vbox);
599         controls_layout.add (*h);
600
601         controls_layout.set_name ("EditControlsBase");
602         controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
603         controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
604         controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
605
606         _cursors = new MouseCursors;
607         _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
608         cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
609
610         /* Push default cursor to ever-present bottom of cursor stack. */
611         push_canvas_cursor(_cursors->grabber);
612
613         ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
614
615         ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
616         pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
617         pad_line_1->set_outline_color (0xFF0000FF);
618         pad_line_1->show();
619
620         // CAIROCANVAS
621         time_pad->show();
622
623         edit_packer.set_col_spacings (0);
624         edit_packer.set_row_spacings (0);
625         edit_packer.set_homogeneous (false);
626         edit_packer.set_border_width (0);
627         edit_packer.set_name ("EditorWindow");
628
629         time_bars_event_box.add (time_bars_vbox);
630         time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
631         time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
632
633         /* labels for the time bars */
634         edit_packer.attach (time_bars_event_box,     0, 1, 0, 1,    FILL,        SHRINK, 0, 0);
635         /* track controls */
636         edit_packer.attach (controls_layout,         0, 1, 1, 2,    FILL,        FILL|EXPAND, 0, 0);
637         /* canvas */
638         edit_packer.attach (*_track_canvas_viewport,  1, 2, 0, 2,    FILL|EXPAND, FILL|EXPAND, 0, 0);
639
640         bottom_hbox.set_border_width (2);
641         bottom_hbox.set_spacing (3);
642
643         _route_groups = new EditorRouteGroups (this);
644         _routes = new EditorRoutes (this);
645         _regions = new EditorRegions (this);
646         _snapshots = new EditorSnapshots (this);
647         _locations = new EditorLocations (this);
648         _time_info_box = new TimeInfoBox ();
649
650         /* these are static location signals */
651
652         Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
653         Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
654         Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
655
656         add_notebook_page (_("Regions"), _regions->widget ());
657         add_notebook_page (_("Tracks & Busses"), _routes->widget ());
658         add_notebook_page (_("Snapshots"), _snapshots->widget ());
659         add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
660         add_notebook_page (_("Ranges & Marks"), _locations->widget ());
661
662         _the_notebook.set_show_tabs (true);
663         _the_notebook.set_scrollable (true);
664         _the_notebook.popup_disable ();
665         _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
666         _the_notebook.show_all ();
667
668         _notebook_shrunk = false;
669
670
671         /* Pick up some settings we need to cache, early */
672
673         XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
674         XMLProperty* prop;
675
676         if (settings && (prop = settings->property ("notebook-shrunk"))) {
677                 _notebook_shrunk = string_is_affirmative (prop->value ());
678         }
679
680         editor_summary_pane.set_check_divider_position (true);
681         editor_summary_pane.add (edit_packer);
682
683         Button* summary_arrows_left_left = manage (new Button);
684         summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
685         summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
686         summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
687
688         Button* summary_arrows_left_right = manage (new Button);
689         summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
690         summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
691         summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
692
693         VBox* summary_arrows_left = manage (new VBox);
694         summary_arrows_left->pack_start (*summary_arrows_left_left);
695         summary_arrows_left->pack_start (*summary_arrows_left_right);
696
697         Button* summary_arrows_right_up = manage (new Button);
698         summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
699         summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
700         summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
701
702         Button* summary_arrows_right_down = manage (new Button);
703         summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
704         summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
705         summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
706
707         VBox* summary_arrows_right = manage (new VBox);
708         summary_arrows_right->pack_start (*summary_arrows_right_up);
709         summary_arrows_right->pack_start (*summary_arrows_right_down);
710
711         Frame* summary_frame = manage (new Frame);
712         summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
713
714         summary_frame->add (*_summary);
715         summary_frame->show ();
716
717         _summary_hbox.pack_start (*summary_arrows_left, false, false);
718         _summary_hbox.pack_start (*summary_frame, true, true);
719         _summary_hbox.pack_start (*summary_arrows_right, false, false);
720
721         if (!ARDOUR::Profile->get_trx()) {
722                 editor_summary_pane.add (_summary_hbox);
723         }
724
725         edit_pane.set_check_divider_position (true);
726         edit_pane.add (editor_summary_pane);
727         if (!ARDOUR::Profile->get_trx()) {
728                 VBox* editor_list_vbox = manage (new VBox);
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 || ((prop = settings->property ("edit-horizontal-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
744                         /* initial allocation is 90% to canvas, 10% to notebook */
745                         edit_pane.set_divider (0, 0.90);
746                 } else {
747                         edit_pane.set_divider (0, fract);
748                 }
749
750                 if (!settings || ((prop = settings->property ("edit-vertical-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
751                         /* initial allocation is 90% to canvas, 10% to summary */
752                         editor_summary_pane.set_divider (0, 0.90);
753                 } else {
754
755                         editor_summary_pane.set_divider (0, fract);
756                 }
757         }
758
759         global_vpacker.set_spacing (2);
760         global_vpacker.set_border_width (0);
761
762         global_vpacker.pack_start (toolbar_hbox, false, false);
763         global_vpacker.pack_start (edit_pane, true, true);
764         global_hpacker.pack_start (global_vpacker, true, true);
765
766         /* need to show the "contents" widget so that notebook will show if tab is switched to
767          */
768
769         global_hpacker.show ();
770
771         /* register actions now so that set_state() can find them and set toggles/checks etc */
772
773         register_actions ();
774         load_bindings ();
775
776         setup_toolbar ();
777
778         _playlist_selector = new PlaylistSelector();
779         _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
780
781         RegionView::RegionViewGoingAway.connect (*this, invalidator (*this),  boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
782
783         /* nudge stuff */
784
785         nudge_forward_button.set_name ("nudge button");
786         nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
787
788         nudge_backward_button.set_name ("nudge button");
789         nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
790
791         fade_context_menu.set_name ("ArdourContextMenu");
792
793         Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
794
795         /* allow external control surfaces/protocols to do various things */
796
797         ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
798         ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
799         ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
800         ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
801         ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
802         ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
803         ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
804         ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
805         ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
806         ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
807         ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
808         ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
809         ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
810         ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
811
812         ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
813         ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
814         ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
815         ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
816         ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
817
818         BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
819
820         /* handle escape */
821
822         ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
823
824         /* problematic: has to return a value and thus cannot be x-thread */
825
826         Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
827
828         Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
829         UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
830
831         TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
832
833         _ignore_region_action = false;
834         _last_region_menu_was_main = false;
835         _popup_region_menu_item = 0;
836
837         _ignore_follow_edits = false;
838
839         _show_marker_lines = false;
840
841         /* Button bindings */
842
843         button_bindings = new Bindings ("editor-mouse");
844
845         XMLNode* node = button_settings();
846         if (node) {
847                 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
848                         button_bindings->load_operation (**i);
849                 }
850         }
851
852         constructed = true;
853
854         /* grab current parameter state */
855         boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
856         UIConfiguration::instance().map_parameters (pc);
857
858         setup_fade_images ();
859
860         LuaInstance::instance(); // instantiate
861         LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name));
862
863         instant_save ();
864 }
865
866 Editor::~Editor()
867 {
868         delete button_bindings;
869         delete _routes;
870         delete _route_groups;
871         delete _track_canvas_viewport;
872         delete _drags;
873         delete nudge_clock;
874         delete _verbose_cursor;
875         delete quantize_dialog;
876         delete _summary;
877         delete _group_tabs;
878         delete _regions;
879         delete _snapshots;
880         delete _locations;
881         delete _playlist_selector;
882         delete _time_info_box;
883
884         for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
885                 delete *i;
886         }
887 }
888
889 XMLNode*
890 Editor::button_settings () const
891 {
892         XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
893         XMLNode* node = find_named_node (*settings, X_("Buttons"));
894
895         if (!node) {
896                 node = new XMLNode (X_("Buttons"));
897         }
898
899         return node;
900 }
901
902 bool
903 Editor::get_smart_mode () const
904 {
905         return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
906 }
907
908 void
909 Editor::catch_vanishing_regionview (RegionView *rv)
910 {
911         /* note: the selection will take care of the vanishing
912            audioregionview by itself.
913         */
914
915         if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
916                 _drags->abort ();
917         }
918
919         if (clicked_regionview == rv) {
920                 clicked_regionview = 0;
921         }
922
923         if (entered_regionview == rv) {
924                 set_entered_regionview (0);
925         }
926
927         if (!_all_region_actions_sensitized) {
928                 sensitize_all_region_actions (true);
929         }
930 }
931
932 void
933 Editor::set_entered_regionview (RegionView* rv)
934 {
935         if (rv == entered_regionview) {
936                 return;
937         }
938
939         if (entered_regionview) {
940                 entered_regionview->exited ();
941         }
942
943         entered_regionview = rv;
944
945         if (entered_regionview  != 0) {
946                 entered_regionview->entered ();
947         }
948
949         if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
950                 /* This RegionView entry might have changed what region actions
951                    are allowed, so sensitize them all in case a key is pressed.
952                 */
953                 sensitize_all_region_actions (true);
954         }
955 }
956
957 void
958 Editor::set_entered_track (TimeAxisView* tav)
959 {
960         if (entered_track) {
961                 entered_track->exited ();
962         }
963
964         entered_track = tav;
965
966         if (entered_track) {
967                 entered_track->entered ();
968         }
969 }
970
971 void
972 Editor::instant_save ()
973 {
974         if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
975                 return;
976         }
977
978         if (_session) {
979                 _session->add_instant_xml(get_state());
980         } else {
981                 Config->add_instant_xml(get_state());
982         }
983 }
984
985 void
986 Editor::control_vertical_zoom_in_all ()
987 {
988         tav_zoom_smooth (false, true);
989 }
990
991 void
992 Editor::control_vertical_zoom_out_all ()
993 {
994         tav_zoom_smooth (true, true);
995 }
996
997 void
998 Editor::control_vertical_zoom_in_selected ()
999 {
1000         tav_zoom_smooth (false, false);
1001 }
1002
1003 void
1004 Editor::control_vertical_zoom_out_selected ()
1005 {
1006         tav_zoom_smooth (true, false);
1007 }
1008
1009 void
1010 Editor::control_view (uint32_t view)
1011 {
1012         goto_visual_state (view);
1013 }
1014
1015 void
1016 Editor::control_unselect ()
1017 {
1018         selection->clear_tracks ();
1019 }
1020
1021 void
1022 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1023 {
1024         TimeAxisView* tav = axis_view_from_stripable (s);
1025
1026         if (tav) {
1027                 switch (op) {
1028                 case Selection::Add:
1029                         selection->add (tav);
1030                         break;
1031                 case Selection::Toggle:
1032                         selection->toggle (tav);
1033                         break;
1034                 case Selection::Extend:
1035                         break;
1036                 case Selection::Set:
1037                         selection->set (tav);
1038                         break;
1039                 }
1040         } else {
1041                 selection->clear_tracks ();
1042         }
1043 }
1044
1045 void
1046 Editor::control_step_tracks_up ()
1047 {
1048         scroll_tracks_up_line ();
1049 }
1050
1051 void
1052 Editor::control_step_tracks_down ()
1053 {
1054         scroll_tracks_down_line ();
1055 }
1056
1057 void
1058 Editor::control_scroll (float fraction)
1059 {
1060         ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1061
1062         if (!_session) {
1063                 return;
1064         }
1065
1066         double step = fraction * current_page_samples();
1067
1068         /*
1069                 _control_scroll_target is an optional<T>
1070
1071                 it acts like a pointer to an framepos_t, with
1072                 a operator conversion to boolean to check
1073                 that it has a value could possibly use
1074                 playhead_cursor->current_frame to store the
1075                 value and a boolean in the class to know
1076                 when it's out of date
1077         */
1078
1079         if (!_control_scroll_target) {
1080                 _control_scroll_target = _session->transport_frame();
1081                 _dragging_playhead = true;
1082         }
1083
1084         if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1085                 *_control_scroll_target = 0;
1086         } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1087                 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1088         } else {
1089                 *_control_scroll_target += (framepos_t) trunc (step);
1090         }
1091
1092         /* move visuals, we'll catch up with it later */
1093
1094         playhead_cursor->set_position (*_control_scroll_target);
1095         UpdateAllTransportClocks (*_control_scroll_target);
1096
1097         if (*_control_scroll_target > (current_page_samples() / 2)) {
1098                 /* try to center PH in window */
1099                 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1100         } else {
1101                 reset_x_origin (0);
1102         }
1103
1104         /*
1105                 Now we do a timeout to actually bring the session to the right place
1106                 according to the playhead. This is to avoid reading disk buffers on every
1107                 call to control_scroll, which is driven by ScrollTimeline and therefore
1108                 probably by a control surface wheel which can generate lots of events.
1109         */
1110         /* cancel the existing timeout */
1111
1112         control_scroll_connection.disconnect ();
1113
1114         /* add the next timeout */
1115
1116         control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1117 }
1118
1119 bool
1120 Editor::deferred_control_scroll (framepos_t /*target*/)
1121 {
1122         _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1123         // reset for next stream
1124         _control_scroll_target = boost::none;
1125         _dragging_playhead = false;
1126         return false;
1127 }
1128
1129 void
1130 Editor::access_action (std::string action_group, std::string action_item)
1131 {
1132         if (!_session) {
1133                 return;
1134         }
1135
1136         ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1137
1138         RefPtr<Action> act;
1139         act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1140
1141         if (act) {
1142                 act->activate();
1143         }
1144 }
1145
1146 void
1147 Editor::on_realize ()
1148 {
1149         Realized ();
1150
1151         if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1152                 start_lock_event_timing ();
1153         }
1154 }
1155
1156 void
1157 Editor::start_lock_event_timing ()
1158 {
1159         /* check if we should lock the GUI every 30 seconds */
1160
1161         Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1162 }
1163
1164 bool
1165 Editor::generic_event_handler (GdkEvent* ev)
1166 {
1167         switch (ev->type) {
1168         case GDK_BUTTON_PRESS:
1169         case GDK_BUTTON_RELEASE:
1170         case GDK_MOTION_NOTIFY:
1171         case GDK_KEY_PRESS:
1172         case GDK_KEY_RELEASE:
1173                 if (contents().is_mapped()) {
1174                         gettimeofday (&last_event_time, 0);
1175                 }
1176                 break;
1177
1178         case GDK_LEAVE_NOTIFY:
1179                 switch (ev->crossing.detail) {
1180                 case GDK_NOTIFY_UNKNOWN:
1181                 case GDK_NOTIFY_INFERIOR:
1182                 case GDK_NOTIFY_ANCESTOR:
1183                         break;
1184                 case GDK_NOTIFY_VIRTUAL:
1185                 case GDK_NOTIFY_NONLINEAR:
1186                 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1187                         /* leaving window, so reset focus, thus ending any and
1188                            all text entry operations.
1189                         */
1190                         ARDOUR_UI::instance()->reset_focus (&contents());
1191                         break;
1192                 }
1193                 break;
1194
1195         default:
1196                 break;
1197         }
1198
1199         return false;
1200 }
1201
1202 bool
1203 Editor::lock_timeout_callback ()
1204 {
1205         struct timeval now, delta;
1206
1207         gettimeofday (&now, 0);
1208
1209         timersub (&now, &last_event_time, &delta);
1210
1211         if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1212                 lock ();
1213                 /* don't call again. Returning false will effectively
1214                    disconnect us from the timer callback.
1215
1216                    unlock() will call start_lock_event_timing() to get things
1217                    started again.
1218                 */
1219                 return false;
1220         }
1221
1222         return true;
1223 }
1224
1225 void
1226 Editor::map_position_change (framepos_t frame)
1227 {
1228         ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1229
1230         if (_session == 0) {
1231                 return;
1232         }
1233
1234         if (_follow_playhead) {
1235                 center_screen (frame);
1236         }
1237
1238         playhead_cursor->set_position (frame);
1239 }
1240
1241 void
1242 Editor::center_screen (framepos_t frame)
1243 {
1244         framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1245
1246         /* if we're off the page, then scroll.
1247          */
1248
1249         if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1250                 center_screen_internal (frame, page);
1251         }
1252 }
1253
1254 void
1255 Editor::center_screen_internal (framepos_t frame, float page)
1256 {
1257         page /= 2;
1258
1259         if (frame > page) {
1260                 frame -= (framepos_t) page;
1261         } else {
1262                 frame = 0;
1263         }
1264
1265         reset_x_origin (frame);
1266 }
1267
1268
1269 void
1270 Editor::update_title ()
1271 {
1272         ENSURE_GUI_THREAD (*this, &Editor::update_title);
1273
1274         if (!own_window()) {
1275                 return;
1276         }
1277
1278         if (_session) {
1279                 bool dirty = _session->dirty();
1280
1281                 string session_name;
1282
1283                 if (_session->snap_name() != _session->name()) {
1284                         session_name = _session->snap_name();
1285                 } else {
1286                         session_name = _session->name();
1287                 }
1288
1289                 if (dirty) {
1290                         session_name = "*" + session_name;
1291                 }
1292
1293                 WindowTitle title(session_name);
1294                 title += S_("Window|Editor");
1295                 title += Glib::get_application_name();
1296                 own_window()->set_title (title.get_string());
1297         } else {
1298                 /* ::session_going_away() will have taken care of it */
1299         }
1300 }
1301
1302 void
1303 Editor::set_session (Session *t)
1304 {
1305         SessionHandlePtr::set_session (t);
1306
1307         if (!_session) {
1308                 return;
1309         }
1310
1311         _playlist_selector->set_session (_session);
1312         nudge_clock->set_session (_session);
1313         _summary->set_session (_session);
1314         _group_tabs->set_session (_session);
1315         _route_groups->set_session (_session);
1316         _regions->set_session (_session);
1317         _snapshots->set_session (_session);
1318         _routes->set_session (_session);
1319         _locations->set_session (_session);
1320         _time_info_box->set_session (_session);
1321
1322         if (rhythm_ferret) {
1323                 rhythm_ferret->set_session (_session);
1324         }
1325
1326         if (analysis_window) {
1327                 analysis_window->set_session (_session);
1328         }
1329
1330         if (sfbrowser) {
1331                 sfbrowser->set_session (_session);
1332         }
1333
1334         compute_fixed_ruler_scale ();
1335
1336         /* Make sure we have auto loop and auto punch ranges */
1337
1338         Location* loc = _session->locations()->auto_loop_location();
1339         if (loc != 0) {
1340                 loc->set_name (_("Loop"));
1341         }
1342
1343         loc = _session->locations()->auto_punch_location();
1344         if (loc != 0) {
1345                 // force name
1346                 loc->set_name (_("Punch"));
1347         }
1348
1349         refresh_location_display ();
1350
1351         /* This must happen after refresh_location_display(), as (amongst other things) we restore
1352            the selected Marker; this needs the LocationMarker list to be available.
1353         */
1354         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1355         set_state (*node, Stateful::loading_state_version);
1356
1357         /* catch up with the playhead */
1358
1359         _session->request_locate (playhead_cursor->current_frame ());
1360         _pending_initial_locate = true;
1361
1362         update_title ();
1363
1364         /* These signals can all be emitted by a non-GUI thread. Therefore the
1365            handlers for them must not attempt to directly interact with the GUI,
1366            but use PBD::Signal<T>::connect() which accepts an event loop
1367            ("context") where the handler will be asked to run.
1368         */
1369
1370         _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1371         _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1372         _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1373         _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1374         _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1375         _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1376         _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1377         _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::marker_position_changed, this), gui_context());
1378         _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1379         _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1380         _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1381         _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1382         _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1383         _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1384         _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1385
1386         playhead_cursor->show ();
1387
1388         boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1389         Config->map_parameters (pc);
1390         _session->config.map_parameters (pc);
1391
1392         restore_ruler_visibility ();
1393         //tempo_map_changed (PropertyChange (0));
1394         _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1395
1396         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1397                 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1398         }
1399
1400         super_rapid_screen_update_connection = Timers::super_rapid_connect (
1401                 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1402                 );
1403
1404         switch (_snap_type) {
1405         case SnapToRegionStart:
1406         case SnapToRegionEnd:
1407         case SnapToRegionSync:
1408         case SnapToRegionBoundary:
1409                 build_region_boundary_cache ();
1410                 break;
1411
1412         default:
1413                 break;
1414         }
1415
1416         /* catch up on selection of stripables (other selection state is lost
1417          * when a session is closed
1418          */
1419
1420         StripableList sl;
1421         TrackViewList tl;
1422         _session->get_stripables (sl);
1423         for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
1424                 if ((*s)->presentation_info().selected()) {
1425                         RouteTimeAxisView* rtav = get_route_view_by_route_id ((*s)->id());
1426                         if (rtav) {
1427                                 tl.push_back (rtav);
1428                         }
1429                 }
1430         }
1431         if (!tl.empty()) {
1432                 selection->set (tl);
1433         }
1434
1435         /* register for undo history */
1436         _session->register_with_memento_command_factory(id(), this);
1437         _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1438
1439         ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1440
1441         LuaInstance::instance()->set_session(_session);
1442
1443         start_updating_meters ();
1444 }
1445
1446 void
1447 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1448 {
1449         if (a->get_name() == "RegionMenu") {
1450                 /* When the main menu's region menu is opened, we setup the actions so that they look right
1451                    in the menu.  I can't find a way of getting a signal when this menu is subsequently closed,
1452                    so we resensitize all region actions when the entered regionview or the region selection
1453                    changes.  HOWEVER we can't always resensitize on entered_regionview change because that
1454                    happens after the region context menu is opened.  So we set a flag here, too.
1455
1456                    What a carry on :(
1457                 */
1458                 sensitize_the_right_region_actions ();
1459                 _last_region_menu_was_main = true;
1460         }
1461 }
1462
1463 void
1464 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1465 {
1466         using namespace Menu_Helpers;
1467
1468         void (Editor::*emf)(FadeShape);
1469         std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1470
1471         if (start) {
1472                 images = &_xfade_in_images;
1473                 emf = &Editor::set_fade_in_shape;
1474         } else {
1475                 images = &_xfade_out_images;
1476                 emf = &Editor::set_fade_out_shape;
1477         }
1478
1479         items.push_back (
1480                 ImageMenuElem (
1481                         _("Linear (for highly correlated material)"),
1482                         *(*images)[FadeLinear],
1483                         sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1484                         )
1485                 );
1486
1487         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1488
1489         items.push_back (
1490                 ImageMenuElem (
1491                         _("Constant power"),
1492                         *(*images)[FadeConstantPower],
1493                         sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1494                         ));
1495
1496         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1497
1498         items.push_back (
1499                 ImageMenuElem (
1500                         _("Symmetric"),
1501                         *(*images)[FadeSymmetric],
1502                         sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1503                         )
1504                 );
1505
1506         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1507
1508         items.push_back (
1509                 ImageMenuElem (
1510                         _("Slow"),
1511                         *(*images)[FadeSlow],
1512                         sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1513                         ));
1514
1515         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1516
1517         items.push_back (
1518                 ImageMenuElem (
1519                         _("Fast"),
1520                         *(*images)[FadeFast],
1521                         sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1522                         ));
1523
1524         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1525 }
1526
1527 /** Pop up a context menu for when the user clicks on a start crossfade */
1528 void
1529 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1530 {
1531         using namespace Menu_Helpers;
1532         AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1533         if (!arv) {
1534                 return;
1535         }
1536
1537         MenuList& items (xfade_in_context_menu.items());
1538         items.clear ();
1539
1540         if (arv->audio_region()->fade_in_active()) {
1541                 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1542         } else {
1543                 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1544         }
1545
1546         items.push_back (SeparatorElem());
1547         fill_xfade_menu (items, true);
1548
1549         xfade_in_context_menu.popup (button, time);
1550 }
1551
1552 /** Pop up a context menu for when the user clicks on an end crossfade */
1553 void
1554 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1555 {
1556         using namespace Menu_Helpers;
1557         AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1558         if (!arv) {
1559                 return;
1560         }
1561
1562         MenuList& items (xfade_out_context_menu.items());
1563         items.clear ();
1564
1565         if (arv->audio_region()->fade_out_active()) {
1566                 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1567         } else {
1568                 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1569         }
1570
1571         items.push_back (SeparatorElem());
1572         fill_xfade_menu (items, false);
1573
1574         xfade_out_context_menu.popup (button, time);
1575 }
1576
1577 void
1578 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1579 {
1580         using namespace Menu_Helpers;
1581         Menu* (Editor::*build_menu_function)();
1582         Menu *menu;
1583
1584         switch (item_type) {
1585         case RegionItem:
1586         case RegionViewName:
1587         case RegionViewNameHighlight:
1588         case LeftFrameHandle:
1589         case RightFrameHandle:
1590                 if (with_selection) {
1591                         build_menu_function = &Editor::build_track_selection_context_menu;
1592                 } else {
1593                         build_menu_function = &Editor::build_track_region_context_menu;
1594                 }
1595                 break;
1596
1597         case SelectionItem:
1598                 if (with_selection) {
1599                         build_menu_function = &Editor::build_track_selection_context_menu;
1600                 } else {
1601                         build_menu_function = &Editor::build_track_context_menu;
1602                 }
1603                 break;
1604
1605         case StreamItem:
1606                 if (clicked_routeview->track()) {
1607                         build_menu_function = &Editor::build_track_context_menu;
1608                 } else {
1609                         build_menu_function = &Editor::build_track_bus_context_menu;
1610                 }
1611                 break;
1612
1613         default:
1614                 /* probably shouldn't happen but if it does, we don't care */
1615                 return;
1616         }
1617
1618         menu = (this->*build_menu_function)();
1619         menu->set_name ("ArdourContextMenu");
1620
1621         /* now handle specific situations */
1622
1623         switch (item_type) {
1624         case RegionItem:
1625         case RegionViewName:
1626         case RegionViewNameHighlight:
1627         case LeftFrameHandle:
1628         case RightFrameHandle:
1629                 if (!with_selection) {
1630                         if (region_edit_menu_split_item) {
1631                                 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1632                                         ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1633                                 } else {
1634                                         ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1635                                 }
1636                         }
1637                         if (region_edit_menu_split_multichannel_item) {
1638                                 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1639                                         region_edit_menu_split_multichannel_item->set_sensitive (true);
1640                                 } else {
1641                                         region_edit_menu_split_multichannel_item->set_sensitive (false);
1642                                 }
1643                         }
1644                 }
1645                 break;
1646
1647         case SelectionItem:
1648                 break;
1649
1650         case StreamItem:
1651                 break;
1652
1653         default:
1654                 /* probably shouldn't happen but if it does, we don't care */
1655                 return;
1656         }
1657
1658         if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1659
1660                 /* Bounce to disk */
1661
1662                 using namespace Menu_Helpers;
1663                 MenuList& edit_items  = menu->items();
1664
1665                 edit_items.push_back (SeparatorElem());
1666
1667                 switch (clicked_routeview->audio_track()->freeze_state()) {
1668                 case AudioTrack::NoFreeze:
1669                         edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1670                         break;
1671
1672                 case AudioTrack::Frozen:
1673                         edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1674                         break;
1675
1676                 case AudioTrack::UnFrozen:
1677                         edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1678                         break;
1679                 }
1680
1681         }
1682
1683         if (item_type == StreamItem && clicked_routeview) {
1684                 clicked_routeview->build_underlay_menu(menu);
1685         }
1686
1687         /* When the region menu is opened, we setup the actions so that they look right
1688            in the menu.
1689         */
1690         sensitize_the_right_region_actions ();
1691         _last_region_menu_was_main = false;
1692
1693         menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1694         menu->popup (button, time);
1695 }
1696
1697 Menu*
1698 Editor::build_track_context_menu ()
1699 {
1700         using namespace Menu_Helpers;
1701
1702         MenuList& edit_items = track_context_menu.items();
1703         edit_items.clear();
1704
1705         add_dstream_context_items (edit_items);
1706         return &track_context_menu;
1707 }
1708
1709 Menu*
1710 Editor::build_track_bus_context_menu ()
1711 {
1712         using namespace Menu_Helpers;
1713
1714         MenuList& edit_items = track_context_menu.items();
1715         edit_items.clear();
1716
1717         add_bus_context_items (edit_items);
1718         return &track_context_menu;
1719 }
1720
1721 Menu*
1722 Editor::build_track_region_context_menu ()
1723 {
1724         using namespace Menu_Helpers;
1725         MenuList& edit_items  = track_region_context_menu.items();
1726         edit_items.clear();
1727
1728         /* we've just cleared the track region context menu, so the menu that these
1729            two items were on will have disappeared; stop them dangling.
1730         */
1731         region_edit_menu_split_item = 0;
1732         region_edit_menu_split_multichannel_item = 0;
1733
1734         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1735
1736         if (rtv) {
1737                 boost::shared_ptr<Track> tr;
1738                 boost::shared_ptr<Playlist> pl;
1739
1740                 if ((tr = rtv->track())) {
1741                         add_region_context_items (edit_items, tr);
1742                 }
1743         }
1744
1745         add_dstream_context_items (edit_items);
1746
1747         return &track_region_context_menu;
1748 }
1749
1750 void
1751 Editor::loudness_analyze_region_selection ()
1752 {
1753         if (!_session) {
1754                 return;
1755         }
1756         Selection& s (PublicEditor::instance ().get_selection ());
1757         RegionSelection ars = s.regions;
1758         ARDOUR::AnalysisGraph ag (_session);
1759         framecnt_t total_work = 0;
1760
1761         for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1762                 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1763                 if (!arv) {
1764                         continue;
1765                 }
1766                 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1767                         continue;
1768                 }
1769                 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1770                 total_work += arv->region ()->length ();
1771         }
1772
1773         SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1774         ScopedConnection c;
1775         ag.set_total_frames (total_work);
1776         ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1777         spd.show();
1778
1779         for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1780                 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1781                 if (!arv) {
1782                         continue;
1783                 }
1784                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1785                 if (!ar) {
1786                         continue;
1787                 }
1788                 ag.analyze_region (ar);
1789         }
1790         spd.hide();
1791         if (!ag.canceled ()) {
1792                 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1793                 er.run();
1794         }
1795 }
1796
1797 void
1798 Editor::loudness_analyze_range_selection ()
1799 {
1800         if (!_session) {
1801                 return;
1802         }
1803         Selection& s (PublicEditor::instance ().get_selection ());
1804         TimeSelection ts = s.time;
1805         ARDOUR::AnalysisGraph ag (_session);
1806         framecnt_t total_work = 0;
1807
1808         for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1809                 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1810                 if (!pl) {
1811                         continue;
1812                 }
1813                 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1814                 if (!pl || !rui) {
1815                         continue;
1816                 }
1817                 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1818                         total_work += j->length ();
1819                 }
1820         }
1821
1822         SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1823         ScopedConnection c;
1824         ag.set_total_frames (total_work);
1825         ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1826         spd.show();
1827
1828         for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1829                 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1830                 if (!pl) {
1831                         continue;
1832                 }
1833                 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1834                 if (!pl || !rui) {
1835                         continue;
1836                 }
1837                 ag.analyze_range (rui->route (), pl, ts);
1838         }
1839         spd.hide();
1840         if (!ag.canceled ()) {
1841                 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1842                 er.run();
1843         }
1844 }
1845
1846 void
1847 Editor::spectral_analyze_region_selection ()
1848 {
1849         if (analysis_window == 0) {
1850                 analysis_window = new AnalysisWindow();
1851
1852                 if (_session != 0)
1853                         analysis_window->set_session(_session);
1854
1855                 analysis_window->show_all();
1856         }
1857
1858         analysis_window->set_regionmode();
1859         analysis_window->analyze();
1860
1861         analysis_window->present();
1862 }
1863
1864 void
1865 Editor::spectral_analyze_range_selection()
1866 {
1867         if (analysis_window == 0) {
1868                 analysis_window = new AnalysisWindow();
1869
1870                 if (_session != 0)
1871                         analysis_window->set_session(_session);
1872
1873                 analysis_window->show_all();
1874         }
1875
1876         analysis_window->set_rangemode();
1877         analysis_window->analyze();
1878
1879         analysis_window->present();
1880 }
1881
1882 Menu*
1883 Editor::build_track_selection_context_menu ()
1884 {
1885         using namespace Menu_Helpers;
1886         MenuList& edit_items  = track_selection_context_menu.items();
1887         edit_items.clear ();
1888
1889         add_selection_context_items (edit_items);
1890         // edit_items.push_back (SeparatorElem());
1891         // add_dstream_context_items (edit_items);
1892
1893         return &track_selection_context_menu;
1894 }
1895
1896 void
1897 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1898 {
1899         using namespace Menu_Helpers;
1900
1901         /* OK, stick the region submenu at the top of the list, and then add
1902            the standard items.
1903         */
1904
1905         RegionSelection rs = get_regions_from_selection_and_entered ();
1906
1907         string::size_type pos = 0;
1908         string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1909
1910         /* we have to hack up the region name because "_" has a special
1911            meaning for menu titles.
1912         */
1913
1914         while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1915                 menu_item_name.replace (pos, 1, "__");
1916                 pos += 2;
1917         }
1918
1919         if (_popup_region_menu_item == 0) {
1920                 _popup_region_menu_item = new MenuItem (menu_item_name);
1921                 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1922                 _popup_region_menu_item->show ();
1923         } else {
1924                 _popup_region_menu_item->set_label (menu_item_name);
1925         }
1926
1927         /* No latering allowed in later is higher layering model */
1928         RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1929         if (act && Config->get_layer_model() == LaterHigher) {
1930                 act->set_sensitive (false);
1931         } else if (act) {
1932                 act->set_sensitive (true);
1933         }
1934
1935         const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1936
1937         edit_items.push_back (*_popup_region_menu_item);
1938         if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1939                 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1940         }
1941         edit_items.push_back (SeparatorElem());
1942 }
1943
1944 /** Add context menu items relevant to selection ranges.
1945  * @param edit_items List to add the items to.
1946  */
1947 void
1948 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1949 {
1950         using namespace Menu_Helpers;
1951
1952         edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1953         edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1954
1955         edit_items.push_back (SeparatorElem());
1956         edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1957
1958         edit_items.push_back (SeparatorElem());
1959         edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1960         edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1961
1962         edit_items.push_back (SeparatorElem());
1963
1964         edit_items.push_back (
1965                 MenuElem (
1966                         _("Move Range Start to Previous Region Boundary"),
1967                         sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1968                         )
1969                 );
1970
1971         edit_items.push_back (
1972                 MenuElem (
1973                         _("Move Range Start to Next Region Boundary"),
1974                         sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1975                         )
1976                 );
1977
1978         edit_items.push_back (
1979                 MenuElem (
1980                         _("Move Range End to Previous Region Boundary"),
1981                         sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1982                         )
1983                 );
1984
1985         edit_items.push_back (
1986                 MenuElem (
1987                         _("Move Range End to Next Region Boundary"),
1988                         sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1989                         )
1990                 );
1991
1992         edit_items.push_back (SeparatorElem());
1993         edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1994         edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1995
1996         edit_items.push_back (SeparatorElem());
1997         edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1998
1999         edit_items.push_back (SeparatorElem());
2000         edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
2001         edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
2002         edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
2003
2004         edit_items.push_back (SeparatorElem());
2005         edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
2006
2007         edit_items.push_back (SeparatorElem());
2008         edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
2009         edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
2010
2011         edit_items.push_back (SeparatorElem());
2012         edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2013         edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2014         edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2015         edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2016         edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2017         if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2018                 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2019         }
2020 }
2021
2022
2023 void
2024 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2025 {
2026         using namespace Menu_Helpers;
2027
2028         /* Playback */
2029
2030         Menu *play_menu = manage (new Menu);
2031         MenuList& play_items = play_menu->items();
2032         play_menu->set_name ("ArdourContextMenu");
2033
2034         play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2035         play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2036         play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2037         play_items.push_back (SeparatorElem());
2038         play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2039
2040         edit_items.push_back (MenuElem (_("Play"), *play_menu));
2041
2042         /* Selection */
2043
2044         Menu *select_menu = manage (new Menu);
2045         MenuList& select_items = select_menu->items();
2046         select_menu->set_name ("ArdourContextMenu");
2047
2048         select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2049         select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2050         select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2051         select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2052         select_items.push_back (SeparatorElem());
2053         select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2054         select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2055         select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2056         select_items.push_back (SeparatorElem());
2057         select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2058         select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2059         select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2060         select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2061         select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2062         select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2063         select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2064
2065         edit_items.push_back (MenuElem (_("Select"), *select_menu));
2066
2067         /* Cut-n-Paste */
2068
2069         Menu *cutnpaste_menu = manage (new Menu);
2070         MenuList& cutnpaste_items = cutnpaste_menu->items();
2071         cutnpaste_menu->set_name ("ArdourContextMenu");
2072
2073         cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2074         cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2075         cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2076
2077         cutnpaste_items.push_back (SeparatorElem());
2078
2079         cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2080         cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2081
2082         edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2083
2084         /* Adding new material */
2085
2086         edit_items.push_back (SeparatorElem());
2087         edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2088         edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2089
2090         /* Nudge track */
2091
2092         Menu *nudge_menu = manage (new Menu());
2093         MenuList& nudge_items = nudge_menu->items();
2094         nudge_menu->set_name ("ArdourContextMenu");
2095
2096         edit_items.push_back (SeparatorElem());
2097         nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2098         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2099         nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2100         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2101
2102         edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2103 }
2104
2105 void
2106 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2107 {
2108         using namespace Menu_Helpers;
2109
2110         /* Playback */
2111
2112         Menu *play_menu = manage (new Menu);
2113         MenuList& play_items = play_menu->items();
2114         play_menu->set_name ("ArdourContextMenu");
2115
2116         play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2117         play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2118         edit_items.push_back (MenuElem (_("Play"), *play_menu));
2119
2120         /* Selection */
2121
2122         Menu *select_menu = manage (new Menu);
2123         MenuList& select_items = select_menu->items();
2124         select_menu->set_name ("ArdourContextMenu");
2125
2126         select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2127         select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2128         select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2129         select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2130         select_items.push_back (SeparatorElem());
2131         select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2132         select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2133         select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2134         select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2135
2136         edit_items.push_back (MenuElem (_("Select"), *select_menu));
2137
2138         /* Cut-n-Paste */
2139
2140         Menu *cutnpaste_menu = manage (new Menu);
2141         MenuList& cutnpaste_items = cutnpaste_menu->items();
2142         cutnpaste_menu->set_name ("ArdourContextMenu");
2143
2144         cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2145         cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2146         cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2147
2148         Menu *nudge_menu = manage (new Menu());
2149         MenuList& nudge_items = nudge_menu->items();
2150         nudge_menu->set_name ("ArdourContextMenu");
2151
2152         edit_items.push_back (SeparatorElem());
2153         nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2154         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2155         nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2156         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2157
2158         edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2159 }
2160
2161 SnapType
2162 Editor::snap_type() const
2163 {
2164         return _snap_type;
2165 }
2166
2167 bool
2168 Editor::snap_musical() const
2169 {
2170         switch (_snap_type) {
2171         case SnapToBeatDiv128:
2172         case SnapToBeatDiv64:
2173         case SnapToBeatDiv32:
2174         case SnapToBeatDiv28:
2175         case SnapToBeatDiv24:
2176         case SnapToBeatDiv20:
2177         case SnapToBeatDiv16:
2178         case SnapToBeatDiv14:
2179         case SnapToBeatDiv12:
2180         case SnapToBeatDiv10:
2181         case SnapToBeatDiv8:
2182         case SnapToBeatDiv7:
2183         case SnapToBeatDiv6:
2184         case SnapToBeatDiv5:
2185         case SnapToBeatDiv4:
2186         case SnapToBeatDiv3:
2187         case SnapToBeatDiv2:
2188         case SnapToBeat:
2189         case SnapToBar:
2190                 return true;
2191         default:
2192                 break;
2193         }
2194
2195         return false;
2196 }
2197
2198 SnapMode
2199 Editor::snap_mode() const
2200 {
2201         return _snap_mode;
2202 }
2203
2204 void
2205 Editor::set_snap_to (SnapType st)
2206 {
2207         unsigned int snap_ind = (unsigned int)st;
2208
2209         if (internal_editing()) {
2210                 internal_snap_type = st;
2211         } else {
2212                 pre_internal_snap_type = st;
2213         }
2214
2215         _snap_type = st;
2216
2217         if (snap_ind > snap_type_strings.size() - 1) {
2218                 snap_ind = 0;
2219                 _snap_type = (SnapType)snap_ind;
2220         }
2221
2222         string str = snap_type_strings[snap_ind];
2223
2224         if (str != snap_type_selector.get_text()) {
2225                 snap_type_selector.set_text (str);
2226         }
2227
2228         instant_save ();
2229
2230         switch (_snap_type) {
2231         case SnapToBeatDiv128:
2232         case SnapToBeatDiv64:
2233         case SnapToBeatDiv32:
2234         case SnapToBeatDiv28:
2235         case SnapToBeatDiv24:
2236         case SnapToBeatDiv20:
2237         case SnapToBeatDiv16:
2238         case SnapToBeatDiv14:
2239         case SnapToBeatDiv12:
2240         case SnapToBeatDiv10:
2241         case SnapToBeatDiv8:
2242         case SnapToBeatDiv7:
2243         case SnapToBeatDiv6:
2244         case SnapToBeatDiv5:
2245         case SnapToBeatDiv4:
2246         case SnapToBeatDiv3:
2247         case SnapToBeatDiv2: {
2248                 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
2249                 update_tempo_based_rulers ();
2250                 break;
2251         }
2252
2253         case SnapToRegionStart:
2254         case SnapToRegionEnd:
2255         case SnapToRegionSync:
2256         case SnapToRegionBoundary:
2257                 build_region_boundary_cache ();
2258                 break;
2259
2260         default:
2261                 /* relax */
2262                 break;
2263         }
2264
2265         redisplay_tempo (false);
2266
2267         SnapChanged (); /* EMIT SIGNAL */
2268 }
2269
2270 void
2271 Editor::set_snap_mode (SnapMode mode)
2272 {
2273         string str = snap_mode_strings[(int)mode];
2274
2275         if (internal_editing()) {
2276                 internal_snap_mode = mode;
2277         } else {
2278                 pre_internal_snap_mode = mode;
2279         }
2280
2281         _snap_mode = mode;
2282
2283         if (str != snap_mode_selector.get_text ()) {
2284                 snap_mode_selector.set_text (str);
2285         }
2286
2287         instant_save ();
2288 }
2289
2290 void
2291 Editor::set_edit_point_preference (EditPoint ep, bool force)
2292 {
2293         bool changed = (_edit_point != ep);
2294
2295         _edit_point = ep;
2296         if (Profile->get_mixbus())
2297                 if (ep == EditAtSelectedMarker)
2298                         ep = EditAtPlayhead;
2299
2300         string str = edit_point_strings[(int)ep];
2301         if (str != edit_point_selector.get_text ()) {
2302                 edit_point_selector.set_text (str);
2303         }
2304
2305         update_all_enter_cursors();
2306
2307         if (!force && !changed) {
2308                 return;
2309         }
2310
2311         const char* action=NULL;
2312
2313         switch (_edit_point) {
2314         case EditAtPlayhead:
2315                 action = "edit-at-playhead";
2316                 break;
2317         case EditAtSelectedMarker:
2318                 action = "edit-at-marker";
2319                 break;
2320         case EditAtMouse:
2321                 action = "edit-at-mouse";
2322                 break;
2323         }
2324
2325         Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2326         if (act) {
2327                 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2328         }
2329
2330         framepos_t foo;
2331         bool in_track_canvas;
2332
2333         if (!mouse_frame (foo, in_track_canvas)) {
2334                 in_track_canvas = false;
2335         }
2336
2337         reset_canvas_action_sensitivity (in_track_canvas);
2338
2339         instant_save ();
2340 }
2341
2342 int
2343 Editor::set_state (const XMLNode& node, int version)
2344 {
2345         XMLProperty const * prop;
2346         set_id (node);
2347         PBD::Unwinder<bool> nsi (no_save_instant, true);
2348         LocaleGuard lg;
2349
2350         Tabbable::set_state (node, version);
2351
2352         if (_session && (prop = node.property ("playhead"))) {
2353                 framepos_t pos;
2354                 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2355                 if (pos >= 0) {
2356                         playhead_cursor->set_position (pos);
2357                 } else {
2358                         warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2359                         playhead_cursor->set_position (0);
2360                 }
2361         } else {
2362                 playhead_cursor->set_position (0);
2363         }
2364
2365         if ((prop = node.property ("mixer-width"))) {
2366                 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2367         }
2368
2369         if ((prop = node.property ("zoom-focus"))) {
2370                 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2371         } else {
2372                 zoom_focus_selection_done (zoom_focus);
2373         }
2374
2375         if ((prop = node.property ("zoom"))) {
2376                 /* older versions of ardour used floating point samples_per_pixel */
2377                 double f = PBD::atof (prop->value());
2378                 reset_zoom (llrintf (f));
2379         } else {
2380                 reset_zoom (samples_per_pixel);
2381         }
2382
2383         if ((prop = node.property ("visible-track-count"))) {
2384                 set_visible_track_count (PBD::atoi (prop->value()));
2385         }
2386
2387         if ((prop = node.property ("snap-to"))) {
2388                 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2389                 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2390         } else {
2391                 set_snap_to (_snap_type);
2392         }
2393
2394         if ((prop = node.property ("snap-mode"))) {
2395                 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2396                 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2397                  * snap_mode_selection_done() will only mark an already active item as active
2398                  * which does not trigger set_text().
2399                  */
2400                 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2401         } else {
2402                 set_snap_mode (_snap_mode);
2403         }
2404
2405         if ((prop = node.property ("internal-snap-to"))) {
2406                 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2407         }
2408
2409         if ((prop = node.property ("internal-snap-mode"))) {
2410                 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2411         }
2412
2413         if ((prop = node.property ("pre-internal-snap-to"))) {
2414                 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2415         }
2416
2417         if ((prop = node.property ("pre-internal-snap-mode"))) {
2418                 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2419         }
2420
2421         if ((prop = node.property ("mouse-mode"))) {
2422                 MouseMode m = str2mousemode(prop->value());
2423                 set_mouse_mode (m, true);
2424         } else {
2425                 set_mouse_mode (MouseObject, true);
2426         }
2427
2428         if ((prop = node.property ("left-frame")) != 0) {
2429                 framepos_t pos;
2430                 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2431                         if (pos < 0) {
2432                                 pos = 0;
2433                         }
2434                         reset_x_origin (pos);
2435                 }
2436         }
2437
2438         if ((prop = node.property ("y-origin")) != 0) {
2439                 reset_y_origin (atof (prop->value ()));
2440         }
2441
2442         if ((prop = node.property ("join-object-range"))) {
2443                 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2444                 bool yn = string_is_affirmative (prop->value());
2445                 if (act) {
2446                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2447                         tact->set_active (!yn);
2448                         tact->set_active (yn);
2449                 }
2450                 set_mouse_mode(mouse_mode, true);
2451         }
2452
2453         if ((prop = node.property ("edit-point"))) {
2454                 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2455         } else {
2456                 set_edit_point_preference (_edit_point);
2457         }
2458
2459         if ((prop = node.property ("show-measures"))) {
2460                 bool yn = string_is_affirmative (prop->value());
2461                 _show_measures = yn;
2462         }
2463
2464         if ((prop = node.property ("follow-playhead"))) {
2465                 bool yn = string_is_affirmative (prop->value());
2466                 set_follow_playhead (yn);
2467         }
2468
2469         if ((prop = node.property ("stationary-playhead"))) {
2470                 bool yn = string_is_affirmative (prop->value());
2471                 set_stationary_playhead (yn);
2472         }
2473
2474         if ((prop = node.property ("region-list-sort-type"))) {
2475                 RegionListSortType st;
2476                 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2477         }
2478
2479         if ((prop = node.property ("show-editor-mixer"))) {
2480
2481                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2482                 assert (act);
2483
2484                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2485                 bool yn = string_is_affirmative (prop->value());
2486
2487                 /* do it twice to force the change */
2488
2489                 tact->set_active (!yn);
2490                 tact->set_active (yn);
2491         }
2492
2493         if ((prop = node.property ("show-editor-list"))) {
2494
2495                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2496                 assert (act);
2497
2498                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2499                 bool yn = string_is_affirmative (prop->value());
2500
2501                 /* do it twice to force the change */
2502
2503                 tact->set_active (!yn);
2504                 tact->set_active (yn);
2505         }
2506
2507         if ((prop = node.property (X_("editor-list-page")))) {
2508                 _the_notebook.set_current_page (atoi (prop->value ()));
2509         }
2510
2511         if ((prop = node.property (X_("show-marker-lines")))) {
2512                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2513                 assert (act);
2514                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2515                 bool yn = string_is_affirmative (prop->value ());
2516
2517                 tact->set_active (!yn);
2518                 tact->set_active (yn);
2519         }
2520
2521         XMLNodeList children = node.children ();
2522         for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2523                 selection->set_state (**i, Stateful::current_state_version);
2524                 _regions->set_state (**i);
2525         }
2526
2527         if ((prop = node.property ("maximised"))) {
2528                 bool yn = string_is_affirmative (prop->value());
2529                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2530                 assert (act);
2531                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2532                 bool fs = tact && tact->get_active();
2533                 if (yn ^ fs) {
2534                         ActionManager::do_action ("Common", "ToggleMaximalEditor");
2535                 }
2536         }
2537
2538         if ((prop = node.property ("nudge-clock-value"))) {
2539                 framepos_t f;
2540                 sscanf (prop->value().c_str(), "%" PRId64, &f);
2541                 nudge_clock->set (f);
2542         } else {
2543                 nudge_clock->set_mode (AudioClock::Timecode);
2544                 nudge_clock->set (_session->frame_rate() * 5, true);
2545         }
2546
2547         {
2548                 /* apply state
2549                  * Not all properties may have been in XML, but
2550                  * those that are linked to a private variable may need changing
2551                  */
2552                 RefPtr<Action> act;
2553                 bool yn;
2554
2555                 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2556                 if (act) {
2557                         yn = _show_measures;
2558                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2559                         /* do it twice to force the change */
2560                         tact->set_active (!yn);
2561                         tact->set_active (yn);
2562                 }
2563
2564                 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2565                 yn = _follow_playhead;
2566                 if (act) {
2567                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2568                         if (tact->get_active() != yn) {
2569                                 tact->set_active (yn);
2570                         }
2571                 }
2572
2573                 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2574                 yn = _stationary_playhead;
2575                 if (act) {
2576                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2577                         if (tact->get_active() != yn) {
2578                                 tact->set_active (yn);
2579                         }
2580                 }
2581         }
2582
2583         return LuaInstance::instance()->set_state(node);
2584 }
2585
2586 XMLNode&
2587 Editor::get_state ()
2588 {
2589         XMLNode* node = new XMLNode (X_("Editor"));
2590         char buf[32];
2591         LocaleGuard lg;
2592
2593         id().print (buf, sizeof (buf));
2594         node->add_property ("id", buf);
2595
2596         node->add_child_nocopy (Tabbable::get_state());
2597
2598         snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ());
2599         node->add_property("edit-horizontal-pane-pos", string(buf));
2600         node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2601         snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider());
2602         node->add_property("edit-vertical-pane-pos", string(buf));
2603
2604         maybe_add_mixer_strip_width (*node);
2605
2606         node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2607
2608         snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2609         node->add_property ("zoom", buf);
2610         node->add_property ("snap-to", enum_2_string (_snap_type));
2611         node->add_property ("snap-mode", enum_2_string (_snap_mode));
2612         node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2613         node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2614         node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2615         node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2616         node->add_property ("edit-point", enum_2_string (_edit_point));
2617         snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2618         node->add_property ("visible-track-count", buf);
2619
2620         snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2621         node->add_property ("playhead", buf);
2622         snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2623         node->add_property ("left-frame", buf);
2624         snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2625         node->add_property ("y-origin", buf);
2626
2627         node->add_property ("show-measures", _show_measures ? "yes" : "no");
2628         node->add_property ("maximised", _maximised ? "yes" : "no");
2629         node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2630         node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2631         node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2632         node->add_property ("mouse-mode", enum2str(mouse_mode));
2633         node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2634
2635         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2636         if (act) {
2637                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2638                 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2639         }
2640
2641         act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2642         if (act) {
2643                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2644                 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2645         }
2646
2647         snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2648         node->add_property (X_("editor-list-page"), buf);
2649
2650         if (button_bindings) {
2651                 XMLNode* bb = new XMLNode (X_("Buttons"));
2652                 button_bindings->save (*bb);
2653                 node->add_child_nocopy (*bb);
2654         }
2655
2656         node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2657
2658         node->add_child_nocopy (selection->get_state ());
2659         node->add_child_nocopy (_regions->get_state ());
2660
2661         snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2662         node->add_property ("nudge-clock-value", buf);
2663
2664         node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2665         node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2666
2667         return *node;
2668 }
2669
2670 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2671  *  if @param trackview_relative_offset is false, @param y y is a global canvas *  coordinate, in pixel units
2672  *
2673  *  @return pair: TimeAxisView that y is over, layer index.
2674  *
2675  *  TimeAxisView may be 0.  Layer index is the layer number if the TimeAxisView is valid and is
2676  *  in stacked or expanded region display mode, otherwise 0.
2677  */
2678 std::pair<TimeAxisView *, double>
2679 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2680 {
2681         if (!trackview_relative_offset) {
2682                 y -= _trackview_group->canvas_origin().y;
2683         }
2684
2685         if (y < 0) {
2686                 return std::make_pair ( (TimeAxisView *) 0, 0);
2687         }
2688
2689         for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2690
2691                 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2692
2693                 if (r.first) {
2694                         return r;
2695                 }
2696         }
2697
2698         return std::make_pair ( (TimeAxisView *) 0, 0);
2699 }
2700
2701 /** Snap a position to the grid, if appropriate, taking into account current
2702  *  grid settings and also the state of any snap modifier keys that may be pressed.
2703  *  @param start Position to snap.
2704  *  @param event Event to get current key modifier information from, or 0.
2705  */
2706 void
2707 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2708 {
2709         if (!_session || !event) {
2710                 return;
2711         }
2712
2713         if (ArdourKeyboard::indicates_snap (event->button.state)) {
2714                 if (_snap_mode == SnapOff) {
2715                         snap_to_internal (start, direction, for_mark);
2716                 }
2717         } else {
2718                 if (_snap_mode != SnapOff) {
2719                         snap_to_internal (start, direction, for_mark);
2720                 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2721                         /* SnapOff, but we pressed the snap_delta modifier */
2722                         snap_to_internal (start, direction, for_mark);
2723                 }
2724         }
2725 }
2726
2727 void
2728 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2729 {
2730         if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2731                 return;
2732         }
2733
2734         snap_to_internal (start, direction, for_mark, ensure_snap);
2735 }
2736
2737 void
2738 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2739 {
2740         const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2741         framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2742
2743         switch (_snap_type) {
2744         case SnapToTimecodeFrame:
2745                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2746                     fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2747                         /* start is already on a whole timecode frame, do nothing */
2748                 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2749                         start = (framepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2750                 } else {
2751                         start = (framepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) *  _session->samples_per_timecode_frame());
2752                 }
2753                 break;
2754
2755         case SnapToTimecodeSeconds:
2756                 if (_session->config.get_timecode_offset_negative()) {
2757                         start += _session->config.get_timecode_offset ();
2758                 } else {
2759                         start -= _session->config.get_timecode_offset ();
2760                 }
2761                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2762                     (start % one_timecode_second == 0)) {
2763                         /* start is already on a whole second, do nothing */
2764                 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2765                         start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2766                 } else {
2767                         start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2768                 }
2769
2770                 if (_session->config.get_timecode_offset_negative()) {
2771                         start -= _session->config.get_timecode_offset ();
2772                 } else {
2773                         start += _session->config.get_timecode_offset ();
2774                 }
2775                 break;
2776
2777         case SnapToTimecodeMinutes:
2778                 if (_session->config.get_timecode_offset_negative()) {
2779                         start += _session->config.get_timecode_offset ();
2780                 } else {
2781                         start -= _session->config.get_timecode_offset ();
2782                 }
2783                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2784                     (start % one_timecode_minute == 0)) {
2785                         /* start is already on a whole minute, do nothing */
2786                 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2787                         start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2788                 } else {
2789                         start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2790                 }
2791                 if (_session->config.get_timecode_offset_negative()) {
2792                         start -= _session->config.get_timecode_offset ();
2793                 } else {
2794                         start += _session->config.get_timecode_offset ();
2795                 }
2796                 break;
2797         default:
2798                 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2799                 abort(); /*NOTREACHED*/
2800         }
2801 }
2802
2803 void
2804 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2805 {
2806         const framepos_t one_second = _session->frame_rate();
2807         const framepos_t one_minute = _session->frame_rate() * 60;
2808         framepos_t presnap = start;
2809         framepos_t before;
2810         framepos_t after;
2811
2812         switch (_snap_type) {
2813         case SnapToTimecodeFrame:
2814         case SnapToTimecodeSeconds:
2815         case SnapToTimecodeMinutes:
2816                 return timecode_snap_to_internal (start, direction, for_mark);
2817
2818         case SnapToCDFrame:
2819                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2820                     start % (one_second/75) == 0) {
2821                         /* start is already on a whole CD frame, do nothing */
2822                 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2823                         start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2824                 } else {
2825                         start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2826                 }
2827                 break;
2828
2829         case SnapToSeconds:
2830                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2831                     start % one_second == 0) {
2832                         /* start is already on a whole second, do nothing */
2833                 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2834                         start = (framepos_t) ceil ((double) start / one_second) * one_second;
2835                 } else {
2836                         start = (framepos_t) floor ((double) start / one_second) * one_second;
2837                 }
2838                 break;
2839
2840         case SnapToMinutes:
2841                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2842                     start % one_minute == 0) {
2843                         /* start is already on a whole minute, do nothing */
2844                 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2845                         start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2846                 } else {
2847                         start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2848                 }
2849                 break;
2850
2851         case SnapToBar:
2852                 start = _session->tempo_map().round_to_bar (start, direction);
2853                 break;
2854
2855         case SnapToBeat:
2856                 start = _session->tempo_map().round_to_beat (start, direction);
2857                 break;
2858
2859         case SnapToBeatDiv128:
2860                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 128, direction);
2861                 break;
2862         case SnapToBeatDiv64:
2863                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 64, direction);
2864                 break;
2865         case SnapToBeatDiv32:
2866                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 32, direction);
2867                 break;
2868         case SnapToBeatDiv28:
2869                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 28, direction);
2870                 break;
2871         case SnapToBeatDiv24:
2872                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 24, direction);
2873                 break;
2874         case SnapToBeatDiv20:
2875                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 20, direction);
2876                 break;
2877         case SnapToBeatDiv16:
2878                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 16, direction);
2879                 break;
2880         case SnapToBeatDiv14:
2881                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 14, direction);
2882                 break;
2883         case SnapToBeatDiv12:
2884                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 12, direction);
2885                 break;
2886         case SnapToBeatDiv10:
2887                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 10, direction);
2888                 break;
2889         case SnapToBeatDiv8:
2890                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 8, direction);
2891                 break;
2892         case SnapToBeatDiv7:
2893                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 7, direction);
2894                 break;
2895         case SnapToBeatDiv6:
2896                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 6, direction);
2897                 break;
2898         case SnapToBeatDiv5:
2899                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 5, direction);
2900                 break;
2901         case SnapToBeatDiv4:
2902                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 4, direction);
2903                 break;
2904         case SnapToBeatDiv3:
2905                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 3, direction);
2906                 break;
2907         case SnapToBeatDiv2:
2908                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 2, direction);
2909                 break;
2910
2911         case SnapToMark:
2912                 if (for_mark) {
2913                         return;
2914                 }
2915
2916                 _session->locations()->marks_either_side (start, before, after);
2917
2918                 if (before == max_framepos && after == max_framepos) {
2919                         /* No marks to snap to, so just don't snap */
2920                         return;
2921                 } else if (before == max_framepos) {
2922                         start = after;
2923                 } else if (after == max_framepos) {
2924                         start = before;
2925                 } else if (before != max_framepos && after != max_framepos) {
2926                         /* have before and after */
2927                         if ((start - before) < (after - start)) {
2928                                 start = before;
2929                         } else {
2930                                 start = after;
2931                         }
2932                 }
2933
2934                 break;
2935
2936         case SnapToRegionStart:
2937         case SnapToRegionEnd:
2938         case SnapToRegionSync:
2939         case SnapToRegionBoundary:
2940                 if (!region_boundary_cache.empty()) {
2941
2942                         vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2943                         vector<framepos_t>::iterator next = region_boundary_cache.end ();
2944
2945                         if (direction > 0) {
2946                                 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2947                         } else {
2948                                 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2949                         }
2950
2951                         if (next != region_boundary_cache.begin ()) {
2952                                 prev = next;
2953                                 prev--;
2954                         }
2955
2956                         framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2957                         framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2958
2959                         if (start > (p + n) / 2) {
2960                                 start = n;
2961                         } else {
2962                                 start = p;
2963                         }
2964                 }
2965                 break;
2966         }
2967
2968         switch (_snap_mode) {
2969         case SnapNormal:
2970                 return;
2971
2972         case SnapMagnetic:
2973
2974                 if (ensure_snap) {
2975                         return;
2976                 }
2977
2978                 if (presnap > start) {
2979                         if (presnap > (start + pixel_to_sample(snap_threshold))) {
2980                                 start = presnap;
2981                         }
2982
2983                 } else if (presnap < start) {
2984                         if (presnap < (start - pixel_to_sample(snap_threshold))) {
2985                                 start = presnap;
2986                         }
2987                 }
2988
2989         default:
2990                 /* handled at entry */
2991                 return;
2992
2993         }
2994 }
2995
2996
2997 void
2998 Editor::setup_toolbar ()
2999 {
3000         HBox* mode_box = manage(new HBox);
3001         mode_box->set_border_width (2);
3002         mode_box->set_spacing(2);
3003
3004         HBox* mouse_mode_box = manage (new HBox);
3005         HBox* mouse_mode_hbox = manage (new HBox);
3006         VBox* mouse_mode_vbox = manage (new VBox);
3007         Alignment* mouse_mode_align = manage (new Alignment);
3008
3009         Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3010         mouse_mode_size_group->add_widget (smart_mode_button);
3011         mouse_mode_size_group->add_widget (mouse_move_button);
3012         mouse_mode_size_group->add_widget (mouse_cut_button);
3013         mouse_mode_size_group->add_widget (mouse_select_button);
3014         mouse_mode_size_group->add_widget (mouse_timefx_button);
3015         mouse_mode_size_group->add_widget (mouse_audition_button);
3016         mouse_mode_size_group->add_widget (mouse_draw_button);
3017         mouse_mode_size_group->add_widget (mouse_content_button);
3018
3019         mouse_mode_size_group->add_widget (zoom_in_button);
3020         mouse_mode_size_group->add_widget (zoom_out_button);
3021         mouse_mode_size_group->add_widget (zoom_preset_selector);
3022         mouse_mode_size_group->add_widget (zoom_out_full_button);
3023         mouse_mode_size_group->add_widget (zoom_focus_selector);
3024
3025         mouse_mode_size_group->add_widget (tav_shrink_button);
3026         mouse_mode_size_group->add_widget (tav_expand_button);
3027         mouse_mode_size_group->add_widget (visible_tracks_selector);
3028
3029         mouse_mode_size_group->add_widget (snap_type_selector);
3030         mouse_mode_size_group->add_widget (snap_mode_selector);
3031
3032         mouse_mode_size_group->add_widget (edit_point_selector);
3033         mouse_mode_size_group->add_widget (edit_mode_selector);
3034
3035         mouse_mode_size_group->add_widget (*nudge_clock);
3036         mouse_mode_size_group->add_widget (nudge_forward_button);
3037         mouse_mode_size_group->add_widget (nudge_backward_button);
3038
3039         mouse_mode_hbox->set_spacing (2);
3040
3041         if (!ARDOUR::Profile->get_trx()) {
3042                 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3043         }
3044
3045         mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3046         mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3047
3048         if (!ARDOUR::Profile->get_mixbus()) {
3049                 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3050         }
3051
3052         if (!ARDOUR::Profile->get_trx()) {
3053                 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3054                 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3055                 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3056                 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3057         }
3058
3059         mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3060
3061         mouse_mode_align->add (*mouse_mode_vbox);
3062         mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3063
3064         mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3065
3066         edit_mode_selector.set_name ("mouse mode button");
3067
3068         if (!ARDOUR::Profile->get_trx()) {
3069                 mode_box->pack_start (edit_mode_selector, false, false);
3070         }
3071
3072         mode_box->pack_start (*mouse_mode_box, false, false);
3073
3074         /* Zoom */
3075
3076         _zoom_box.set_spacing (2);
3077         _zoom_box.set_border_width (2);
3078
3079         RefPtr<Action> act;
3080
3081         zoom_preset_selector.set_name ("zoom button");
3082         zoom_preset_selector.set_image(::get_icon ("time_exp"));
3083         zoom_preset_selector.set_size_request (42, -1);
3084
3085         zoom_in_button.set_name ("zoom button");
3086         zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3087         act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3088         zoom_in_button.set_related_action (act);
3089
3090         zoom_out_button.set_name ("zoom button");
3091         zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3092         act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3093         zoom_out_button.set_related_action (act);
3094
3095         zoom_out_full_button.set_name ("zoom button");
3096         zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3097         act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3098         zoom_out_full_button.set_related_action (act);
3099
3100         zoom_focus_selector.set_name ("zoom button");
3101
3102         if (ARDOUR::Profile->get_mixbus()) {
3103                 _zoom_box.pack_start (zoom_preset_selector, false, false);
3104         } else if (ARDOUR::Profile->get_trx()) {
3105                 mode_box->pack_start (zoom_out_button, false, false);
3106                 mode_box->pack_start (zoom_in_button, false, false);
3107         } else {
3108                 _zoom_box.pack_start (zoom_out_button, false, false);
3109                 _zoom_box.pack_start (zoom_in_button, false, false);
3110                 _zoom_box.pack_start (zoom_out_full_button, false, false);
3111                 _zoom_box.pack_start (zoom_focus_selector, false, false);
3112         }
3113
3114         /* Track zoom buttons */
3115         _track_box.set_spacing (2);
3116         _track_box.set_border_width (2);
3117
3118         visible_tracks_selector.set_name ("zoom button");
3119         if (Profile->get_mixbus()) {
3120                 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3121                 visible_tracks_selector.set_size_request (42, -1);
3122         } else {
3123                 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3124         }
3125
3126         tav_expand_button.set_name ("zoom button");
3127         tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3128         act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3129         tav_expand_button.set_related_action (act);
3130
3131         tav_shrink_button.set_name ("zoom button");
3132         tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3133         act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3134         tav_shrink_button.set_related_action (act);
3135
3136         if (ARDOUR::Profile->get_mixbus()) {
3137                 _track_box.pack_start (visible_tracks_selector);
3138         } else if (ARDOUR::Profile->get_trx()) {
3139                 _track_box.pack_start (tav_shrink_button);
3140                 _track_box.pack_start (tav_expand_button);
3141         } else {
3142                 _track_box.pack_start (visible_tracks_selector);
3143                 _track_box.pack_start (tav_shrink_button);
3144                 _track_box.pack_start (tav_expand_button);
3145         }
3146
3147         snap_box.set_spacing (2);
3148         snap_box.set_border_width (2);
3149
3150         snap_type_selector.set_name ("mouse mode button");
3151
3152         snap_mode_selector.set_name ("mouse mode button");
3153
3154         edit_point_selector.set_name ("mouse mode button");
3155
3156         snap_box.pack_start (snap_mode_selector, false, false);
3157         snap_box.pack_start (snap_type_selector, false, false);
3158
3159         /* Edit Point*/
3160         HBox *ep_box = manage (new HBox);
3161         ep_box->set_spacing (2);
3162         ep_box->set_border_width (2);
3163
3164         ep_box->pack_start (edit_point_selector, false, false);
3165
3166         /* Nudge */
3167
3168         HBox *nudge_box = manage (new HBox);
3169         nudge_box->set_spacing (2);
3170         nudge_box->set_border_width (2);
3171
3172         nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3173         nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3174
3175         nudge_box->pack_start (nudge_backward_button, false, false);
3176         nudge_box->pack_start (nudge_forward_button, false, false);
3177         nudge_box->pack_start (*nudge_clock, false, false);
3178
3179
3180         /* Pack everything in... */
3181
3182         toolbar_hbox.set_spacing (2);
3183         toolbar_hbox.set_border_width (2);
3184
3185         toolbar_hbox.pack_start (*mode_box, false, false);
3186
3187         if (!ARDOUR::Profile->get_trx()) {
3188
3189                 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3190
3191                 toolbar_hbox.pack_start (_zoom_box, false, false);
3192
3193                 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3194
3195                 toolbar_hbox.pack_start (_track_box, false, false);
3196
3197                 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3198
3199                 toolbar_hbox.pack_start (snap_box, false, false);
3200
3201                 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3202
3203                 toolbar_hbox.pack_start (*ep_box, false, false);
3204
3205                 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3206
3207                 toolbar_hbox.pack_start (*nudge_box, false, false);
3208         }
3209
3210         toolbar_hbox.show_all ();
3211 }
3212
3213 void
3214 Editor::build_edit_point_menu ()
3215 {
3216         using namespace Menu_Helpers;
3217
3218         edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3219         if(!Profile->get_mixbus())
3220                 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3221         edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3222
3223         set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3224 }
3225
3226 void
3227 Editor::build_edit_mode_menu ()
3228 {
3229         using namespace Menu_Helpers;
3230
3231         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3232 //      edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3233         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3234         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode)  Lock)));
3235
3236         set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3237 }
3238
3239 void
3240 Editor::build_snap_mode_menu ()
3241 {
3242         using namespace Menu_Helpers;
3243
3244         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3245         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3246         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3247
3248         set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3249 }
3250
3251 void
3252 Editor::build_snap_type_menu ()
3253 {
3254         using namespace Menu_Helpers;
3255
3256         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3257         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3258         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3259         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3260         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3261         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3262         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3263         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3264         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3265         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3266         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3267         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3268         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3269         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3270         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3271         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3272         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3273         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3274         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3275         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3276         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3277         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3278         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3279         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3280         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3281         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3282         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3283         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3284         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3285         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3286
3287         set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3288
3289 }
3290
3291 void
3292 Editor::setup_tooltips ()
3293 {
3294         set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3295         set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3296         set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3297         set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3298         set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3299         set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3300         set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3301         set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3302         set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3303         set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3304         set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3305         set_tooltip (zoom_in_button, _("Zoom In"));
3306         set_tooltip (zoom_out_button, _("Zoom Out"));
3307         set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3308         set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3309         set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3310         set_tooltip (tav_expand_button, _("Expand Tracks"));
3311         set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3312         set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3313         set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3314         set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3315         set_tooltip (edit_point_selector, _("Edit Point"));
3316         set_tooltip (edit_mode_selector, _("Edit Mode"));
3317         set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3318 }
3319
3320 int
3321 Editor::convert_drop_to_paths (
3322                 vector<string>&                paths,
3323                 const RefPtr<Gdk::DragContext>& /*context*/,
3324                 gint                            /*x*/,
3325                 gint                            /*y*/,
3326                 const SelectionData&            data,
3327                 guint                           /*info*/,
3328                 guint                           /*time*/)
3329 {
3330         if (_session == 0) {
3331                 return -1;
3332         }
3333
3334         vector<string> uris = data.get_uris();
3335
3336         if (uris.empty()) {
3337
3338                 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3339                    are actually URI lists. So do it by hand.
3340                 */
3341
3342                 if (data.get_target() != "text/plain") {
3343                         return -1;
3344                 }
3345
3346                 /* Parse the "uri-list" format that Nautilus provides,
3347                    where each pathname is delimited by \r\n.
3348
3349                    THERE MAY BE NO NULL TERMINATING CHAR!!!
3350                 */
3351
3352                 string txt = data.get_text();
3353                 char* p;
3354                 const char* q;
3355
3356                 p = (char *) malloc (txt.length() + 1);
3357                 txt.copy (p, txt.length(), 0);
3358                 p[txt.length()] = '\0';
3359
3360                 while (p)
3361                 {
3362                         if (*p != '#')
3363                         {
3364                                 while (g_ascii_isspace (*p))
3365                                         p++;
3366
3367                                 q = p;
3368                                 while (*q && (*q != '\n') && (*q != '\r')) {
3369                                         q++;
3370                                 }
3371
3372                                 if (q > p)
3373                                 {
3374                                         q--;
3375                                         while (q > p && g_ascii_isspace (*q))
3376                                                 q--;
3377
3378                                         if (q > p)
3379                                         {
3380                                                 uris.push_back (string (p, q - p + 1));
3381                                         }
3382                                 }
3383                         }
3384                         p = strchr (p, '\n');
3385                         if (p)
3386                                 p++;
3387                 }
3388
3389                 free ((void*)p);
3390
3391                 if (uris.empty()) {
3392                         return -1;
3393                 }
3394         }
3395
3396         for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3397                 if ((*i).substr (0,7) == "file://") {
3398                         paths.push_back (Glib::filename_from_uri (*i));
3399                 }
3400         }
3401
3402         return 0;
3403 }
3404
3405 void
3406 Editor::new_tempo_section ()
3407 {
3408 }
3409
3410 void
3411 Editor::map_transport_state ()
3412 {
3413         ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3414
3415         if (_session && _session->transport_stopped()) {
3416                 have_pending_keyboard_selection = false;
3417         }
3418
3419         update_loop_range_view ();
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         framepos_t offset_pos = pos + offset;
4036         snap_to(offset_pos, RoundUpMaybe);
4037         offset = offset_pos - 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 (vc.time_origin / samples_per_pixel);
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         switch (ep) {
4709         case EditAtPlayhead:
4710                 if (_dragging_playhead) {
4711                         where = *_control_scroll_target;
4712                 } else {
4713                         where = _session->audible_frame();
4714                 }
4715                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4716                 break;
4717
4718         case EditAtSelectedMarker:
4719                 if (!selection->markers.empty()) {
4720                         bool is_start;
4721                         Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4722                         if (loc) {
4723                                 if (is_start) {
4724                                         where =  loc->start();
4725                                 } else {
4726                                         where = loc->end();
4727                                 }
4728                                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4729                                 break;
4730                         }
4731                 }
4732                 /* fallthru */
4733
4734         default:
4735         case EditAtMouse:
4736                 if (!mouse_frame (where, ignored)) {
4737                         /* XXX not right but what can we do ? */
4738                         return 0;
4739                 }
4740                 snap_to (where);
4741                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4742                 break;
4743         }
4744
4745         return where;
4746 }
4747
4748 void
4749 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4750 {
4751         if (!_session) return;
4752
4753         begin_reversible_command (cmd);
4754
4755         Location* tll;
4756
4757         if ((tll = transport_loop_location()) == 0) {
4758                 Location* loc = new Location (*_session, start, end, _("Loop"),  Location::IsAutoLoop);
4759                 XMLNode &before = _session->locations()->get_state();
4760                 _session->locations()->add (loc, true);
4761                 _session->set_auto_loop_location (loc);
4762                 XMLNode &after = _session->locations()->get_state();
4763                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4764         } else {
4765                 XMLNode &before = tll->get_state();
4766                 tll->set_hidden (false, this);
4767                 tll->set (start, end);
4768                 XMLNode &after = tll->get_state();
4769                 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4770         }
4771
4772         commit_reversible_command ();
4773 }
4774
4775 void
4776 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4777 {
4778         if (!_session) return;
4779
4780         begin_reversible_command (cmd);
4781
4782         Location* tpl;
4783
4784         if ((tpl = transport_punch_location()) == 0) {
4785                 Location* loc = new Location (*_session, start, end, _("Punch"),  Location::IsAutoPunch);
4786                 XMLNode &before = _session->locations()->get_state();
4787                 _session->locations()->add (loc, true);
4788                 _session->set_auto_punch_location (loc);
4789                 XMLNode &after = _session->locations()->get_state();
4790                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4791         } else {
4792                 XMLNode &before = tpl->get_state();
4793                 tpl->set_hidden (false, this);
4794                 tpl->set (start, end);
4795                 XMLNode &after = tpl->get_state();
4796                 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4797         }
4798
4799         commit_reversible_command ();
4800 }
4801
4802 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4803  *  @param rs List to which found regions are added.
4804  *  @param where Time to look at.
4805  *  @param ts Tracks to look on; if this is empty, all tracks are examined.
4806  */
4807 void
4808 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4809 {
4810         const TrackViewList* tracks;
4811
4812         if (ts.empty()) {
4813                 tracks = &track_views;
4814         } else {
4815                 tracks = &ts;
4816         }
4817
4818         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4819
4820                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4821
4822                 if (rtv) {
4823                         boost::shared_ptr<Track> tr;
4824                         boost::shared_ptr<Playlist> pl;
4825
4826                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4827
4828                                 boost::shared_ptr<RegionList> regions = pl->regions_at (
4829                                                 (framepos_t) floor ( (double) where * tr->speed()));
4830
4831                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4832                                         RegionView* rv = rtv->view()->find_view (*i);
4833                                         if (rv) {
4834                                                 rs.add (rv);
4835                                         }
4836                                 }
4837                         }
4838                 }
4839         }
4840 }
4841
4842 void
4843 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4844 {
4845         const TrackViewList* tracks;
4846
4847         if (ts.empty()) {
4848                 tracks = &track_views;
4849         } else {
4850                 tracks = &ts;
4851         }
4852
4853         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4854                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4855                 if (rtv) {
4856                         boost::shared_ptr<Track> tr;
4857                         boost::shared_ptr<Playlist> pl;
4858
4859                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4860
4861                                 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4862                                         (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4863
4864                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4865
4866                                         RegionView* rv = rtv->view()->find_view (*i);
4867
4868                                         if (rv) {
4869                                                 rs.add (rv);
4870                                         }
4871                                 }
4872                         }
4873                 }
4874         }
4875 }
4876
4877 /** Get regions using the following method:
4878  *
4879  *  Make a region list using:
4880  *   (a) any selected regions
4881  *   (b) the intersection of any selected tracks and the edit point(*)
4882  *   (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4883  *
4884  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4885  *
4886  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4887  */
4888
4889 RegionSelection
4890 Editor::get_regions_from_selection_and_edit_point ()
4891 {
4892         RegionSelection regions;
4893
4894         if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4895                 regions.add (entered_regionview);
4896         } else {
4897                 regions = selection->regions;
4898         }
4899
4900         if ( regions.empty() ) {
4901                 TrackViewList tracks = selection->tracks;
4902
4903                 if (!tracks.empty()) {
4904                         /* no region selected or entered, but some selected tracks:
4905                          * act on all regions on the selected tracks at the edit point
4906                          */
4907                         framepos_t const where = get_preferred_edit_position ();
4908                         get_regions_at(regions, where, tracks);
4909                 }
4910         }
4911
4912         return regions;
4913 }
4914
4915 /** Get regions using the following method:
4916  *
4917  *  Make a region list using:
4918  *   (a) any selected regions
4919  *   (b) the intersection of any selected tracks and the edit point(*)
4920  *   (c) if neither exists, then whatever region is under the mouse
4921  *
4922  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4923  *
4924  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4925  */
4926 RegionSelection
4927 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4928 {
4929         RegionSelection regions;
4930
4931         if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4932                 regions.add (entered_regionview);
4933         } else {
4934                 regions = selection->regions;
4935         }
4936
4937         if ( regions.empty() ) {
4938                 TrackViewList tracks = selection->tracks;
4939
4940                 if (!tracks.empty()) {
4941                         /* no region selected or entered, but some selected tracks:
4942                          * act on all regions on the selected tracks at the edit point
4943                          */
4944                         get_regions_at(regions, pos, tracks);
4945                 }
4946         }
4947
4948         return regions;
4949 }
4950
4951 /** Start with regions that are selected, or the entered regionview if none are selected.
4952  *  Then add equivalent regions on tracks in the same active edit-enabled route group as any
4953  *  of the regions that we started with.
4954  */
4955
4956 RegionSelection
4957 Editor::get_regions_from_selection_and_entered () const
4958 {
4959         RegionSelection regions = selection->regions;
4960
4961         if (regions.empty() && entered_regionview) {
4962                 regions.add (entered_regionview);
4963         }
4964
4965         return regions;
4966 }
4967
4968 void
4969 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4970 {
4971         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4972                 RouteTimeAxisView* rtav;
4973
4974                 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4975                         boost::shared_ptr<Playlist> pl;
4976                         std::vector<boost::shared_ptr<Region> > results;
4977                         boost::shared_ptr<Track> tr;
4978
4979                         if ((tr = rtav->track()) == 0) {
4980                                 /* bus */
4981                                 continue;
4982                         }
4983
4984                         if ((pl = (tr->playlist())) != 0) {
4985                                 boost::shared_ptr<Region> r = pl->region_by_id (id);
4986                                 if (r) {
4987                                         RegionView* rv = rtav->view()->find_view (r);
4988                                         if (rv) {
4989                                                 regions.push_back (rv);
4990                                         }
4991                                 }
4992                         }
4993                 }
4994         }
4995 }
4996
4997 void
4998 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4999 {
5000
5001         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5002                 MidiTimeAxisView* mtav;
5003
5004                 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5005
5006                         mtav->get_per_region_note_selection (selection);
5007                 }
5008         }
5009
5010 }
5011
5012 void
5013 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5014 {
5015         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5016
5017                 RouteTimeAxisView* tatv;
5018
5019                 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5020
5021                         boost::shared_ptr<Playlist> pl;
5022                         vector<boost::shared_ptr<Region> > results;
5023                         RegionView* marv;
5024                         boost::shared_ptr<Track> tr;
5025
5026                         if ((tr = tatv->track()) == 0) {
5027                                 /* bus */
5028                                 continue;
5029                         }
5030
5031                         if ((pl = (tr->playlist())) != 0) {
5032                                 if (src_comparison) {
5033                                         pl->get_source_equivalent_regions (region, results);
5034                                 } else {
5035                                         pl->get_region_list_equivalent_regions (region, results);
5036                                 }
5037                         }
5038
5039                         for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5040                                 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5041                                         regions.push_back (marv);
5042                                 }
5043                         }
5044
5045                 }
5046         }
5047 }
5048
5049 void
5050 Editor::show_rhythm_ferret ()
5051 {
5052         if (rhythm_ferret == 0) {
5053                 rhythm_ferret = new RhythmFerret(*this);
5054         }
5055
5056         rhythm_ferret->set_session (_session);
5057         rhythm_ferret->show ();
5058         rhythm_ferret->present ();
5059 }
5060
5061 void
5062 Editor::first_idle ()
5063 {
5064         MessageDialog* dialog = 0;
5065
5066         if (track_views.size() > 1) {
5067                 Timers::TimerSuspender t;
5068                 dialog = new MessageDialog (
5069                         string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5070                         true
5071                         );
5072                 dialog->present ();
5073                 ARDOUR_UI::instance()->flush_pending (60);
5074         }
5075
5076         for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5077                 (*t)->first_idle();
5078         }
5079
5080         // first idle adds route children (automation tracks), so we need to redisplay here
5081         _routes->redisplay ();
5082
5083         delete dialog;
5084
5085         if (_session->undo_depth() == 0) {
5086                 undo_action->set_sensitive(false);
5087         }
5088         redo_action->set_sensitive(false);
5089         begin_selection_op_history ();
5090
5091         _have_idled = true;
5092 }
5093
5094 gboolean
5095 Editor::_idle_resize (gpointer arg)
5096 {
5097         return ((Editor*)arg)->idle_resize ();
5098 }
5099
5100 void
5101 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5102 {
5103         if (resize_idle_id < 0) {
5104                 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5105                  * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5106                  * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5107                  */
5108                 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5109                 _pending_resize_amount = 0;
5110         }
5111
5112         /* make a note of the smallest resulting height, so that we can clamp the
5113            lower limit at TimeAxisView::hSmall */
5114
5115         int32_t min_resulting = INT32_MAX;
5116
5117         _pending_resize_amount += h;
5118         _pending_resize_view = view;
5119
5120         min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5121
5122         if (selection->tracks.contains (_pending_resize_view)) {
5123                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5124                         min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5125                 }
5126         }
5127
5128         if (min_resulting < 0) {
5129                 min_resulting = 0;
5130         }
5131
5132         /* clamp */
5133         if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5134                 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5135         }
5136 }
5137
5138 /** Handle pending resizing of tracks */
5139 bool
5140 Editor::idle_resize ()
5141 {
5142         _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5143
5144         if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5145             selection->tracks.contains (_pending_resize_view)) {
5146
5147                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5148                         if (*i != _pending_resize_view) {
5149                                 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5150                         }
5151                 }
5152         }
5153
5154         _pending_resize_amount = 0;
5155         _group_tabs->set_dirty ();
5156         resize_idle_id = -1;
5157
5158         return false;
5159 }
5160
5161 void
5162 Editor::located ()
5163 {
5164         ENSURE_GUI_THREAD (*this, &Editor::located);
5165
5166         if (_session) {
5167                 playhead_cursor->set_position (_session->audible_frame ());
5168                 if (_follow_playhead && !_pending_initial_locate) {
5169                         reset_x_origin_to_follow_playhead ();
5170                 }
5171         }
5172
5173         _pending_locate_request = false;
5174         _pending_initial_locate = false;
5175 }
5176
5177 void
5178 Editor::region_view_added (RegionView * rv)
5179 {
5180         for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5181                 if (rv->region ()->id () == (*pr)) {
5182                         selection->add (rv);
5183                         selection->regions.pending.erase (pr);
5184                         break;
5185                 }
5186         }
5187
5188         MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5189         if (mrv) {
5190                 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5191                 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5192                         if (rv->region()->id () == (*rnote).first) {
5193                                 mrv->select_notes ((*rnote).second);
5194                                 selection->pending_midi_note_selection.erase(rnote);
5195                                 break;
5196                         }
5197                 }
5198         }
5199
5200         _summary->set_background_dirty ();
5201 }
5202
5203 void
5204 Editor::region_view_removed ()
5205 {
5206         _summary->set_background_dirty ();
5207 }
5208
5209 TimeAxisView*
5210 Editor::axis_view_from_stripable (boost::shared_ptr<Stripable> s) const
5211 {
5212         for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5213                 if ((*j)->stripable() == s) {
5214                         return *j;
5215                 }
5216         }
5217
5218         return 0;
5219 }
5220
5221
5222 TrackViewList
5223 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5224 {
5225         TrackViewList t;
5226
5227         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5228                 TimeAxisView* tv = axis_view_from_stripable (*i);
5229                 if (tv) {
5230                         t.push_back (tv);
5231                 }
5232         }
5233
5234         return t;
5235 }
5236
5237 void
5238 Editor::suspend_route_redisplay ()
5239 {
5240         if (_routes) {
5241                 _routes->suspend_redisplay();
5242         }
5243 }
5244
5245 void
5246 Editor::resume_route_redisplay ()
5247 {
5248         if (_routes) {
5249                 _routes->redisplay(); // queue redisplay
5250                 _routes->resume_redisplay();
5251         }
5252 }
5253
5254 void
5255 Editor::add_vcas (VCAList& vlist)
5256 {
5257         StripableList sl;
5258
5259         for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5260                 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5261         }
5262
5263         add_stripables (sl);
5264 }
5265
5266 void
5267 Editor::add_routes (RouteList& rlist)
5268 {
5269         StripableList sl;
5270
5271         for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5272                 sl.push_back (*r);
5273         }
5274
5275         add_stripables (sl);
5276 }
5277
5278 void
5279 Editor::add_stripables (StripableList& sl)
5280 {
5281         list<TimeAxisView*> new_views;
5282         boost::shared_ptr<VCA> v;
5283         boost::shared_ptr<Route> r;
5284         TrackViewList new_selection;
5285         bool from_scratch = (track_views.size() == 0);
5286
5287         sl.sort (StripablePresentationInfoSorter());
5288
5289         for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5290
5291                 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5292
5293                         VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5294                         vtv->set_vca (v);
5295                         new_views.push_back (vtv);
5296
5297                 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5298
5299                         if (r->is_auditioner() || r->is_monitor()) {
5300                                 continue;
5301                         }
5302
5303                         RouteTimeAxisView* rtv;
5304                         DataType dt = r->input()->default_type();
5305
5306                         if (dt == ARDOUR::DataType::AUDIO) {
5307                                 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5308                                 rtv->set_route (r);
5309                         } else if (dt == ARDOUR::DataType::MIDI) {
5310                                 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5311                                 rtv->set_route (r);
5312                         } else {
5313                                 throw unknown_type();
5314                         }
5315
5316                         new_views.push_back (rtv);
5317                         track_views.push_back (rtv);
5318                         new_selection.push_back (rtv);
5319
5320                         rtv->effective_gain_display ();
5321
5322                         rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5323                         rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5324                 }
5325         }
5326
5327         if (new_views.size() > 0) {
5328                 _routes->time_axis_views_added (new_views);
5329                 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5330         }
5331
5332         /* note: !new_selection.empty() means that we got some routes rather
5333          * than just VCAs
5334          */
5335
5336         if (!from_scratch && !new_selection.empty()) {
5337                 selection->tracks.clear();
5338                 selection->add (new_selection);
5339                 begin_selection_op_history();
5340         }
5341
5342         if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5343                 show_editor_mixer (true);
5344         }
5345
5346         editor_list_button.set_sensitive (true);
5347 }
5348
5349 void
5350 Editor::timeaxisview_deleted (TimeAxisView *tv)
5351 {
5352         if (tv == entered_track) {
5353                 entered_track = 0;
5354         }
5355
5356         if (_session && _session->deletion_in_progress()) {
5357                 /* the situation is under control */
5358                 return;
5359         }
5360
5361         ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5362
5363         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5364
5365         _routes->route_removed (tv);
5366
5367         TimeAxisView::Children c = tv->get_child_list ();
5368         for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5369                 if (entered_track == i->get()) {
5370                         entered_track = 0;
5371                 }
5372         }
5373
5374         /* remove it from the list of track views */
5375
5376         TrackViewList::iterator i;
5377
5378         if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5379                 i = track_views.erase (i);
5380         }
5381
5382         /* update whatever the current mixer strip is displaying, if revelant */
5383
5384         boost::shared_ptr<Route> route;
5385
5386         if (rtav) {
5387                 route = rtav->route ();
5388         }
5389
5390         if (current_mixer_strip && current_mixer_strip->route() == route) {
5391
5392                 TimeAxisView* next_tv;
5393
5394                 if (track_views.empty()) {
5395                         next_tv = 0;
5396                 } else if (i == track_views.end()) {
5397                         next_tv = track_views.front();
5398                 } else {
5399                         next_tv = (*i);
5400                 }
5401
5402
5403                 if (next_tv) {
5404                         set_selected_mixer_strip (*next_tv);
5405                 } else {
5406                         /* make the editor mixer strip go away setting the
5407                          * button to inactive (which also unticks the menu option)
5408                          */
5409
5410                         ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5411                 }
5412         }
5413 }
5414
5415 void
5416 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5417 {
5418         if (apply_to_selection) {
5419                 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5420
5421                         TrackSelection::iterator j = i;
5422                         ++j;
5423
5424                         hide_track_in_display (*i, false);
5425
5426                         i = j;
5427                 }
5428         } else {
5429                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5430
5431                 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5432                         // this will hide the mixer strip
5433                         set_selected_mixer_strip (*tv);
5434                 }
5435
5436                 _routes->hide_track_in_display (*tv);
5437         }
5438 }
5439
5440 bool
5441 Editor::sync_track_view_list_and_routes ()
5442 {
5443         track_views = TrackViewList (_routes->views ());
5444
5445         _summary->set_background_dirty();
5446         _group_tabs->set_dirty ();
5447
5448         return false; // do not call again (until needed)
5449 }
5450
5451 void
5452 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5453 {
5454         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5455                 theslot (**i);
5456         }
5457 }
5458
5459 /** Find a RouteTimeAxisView by the ID of its route */
5460 RouteTimeAxisView*
5461 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5462 {
5463         RouteTimeAxisView* v;
5464
5465         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5466                 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5467                         if(v->route()->id() == id) {
5468                                 return v;
5469                         }
5470                 }
5471         }
5472
5473         return 0;
5474 }
5475
5476 void
5477 Editor::fit_route_group (RouteGroup *g)
5478 {
5479         TrackViewList ts = axis_views_from_routes (g->route_list ());
5480         fit_tracks (ts);
5481 }
5482
5483 void
5484 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5485 {
5486         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5487
5488         if (r == 0) {
5489                 _session->cancel_audition ();
5490                 return;
5491         }
5492
5493         if (_session->is_auditioning()) {
5494                 _session->cancel_audition ();
5495                 if (r == last_audition_region) {
5496                         return;
5497                 }
5498         }
5499
5500         _session->audition_region (r);
5501         last_audition_region = r;
5502 }
5503
5504
5505 void
5506 Editor::hide_a_region (boost::shared_ptr<Region> r)
5507 {
5508         r->set_hidden (true);
5509 }
5510
5511 void
5512 Editor::show_a_region (boost::shared_ptr<Region> r)
5513 {
5514         r->set_hidden (false);
5515 }
5516
5517 void
5518 Editor::audition_region_from_region_list ()
5519 {
5520         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5521 }
5522
5523 void
5524 Editor::hide_region_from_region_list ()
5525 {
5526         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5527 }
5528
5529 void
5530 Editor::show_region_in_region_list ()
5531 {
5532         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5533 }
5534
5535 void
5536 Editor::step_edit_status_change (bool yn)
5537 {
5538         if (yn) {
5539                 start_step_editing ();
5540         } else {
5541                 stop_step_editing ();
5542         }
5543 }
5544
5545 void
5546 Editor::start_step_editing ()
5547 {
5548         step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5549 }
5550
5551 void
5552 Editor::stop_step_editing ()
5553 {
5554         step_edit_connection.disconnect ();
5555 }
5556
5557 bool
5558 Editor::check_step_edit ()
5559 {
5560         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5561                 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5562                 if (mtv) {
5563                         mtv->check_step_edit ();
5564                 }
5565         }
5566
5567         return true; // do it again, till we stop
5568 }
5569
5570 bool
5571 Editor::scroll_press (Direction dir)
5572 {
5573         ++_scroll_callbacks;
5574
5575         if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5576                 /* delay the first auto-repeat */
5577                 return true;
5578         }
5579
5580         switch (dir) {
5581         case LEFT:
5582                 scroll_backward (1);
5583                 break;
5584
5585         case RIGHT:
5586                 scroll_forward (1);
5587                 break;
5588
5589         case UP:
5590                 scroll_up_one_track ();
5591                 break;
5592
5593         case DOWN:
5594                 scroll_down_one_track ();
5595                 break;
5596         }
5597
5598         /* do hacky auto-repeat */
5599         if (!_scroll_connection.connected ()) {
5600
5601                 _scroll_connection = Glib::signal_timeout().connect (
5602                         sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5603                         );
5604
5605                 _scroll_callbacks = 0;
5606         }
5607
5608         return true;
5609 }
5610
5611 void
5612 Editor::scroll_release ()
5613 {
5614         _scroll_connection.disconnect ();
5615 }
5616
5617 /** Queue a change for the Editor viewport x origin to follow the playhead */
5618 void
5619 Editor::reset_x_origin_to_follow_playhead ()
5620 {
5621         framepos_t const frame = playhead_cursor->current_frame ();
5622
5623         if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5624
5625                 if (_session->transport_speed() < 0) {
5626
5627                         if (frame > (current_page_samples() / 2)) {
5628                                 center_screen (frame-(current_page_samples()/2));
5629                         } else {
5630                                 center_screen (current_page_samples()/2);
5631                         }
5632
5633                 } else {
5634
5635                         framepos_t l = 0;
5636
5637                         if (frame < leftmost_frame) {
5638                                 /* moving left */
5639                                 if (_session->transport_rolling()) {
5640                                         /* rolling; end up with the playhead at the right of the page */
5641                                         l = frame - current_page_samples ();
5642                                 } else {
5643                                         /* not rolling: end up with the playhead 1/4 of the way along the page */
5644                                         l = frame - current_page_samples() / 4;
5645                                 }
5646                         } else {
5647                                 /* moving right */
5648                                 if (_session->transport_rolling()) {
5649                                         /* rolling: end up with the playhead on the left of the page */
5650                                         l = frame;
5651                                 } else {
5652                                         /* not rolling: end up with the playhead 3/4 of the way along the page */
5653                                         l = frame - 3 * current_page_samples() / 4;
5654                                 }
5655                         }
5656
5657                         if (l < 0) {
5658                                 l = 0;
5659                         }
5660
5661                         center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5662                 }
5663         }
5664 }
5665
5666 void
5667 Editor::super_rapid_screen_update ()
5668 {
5669         if (!_session || !_session->engine().running()) {
5670                 return;
5671         }
5672
5673         /* METERING / MIXER STRIPS */
5674
5675         /* update track meters, if required */
5676         if (contents().is_mapped() && meters_running) {
5677                 RouteTimeAxisView* rtv;
5678                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5679                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5680                                 rtv->fast_update ();
5681                         }
5682                 }
5683         }
5684
5685         /* and any current mixer strip */
5686         if (current_mixer_strip) {
5687                 current_mixer_strip->fast_update ();
5688         }
5689
5690         /* PLAYHEAD AND VIEWPORT */
5691
5692         framepos_t const frame = _session->audible_frame();
5693
5694         /* There are a few reasons why we might not update the playhead / viewport stuff:
5695          *
5696          * 1.  we don't update things when there's a pending locate request, otherwise
5697          *     when the editor requests a locate there is a chance that this method
5698          *     will move the playhead before the locate request is processed, causing
5699          *     a visual glitch.
5700          * 2.  if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5701          * 3.  if we're still at the same frame that we were last time, there's nothing to do.
5702          */
5703
5704         if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5705
5706                 last_update_frame = frame;
5707
5708                 if (!_dragging_playhead) {
5709                         playhead_cursor->set_position (frame);
5710                 }
5711
5712                 if (!_stationary_playhead) {
5713
5714                         if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5715                                 /* We only do this if we aren't already
5716                                    handling a visual change (ie if
5717                                    pending_visual_change.being_handled is
5718                                    false) so that these requests don't stack
5719                                    up there are too many of them to handle in
5720                                    time.
5721                                 */
5722                                 reset_x_origin_to_follow_playhead ();
5723                         }
5724
5725                 } else {
5726
5727                         if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5728                                 framepos_t const frame = playhead_cursor->current_frame ();
5729                                 double target = ((double)frame - (double)current_page_samples()/2.0);
5730                                 if (target <= 0.0) {
5731                                         target = 0.0;
5732                                 }
5733                                 // compare to EditorCursor::set_position()
5734                                 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5735                                 double const new_pos = sample_to_pixel_unrounded (target);
5736                                 if (rint (new_pos) != rint (old_pos)) {
5737                                         reset_x_origin (pixel_to_sample (floor (new_pos)));
5738                                 }
5739                         }
5740
5741                 }
5742
5743         }
5744 }
5745
5746
5747 void
5748 Editor::session_going_away ()
5749 {
5750         _have_idled = false;
5751
5752         _session_connections.drop_connections ();
5753
5754         super_rapid_screen_update_connection.disconnect ();
5755
5756         selection->clear ();
5757         cut_buffer->clear ();
5758
5759         clicked_regionview = 0;
5760         clicked_axisview = 0;
5761         clicked_routeview = 0;
5762         entered_regionview = 0;
5763         entered_track = 0;
5764         last_update_frame = 0;
5765         _drags->abort ();
5766
5767         playhead_cursor->hide ();
5768
5769         /* rip everything out of the list displays */
5770
5771         _regions->clear ();
5772         _routes->clear ();
5773         _route_groups->clear ();
5774
5775         /* do this first so that deleting a track doesn't reset cms to null
5776            and thus cause a leak.
5777         */
5778
5779         if (current_mixer_strip) {
5780                 if (current_mixer_strip->get_parent() != 0) {
5781                         global_hpacker.remove (*current_mixer_strip);
5782                 }
5783                 delete current_mixer_strip;
5784                 current_mixer_strip = 0;
5785         }
5786
5787         /* delete all trackviews */
5788
5789         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5790                 delete *i;
5791         }
5792         track_views.clear ();
5793
5794         nudge_clock->set_session (0);
5795
5796         editor_list_button.set_active(false);
5797         editor_list_button.set_sensitive(false);
5798
5799         /* clear tempo/meter rulers */
5800         remove_metric_marks ();
5801         hide_measures ();
5802         clear_marker_display ();
5803
5804         stop_step_editing ();
5805
5806         if (own_window()) {
5807
5808                 /* get rid of any existing editor mixer strip */
5809
5810                 WindowTitle title(Glib::get_application_name());
5811                 title += _("Editor");
5812
5813                 own_window()->set_title (title.get_string());
5814         }
5815
5816         SessionHandlePtr::session_going_away ();
5817 }
5818
5819 void
5820 Editor::trigger_script (int i)
5821 {
5822         LuaInstance::instance()-> call_action (i);
5823 }
5824
5825 void
5826 Editor::set_script_action_name (int i, const std::string& n)
5827 {
5828         string const a = string_compose (X_("script-action-%1"), i + 1);
5829         Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5830         assert (act);
5831         if (n.empty ()) {
5832                 act->set_label (string_compose (_("Unset #%1"), i + 1));
5833                 act->set_tooltip (_("no action bound"));
5834                 act->set_sensitive (false);
5835         } else {
5836                 act->set_label (n);
5837                 act->set_tooltip (n);
5838                 act->set_sensitive (true);
5839         }
5840         KeyEditor::UpdateBindings ();
5841 }
5842
5843 void
5844 Editor::show_editor_list (bool yn)
5845 {
5846         if (yn) {
5847                 _the_notebook.show ();
5848         } else {
5849                 _the_notebook.hide ();
5850         }
5851 }
5852
5853 void
5854 Editor::change_region_layering_order (bool from_context_menu)
5855 {
5856         const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5857
5858         if (!clicked_routeview) {
5859                 if (layering_order_editor) {
5860                         layering_order_editor->hide ();
5861                 }
5862                 return;
5863         }
5864
5865         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5866
5867         if (!track) {
5868                 return;
5869         }
5870
5871         boost::shared_ptr<Playlist> pl = track->playlist();
5872
5873         if (!pl) {
5874                 return;
5875         }
5876
5877         if (layering_order_editor == 0) {
5878                 layering_order_editor = new RegionLayeringOrderEditor (*this);
5879         }
5880
5881         layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5882         layering_order_editor->maybe_present ();
5883 }
5884
5885 void
5886 Editor::update_region_layering_order_editor ()
5887 {
5888         if (layering_order_editor && layering_order_editor->is_visible ()) {
5889                 change_region_layering_order (true);
5890         }
5891 }
5892
5893 void
5894 Editor::setup_fade_images ()
5895 {
5896         _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5897         _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5898         _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5899         _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5900         _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5901
5902         _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5903         _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5904         _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5905         _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5906         _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5907
5908         _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5909         _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5910         _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5911         _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5912         _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5913
5914         _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5915         _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5916         _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5917         _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5918         _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5919
5920 }
5921
5922 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5923 Gtk::MenuItem&
5924 Editor::action_menu_item (std::string const & name)
5925 {
5926         Glib::RefPtr<Action> a = editor_actions->get_action (name);
5927         assert (a);
5928
5929         return *manage (a->create_menu_item ());
5930 }
5931
5932 void
5933 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5934 {
5935         EventBox* b = manage (new EventBox);
5936         b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5937         Label* l = manage (new Label (name));
5938         l->set_angle (-90);
5939         b->add (*l);
5940         b->show_all ();
5941         _the_notebook.append_page (widget, *b);
5942 }
5943
5944 bool
5945 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5946 {
5947         if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5948                 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5949         }
5950
5951         if (ev->type == GDK_2BUTTON_PRESS) {
5952
5953                 /* double-click on a notebook tab shrinks or expands the notebook */
5954
5955                 if (_notebook_shrunk) {
5956                         if (pre_notebook_shrink_pane_width) {
5957                                 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
5958                         }
5959                         _notebook_shrunk = false;
5960                 } else {
5961                         pre_notebook_shrink_pane_width = edit_pane.get_divider();
5962
5963                         /* this expands the LHS of the edit pane to cover the notebook
5964                            PAGE but leaves the tabs visible.
5965                          */
5966                         edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
5967                         _notebook_shrunk = true;
5968                 }
5969         }
5970
5971         return true;
5972 }
5973
5974 void
5975 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5976 {
5977         using namespace Menu_Helpers;
5978
5979         MenuList& items = _control_point_context_menu.items ();
5980         items.clear ();
5981
5982         items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5983         items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5984         if (!can_remove_control_point (item)) {
5985                 items.back().set_sensitive (false);
5986         }
5987
5988         _control_point_context_menu.popup (event->button.button, event->button.time);
5989 }
5990
5991 void
5992 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5993 {
5994         using namespace Menu_Helpers;
5995
5996         NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5997         if (!note) {
5998                 return;
5999         }
6000
6001         /* We need to get the selection here and pass it to the operations, since
6002            popping up the menu will cause a region leave event which clears
6003            entered_regionview. */
6004
6005         MidiRegionView&       mrv = note->region_view();
6006         const RegionSelection rs  = get_regions_from_selection_and_entered ();
6007         const uint32_t sel_size = mrv.selection_size ();
6008
6009         MenuList& items = _note_context_menu.items();
6010         items.clear();
6011
6012         if (sel_size > 0) {
6013                 items.push_back(MenuElem(_("Delete"),
6014                                          sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6015         }
6016
6017         items.push_back(MenuElem(_("Edit..."),
6018                                  sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6019         if (sel_size != 1) {
6020                 items.back().set_sensitive (false);
6021         }
6022
6023         items.push_back(MenuElem(_("Transpose..."),
6024                                  sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6025
6026
6027         items.push_back(MenuElem(_("Legatize"),
6028                                  sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6029         if (sel_size < 2) {
6030                 items.back().set_sensitive (false);
6031         }
6032
6033         items.push_back(MenuElem(_("Quantize..."),
6034                                  sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6035
6036         items.push_back(MenuElem(_("Remove Overlap"),
6037                                  sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6038         if (sel_size < 2) {
6039                 items.back().set_sensitive (false);
6040         }
6041
6042         items.push_back(MenuElem(_("Transform..."),
6043                                  sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6044
6045         _note_context_menu.popup (event->button.button, event->button.time);
6046 }
6047
6048 void
6049 Editor::zoom_vertical_modifier_released()
6050 {
6051         _stepping_axis_view = 0;
6052 }
6053
6054 void
6055 Editor::ui_parameter_changed (string parameter)
6056 {
6057         if (parameter == "icon-set") {
6058                 while (!_cursor_stack.empty()) {
6059                         _cursor_stack.pop_back();
6060                 }
6061                 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6062                 _cursor_stack.push_back(_cursors->grabber);
6063                 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6064                 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6065
6066         } else if (parameter == "draggable-playhead") {
6067                 if (_verbose_cursor) {
6068                         playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6069                 }
6070         }
6071 }
6072
6073 Gtk::Window*
6074 Editor::use_own_window (bool and_fill_it)
6075 {
6076         bool new_window = !own_window();
6077
6078         Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6079
6080         if (win && new_window) {
6081                 win->set_name ("EditorWindow");
6082
6083                 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6084
6085                 // win->signal_realize().connect (*this, &Editor::on_realize);
6086                 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6087                 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6088                 win->set_data ("ardour-bindings", bindings);
6089
6090                 update_title ();
6091         }
6092
6093         DisplaySuspender ds;
6094         contents().show_all ();
6095
6096         /* XXX: this is a bit unfortunate; it would probably
6097            be nicer if we could just call show () above rather
6098            than needing the show_all ()
6099         */
6100
6101         /* re-hide stuff if necessary */
6102         editor_list_button_toggled ();
6103         parameter_changed ("show-summary");
6104         parameter_changed ("show-group-tabs");
6105         parameter_changed ("show-zoom-tools");
6106
6107         /* now reset all audio_time_axis heights, because widgets might need
6108            to be re-hidden
6109         */
6110
6111         TimeAxisView *tv;
6112
6113         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6114                 tv = (static_cast<TimeAxisView*>(*i));
6115                 tv->reset_height ();
6116         }
6117
6118         if (current_mixer_strip) {
6119                 current_mixer_strip->hide_things ();
6120                 current_mixer_strip->parameter_changed ("mixer-element-visibility");
6121         }
6122
6123         return win;
6124 }