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