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