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