Add API to query editor's playhead cursor position
[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), Horizontal)));
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                 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
2243                 update_tempo_based_rulers ();
2244                 break;
2245         }
2246
2247         case SnapToRegionStart:
2248         case SnapToRegionEnd:
2249         case SnapToRegionSync:
2250         case SnapToRegionBoundary:
2251                 build_region_boundary_cache ();
2252                 break;
2253
2254         default:
2255                 /* relax */
2256                 break;
2257         }
2258
2259         redisplay_tempo (false);
2260
2261         SnapChanged (); /* EMIT SIGNAL */
2262 }
2263
2264 void
2265 Editor::set_snap_mode (SnapMode mode)
2266 {
2267         string str = snap_mode_strings[(int)mode];
2268
2269         if (internal_editing()) {
2270                 internal_snap_mode = mode;
2271         } else {
2272                 pre_internal_snap_mode = mode;
2273         }
2274
2275         _snap_mode = mode;
2276
2277         if (str != snap_mode_selector.get_text ()) {
2278                 snap_mode_selector.set_text (str);
2279         }
2280
2281         instant_save ();
2282 }
2283
2284 void
2285 Editor::set_edit_point_preference (EditPoint ep, bool force)
2286 {
2287         bool changed = (_edit_point != ep);
2288
2289         _edit_point = ep;
2290         if (Profile->get_mixbus())
2291                 if (ep == EditAtSelectedMarker)
2292                         ep = EditAtPlayhead;
2293
2294         string str = edit_point_strings[(int)ep];
2295         if (str != edit_point_selector.get_text ()) {
2296                 edit_point_selector.set_text (str);
2297         }
2298
2299         update_all_enter_cursors();
2300
2301         if (!force && !changed) {
2302                 return;
2303         }
2304
2305         const char* action=NULL;
2306
2307         switch (_edit_point) {
2308         case EditAtPlayhead:
2309                 action = "edit-at-playhead";
2310                 break;
2311         case EditAtSelectedMarker:
2312                 action = "edit-at-marker";
2313                 break;
2314         case EditAtMouse:
2315                 action = "edit-at-mouse";
2316                 break;
2317         }
2318
2319         Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2320         if (act) {
2321                 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2322         }
2323
2324         framepos_t foo;
2325         bool in_track_canvas;
2326
2327         if (!mouse_frame (foo, in_track_canvas)) {
2328                 in_track_canvas = false;
2329         }
2330
2331         reset_canvas_action_sensitivity (in_track_canvas);
2332
2333         instant_save ();
2334 }
2335
2336 int
2337 Editor::set_state (const XMLNode& node, int version)
2338 {
2339         XMLProperty const * prop;
2340         set_id (node);
2341         PBD::Unwinder<bool> nsi (no_save_instant, true);
2342         LocaleGuard lg;
2343
2344         Tabbable::set_state (node, version);
2345
2346         if (_session && (prop = node.property ("playhead"))) {
2347                 framepos_t pos;
2348                 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2349                 if (pos >= 0) {
2350                         playhead_cursor->set_position (pos);
2351                 } else {
2352                         warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2353                         playhead_cursor->set_position (0);
2354                 }
2355         } else {
2356                 playhead_cursor->set_position (0);
2357         }
2358
2359         if ((prop = node.property ("mixer-width"))) {
2360                 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2361         }
2362
2363         if ((prop = node.property ("zoom-focus"))) {
2364                 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2365         } else {
2366                 zoom_focus_selection_done (zoom_focus);
2367         }
2368
2369         if ((prop = node.property ("zoom"))) {
2370                 /* older versions of ardour used floating point samples_per_pixel */
2371                 double f = PBD::atof (prop->value());
2372                 reset_zoom (llrintf (f));
2373         } else {
2374                 reset_zoom (samples_per_pixel);
2375         }
2376
2377         if ((prop = node.property ("visible-track-count"))) {
2378                 set_visible_track_count (PBD::atoi (prop->value()));
2379         }
2380
2381         if ((prop = node.property ("snap-to"))) {
2382                 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2383                 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2384         } else {
2385                 set_snap_to (_snap_type);
2386         }
2387
2388         if ((prop = node.property ("snap-mode"))) {
2389                 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2390                 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2391                  * snap_mode_selection_done() will only mark an already active item as active
2392                  * which does not trigger set_text().
2393                  */
2394                 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2395         } else {
2396                 set_snap_mode (_snap_mode);
2397         }
2398
2399         if ((prop = node.property ("internal-snap-to"))) {
2400                 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2401         }
2402
2403         if ((prop = node.property ("internal-snap-mode"))) {
2404                 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2405         }
2406
2407         if ((prop = node.property ("pre-internal-snap-to"))) {
2408                 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2409         }
2410
2411         if ((prop = node.property ("pre-internal-snap-mode"))) {
2412                 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2413         }
2414
2415         if ((prop = node.property ("mouse-mode"))) {
2416                 MouseMode m = str2mousemode(prop->value());
2417                 set_mouse_mode (m, true);
2418         } else {
2419                 set_mouse_mode (MouseObject, true);
2420         }
2421
2422         if ((prop = node.property ("left-frame")) != 0) {
2423                 framepos_t pos;
2424                 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2425                         if (pos < 0) {
2426                                 pos = 0;
2427                         }
2428                         reset_x_origin (pos);
2429                 }
2430         }
2431
2432         if ((prop = node.property ("y-origin")) != 0) {
2433                 reset_y_origin (atof (prop->value ()));
2434         }
2435
2436         if ((prop = node.property ("join-object-range"))) {
2437                 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2438                 bool yn = string_is_affirmative (prop->value());
2439                 if (act) {
2440                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2441                         tact->set_active (!yn);
2442                         tact->set_active (yn);
2443                 }
2444                 set_mouse_mode(mouse_mode, true);
2445         }
2446
2447         if ((prop = node.property ("edit-point"))) {
2448                 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2449         } else {
2450                 set_edit_point_preference (_edit_point);
2451         }
2452
2453         if ((prop = node.property ("show-measures"))) {
2454                 bool yn = string_is_affirmative (prop->value());
2455                 _show_measures = yn;
2456         }
2457
2458         if ((prop = node.property ("follow-playhead"))) {
2459                 bool yn = string_is_affirmative (prop->value());
2460                 set_follow_playhead (yn);
2461         }
2462
2463         if ((prop = node.property ("stationary-playhead"))) {
2464                 bool yn = string_is_affirmative (prop->value());
2465                 set_stationary_playhead (yn);
2466         }
2467
2468         if ((prop = node.property ("region-list-sort-type"))) {
2469                 RegionListSortType st;
2470                 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2471         }
2472
2473         if ((prop = node.property ("show-editor-mixer"))) {
2474
2475                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2476                 assert (act);
2477
2478                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2479                 bool yn = string_is_affirmative (prop->value());
2480
2481                 /* do it twice to force the change */
2482
2483                 tact->set_active (!yn);
2484                 tact->set_active (yn);
2485         }
2486
2487         if ((prop = node.property ("show-editor-list"))) {
2488
2489                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2490                 assert (act);
2491
2492                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2493                 bool yn = string_is_affirmative (prop->value());
2494
2495                 /* do it twice to force the change */
2496
2497                 tact->set_active (!yn);
2498                 tact->set_active (yn);
2499         }
2500
2501         if ((prop = node.property (X_("editor-list-page")))) {
2502                 _the_notebook.set_current_page (atoi (prop->value ()));
2503         }
2504
2505         if ((prop = node.property (X_("show-marker-lines")))) {
2506                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2507                 assert (act);
2508                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2509                 bool yn = string_is_affirmative (prop->value ());
2510
2511                 tact->set_active (!yn);
2512                 tact->set_active (yn);
2513         }
2514
2515         XMLNodeList children = node.children ();
2516         for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2517                 selection->set_state (**i, Stateful::current_state_version);
2518                 _regions->set_state (**i);
2519         }
2520
2521         if ((prop = node.property ("maximised"))) {
2522                 bool yn = string_is_affirmative (prop->value());
2523                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2524                 assert (act);
2525                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2526                 bool fs = tact && tact->get_active();
2527                 if (yn ^ fs) {
2528                         ActionManager::do_action ("Common", "ToggleMaximalEditor");
2529                 }
2530         }
2531
2532         if ((prop = node.property ("nudge-clock-value"))) {
2533                 framepos_t f;
2534                 sscanf (prop->value().c_str(), "%" PRId64, &f);
2535                 nudge_clock->set (f);
2536         } else {
2537                 nudge_clock->set_mode (AudioClock::Timecode);
2538                 nudge_clock->set (_session->frame_rate() * 5, true);
2539         }
2540
2541         {
2542                 /* apply state
2543                  * Not all properties may have been in XML, but
2544                  * those that are linked to a private variable may need changing
2545                  */
2546                 RefPtr<Action> act;
2547                 bool yn;
2548
2549                 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2550                 if (act) {
2551                         yn = _show_measures;
2552                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2553                         /* do it twice to force the change */
2554                         tact->set_active (!yn);
2555                         tact->set_active (yn);
2556                 }
2557
2558                 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2559                 yn = _follow_playhead;
2560                 if (act) {
2561                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2562                         if (tact->get_active() != yn) {
2563                                 tact->set_active (yn);
2564                         }
2565                 }
2566
2567                 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2568                 yn = _stationary_playhead;
2569                 if (act) {
2570                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2571                         if (tact->get_active() != yn) {
2572                                 tact->set_active (yn);
2573                         }
2574                 }
2575         }
2576
2577         return LuaInstance::instance()->set_state(node);
2578 }
2579
2580 XMLNode&
2581 Editor::get_state ()
2582 {
2583         XMLNode* node = new XMLNode (X_("Editor"));
2584         char buf[32];
2585         LocaleGuard lg;
2586
2587         id().print (buf, sizeof (buf));
2588         node->add_property ("id", buf);
2589
2590         node->add_child_nocopy (Tabbable::get_state());
2591
2592         snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ());
2593         node->add_property("edit-horizontal-pane-pos", string(buf));
2594         node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2595         snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider());
2596         node->add_property("edit-vertical-pane-pos", string(buf));
2597
2598         maybe_add_mixer_strip_width (*node);
2599
2600         node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2601
2602         snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2603         node->add_property ("zoom", buf);
2604         node->add_property ("snap-to", enum_2_string (_snap_type));
2605         node->add_property ("snap-mode", enum_2_string (_snap_mode));
2606         node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2607         node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2608         node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2609         node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2610         node->add_property ("edit-point", enum_2_string (_edit_point));
2611         snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2612         node->add_property ("visible-track-count", buf);
2613
2614         snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2615         node->add_property ("playhead", buf);
2616         snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2617         node->add_property ("left-frame", buf);
2618         snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2619         node->add_property ("y-origin", buf);
2620
2621         node->add_property ("show-measures", _show_measures ? "yes" : "no");
2622         node->add_property ("maximised", _maximised ? "yes" : "no");
2623         node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2624         node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2625         node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2626         node->add_property ("mouse-mode", enum2str(mouse_mode));
2627         node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2628
2629         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2630         if (act) {
2631                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2632                 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2633         }
2634
2635         act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2636         if (act) {
2637                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2638                 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2639         }
2640
2641         snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2642         node->add_property (X_("editor-list-page"), buf);
2643
2644         if (button_bindings) {
2645                 XMLNode* bb = new XMLNode (X_("Buttons"));
2646                 button_bindings->save (*bb);
2647                 node->add_child_nocopy (*bb);
2648         }
2649
2650         node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2651
2652         node->add_child_nocopy (selection->get_state ());
2653         node->add_child_nocopy (_regions->get_state ());
2654
2655         snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2656         node->add_property ("nudge-clock-value", buf);
2657
2658         node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2659         node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2660
2661         return *node;
2662 }
2663
2664 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2665  *  if @param trackview_relative_offset is false, @param y y is a global canvas *  coordinate, in pixel units
2666  *
2667  *  @return pair: TimeAxisView that y is over, layer index.
2668  *
2669  *  TimeAxisView may be 0.  Layer index is the layer number if the TimeAxisView is valid and is
2670  *  in stacked or expanded region display mode, otherwise 0.
2671  */
2672 std::pair<TimeAxisView *, double>
2673 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2674 {
2675         if (!trackview_relative_offset) {
2676                 y -= _trackview_group->canvas_origin().y;
2677         }
2678
2679         if (y < 0) {
2680                 return std::make_pair ( (TimeAxisView *) 0, 0);
2681         }
2682
2683         for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2684
2685                 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2686
2687                 if (r.first) {
2688                         return r;
2689                 }
2690         }
2691
2692         return std::make_pair ( (TimeAxisView *) 0, 0);
2693 }
2694
2695 /** Snap a position to the grid, if appropriate, taking into account current
2696  *  grid settings and also the state of any snap modifier keys that may be pressed.
2697  *  @param start Position to snap.
2698  *  @param event Event to get current key modifier information from, or 0.
2699  */
2700 void
2701 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2702 {
2703         if (!_session || !event) {
2704                 return;
2705         }
2706
2707         if (ArdourKeyboard::indicates_snap (event->button.state)) {
2708                 if (_snap_mode == SnapOff) {
2709                         snap_to_internal (start, direction, for_mark);
2710                 }
2711         } else {
2712                 if (_snap_mode != SnapOff) {
2713                         snap_to_internal (start, direction, for_mark);
2714                 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2715                         /* SnapOff, but we pressed the snap_delta modifier */
2716                         snap_to_internal (start, direction, for_mark);
2717                 }
2718         }
2719 }
2720
2721 void
2722 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2723 {
2724         if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2725                 return;
2726         }
2727
2728         snap_to_internal (start, direction, for_mark, ensure_snap);
2729 }
2730
2731 void
2732 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2733 {
2734         const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2735         framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2736
2737         switch (_snap_type) {
2738         case SnapToTimecodeFrame:
2739                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2740                     fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2741                         /* start is already on a whole timecode frame, do nothing */
2742                 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2743                         start = (framepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2744                 } else {
2745                         start = (framepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) *  _session->samples_per_timecode_frame());
2746                 }
2747                 break;
2748
2749         case SnapToTimecodeSeconds:
2750                 if (_session->config.get_timecode_offset_negative()) {
2751                         start += _session->config.get_timecode_offset ();
2752                 } else {
2753                         start -= _session->config.get_timecode_offset ();
2754                 }
2755                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2756                     (start % one_timecode_second == 0)) {
2757                         /* start is already on a whole second, do nothing */
2758                 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2759                         start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2760                 } else {
2761                         start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2762                 }
2763
2764                 if (_session->config.get_timecode_offset_negative()) {
2765                         start -= _session->config.get_timecode_offset ();
2766                 } else {
2767                         start += _session->config.get_timecode_offset ();
2768                 }
2769                 break;
2770
2771         case SnapToTimecodeMinutes:
2772                 if (_session->config.get_timecode_offset_negative()) {
2773                         start += _session->config.get_timecode_offset ();
2774                 } else {
2775                         start -= _session->config.get_timecode_offset ();
2776                 }
2777                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2778                     (start % one_timecode_minute == 0)) {
2779                         /* start is already on a whole minute, do nothing */
2780                 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2781                         start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2782                 } else {
2783                         start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2784                 }
2785                 if (_session->config.get_timecode_offset_negative()) {
2786                         start -= _session->config.get_timecode_offset ();
2787                 } else {
2788                         start += _session->config.get_timecode_offset ();
2789                 }
2790                 break;
2791         default:
2792                 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2793                 abort(); /*NOTREACHED*/
2794         }
2795 }
2796
2797 void
2798 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2799 {
2800         const framepos_t one_second = _session->frame_rate();
2801         const framepos_t one_minute = _session->frame_rate() * 60;
2802         framepos_t presnap = start;
2803         framepos_t before;
2804         framepos_t after;
2805
2806         switch (_snap_type) {
2807         case SnapToTimecodeFrame:
2808         case SnapToTimecodeSeconds:
2809         case SnapToTimecodeMinutes:
2810                 return timecode_snap_to_internal (start, direction, for_mark);
2811
2812         case SnapToCDFrame:
2813                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2814                     start % (one_second/75) == 0) {
2815                         /* start is already on a whole CD frame, do nothing */
2816                 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2817                         start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2818                 } else {
2819                         start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2820                 }
2821                 break;
2822
2823         case SnapToSeconds:
2824                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2825                     start % one_second == 0) {
2826                         /* start is already on a whole second, do nothing */
2827                 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2828                         start = (framepos_t) ceil ((double) start / one_second) * one_second;
2829                 } else {
2830                         start = (framepos_t) floor ((double) start / one_second) * one_second;
2831                 }
2832                 break;
2833
2834         case SnapToMinutes:
2835                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2836                     start % one_minute == 0) {
2837                         /* start is already on a whole minute, do nothing */
2838                 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2839                         start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2840                 } else {
2841                         start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2842                 }
2843                 break;
2844
2845         case SnapToBar:
2846                 start = _session->tempo_map().round_to_bar (start, direction);
2847                 break;
2848
2849         case SnapToBeat:
2850                 start = _session->tempo_map().round_to_beat (start, direction);
2851                 break;
2852
2853         case SnapToBeatDiv128:
2854                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 128, direction);
2855                 break;
2856         case SnapToBeatDiv64:
2857                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 64, direction);
2858                 break;
2859         case SnapToBeatDiv32:
2860                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 32, direction);
2861                 break;
2862         case SnapToBeatDiv28:
2863                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 28, direction);
2864                 break;
2865         case SnapToBeatDiv24:
2866                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 24, direction);
2867                 break;
2868         case SnapToBeatDiv20:
2869                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 20, direction);
2870                 break;
2871         case SnapToBeatDiv16:
2872                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 16, direction);
2873                 break;
2874         case SnapToBeatDiv14:
2875                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 14, direction);
2876                 break;
2877         case SnapToBeatDiv12:
2878                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 12, direction);
2879                 break;
2880         case SnapToBeatDiv10:
2881                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 10, direction);
2882                 break;
2883         case SnapToBeatDiv8:
2884                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 8, direction);
2885                 break;
2886         case SnapToBeatDiv7:
2887                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 7, direction);
2888                 break;
2889         case SnapToBeatDiv6:
2890                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 6, direction);
2891                 break;
2892         case SnapToBeatDiv5:
2893                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 5, direction);
2894                 break;
2895         case SnapToBeatDiv4:
2896                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 4, direction);
2897                 break;
2898         case SnapToBeatDiv3:
2899                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 3, direction);
2900                 break;
2901         case SnapToBeatDiv2:
2902                 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 2, direction);
2903                 break;
2904
2905         case SnapToMark:
2906                 if (for_mark) {
2907                         return;
2908                 }
2909
2910                 _session->locations()->marks_either_side (start, before, after);
2911
2912                 if (before == max_framepos && after == max_framepos) {
2913                         /* No marks to snap to, so just don't snap */
2914                         return;
2915                 } else if (before == max_framepos) {
2916                         start = after;
2917                 } else if (after == max_framepos) {
2918                         start = before;
2919                 } else if (before != max_framepos && after != max_framepos) {
2920                         /* have before and after */
2921                         if ((start - before) < (after - start)) {
2922                                 start = before;
2923                         } else {
2924                                 start = after;
2925                         }
2926                 }
2927
2928                 break;
2929
2930         case SnapToRegionStart:
2931         case SnapToRegionEnd:
2932         case SnapToRegionSync:
2933         case SnapToRegionBoundary:
2934                 if (!region_boundary_cache.empty()) {
2935
2936                         vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2937                         vector<framepos_t>::iterator next = region_boundary_cache.end ();
2938
2939                         if (direction > 0) {
2940                                 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2941                         } else {
2942                                 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2943                         }
2944
2945                         if (next != region_boundary_cache.begin ()) {
2946                                 prev = next;
2947                                 prev--;
2948                         }
2949
2950                         framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2951                         framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2952
2953                         if (start > (p + n) / 2) {
2954                                 start = n;
2955                         } else {
2956                                 start = p;
2957                         }
2958                 }
2959                 break;
2960         }
2961
2962         switch (_snap_mode) {
2963         case SnapNormal:
2964                 return;
2965
2966         case SnapMagnetic:
2967
2968                 if (ensure_snap) {
2969                         return;
2970                 }
2971
2972                 if (presnap > start) {
2973                         if (presnap > (start + pixel_to_sample(snap_threshold))) {
2974                                 start = presnap;
2975                         }
2976
2977                 } else if (presnap < start) {
2978                         if (presnap < (start - pixel_to_sample(snap_threshold))) {
2979                                 start = presnap;
2980                         }
2981                 }
2982
2983         default:
2984                 /* handled at entry */
2985                 return;
2986
2987         }
2988 }
2989
2990
2991 void
2992 Editor::setup_toolbar ()
2993 {
2994         HBox* mode_box = manage(new HBox);
2995         mode_box->set_border_width (2);
2996         mode_box->set_spacing(2);
2997
2998         HBox* mouse_mode_box = manage (new HBox);
2999         HBox* mouse_mode_hbox = manage (new HBox);
3000         VBox* mouse_mode_vbox = manage (new VBox);
3001         Alignment* mouse_mode_align = manage (new Alignment);
3002
3003         Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3004         mouse_mode_size_group->add_widget (smart_mode_button);
3005         mouse_mode_size_group->add_widget (mouse_move_button);
3006         mouse_mode_size_group->add_widget (mouse_cut_button);
3007         mouse_mode_size_group->add_widget (mouse_select_button);
3008         mouse_mode_size_group->add_widget (mouse_timefx_button);
3009         mouse_mode_size_group->add_widget (mouse_audition_button);
3010         mouse_mode_size_group->add_widget (mouse_draw_button);
3011         mouse_mode_size_group->add_widget (mouse_content_button);
3012
3013         mouse_mode_size_group->add_widget (zoom_in_button);
3014         mouse_mode_size_group->add_widget (zoom_out_button);
3015         mouse_mode_size_group->add_widget (zoom_preset_selector);
3016         mouse_mode_size_group->add_widget (zoom_out_full_button);
3017         mouse_mode_size_group->add_widget (zoom_focus_selector);
3018
3019         mouse_mode_size_group->add_widget (tav_shrink_button);
3020         mouse_mode_size_group->add_widget (tav_expand_button);
3021         mouse_mode_size_group->add_widget (visible_tracks_selector);
3022
3023         mouse_mode_size_group->add_widget (snap_type_selector);
3024         mouse_mode_size_group->add_widget (snap_mode_selector);
3025
3026         mouse_mode_size_group->add_widget (edit_point_selector);
3027         mouse_mode_size_group->add_widget (edit_mode_selector);
3028
3029         mouse_mode_size_group->add_widget (*nudge_clock);
3030         mouse_mode_size_group->add_widget (nudge_forward_button);
3031         mouse_mode_size_group->add_widget (nudge_backward_button);
3032
3033         mouse_mode_hbox->set_spacing (2);
3034
3035         if (!ARDOUR::Profile->get_trx()) {
3036                 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3037         }
3038
3039         mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3040         mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3041
3042         if (!ARDOUR::Profile->get_mixbus()) {
3043                 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3044         }
3045
3046         if (!ARDOUR::Profile->get_trx()) {
3047                 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3048                 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3049                 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3050                 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3051         }
3052
3053         mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3054
3055         mouse_mode_align->add (*mouse_mode_vbox);
3056         mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3057
3058         mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3059
3060         edit_mode_selector.set_name ("mouse mode button");
3061
3062         if (!ARDOUR::Profile->get_trx()) {
3063                 mode_box->pack_start (edit_mode_selector, false, false);
3064         }
3065
3066         mode_box->pack_start (*mouse_mode_box, false, false);
3067
3068         /* Zoom */
3069
3070         _zoom_box.set_spacing (2);
3071         _zoom_box.set_border_width (2);
3072
3073         RefPtr<Action> act;
3074
3075         zoom_preset_selector.set_name ("zoom button");
3076         zoom_preset_selector.set_image(::get_icon ("time_exp"));
3077         zoom_preset_selector.set_size_request (42, -1);
3078
3079         zoom_in_button.set_name ("zoom button");
3080         zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3081         act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3082         zoom_in_button.set_related_action (act);
3083
3084         zoom_out_button.set_name ("zoom button");
3085         zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3086         act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3087         zoom_out_button.set_related_action (act);
3088
3089         zoom_out_full_button.set_name ("zoom button");
3090         zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3091         act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3092         zoom_out_full_button.set_related_action (act);
3093
3094         zoom_focus_selector.set_name ("zoom button");
3095
3096         if (ARDOUR::Profile->get_mixbus()) {
3097                 _zoom_box.pack_start (zoom_preset_selector, false, false);
3098         } else if (ARDOUR::Profile->get_trx()) {
3099                 mode_box->pack_start (zoom_out_button, false, false);
3100                 mode_box->pack_start (zoom_in_button, false, false);
3101         } else {
3102                 _zoom_box.pack_start (zoom_out_button, false, false);
3103                 _zoom_box.pack_start (zoom_in_button, false, false);
3104                 _zoom_box.pack_start (zoom_out_full_button, false, false);
3105                 _zoom_box.pack_start (zoom_focus_selector, false, false);
3106         }
3107
3108         /* Track zoom buttons */
3109         visible_tracks_selector.set_name ("zoom button");
3110         if (Profile->get_mixbus()) {
3111                 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3112                 visible_tracks_selector.set_size_request (42, -1);
3113         } else {
3114                 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3115         }
3116
3117         tav_expand_button.set_name ("zoom button");
3118         tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3119         act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3120         tav_expand_button.set_related_action (act);
3121
3122         tav_shrink_button.set_name ("zoom button");
3123         tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3124         act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3125         tav_shrink_button.set_related_action (act);
3126
3127         if (ARDOUR::Profile->get_mixbus()) {
3128                 _zoom_box.pack_start (visible_tracks_selector);
3129         } else if (ARDOUR::Profile->get_trx()) {
3130                 _zoom_box.pack_start (tav_shrink_button);
3131                 _zoom_box.pack_start (tav_expand_button);
3132         } else {
3133                 _zoom_box.pack_start (visible_tracks_selector);
3134                 _zoom_box.pack_start (tav_shrink_button);
3135                 _zoom_box.pack_start (tav_expand_button);
3136         }
3137
3138         snap_box.set_spacing (2);
3139         snap_box.set_border_width (2);
3140
3141         snap_type_selector.set_name ("mouse mode button");
3142
3143         snap_mode_selector.set_name ("mouse mode button");
3144
3145         edit_point_selector.set_name ("mouse mode button");
3146
3147         snap_box.pack_start (snap_mode_selector, false, false);
3148         snap_box.pack_start (snap_type_selector, false, false);
3149         snap_box.pack_start (edit_point_selector, false, false);
3150
3151         /* Nudge */
3152
3153         HBox *nudge_box = manage (new HBox);
3154         nudge_box->set_spacing (2);
3155         nudge_box->set_border_width (2);
3156
3157         nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3158         nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3159
3160         nudge_box->pack_start (nudge_backward_button, false, false);
3161         nudge_box->pack_start (nudge_forward_button, false, false);
3162         nudge_box->pack_start (*nudge_clock, false, false);
3163
3164
3165         /* Pack everything in... */
3166
3167         HBox* hbox = manage (new HBox);
3168         hbox->set_spacing(2);
3169
3170         toolbar_hbox.set_spacing (2);
3171         toolbar_hbox.set_border_width (1);
3172
3173         toolbar_hbox.pack_start (*mode_box, false, false);
3174         if (!ARDOUR::Profile->get_trx()) {
3175                 toolbar_hbox.pack_start (_zoom_box, false, false);
3176                 toolbar_hbox.pack_start (*hbox, false, false);
3177         }
3178
3179         if (!ARDOUR::Profile->get_trx()) {
3180                 hbox->pack_start (snap_box, false, false);
3181                 hbox->pack_start (*nudge_box, false, false);
3182         }
3183
3184         hbox->show_all ();
3185
3186         toolbar_base.set_name ("ToolBarBase");
3187         toolbar_base.add (toolbar_hbox);
3188
3189         _toolbar_viewport.add (toolbar_base);
3190         /* stick to the required height but allow width to vary if there's not enough room */
3191         _toolbar_viewport.set_size_request (1, -1);
3192
3193         toolbar_frame.set_shadow_type (SHADOW_OUT);
3194         toolbar_frame.set_name ("BaseFrame");
3195         toolbar_frame.add (_toolbar_viewport);
3196 }
3197
3198 void
3199 Editor::build_edit_point_menu ()
3200 {
3201         using namespace Menu_Helpers;
3202
3203         edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3204         if(!Profile->get_mixbus())
3205                 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3206         edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3207
3208         set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3209 }
3210
3211 void
3212 Editor::build_edit_mode_menu ()
3213 {
3214         using namespace Menu_Helpers;
3215
3216         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3217 //      edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3218         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3219         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode)  Lock)));
3220
3221         set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3222 }
3223
3224 void
3225 Editor::build_snap_mode_menu ()
3226 {
3227         using namespace Menu_Helpers;
3228
3229         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3230         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3231         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3232
3233         set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3234 }
3235
3236 void
3237 Editor::build_snap_type_menu ()
3238 {
3239         using namespace Menu_Helpers;
3240
3241         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3242         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3243         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3244         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3245         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3246         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3247         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3248         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3249         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3250         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3251         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3252         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3253         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3254         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3255         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3256         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3257         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3258         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3259         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3260         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3261         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3262         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3263         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3264         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3265         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3266         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3267         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3268         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3269         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3270         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3271
3272         set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3273
3274 }
3275
3276 void
3277 Editor::setup_tooltips ()
3278 {
3279         set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3280         set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3281         set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3282         set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3283         set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3284         set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3285         set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3286         set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3287         set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3288         set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3289         set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3290         set_tooltip (zoom_in_button, _("Zoom In"));
3291         set_tooltip (zoom_out_button, _("Zoom Out"));
3292         set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3293         set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3294         set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3295         set_tooltip (tav_expand_button, _("Expand Tracks"));
3296         set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3297         set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3298         set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3299         set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3300         set_tooltip (edit_point_selector, _("Edit Point"));
3301         set_tooltip (edit_mode_selector, _("Edit Mode"));
3302         set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3303 }
3304
3305 int
3306 Editor::convert_drop_to_paths (
3307                 vector<string>&                paths,
3308                 const RefPtr<Gdk::DragContext>& /*context*/,
3309                 gint                            /*x*/,
3310                 gint                            /*y*/,
3311                 const SelectionData&            data,
3312                 guint                           /*info*/,
3313                 guint                           /*time*/)
3314 {
3315         if (_session == 0) {
3316                 return -1;
3317         }
3318
3319         vector<string> uris = data.get_uris();
3320
3321         if (uris.empty()) {
3322
3323                 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3324                    are actually URI lists. So do it by hand.
3325                 */
3326
3327                 if (data.get_target() != "text/plain") {
3328                         return -1;
3329                 }
3330
3331                 /* Parse the "uri-list" format that Nautilus provides,
3332                    where each pathname is delimited by \r\n.
3333
3334                    THERE MAY BE NO NULL TERMINATING CHAR!!!
3335                 */
3336
3337                 string txt = data.get_text();
3338                 char* p;
3339                 const char* q;
3340
3341                 p = (char *) malloc (txt.length() + 1);
3342                 txt.copy (p, txt.length(), 0);
3343                 p[txt.length()] = '\0';
3344
3345                 while (p)
3346                 {
3347                         if (*p != '#')
3348                         {
3349                                 while (g_ascii_isspace (*p))
3350                                         p++;
3351
3352                                 q = p;
3353                                 while (*q && (*q != '\n') && (*q != '\r')) {
3354                                         q++;
3355                                 }
3356
3357                                 if (q > p)
3358                                 {
3359                                         q--;
3360                                         while (q > p && g_ascii_isspace (*q))
3361                                                 q--;
3362
3363                                         if (q > p)
3364                                         {
3365                                                 uris.push_back (string (p, q - p + 1));
3366                                         }
3367                                 }
3368                         }
3369                         p = strchr (p, '\n');
3370                         if (p)
3371                                 p++;
3372                 }
3373
3374                 free ((void*)p);
3375
3376                 if (uris.empty()) {
3377                         return -1;
3378                 }
3379         }
3380
3381         for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3382                 if ((*i).substr (0,7) == "file://") {
3383                         paths.push_back (Glib::filename_from_uri (*i));
3384                 }
3385         }
3386
3387         return 0;
3388 }
3389
3390 void
3391 Editor::new_tempo_section ()
3392 {
3393 }
3394
3395 void
3396 Editor::map_transport_state ()
3397 {
3398         ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3399
3400         if (_session && _session->transport_stopped()) {
3401                 have_pending_keyboard_selection = false;
3402         }
3403
3404         update_loop_range_view ();
3405 }
3406
3407 /* UNDO/REDO */
3408
3409 void
3410 Editor::begin_selection_op_history ()
3411 {
3412         selection_op_cmd_depth = 0;
3413         selection_op_history_it = 0;
3414
3415         while(!selection_op_history.empty()) {
3416                 delete selection_op_history.front();
3417                 selection_op_history.pop_front();
3418         }
3419
3420         selection_undo_action->set_sensitive (false);
3421         selection_redo_action->set_sensitive (false);
3422         selection_op_history.push_front (&_selection_memento->get_state ());
3423 }
3424
3425 void
3426 Editor::begin_reversible_selection_op (string name)
3427 {
3428         if (_session) {
3429                 //cerr << name << endl;
3430                 /* begin/commit pairs can be nested */
3431                 selection_op_cmd_depth++;
3432         }
3433 }
3434
3435 void
3436 Editor::commit_reversible_selection_op ()
3437 {
3438         if (_session) {
3439                 if (selection_op_cmd_depth == 1) {
3440
3441                         if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3442                                 /**
3443                                     The user has undone some selection ops and then made a new one,
3444                                     making anything earlier in the list invalid.
3445                                 */
3446
3447                                 list<XMLNode *>::iterator it = selection_op_history.begin();
3448                                 list<XMLNode *>::iterator e_it = it;
3449                                 advance (e_it, selection_op_history_it);
3450
3451                                 for ( ; it != e_it; ++it) {
3452                                         delete *it;
3453                                 }
3454                                 selection_op_history.erase (selection_op_history.begin(), e_it);
3455                         }
3456
3457                         selection_op_history.push_front (&_selection_memento->get_state ());
3458                         selection_op_history_it = 0;
3459
3460                         selection_undo_action->set_sensitive (true);
3461                         selection_redo_action->set_sensitive (false);
3462                 }
3463
3464                 if (selection_op_cmd_depth > 0) {
3465                         selection_op_cmd_depth--;
3466                 }
3467         }
3468 }
3469
3470 void
3471 Editor::undo_selection_op ()
3472 {
3473         if (_session) {
3474                 selection_op_history_it++;
3475                 uint32_t n = 0;
3476                 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3477                         if (n == selection_op_history_it) {
3478                                 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3479                                 selection_redo_action->set_sensitive (true);
3480                         }
3481                         ++n;
3482                 }
3483                 /* is there an earlier entry? */
3484                 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3485                         selection_undo_action->set_sensitive (false);
3486                 }
3487         }
3488 }
3489
3490 void
3491 Editor::redo_selection_op ()
3492 {
3493         if (_session) {
3494                 if (selection_op_history_it > 0) {
3495                         selection_op_history_it--;
3496                 }
3497                 uint32_t n = 0;
3498                 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3499                         if (n == selection_op_history_it) {
3500                                 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3501                                 selection_undo_action->set_sensitive (true);
3502                         }
3503                         ++n;
3504                 }
3505
3506                 if (selection_op_history_it == 0) {
3507                         selection_redo_action->set_sensitive (false);
3508                 }
3509         }
3510 }
3511
3512 void
3513 Editor::begin_reversible_command (string name)
3514 {
3515         if (_session) {
3516                 before.push_back (&_selection_memento->get_state ());
3517                 _session->begin_reversible_command (name);
3518         }
3519 }
3520
3521 void
3522 Editor::begin_reversible_command (GQuark q)
3523 {
3524         if (_session) {
3525                 before.push_back (&_selection_memento->get_state ());
3526                 _session->begin_reversible_command (q);
3527         }
3528 }
3529
3530 void
3531 Editor::abort_reversible_command ()
3532 {
3533         if (_session) {
3534                 while(!before.empty()) {
3535                         delete before.front();
3536                         before.pop_front();
3537                 }
3538                 _session->abort_reversible_command ();
3539         }
3540 }
3541
3542 void
3543 Editor::commit_reversible_command ()
3544 {
3545         if (_session) {
3546                 if (before.size() == 1) {
3547                         _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3548                         redo_action->set_sensitive(false);
3549                         undo_action->set_sensitive(true);
3550                         begin_selection_op_history ();
3551                 }
3552
3553                 if (before.empty()) {
3554                         cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3555                 } else {
3556                         before.pop_back();
3557                 }
3558
3559                 _session->commit_reversible_command ();
3560         }
3561 }
3562
3563 void
3564 Editor::history_changed ()
3565 {
3566         string label;
3567
3568         if (undo_action && _session) {
3569                 if (_session->undo_depth() == 0) {
3570                         label = S_("Command|Undo");
3571                 } else {
3572                         label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3573                 }
3574                 undo_action->property_label() = label;
3575         }
3576
3577         if (redo_action && _session) {
3578                 if (_session->redo_depth() == 0) {
3579                         label = _("Redo");
3580                         redo_action->set_sensitive (false);
3581                 } else {
3582                         label = string_compose(_("Redo (%1)"), _session->next_redo());
3583                         redo_action->set_sensitive (true);
3584                 }
3585                 redo_action->property_label() = label;
3586         }
3587 }
3588
3589 void
3590 Editor::duplicate_range (bool with_dialog)
3591 {
3592         float times = 1.0f;
3593
3594         RegionSelection rs = get_regions_from_selection_and_entered ();
3595
3596         if ( selection->time.length() == 0 && rs.empty()) {
3597                 return;
3598         }
3599
3600         if (with_dialog) {
3601
3602                 ArdourDialog win (_("Duplicate"));
3603                 Label label (_("Number of duplications:"));
3604                 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3605                 SpinButton spinner (adjustment, 0.0, 1);
3606                 HBox hbox;
3607
3608                 win.get_vbox()->set_spacing (12);
3609                 win.get_vbox()->pack_start (hbox);
3610                 hbox.set_border_width (6);
3611                 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3612
3613                 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3614                    place, visually. so do this by hand.
3615                 */
3616
3617                 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3618                 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3619                 spinner.grab_focus();
3620
3621                 hbox.show ();
3622                 label.show ();
3623                 spinner.show ();
3624
3625                 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3626                 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3627                 win.set_default_response (RESPONSE_ACCEPT);
3628
3629                 spinner.grab_focus ();
3630
3631                 switch (win.run ()) {
3632                 case RESPONSE_ACCEPT:
3633                         break;
3634                 default:
3635                         return;
3636                 }
3637
3638                 times = adjustment.get_value();
3639         }
3640
3641         if ((current_mouse_mode() == Editing::MouseRange)) {
3642                 if (selection->time.length()) {
3643                         duplicate_selection (times);
3644                 }
3645         } else if (get_smart_mode()) {
3646                 if (selection->time.length()) {
3647                         duplicate_selection (times);
3648                 } else
3649                         duplicate_some_regions (rs, times);
3650         } else {
3651                 duplicate_some_regions (rs, times);
3652         }
3653 }
3654
3655 void
3656 Editor::set_edit_mode (EditMode m)
3657 {
3658         Config->set_edit_mode (m);
3659 }
3660
3661 void
3662 Editor::cycle_edit_mode ()
3663 {
3664         switch (Config->get_edit_mode()) {
3665         case Slide:
3666                 Config->set_edit_mode (Ripple);
3667                 break;
3668         case Splice:
3669         case Ripple:
3670                 Config->set_edit_mode (Lock);
3671                 break;
3672         case Lock:
3673                 Config->set_edit_mode (Slide);
3674                 break;
3675         }
3676 }
3677
3678 void
3679 Editor::edit_mode_selection_done ( EditMode m )
3680 {
3681         Config->set_edit_mode ( m );
3682 }
3683
3684 void
3685 Editor::snap_type_selection_done (SnapType snaptype)
3686 {
3687         RefPtr<RadioAction> ract = snap_type_action (snaptype);
3688         if (ract) {
3689                 ract->set_active ();
3690         }
3691 }
3692
3693 void
3694 Editor::snap_mode_selection_done (SnapMode mode)
3695 {
3696         RefPtr<RadioAction> ract = snap_mode_action (mode);
3697
3698         if (ract) {
3699                 ract->set_active (true);
3700         }
3701 }
3702
3703 void
3704 Editor::cycle_edit_point (bool with_marker)
3705 {
3706         if(Profile->get_mixbus())
3707                 with_marker = false;
3708
3709         switch (_edit_point) {
3710         case EditAtMouse:
3711                 set_edit_point_preference (EditAtPlayhead);
3712                 break;
3713         case EditAtPlayhead:
3714                 if (with_marker) {
3715                         set_edit_point_preference (EditAtSelectedMarker);
3716                 } else {
3717                         set_edit_point_preference (EditAtMouse);
3718                 }
3719                 break;
3720         case EditAtSelectedMarker:
3721                 set_edit_point_preference (EditAtMouse);
3722                 break;
3723         }
3724 }
3725
3726 void
3727 Editor::edit_point_selection_done (EditPoint ep)
3728 {
3729         set_edit_point_preference ( ep );
3730 }
3731
3732 void
3733 Editor::build_zoom_focus_menu ()
3734 {
3735         using namespace Menu_Helpers;
3736
3737         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3738         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3739         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3740         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3741         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3742         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3743
3744         set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3745 }
3746
3747 void
3748 Editor::zoom_focus_selection_done ( ZoomFocus f )
3749 {
3750         RefPtr<RadioAction> ract = zoom_focus_action (f);
3751         if (ract) {
3752                 ract->set_active ();
3753         }
3754 }
3755
3756 void
3757 Editor::build_track_count_menu ()
3758 {
3759         using namespace Menu_Helpers;
3760
3761         if (!Profile->get_mixbus()) {
3762                 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3763                 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3764                 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3765                 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3766                 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3767                 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3768                 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3769                 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3770                 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3771                 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3772                 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3773                 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3774                 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3775         } else {
3776                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3777                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3778                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3779                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3780                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3781                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3782                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3783                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3784                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3785                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3786
3787                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3788                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3789                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3790                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3791                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3792                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3793                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3794                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3795                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3796                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3797                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3798         }
3799 }
3800
3801 void
3802 Editor::set_zoom_preset (int64_t ms)
3803 {
3804         if ( ms <= 0 ) {
3805                 temporal_zoom_session();
3806                 return;
3807         }
3808
3809         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3810         temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3811 }
3812
3813 void
3814 Editor::set_visible_track_count (int32_t n)
3815 {
3816         _visible_track_count = n;
3817
3818         /* if the canvas hasn't really been allocated any size yet, just
3819            record the desired number of visible tracks and return. when canvas
3820            allocation happens, we will get called again and then we can do the
3821            real work.
3822         */
3823
3824         if (_visible_canvas_height <= 1) {
3825                 return;
3826         }
3827
3828         int h;
3829         string str;
3830         DisplaySuspender ds;
3831
3832         if (_visible_track_count > 0) {
3833                 h = trackviews_height() / _visible_track_count;
3834                 std::ostringstream s;
3835                 s << _visible_track_count;
3836                 str = s.str();
3837         } else if (_visible_track_count == 0) {
3838                 uint32_t n = 0;
3839                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3840                         if ((*i)->marked_for_display()) {
3841                                 ++n;
3842                         }
3843                 }
3844                 h = trackviews_height() / n;
3845                 str = _("All");
3846         } else {
3847                 /* negative value means that the visible track count has
3848                    been overridden by explicit track height changes.
3849                 */
3850                 visible_tracks_selector.set_text (X_("*"));
3851                 return;
3852         }
3853
3854         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3855                 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3856         }
3857
3858         if (str != visible_tracks_selector.get_text()) {
3859                 visible_tracks_selector.set_text (str);
3860         }
3861 }
3862
3863 void
3864 Editor::override_visible_track_count ()
3865 {
3866         _visible_track_count = -1;
3867         visible_tracks_selector.set_text ( _("*") );
3868 }
3869
3870 bool
3871 Editor::edit_controls_button_release (GdkEventButton* ev)
3872 {
3873         if (Keyboard::is_context_menu_event (ev)) {
3874                 ARDOUR_UI::instance()->add_route ();
3875         } else if (ev->button == 1) {
3876                 selection->clear_tracks ();
3877         }
3878
3879         return true;
3880 }
3881
3882 bool
3883 Editor::mouse_select_button_release (GdkEventButton* ev)
3884 {
3885         /* this handles just right-clicks */
3886
3887         if (ev->button != 3) {
3888                 return false;
3889         }
3890
3891         return true;
3892 }
3893
3894 void
3895 Editor::set_zoom_focus (ZoomFocus f)
3896 {
3897         string str = zoom_focus_strings[(int)f];
3898
3899         if (str != zoom_focus_selector.get_text()) {
3900                 zoom_focus_selector.set_text (str);
3901         }
3902
3903         if (zoom_focus != f) {
3904                 zoom_focus = f;
3905                 instant_save ();
3906         }
3907 }
3908
3909 void
3910 Editor::cycle_zoom_focus ()
3911 {
3912         switch (zoom_focus) {
3913         case ZoomFocusLeft:
3914                 set_zoom_focus (ZoomFocusRight);
3915                 break;
3916         case ZoomFocusRight:
3917                 set_zoom_focus (ZoomFocusCenter);
3918                 break;
3919         case ZoomFocusCenter:
3920                 set_zoom_focus (ZoomFocusPlayhead);
3921                 break;
3922         case ZoomFocusPlayhead:
3923                 set_zoom_focus (ZoomFocusMouse);
3924                 break;
3925         case ZoomFocusMouse:
3926                 set_zoom_focus (ZoomFocusEdit);
3927                 break;
3928         case ZoomFocusEdit:
3929                 set_zoom_focus (ZoomFocusLeft);
3930                 break;
3931         }
3932 }
3933
3934 void
3935 Editor::set_show_measures (bool yn)
3936 {
3937         if (_show_measures != yn) {
3938                 hide_measures ();
3939
3940                 if ((_show_measures = yn) == true) {
3941                         if (tempo_lines) {
3942                                 tempo_lines->show();
3943                         }
3944
3945                         std::vector<TempoMap::BBTPoint> grid;
3946                         compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3947                         draw_measures (grid);
3948                 }
3949
3950                 instant_save ();
3951         }
3952 }
3953
3954 void
3955 Editor::toggle_follow_playhead ()
3956 {
3957         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3958         if (act) {
3959                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3960                 set_follow_playhead (tact->get_active());
3961         }
3962 }
3963
3964 /** @param yn true to follow playhead, otherwise false.
3965  *  @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3966  */
3967 void
3968 Editor::set_follow_playhead (bool yn, bool catch_up)
3969 {
3970         if (_follow_playhead != yn) {
3971                 if ((_follow_playhead = yn) == true && catch_up) {
3972                         /* catch up */
3973                         reset_x_origin_to_follow_playhead ();
3974                 }
3975                 instant_save ();
3976         }
3977 }
3978
3979 void
3980 Editor::toggle_stationary_playhead ()
3981 {
3982         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3983         if (act) {
3984                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3985                 set_stationary_playhead (tact->get_active());
3986         }
3987 }
3988
3989 void
3990 Editor::set_stationary_playhead (bool yn)
3991 {
3992         if (_stationary_playhead != yn) {
3993                 if ((_stationary_playhead = yn) == true) {
3994                         /* catch up */
3995                         // FIXME need a 3.0 equivalent of this 2.X call
3996                         // update_current_screen ();
3997                 }
3998                 instant_save ();
3999         }
4000 }
4001
4002 PlaylistSelector&
4003 Editor::playlist_selector () const
4004 {
4005         return *_playlist_selector;
4006 }
4007
4008 framecnt_t
4009 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4010 {
4011         if (paste_count == 0) {
4012                 /* don't bother calculating an offset that will be zero anyway */
4013                 return 0;
4014         }
4015
4016         /* calculate basic unsnapped multi-paste offset */
4017         framecnt_t offset = paste_count * duration;
4018
4019         /* snap offset so pos + offset is aligned to the grid */
4020         framepos_t offset_pos = pos + offset;
4021         snap_to(offset_pos, RoundUpMaybe);
4022         offset = offset_pos - pos;
4023
4024         return offset;
4025 }
4026
4027 unsigned
4028 Editor::get_grid_beat_divisions(framepos_t position)
4029 {
4030         switch (_snap_type) {
4031         case SnapToBeatDiv128: return 128;
4032         case SnapToBeatDiv64:  return 64;
4033         case SnapToBeatDiv32:  return 32;
4034         case SnapToBeatDiv28:  return 28;
4035         case SnapToBeatDiv24:  return 24;
4036         case SnapToBeatDiv20:  return 20;
4037         case SnapToBeatDiv16:  return 16;
4038         case SnapToBeatDiv14:  return 14;
4039         case SnapToBeatDiv12:  return 12;
4040         case SnapToBeatDiv10:  return 10;
4041         case SnapToBeatDiv8:   return 8;
4042         case SnapToBeatDiv7:   return 7;
4043         case SnapToBeatDiv6:   return 6;
4044         case SnapToBeatDiv5:   return 5;
4045         case SnapToBeatDiv4:   return 4;
4046         case SnapToBeatDiv3:   return 3;
4047         case SnapToBeatDiv2:   return 2;
4048         default:               return 0;
4049         }
4050         return 0;
4051 }
4052
4053 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4054     if the grid is non-musical, returns 0.
4055     if the grid is snapped to bars, returns -1.
4056     @param event_state the current keyboard modifier mask.
4057 */
4058 int32_t
4059 Editor::get_grid_music_divisions (uint32_t event_state)
4060 {
4061         if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4062                 return 0;
4063         }
4064
4065         if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4066                 return 0;
4067         }
4068
4069         switch (_snap_type) {
4070         case SnapToBeatDiv128: return 128;
4071         case SnapToBeatDiv64:  return 64;
4072         case SnapToBeatDiv32:  return 32;
4073         case SnapToBeatDiv28:  return 28;
4074         case SnapToBeatDiv24:  return 24;
4075         case SnapToBeatDiv20:  return 20;
4076         case SnapToBeatDiv16:  return 16;
4077         case SnapToBeatDiv14:  return 14;
4078         case SnapToBeatDiv12:  return 12;
4079         case SnapToBeatDiv10:  return 10;
4080         case SnapToBeatDiv8:   return 8;
4081         case SnapToBeatDiv7:   return 7;
4082         case SnapToBeatDiv6:   return 6;
4083         case SnapToBeatDiv5:   return 5;
4084         case SnapToBeatDiv4:   return 4;
4085         case SnapToBeatDiv3:   return 3;
4086         case SnapToBeatDiv2:   return 2;
4087         case SnapToBeat:       return 1;
4088         case SnapToBar :       return -1;
4089         default:               return 0;
4090         }
4091         return 0;
4092 }
4093
4094 Evoral::Beats
4095 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4096 {
4097         success = true;
4098
4099         const unsigned divisions = get_grid_beat_divisions(position);
4100         if (divisions) {
4101                 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4102         }
4103
4104         switch (_snap_type) {
4105         case SnapToBeat:
4106                 return Evoral::Beats(4.0 / _session->tempo_map().meter_at_frame (position).note_divisor());
4107         case SnapToBar:
4108                 if (_session) {
4109                         const Meter& m = _session->tempo_map().meter_at_frame (position);
4110                         return Evoral::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4111                 }
4112                 break;
4113         default:
4114                 success = false;
4115                 break;
4116         }
4117
4118         return Evoral::Beats();
4119 }
4120
4121 framecnt_t
4122 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4123 {
4124         framecnt_t ret;
4125
4126         ret = nudge_clock->current_duration (pos);
4127         next = ret + 1; /* XXXX fix me */
4128
4129         return ret;
4130 }
4131
4132 int
4133 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4134 {
4135         ArdourDialog dialog (_("Playlist Deletion"));
4136         Label  label (string_compose (_("Playlist %1 is currently unused.\n"
4137                                         "If it is kept, its audio files will not be cleaned.\n"
4138                                         "If it is deleted, audio files used by it alone will be cleaned."),
4139                                       pl->name()));
4140
4141         dialog.set_position (WIN_POS_CENTER);
4142         dialog.get_vbox()->pack_start (label);
4143
4144         label.show ();
4145
4146         dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4147         dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4148         Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4149         dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4150         dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4151
4152         // by default gtk uses the left most button
4153         keep->grab_focus ();
4154
4155         switch (dialog.run ()) {
4156         case RESPONSE_NO:
4157                 /* keep this and all remaining ones */
4158                 return -2;
4159                 break;
4160
4161         case RESPONSE_YES:
4162                 /* delete this and all others */
4163                 return 2;
4164                 break;
4165
4166         case RESPONSE_ACCEPT:
4167                 /* delete the playlist */
4168                 return 1;
4169                 break;
4170
4171         case RESPONSE_REJECT:
4172                 /* keep the playlist */
4173                 return 0;
4174                 break;
4175
4176         default:
4177                 break;
4178         }
4179
4180         return -1;
4181 }
4182
4183 bool
4184 Editor::audio_region_selection_covers (framepos_t where)
4185 {
4186         for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4187                 if ((*a)->region()->covers (where)) {
4188                         return true;
4189                 }
4190         }
4191
4192         return false;
4193 }
4194
4195 void
4196 Editor::prepare_for_cleanup ()
4197 {
4198         cut_buffer->clear_regions ();
4199         cut_buffer->clear_playlists ();
4200
4201         selection->clear_regions ();
4202         selection->clear_playlists ();
4203
4204         _regions->suspend_redisplay ();
4205 }
4206
4207 void
4208 Editor::finish_cleanup ()
4209 {
4210         _regions->resume_redisplay ();
4211 }
4212
4213 Location*
4214 Editor::transport_loop_location()
4215 {
4216         if (_session) {
4217                 return _session->locations()->auto_loop_location();
4218         } else {
4219                 return 0;
4220         }
4221 }
4222
4223 Location*
4224 Editor::transport_punch_location()
4225 {
4226         if (_session) {
4227                 return _session->locations()->auto_punch_location();
4228         } else {
4229                 return 0;
4230         }
4231 }
4232
4233 bool
4234 Editor::control_layout_scroll (GdkEventScroll* ev)
4235 {
4236         /* Just forward to the normal canvas scroll method. The coordinate
4237            systems are different but since the canvas is always larger than the
4238            track headers, and aligned with the trackview area, this will work.
4239
4240            In the not too distant future this layout is going away anyway and
4241            headers will be on the canvas.
4242         */
4243         return canvas_scroll_event (ev, false);
4244 }
4245
4246 void
4247 Editor::session_state_saved (string)
4248 {
4249         update_title ();
4250         _snapshots->redisplay ();
4251 }
4252
4253 void
4254 Editor::maximise_editing_space ()
4255 {
4256         if (_maximised) {
4257                 return;
4258         }
4259
4260         Gtk::Window* toplevel = current_toplevel();
4261
4262         if (toplevel) {
4263                 toplevel->fullscreen ();
4264                 _maximised = true;
4265         }
4266 }
4267
4268 void
4269 Editor::restore_editing_space ()
4270 {
4271         if (!_maximised) {
4272                 return;
4273         }
4274
4275         Gtk::Window* toplevel = current_toplevel();
4276
4277         if (toplevel) {
4278                 toplevel->unfullscreen();
4279                 _maximised = false;
4280         }
4281 }
4282
4283 /**
4284  *  Make new playlists for a given track and also any others that belong
4285  *  to the same active route group with the `select' property.
4286  *  @param v Track.
4287  */
4288
4289 void
4290 Editor::new_playlists (TimeAxisView* v)
4291 {
4292         begin_reversible_command (_("new playlists"));
4293         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4294         _session->playlists->get (playlists);
4295         mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4296         commit_reversible_command ();
4297 }
4298
4299 /**
4300  *  Use a copy of the current playlist for a given track and also any others that belong
4301  *  to the same active route group with the `select' property.
4302  *  @param v Track.
4303  */
4304
4305 void
4306 Editor::copy_playlists (TimeAxisView* v)
4307 {
4308         begin_reversible_command (_("copy playlists"));
4309         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4310         _session->playlists->get (playlists);
4311         mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4312         commit_reversible_command ();
4313 }
4314
4315 /** Clear the current playlist for a given track and also any others that belong
4316  *  to the same active route group with the `select' property.
4317  *  @param v Track.
4318  */
4319
4320 void
4321 Editor::clear_playlists (TimeAxisView* v)
4322 {
4323         begin_reversible_command (_("clear playlists"));
4324         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4325         _session->playlists->get (playlists);
4326         mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4327         commit_reversible_command ();
4328 }
4329
4330 void
4331 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4332 {
4333         atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4334 }
4335
4336 void
4337 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4338 {
4339         atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4340 }
4341
4342 void
4343 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4344 {
4345         atv.clear_playlist ();
4346 }
4347
4348 double
4349 Editor::get_y_origin () const
4350 {
4351         return vertical_adjustment.get_value ();
4352 }
4353
4354 /** Queue up a change to the viewport x origin.
4355  *  @param frame New x origin.
4356  */
4357 void
4358 Editor::reset_x_origin (framepos_t frame)
4359 {
4360         pending_visual_change.add (VisualChange::TimeOrigin);
4361         pending_visual_change.time_origin = frame;
4362         ensure_visual_change_idle_handler ();
4363 }
4364
4365 void
4366 Editor::reset_y_origin (double y)
4367 {
4368         pending_visual_change.add (VisualChange::YOrigin);
4369         pending_visual_change.y_origin = y;
4370         ensure_visual_change_idle_handler ();
4371 }
4372
4373 void
4374 Editor::reset_zoom (framecnt_t spp)
4375 {
4376         if (spp == samples_per_pixel) {
4377                 return;
4378         }
4379
4380         pending_visual_change.add (VisualChange::ZoomLevel);
4381         pending_visual_change.samples_per_pixel = spp;
4382         ensure_visual_change_idle_handler ();
4383 }
4384
4385 void
4386 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4387 {
4388         reset_x_origin (frame);
4389         reset_zoom (fpu);
4390
4391         if (!no_save_visual) {
4392                 undo_visual_stack.push_back (current_visual_state(false));
4393         }
4394 }
4395
4396 Editor::VisualState::VisualState (bool with_tracks)
4397         : gui_state (with_tracks ? new GUIObjectState : 0)
4398 {
4399 }
4400
4401 Editor::VisualState::~VisualState ()
4402 {
4403         delete gui_state;
4404 }
4405
4406 Editor::VisualState*
4407 Editor::current_visual_state (bool with_tracks)
4408 {
4409         VisualState* vs = new VisualState (with_tracks);
4410         vs->y_position = vertical_adjustment.get_value();
4411         vs->samples_per_pixel = samples_per_pixel;
4412         vs->leftmost_frame = leftmost_frame;
4413         vs->zoom_focus = zoom_focus;
4414
4415         if (with_tracks) {
4416                 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4417         }
4418
4419         return vs;
4420 }
4421
4422 void
4423 Editor::undo_visual_state ()
4424 {
4425         if (undo_visual_stack.empty()) {
4426                 return;
4427         }
4428
4429         VisualState* vs = undo_visual_stack.back();
4430         undo_visual_stack.pop_back();
4431
4432
4433         redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4434
4435         if (vs) {
4436                 use_visual_state (*vs);
4437         }
4438 }
4439
4440 void
4441 Editor::redo_visual_state ()
4442 {
4443         if (redo_visual_stack.empty()) {
4444                 return;
4445         }
4446
4447         VisualState* vs = redo_visual_stack.back();
4448         redo_visual_stack.pop_back();
4449
4450         // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4451         // why do we check here?
4452         undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4453
4454         if (vs) {
4455                 use_visual_state (*vs);
4456         }
4457 }
4458
4459 void
4460 Editor::swap_visual_state ()
4461 {
4462         if (undo_visual_stack.empty()) {
4463                 redo_visual_state ();
4464         } else {
4465                 undo_visual_state ();
4466         }
4467 }
4468
4469 void
4470 Editor::use_visual_state (VisualState& vs)
4471 {
4472         PBD::Unwinder<bool> nsv (no_save_visual, true);
4473         DisplaySuspender ds;
4474
4475         vertical_adjustment.set_value (vs.y_position);
4476
4477         set_zoom_focus (vs.zoom_focus);
4478         reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4479
4480         if (vs.gui_state) {
4481                 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4482
4483                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4484                         (*i)->clear_property_cache();
4485                         (*i)->reset_visual_state ();
4486                 }
4487         }
4488
4489         _routes->update_visibility ();
4490 }
4491
4492 /** This is the core function that controls the zoom level of the canvas. It is called
4493  *  whenever one or more calls are made to reset_zoom().  It executes in an idle handler.
4494  *  @param spp new number of samples per pixel
4495  */
4496 void
4497 Editor::set_samples_per_pixel (framecnt_t spp)
4498 {
4499         if (spp < 1) {
4500                 return;
4501         }
4502
4503         const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4504         const framecnt_t lots_of_pixels = 4000;
4505
4506         /* if the zoom level is greater than what you'd get trying to display 3
4507          * days of audio on a really big screen, then it's too big.
4508          */
4509
4510         if (spp * lots_of_pixels > three_days) {
4511                 return;
4512         }
4513
4514         samples_per_pixel = spp;
4515
4516         if (tempo_lines) {
4517                 tempo_lines->tempo_map_changed();
4518         }
4519
4520         bool const showing_time_selection = selection->time.length() > 0;
4521
4522         if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4523                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4524                         (*i)->reshow_selection (selection->time);
4525                 }
4526         }
4527
4528         ZoomChanged (); /* EMIT_SIGNAL */
4529
4530         ArdourCanvas::GtkCanvasViewport* c;
4531
4532         c = get_track_canvas();
4533         if (c) {
4534                 c->canvas()->zoomed ();
4535         }
4536
4537         if (playhead_cursor) {
4538                 playhead_cursor->set_position (playhead_cursor->current_frame ());
4539         }
4540
4541         refresh_location_display();
4542         _summary->set_overlays_dirty ();
4543
4544         update_marker_labels ();
4545
4546         instant_save ();
4547 }
4548
4549 framepos_t
4550 Editor::playhead_cursor_sample () const
4551 {
4552         return playhead_cursor->current_frame();
4553 }
4554
4555 void
4556 Editor::queue_visual_videotimeline_update ()
4557 {
4558         /* TODO:
4559          * pending_visual_change.add (VisualChange::VideoTimeline);
4560          * or maybe even more specific: which videotimeline-image
4561          * currently it calls update_video_timeline() to update
4562          * _all outdated_ images on the video-timeline.
4563          * see 'exposeimg()' in video_image_frame.cc
4564          */
4565         ensure_visual_change_idle_handler ();
4566 }
4567
4568 void
4569 Editor::ensure_visual_change_idle_handler ()
4570 {
4571         if (pending_visual_change.idle_handler_id < 0) {
4572                 // see comment in add_to_idle_resize above.
4573                 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4574                 pending_visual_change.being_handled = false;
4575         }
4576 }
4577
4578 int
4579 Editor::_idle_visual_changer (void* arg)
4580 {
4581         return static_cast<Editor*>(arg)->idle_visual_changer ();
4582 }
4583
4584 int
4585 Editor::idle_visual_changer ()
4586 {
4587         /* set_horizontal_position() below (and maybe other calls) call
4588            gtk_main_iteration(), so it's possible that a signal will be handled
4589            half-way through this method.  If this signal wants an
4590            idle_visual_changer we must schedule another one after this one, so
4591            mark the idle_handler_id as -1 here to allow that.  Also make a note
4592            that we are doing the visual change, so that changes in response to
4593            super-rapid-screen-update can be dropped if we are still processing
4594            the last one.
4595         */
4596
4597         pending_visual_change.idle_handler_id = -1;
4598         pending_visual_change.being_handled = true;
4599
4600         VisualChange vc = pending_visual_change;
4601
4602         pending_visual_change.pending = (VisualChange::Type) 0;
4603
4604         visual_changer (vc);
4605
4606         pending_visual_change.being_handled = false;
4607
4608         return 0; /* this is always a one-shot call */
4609 }
4610
4611 void
4612 Editor::visual_changer (const VisualChange& vc)
4613 {
4614         double const last_time_origin = horizontal_position ();
4615
4616         if (vc.pending & VisualChange::ZoomLevel) {
4617                 set_samples_per_pixel (vc.samples_per_pixel);
4618
4619                 compute_fixed_ruler_scale ();
4620
4621                 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4622                 update_tempo_based_rulers ();
4623
4624                 update_video_timeline();
4625         }
4626
4627         if (vc.pending & VisualChange::TimeOrigin) {
4628                 set_horizontal_position (vc.time_origin / samples_per_pixel);
4629         }
4630
4631         if (vc.pending & VisualChange::YOrigin) {
4632                 vertical_adjustment.set_value (vc.y_origin);
4633         }
4634
4635         if (last_time_origin == horizontal_position ()) {
4636                 /* changed signal not emitted */
4637                 update_fixed_rulers ();
4638                 redisplay_tempo (true);
4639         }
4640
4641         if (!(vc.pending & VisualChange::ZoomLevel)) {
4642                 update_video_timeline();
4643         }
4644
4645         _summary->set_overlays_dirty ();
4646 }
4647
4648 struct EditorOrderTimeAxisSorter {
4649     bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4650             return a->order () < b->order ();
4651     }
4652 };
4653
4654 void
4655 Editor::sort_track_selection (TrackViewList& sel)
4656 {
4657         EditorOrderTimeAxisSorter cmp;
4658         sel.sort (cmp);
4659 }
4660
4661 framepos_t
4662 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4663 {
4664         bool ignored;
4665         framepos_t where = 0;
4666         EditPoint ep = _edit_point;
4667
4668         if (Profile->get_mixbus()) {
4669                 if (ep == EditAtSelectedMarker) {
4670                         ep = EditAtPlayhead;
4671                 }
4672         }
4673
4674         if (from_outside_canvas && (ep == EditAtMouse)) {
4675                 ep = EditAtPlayhead;
4676         } else if (from_context_menu && (ep == EditAtMouse)) {
4677                 return  canvas_event_sample (&context_click_event, 0, 0);
4678         }
4679
4680         if (entered_marker) {
4681                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4682                 return entered_marker->position();
4683         }
4684
4685         if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4686                 ep = EditAtSelectedMarker;
4687         }
4688
4689         if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4690                 ep = EditAtPlayhead;
4691         }
4692
4693         switch (ep) {
4694         case EditAtPlayhead:
4695                 if (_dragging_playhead) {
4696                         where = *_control_scroll_target;
4697                 } else {
4698                         where = _session->audible_frame();
4699                 }
4700                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4701                 break;
4702
4703         case EditAtSelectedMarker:
4704                 if (!selection->markers.empty()) {
4705                         bool is_start;
4706                         Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4707                         if (loc) {
4708                                 if (is_start) {
4709                                         where =  loc->start();
4710                                 } else {
4711                                         where = loc->end();
4712                                 }
4713                                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4714                                 break;
4715                         }
4716                 }
4717                 /* fallthru */
4718
4719         default:
4720         case EditAtMouse:
4721                 if (!mouse_frame (where, ignored)) {
4722                         /* XXX not right but what can we do ? */
4723                         return 0;
4724                 }
4725                 snap_to (where);
4726                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4727                 break;
4728         }
4729
4730         return where;
4731 }
4732
4733 void
4734 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4735 {
4736         if (!_session) return;
4737
4738         begin_reversible_command (cmd);
4739
4740         Location* tll;
4741
4742         if ((tll = transport_loop_location()) == 0) {
4743                 Location* loc = new Location (*_session, start, end, _("Loop"),  Location::IsAutoLoop);
4744                 XMLNode &before = _session->locations()->get_state();
4745                 _session->locations()->add (loc, true);
4746                 _session->set_auto_loop_location (loc);
4747                 XMLNode &after = _session->locations()->get_state();
4748                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4749         } else {
4750                 XMLNode &before = tll->get_state();
4751                 tll->set_hidden (false, this);
4752                 tll->set (start, end);
4753                 XMLNode &after = tll->get_state();
4754                 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4755         }
4756
4757         commit_reversible_command ();
4758 }
4759
4760 void
4761 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4762 {
4763         if (!_session) return;
4764
4765         begin_reversible_command (cmd);
4766
4767         Location* tpl;
4768
4769         if ((tpl = transport_punch_location()) == 0) {
4770                 Location* loc = new Location (*_session, start, end, _("Punch"),  Location::IsAutoPunch);
4771                 XMLNode &before = _session->locations()->get_state();
4772                 _session->locations()->add (loc, true);
4773                 _session->set_auto_punch_location (loc);
4774                 XMLNode &after = _session->locations()->get_state();
4775                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4776         } else {
4777                 XMLNode &before = tpl->get_state();
4778                 tpl->set_hidden (false, this);
4779                 tpl->set (start, end);
4780                 XMLNode &after = tpl->get_state();
4781                 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4782         }
4783
4784         commit_reversible_command ();
4785 }
4786
4787 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4788  *  @param rs List to which found regions are added.
4789  *  @param where Time to look at.
4790  *  @param ts Tracks to look on; if this is empty, all tracks are examined.
4791  */
4792 void
4793 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4794 {
4795         const TrackViewList* tracks;
4796
4797         if (ts.empty()) {
4798                 tracks = &track_views;
4799         } else {
4800                 tracks = &ts;
4801         }
4802
4803         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4804
4805                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4806
4807                 if (rtv) {
4808                         boost::shared_ptr<Track> tr;
4809                         boost::shared_ptr<Playlist> pl;
4810
4811                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4812
4813                                 boost::shared_ptr<RegionList> regions = pl->regions_at (
4814                                                 (framepos_t) floor ( (double) where * tr->speed()));
4815
4816                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4817                                         RegionView* rv = rtv->view()->find_view (*i);
4818                                         if (rv) {
4819                                                 rs.add (rv);
4820                                         }
4821                                 }
4822                         }
4823                 }
4824         }
4825 }
4826
4827 void
4828 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4829 {
4830         const TrackViewList* tracks;
4831
4832         if (ts.empty()) {
4833                 tracks = &track_views;
4834         } else {
4835                 tracks = &ts;
4836         }
4837
4838         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4839                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4840                 if (rtv) {
4841                         boost::shared_ptr<Track> tr;
4842                         boost::shared_ptr<Playlist> pl;
4843
4844                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4845
4846                                 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4847                                         (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4848
4849                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4850
4851                                         RegionView* rv = rtv->view()->find_view (*i);
4852
4853                                         if (rv) {
4854                                                 rs.add (rv);
4855                                         }
4856                                 }
4857                         }
4858                 }
4859         }
4860 }
4861
4862 /** Get regions using the following method:
4863  *
4864  *  Make a region list using:
4865  *   (a) any selected regions
4866  *   (b) the intersection of any selected tracks and the edit point(*)
4867  *   (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4868  *
4869  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4870  *
4871  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4872  */
4873
4874 RegionSelection
4875 Editor::get_regions_from_selection_and_edit_point ()
4876 {
4877         RegionSelection regions;
4878
4879         if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4880                 regions.add (entered_regionview);
4881         } else {
4882                 regions = selection->regions;
4883         }
4884
4885         if ( regions.empty() ) {
4886                 TrackViewList tracks = selection->tracks;
4887
4888                 if (!tracks.empty()) {
4889                         /* no region selected or entered, but some selected tracks:
4890                          * act on all regions on the selected tracks at the edit point
4891                          */
4892                         framepos_t const where = get_preferred_edit_position ();
4893                         get_regions_at(regions, where, tracks);
4894                 }
4895         }
4896
4897         return regions;
4898 }
4899
4900 /** Get regions using the following method:
4901  *
4902  *  Make a region list using:
4903  *   (a) any selected regions
4904  *   (b) the intersection of any selected tracks and the edit point(*)
4905  *   (c) if neither exists, then whatever region is under the mouse
4906  *
4907  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4908  *
4909  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4910  */
4911 RegionSelection
4912 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4913 {
4914         RegionSelection regions;
4915
4916         if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4917                 regions.add (entered_regionview);
4918         } else {
4919                 regions = selection->regions;
4920         }
4921
4922         if ( regions.empty() ) {
4923                 TrackViewList tracks = selection->tracks;
4924
4925                 if (!tracks.empty()) {
4926                         /* no region selected or entered, but some selected tracks:
4927                          * act on all regions on the selected tracks at the edit point
4928                          */
4929                         get_regions_at(regions, pos, tracks);
4930                 }
4931         }
4932
4933         return regions;
4934 }
4935
4936 /** Start with regions that are selected, or the entered regionview if none are selected.
4937  *  Then add equivalent regions on tracks in the same active edit-enabled route group as any
4938  *  of the regions that we started with.
4939  */
4940
4941 RegionSelection
4942 Editor::get_regions_from_selection_and_entered () const
4943 {
4944         RegionSelection regions = selection->regions;
4945
4946         if (regions.empty() && entered_regionview) {
4947                 regions.add (entered_regionview);
4948         }
4949
4950         return regions;
4951 }
4952
4953 void
4954 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4955 {
4956         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4957                 RouteTimeAxisView* rtav;
4958
4959                 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4960                         boost::shared_ptr<Playlist> pl;
4961                         std::vector<boost::shared_ptr<Region> > results;
4962                         boost::shared_ptr<Track> tr;
4963
4964                         if ((tr = rtav->track()) == 0) {
4965                                 /* bus */
4966                                 continue;
4967                         }
4968
4969                         if ((pl = (tr->playlist())) != 0) {
4970                                 boost::shared_ptr<Region> r = pl->region_by_id (id);
4971                                 if (r) {
4972                                         RegionView* rv = rtav->view()->find_view (r);
4973                                         if (rv) {
4974                                                 regions.push_back (rv);
4975                                         }
4976                                 }
4977                         }
4978                 }
4979         }
4980 }
4981
4982 void
4983 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4984 {
4985
4986         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4987                 MidiTimeAxisView* mtav;
4988
4989                 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4990
4991                         mtav->get_per_region_note_selection (selection);
4992                 }
4993         }
4994
4995 }
4996
4997 void
4998 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4999 {
5000         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5001
5002                 RouteTimeAxisView* tatv;
5003
5004                 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5005
5006                         boost::shared_ptr<Playlist> pl;
5007                         vector<boost::shared_ptr<Region> > results;
5008                         RegionView* marv;
5009                         boost::shared_ptr<Track> tr;
5010
5011                         if ((tr = tatv->track()) == 0) {
5012                                 /* bus */
5013                                 continue;
5014                         }
5015
5016                         if ((pl = (tr->playlist())) != 0) {
5017                                 if (src_comparison) {
5018                                         pl->get_source_equivalent_regions (region, results);
5019                                 } else {
5020                                         pl->get_region_list_equivalent_regions (region, results);
5021                                 }
5022                         }
5023
5024                         for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5025                                 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5026                                         regions.push_back (marv);
5027                                 }
5028                         }
5029
5030                 }
5031         }
5032 }
5033
5034 void
5035 Editor::show_rhythm_ferret ()
5036 {
5037         if (rhythm_ferret == 0) {
5038                 rhythm_ferret = new RhythmFerret(*this);
5039         }
5040
5041         rhythm_ferret->set_session (_session);
5042         rhythm_ferret->show ();
5043         rhythm_ferret->present ();
5044 }
5045
5046 void
5047 Editor::first_idle ()
5048 {
5049         MessageDialog* dialog = 0;
5050
5051         if (track_views.size() > 1) {
5052                 Timers::TimerSuspender t;
5053                 dialog = new MessageDialog (
5054                         string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5055                         true
5056                         );
5057                 dialog->present ();
5058                 ARDOUR_UI::instance()->flush_pending (60);
5059         }
5060
5061         for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5062                 (*t)->first_idle();
5063         }
5064
5065         // first idle adds route children (automation tracks), so we need to redisplay here
5066         _routes->redisplay ();
5067
5068         delete dialog;
5069
5070         if (_session->undo_depth() == 0) {
5071                 undo_action->set_sensitive(false);
5072         }
5073         redo_action->set_sensitive(false);
5074         begin_selection_op_history ();
5075
5076         _have_idled = true;
5077 }
5078
5079 gboolean
5080 Editor::_idle_resize (gpointer arg)
5081 {
5082         return ((Editor*)arg)->idle_resize ();
5083 }
5084
5085 void
5086 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5087 {
5088         if (resize_idle_id < 0) {
5089                 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5090                  * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5091                  * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5092                  */
5093                 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5094                 _pending_resize_amount = 0;
5095         }
5096
5097         /* make a note of the smallest resulting height, so that we can clamp the
5098            lower limit at TimeAxisView::hSmall */
5099
5100         int32_t min_resulting = INT32_MAX;
5101
5102         _pending_resize_amount += h;
5103         _pending_resize_view = view;
5104
5105         min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5106
5107         if (selection->tracks.contains (_pending_resize_view)) {
5108                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5109                         min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5110                 }
5111         }
5112
5113         if (min_resulting < 0) {
5114                 min_resulting = 0;
5115         }
5116
5117         /* clamp */
5118         if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5119                 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5120         }
5121 }
5122
5123 /** Handle pending resizing of tracks */
5124 bool
5125 Editor::idle_resize ()
5126 {
5127         _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5128
5129         if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5130             selection->tracks.contains (_pending_resize_view)) {
5131
5132                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5133                         if (*i != _pending_resize_view) {
5134                                 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5135                         }
5136                 }
5137         }
5138
5139         _pending_resize_amount = 0;
5140         _group_tabs->set_dirty ();
5141         resize_idle_id = -1;
5142
5143         return false;
5144 }
5145
5146 void
5147 Editor::located ()
5148 {
5149         ENSURE_GUI_THREAD (*this, &Editor::located);
5150
5151         if (_session) {
5152                 playhead_cursor->set_position (_session->audible_frame ());
5153                 if (_follow_playhead && !_pending_initial_locate) {
5154                         reset_x_origin_to_follow_playhead ();
5155                 }
5156         }
5157
5158         _pending_locate_request = false;
5159         _pending_initial_locate = false;
5160 }
5161
5162 void
5163 Editor::region_view_added (RegionView * rv)
5164 {
5165         for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5166                 if (rv->region ()->id () == (*pr)) {
5167                         selection->add (rv);
5168                         selection->regions.pending.erase (pr);
5169                         break;
5170                 }
5171         }
5172
5173         MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5174         if (mrv) {
5175                 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5176                 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5177                         if (rv->region()->id () == (*rnote).first) {
5178                                 mrv->select_notes ((*rnote).second);
5179                                 selection->pending_midi_note_selection.erase(rnote);
5180                                 break;
5181                         }
5182                 }
5183         }
5184
5185         _summary->set_background_dirty ();
5186 }
5187
5188 void
5189 Editor::region_view_removed ()
5190 {
5191         _summary->set_background_dirty ();
5192 }
5193
5194 TimeAxisView*
5195 Editor::axis_view_from_stripable (boost::shared_ptr<Stripable> s) const
5196 {
5197         for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5198                 if ((*j)->stripable() == s) {
5199                         return *j;
5200                 }
5201         }
5202
5203         return 0;
5204 }
5205
5206
5207 TrackViewList
5208 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5209 {
5210         TrackViewList t;
5211
5212         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5213                 TimeAxisView* tv = axis_view_from_stripable (*i);
5214                 if (tv) {
5215                         t.push_back (tv);
5216                 }
5217         }
5218
5219         return t;
5220 }
5221
5222 void
5223 Editor::suspend_route_redisplay ()
5224 {
5225         if (_routes) {
5226                 _routes->suspend_redisplay();
5227         }
5228 }
5229
5230 void
5231 Editor::resume_route_redisplay ()
5232 {
5233         if (_routes) {
5234                 _routes->redisplay(); // queue redisplay
5235                 _routes->resume_redisplay();
5236         }
5237 }
5238
5239 void
5240 Editor::add_vcas (VCAList& vlist)
5241 {
5242         StripableList sl;
5243
5244         for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5245                 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5246         }
5247
5248         add_stripables (sl);
5249 }
5250
5251 void
5252 Editor::add_routes (RouteList& rlist)
5253 {
5254         StripableList sl;
5255
5256         for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5257                 sl.push_back (*r);
5258         }
5259
5260         add_stripables (sl);
5261 }
5262
5263 void
5264 Editor::add_stripables (StripableList& sl)
5265 {
5266         list<TimeAxisView*> new_views;
5267         boost::shared_ptr<VCA> v;
5268         boost::shared_ptr<Route> r;
5269         TrackViewList new_selection;
5270         bool from_scratch = (track_views.size() == 0);
5271
5272         sl.sort (StripablePresentationInfoSorter());
5273
5274         for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5275
5276                 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5277
5278                         VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5279                         vtv->set_vca (v);
5280                         new_views.push_back (vtv);
5281
5282                 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5283
5284                         if (r->is_auditioner() || r->is_monitor()) {
5285                                 continue;
5286                         }
5287
5288                         RouteTimeAxisView* rtv;
5289                         DataType dt = r->input()->default_type();
5290
5291                         if (dt == ARDOUR::DataType::AUDIO) {
5292                                 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5293                                 rtv->set_route (r);
5294                         } else if (dt == ARDOUR::DataType::MIDI) {
5295                                 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5296                                 rtv->set_route (r);
5297                         } else {
5298                                 throw unknown_type();
5299                         }
5300
5301                         new_views.push_back (rtv);
5302                         track_views.push_back (rtv);
5303                         new_selection.push_back (rtv);
5304
5305                         rtv->effective_gain_display ();
5306
5307                         rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5308                         rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5309                 }
5310         }
5311
5312         if (new_views.size() > 0) {
5313                 _routes->time_axis_views_added (new_views);
5314                 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5315         }
5316
5317         /* note: !new_selection.empty() means that we got some routes rather
5318          * than just VCAs
5319          */
5320
5321         if (!from_scratch && !new_selection.empty()) {
5322                 selection->tracks.clear();
5323                 selection->add (new_selection);
5324                 begin_selection_op_history();
5325         }
5326
5327         if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5328                 show_editor_mixer (true);
5329         }
5330
5331         editor_list_button.set_sensitive (true);
5332 }
5333
5334 void
5335 Editor::timeaxisview_deleted (TimeAxisView *tv)
5336 {
5337         if (tv == entered_track) {
5338                 entered_track = 0;
5339         }
5340
5341         if (_session && _session->deletion_in_progress()) {
5342                 /* the situation is under control */
5343                 return;
5344         }
5345
5346         ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5347
5348         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5349
5350         _routes->route_removed (tv);
5351
5352         TimeAxisView::Children c = tv->get_child_list ();
5353         for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5354                 if (entered_track == i->get()) {
5355                         entered_track = 0;
5356                 }
5357         }
5358
5359         /* remove it from the list of track views */
5360
5361         TrackViewList::iterator i;
5362
5363         if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5364                 i = track_views.erase (i);
5365         }
5366
5367         /* update whatever the current mixer strip is displaying, if revelant */
5368
5369         boost::shared_ptr<Route> route;
5370
5371         if (rtav) {
5372                 route = rtav->route ();
5373         }
5374
5375         if (current_mixer_strip && current_mixer_strip->route() == route) {
5376
5377                 TimeAxisView* next_tv;
5378
5379                 if (track_views.empty()) {
5380                         next_tv = 0;
5381                 } else if (i == track_views.end()) {
5382                         next_tv = track_views.front();
5383                 } else {
5384                         next_tv = (*i);
5385                 }
5386
5387
5388                 if (next_tv) {
5389                         set_selected_mixer_strip (*next_tv);
5390                 } else {
5391                         /* make the editor mixer strip go away setting the
5392                          * button to inactive (which also unticks the menu option)
5393                          */
5394
5395                         ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5396                 }
5397         }
5398 }
5399
5400 void
5401 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5402 {
5403         if (apply_to_selection) {
5404                 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5405
5406                         TrackSelection::iterator j = i;
5407                         ++j;
5408
5409                         hide_track_in_display (*i, false);
5410
5411                         i = j;
5412                 }
5413         } else {
5414                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5415
5416                 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5417                         // this will hide the mixer strip
5418                         set_selected_mixer_strip (*tv);
5419                 }
5420
5421                 _routes->hide_track_in_display (*tv);
5422         }
5423 }
5424
5425 bool
5426 Editor::sync_track_view_list_and_routes ()
5427 {
5428         track_views = TrackViewList (_routes->views ());
5429
5430         _summary->set_background_dirty();
5431         _group_tabs->set_dirty ();
5432
5433         return false; // do not call again (until needed)
5434 }
5435
5436 void
5437 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5438 {
5439         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5440                 theslot (**i);
5441         }
5442 }
5443
5444 /** Find a RouteTimeAxisView by the ID of its route */
5445 RouteTimeAxisView*
5446 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5447 {
5448         RouteTimeAxisView* v;
5449
5450         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5451                 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5452                         if(v->route()->id() == id) {
5453                                 return v;
5454                         }
5455                 }
5456         }
5457
5458         return 0;
5459 }
5460
5461 void
5462 Editor::fit_route_group (RouteGroup *g)
5463 {
5464         TrackViewList ts = axis_views_from_routes (g->route_list ());
5465         fit_tracks (ts);
5466 }
5467
5468 void
5469 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5470 {
5471         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5472
5473         if (r == 0) {
5474                 _session->cancel_audition ();
5475                 return;
5476         }
5477
5478         if (_session->is_auditioning()) {
5479                 _session->cancel_audition ();
5480                 if (r == last_audition_region) {
5481                         return;
5482                 }
5483         }
5484
5485         _session->audition_region (r);
5486         last_audition_region = r;
5487 }
5488
5489
5490 void
5491 Editor::hide_a_region (boost::shared_ptr<Region> r)
5492 {
5493         r->set_hidden (true);
5494 }
5495
5496 void
5497 Editor::show_a_region (boost::shared_ptr<Region> r)
5498 {
5499         r->set_hidden (false);
5500 }
5501
5502 void
5503 Editor::audition_region_from_region_list ()
5504 {
5505         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5506 }
5507
5508 void
5509 Editor::hide_region_from_region_list ()
5510 {
5511         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5512 }
5513
5514 void
5515 Editor::show_region_in_region_list ()
5516 {
5517         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5518 }
5519
5520 void
5521 Editor::step_edit_status_change (bool yn)
5522 {
5523         if (yn) {
5524                 start_step_editing ();
5525         } else {
5526                 stop_step_editing ();
5527         }
5528 }
5529
5530 void
5531 Editor::start_step_editing ()
5532 {
5533         step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5534 }
5535
5536 void
5537 Editor::stop_step_editing ()
5538 {
5539         step_edit_connection.disconnect ();
5540 }
5541
5542 bool
5543 Editor::check_step_edit ()
5544 {
5545         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5546                 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5547                 if (mtv) {
5548                         mtv->check_step_edit ();
5549                 }
5550         }
5551
5552         return true; // do it again, till we stop
5553 }
5554
5555 bool
5556 Editor::scroll_press (Direction dir)
5557 {
5558         ++_scroll_callbacks;
5559
5560         if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5561                 /* delay the first auto-repeat */
5562                 return true;
5563         }
5564
5565         switch (dir) {
5566         case LEFT:
5567                 scroll_backward (1);
5568                 break;
5569
5570         case RIGHT:
5571                 scroll_forward (1);
5572                 break;
5573
5574         case UP:
5575                 scroll_up_one_track ();
5576                 break;
5577
5578         case DOWN:
5579                 scroll_down_one_track ();
5580                 break;
5581         }
5582
5583         /* do hacky auto-repeat */
5584         if (!_scroll_connection.connected ()) {
5585
5586                 _scroll_connection = Glib::signal_timeout().connect (
5587                         sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5588                         );
5589
5590                 _scroll_callbacks = 0;
5591         }
5592
5593         return true;
5594 }
5595
5596 void
5597 Editor::scroll_release ()
5598 {
5599         _scroll_connection.disconnect ();
5600 }
5601
5602 /** Queue a change for the Editor viewport x origin to follow the playhead */
5603 void
5604 Editor::reset_x_origin_to_follow_playhead ()
5605 {
5606         framepos_t const frame = playhead_cursor->current_frame ();
5607
5608         if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5609
5610                 if (_session->transport_speed() < 0) {
5611
5612                         if (frame > (current_page_samples() / 2)) {
5613                                 center_screen (frame-(current_page_samples()/2));
5614                         } else {
5615                                 center_screen (current_page_samples()/2);
5616                         }
5617
5618                 } else {
5619
5620                         framepos_t l = 0;
5621
5622                         if (frame < leftmost_frame) {
5623                                 /* moving left */
5624                                 if (_session->transport_rolling()) {
5625                                         /* rolling; end up with the playhead at the right of the page */
5626                                         l = frame - current_page_samples ();
5627                                 } else {
5628                                         /* not rolling: end up with the playhead 1/4 of the way along the page */
5629                                         l = frame - current_page_samples() / 4;
5630                                 }
5631                         } else {
5632                                 /* moving right */
5633                                 if (_session->transport_rolling()) {
5634                                         /* rolling: end up with the playhead on the left of the page */
5635                                         l = frame;
5636                                 } else {
5637                                         /* not rolling: end up with the playhead 3/4 of the way along the page */
5638                                         l = frame - 3 * current_page_samples() / 4;
5639                                 }
5640                         }
5641
5642                         if (l < 0) {
5643                                 l = 0;
5644                         }
5645
5646                         center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5647                 }
5648         }
5649 }
5650
5651 void
5652 Editor::super_rapid_screen_update ()
5653 {
5654         if (!_session || !_session->engine().running()) {
5655                 return;
5656         }
5657
5658         /* METERING / MIXER STRIPS */
5659
5660         /* update track meters, if required */
5661         if (contents().is_mapped() && meters_running) {
5662                 RouteTimeAxisView* rtv;
5663                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5664                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5665                                 rtv->fast_update ();
5666                         }
5667                 }
5668         }
5669
5670         /* and any current mixer strip */
5671         if (current_mixer_strip) {
5672                 current_mixer_strip->fast_update ();
5673         }
5674
5675         /* PLAYHEAD AND VIEWPORT */
5676
5677         framepos_t const frame = _session->audible_frame();
5678
5679         /* There are a few reasons why we might not update the playhead / viewport stuff:
5680          *
5681          * 1.  we don't update things when there's a pending locate request, otherwise
5682          *     when the editor requests a locate there is a chance that this method
5683          *     will move the playhead before the locate request is processed, causing
5684          *     a visual glitch.
5685          * 2.  if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5686          * 3.  if we're still at the same frame that we were last time, there's nothing to do.
5687          */
5688
5689         if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5690
5691                 last_update_frame = frame;
5692
5693                 if (!_dragging_playhead) {
5694                         playhead_cursor->set_position (frame);
5695                 }
5696
5697                 if (!_stationary_playhead) {
5698
5699                         if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5700                                 /* We only do this if we aren't already
5701                                    handling a visual change (ie if
5702                                    pending_visual_change.being_handled is
5703                                    false) so that these requests don't stack
5704                                    up there are too many of them to handle in
5705                                    time.
5706                                 */
5707                                 reset_x_origin_to_follow_playhead ();
5708                         }
5709
5710                 } else {
5711
5712                         if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5713                                 framepos_t const frame = playhead_cursor->current_frame ();
5714                                 double target = ((double)frame - (double)current_page_samples()/2.0);
5715                                 if (target <= 0.0) {
5716                                         target = 0.0;
5717                                 }
5718                                 // compare to EditorCursor::set_position()
5719                                 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5720                                 double const new_pos = sample_to_pixel_unrounded (target);
5721                                 if (rint (new_pos) != rint (old_pos)) {
5722                                         reset_x_origin (pixel_to_sample (floor (new_pos)));
5723                                 }
5724                         }
5725
5726                 }
5727
5728         }
5729 }
5730
5731
5732 void
5733 Editor::session_going_away ()
5734 {
5735         _have_idled = false;
5736
5737         _session_connections.drop_connections ();
5738
5739         super_rapid_screen_update_connection.disconnect ();
5740
5741         selection->clear ();
5742         cut_buffer->clear ();
5743
5744         clicked_regionview = 0;
5745         clicked_axisview = 0;
5746         clicked_routeview = 0;
5747         entered_regionview = 0;
5748         entered_track = 0;
5749         last_update_frame = 0;
5750         _drags->abort ();
5751
5752         playhead_cursor->hide ();
5753
5754         /* rip everything out of the list displays */
5755
5756         _regions->clear ();
5757         _routes->clear ();
5758         _route_groups->clear ();
5759
5760         /* do this first so that deleting a track doesn't reset cms to null
5761            and thus cause a leak.
5762         */
5763
5764         if (current_mixer_strip) {
5765                 if (current_mixer_strip->get_parent() != 0) {
5766                         global_hpacker.remove (*current_mixer_strip);
5767                 }
5768                 delete current_mixer_strip;
5769                 current_mixer_strip = 0;
5770         }
5771
5772         /* delete all trackviews */
5773
5774         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5775                 delete *i;
5776         }
5777         track_views.clear ();
5778
5779         nudge_clock->set_session (0);
5780
5781         editor_list_button.set_active(false);
5782         editor_list_button.set_sensitive(false);
5783
5784         /* clear tempo/meter rulers */
5785         remove_metric_marks ();
5786         hide_measures ();
5787         clear_marker_display ();
5788
5789         stop_step_editing ();
5790
5791         if (own_window()) {
5792
5793                 /* get rid of any existing editor mixer strip */
5794
5795                 WindowTitle title(Glib::get_application_name());
5796                 title += _("Editor");
5797
5798                 own_window()->set_title (title.get_string());
5799         }
5800
5801         SessionHandlePtr::session_going_away ();
5802 }
5803
5804 void
5805 Editor::trigger_script (int i)
5806 {
5807         LuaInstance::instance()-> call_action (i);
5808 }
5809
5810 void
5811 Editor::set_script_action_name (int i, const std::string& n)
5812 {
5813         string const a = string_compose (X_("script-action-%1"), i + 1);
5814         Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5815         assert (act);
5816         if (n.empty ()) {
5817                 act->set_label (string_compose (_("Unset #%1"), i + 1));
5818                 act->set_tooltip (_("no action bound"));
5819                 act->set_sensitive (false);
5820         } else {
5821                 act->set_label (n);
5822                 act->set_tooltip (n);
5823                 act->set_sensitive (true);
5824         }
5825         KeyEditor::UpdateBindings ();
5826 }
5827
5828 void
5829 Editor::show_editor_list (bool yn)
5830 {
5831         if (yn) {
5832                 _the_notebook.show ();
5833         } else {
5834                 _the_notebook.hide ();
5835         }
5836 }
5837
5838 void
5839 Editor::change_region_layering_order (bool from_context_menu)
5840 {
5841         const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5842
5843         if (!clicked_routeview) {
5844                 if (layering_order_editor) {
5845                         layering_order_editor->hide ();
5846                 }
5847                 return;
5848         }
5849
5850         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5851
5852         if (!track) {
5853                 return;
5854         }
5855
5856         boost::shared_ptr<Playlist> pl = track->playlist();
5857
5858         if (!pl) {
5859                 return;
5860         }
5861
5862         if (layering_order_editor == 0) {
5863                 layering_order_editor = new RegionLayeringOrderEditor (*this);
5864         }
5865
5866         layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5867         layering_order_editor->maybe_present ();
5868 }
5869
5870 void
5871 Editor::update_region_layering_order_editor ()
5872 {
5873         if (layering_order_editor && layering_order_editor->is_visible ()) {
5874                 change_region_layering_order (true);
5875         }
5876 }
5877
5878 void
5879 Editor::setup_fade_images ()
5880 {
5881         _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5882         _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5883         _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5884         _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5885         _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5886
5887         _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5888         _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5889         _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5890         _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5891         _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5892
5893         _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5894         _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5895         _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5896         _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5897         _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5898
5899         _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5900         _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5901         _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5902         _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5903         _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5904
5905 }
5906
5907 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5908 Gtk::MenuItem&
5909 Editor::action_menu_item (std::string const & name)
5910 {
5911         Glib::RefPtr<Action> a = editor_actions->get_action (name);
5912         assert (a);
5913
5914         return *manage (a->create_menu_item ());
5915 }
5916
5917 void
5918 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5919 {
5920         EventBox* b = manage (new EventBox);
5921         b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5922         Label* l = manage (new Label (name));
5923         l->set_angle (-90);
5924         b->add (*l);
5925         b->show_all ();
5926         _the_notebook.append_page (widget, *b);
5927 }
5928
5929 bool
5930 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5931 {
5932         if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5933                 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5934         }
5935
5936         if (ev->type == GDK_2BUTTON_PRESS) {
5937
5938                 /* double-click on a notebook tab shrinks or expands the notebook */
5939
5940                 if (_notebook_shrunk) {
5941                         if (pre_notebook_shrink_pane_width) {
5942                                 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
5943                         }
5944                         _notebook_shrunk = false;
5945                 } else {
5946                         pre_notebook_shrink_pane_width = edit_pane.get_divider();
5947
5948                         /* this expands the LHS of the edit pane to cover the notebook
5949                            PAGE but leaves the tabs visible.
5950                          */
5951                         edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
5952                         _notebook_shrunk = true;
5953                 }
5954         }
5955
5956         return true;
5957 }
5958
5959 void
5960 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5961 {
5962         using namespace Menu_Helpers;
5963
5964         MenuList& items = _control_point_context_menu.items ();
5965         items.clear ();
5966
5967         items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5968         items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5969         if (!can_remove_control_point (item)) {
5970                 items.back().set_sensitive (false);
5971         }
5972
5973         _control_point_context_menu.popup (event->button.button, event->button.time);
5974 }
5975
5976 void
5977 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5978 {
5979         using namespace Menu_Helpers;
5980
5981         NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5982         if (!note) {
5983                 return;
5984         }
5985
5986         /* We need to get the selection here and pass it to the operations, since
5987            popping up the menu will cause a region leave event which clears
5988            entered_regionview. */
5989
5990         MidiRegionView&       mrv = note->region_view();
5991         const RegionSelection rs  = get_regions_from_selection_and_entered ();
5992         const uint32_t sel_size = mrv.selection_size ();
5993
5994         MenuList& items = _note_context_menu.items();
5995         items.clear();
5996
5997         if (sel_size > 0) {
5998                 items.push_back(MenuElem(_("Delete"),
5999                                          sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6000         }
6001
6002         items.push_back(MenuElem(_("Edit..."),
6003                                  sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6004         if (sel_size != 1) {
6005                 items.back().set_sensitive (false);
6006         }
6007
6008         items.push_back(MenuElem(_("Transpose..."),
6009                                  sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6010
6011
6012         items.push_back(MenuElem(_("Legatize"),
6013                                  sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6014         if (sel_size < 2) {
6015                 items.back().set_sensitive (false);
6016         }
6017
6018         items.push_back(MenuElem(_("Quantize..."),
6019                                  sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6020
6021         items.push_back(MenuElem(_("Remove Overlap"),
6022                                  sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6023         if (sel_size < 2) {
6024                 items.back().set_sensitive (false);
6025         }
6026
6027         items.push_back(MenuElem(_("Transform..."),
6028                                  sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6029
6030         _note_context_menu.popup (event->button.button, event->button.time);
6031 }
6032
6033 void
6034 Editor::zoom_vertical_modifier_released()
6035 {
6036         _stepping_axis_view = 0;
6037 }
6038
6039 void
6040 Editor::ui_parameter_changed (string parameter)
6041 {
6042         if (parameter == "icon-set") {
6043                 while (!_cursor_stack.empty()) {
6044                         _cursor_stack.pop_back();
6045                 }
6046                 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6047                 _cursor_stack.push_back(_cursors->grabber);
6048                 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6049                 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6050
6051         } else if (parameter == "draggable-playhead") {
6052                 if (_verbose_cursor) {
6053                         playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6054                 }
6055         }
6056 }
6057
6058 Gtk::Window*
6059 Editor::use_own_window (bool and_fill_it)
6060 {
6061         bool new_window = !own_window();
6062
6063         Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6064
6065         if (win && new_window) {
6066                 win->set_name ("EditorWindow");
6067
6068                 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6069
6070                 // win->signal_realize().connect (*this, &Editor::on_realize);
6071                 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6072                 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6073                 win->set_data ("ardour-bindings", bindings);
6074
6075                 update_title ();
6076         }
6077
6078         DisplaySuspender ds;
6079         contents().show_all ();
6080
6081         /* XXX: this is a bit unfortunate; it would probably
6082            be nicer if we could just call show () above rather
6083            than needing the show_all ()
6084         */
6085
6086         /* re-hide stuff if necessary */
6087         editor_list_button_toggled ();
6088         parameter_changed ("show-summary");
6089         parameter_changed ("show-group-tabs");
6090         parameter_changed ("show-zoom-tools");
6091
6092         /* now reset all audio_time_axis heights, because widgets might need
6093            to be re-hidden
6094         */
6095
6096         TimeAxisView *tv;
6097
6098         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6099                 tv = (static_cast<TimeAxisView*>(*i));
6100                 tv->reset_height ();
6101         }
6102
6103         if (current_mixer_strip) {
6104                 current_mixer_strip->hide_things ();
6105                 current_mixer_strip->parameter_changed ("mixer-element-visibility");
6106         }
6107
6108         return win;
6109 }