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