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