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