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