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