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