ff587b2fc14683886a363d346e6e0ffeaa3fe3a0
[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         if (Profile->get_mixbus()) {
2306                 if (ep == EditAtSelectedMarker) {
2307                         ep = EditAtPlayhead;
2308                 }
2309         }
2310
2311         bool changed = (_edit_point != ep);
2312
2313         _edit_point = ep;
2314
2315         string str = edit_point_strings[(int)ep];
2316         if (str != edit_point_selector.get_text ()) {
2317                 edit_point_selector.set_text (str);
2318         }
2319
2320         update_all_enter_cursors();
2321
2322         if (!force && !changed) {
2323                 return;
2324         }
2325
2326         const char* action=NULL;
2327
2328         switch (_edit_point) {
2329         case EditAtPlayhead:
2330                 action = "edit-at-playhead";
2331                 break;
2332         case EditAtSelectedMarker:
2333                 action = "edit-at-selected-marker";
2334                 break;
2335         case EditAtMouse:
2336                 action = "edit-at-mouse";
2337                 break;
2338         }
2339
2340         Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action ("Editor", action);
2341         tact->set_active (true);
2342
2343         samplepos_t foo;
2344         bool in_track_canvas;
2345
2346         if (!mouse_sample (foo, in_track_canvas)) {
2347                 in_track_canvas = false;
2348         }
2349
2350         reset_canvas_action_sensitivity (in_track_canvas);
2351         sensitize_the_right_region_actions (false);
2352
2353         instant_save ();
2354 }
2355
2356 int
2357 Editor::set_state (const XMLNode& node, int version)
2358 {
2359         set_id (node);
2360         PBD::Unwinder<bool> nsi (no_save_instant, true);
2361         bool yn;
2362
2363         Tabbable::set_state (node, version);
2364
2365         samplepos_t ph_pos;
2366         if (_session && node.get_property ("playhead", ph_pos)) {
2367                 if (ph_pos >= 0) {
2368                         playhead_cursor->set_position (ph_pos);
2369                 } else {
2370                         warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2371                         playhead_cursor->set_position (0);
2372                 }
2373         } else {
2374                 playhead_cursor->set_position (0);
2375         }
2376
2377         node.get_property ("mixer-width", editor_mixer_strip_width);
2378
2379         node.get_property ("zoom-focus", zoom_focus);
2380         zoom_focus_selection_done (zoom_focus);
2381
2382         double z;
2383         if (node.get_property ("zoom", z)) {
2384                 /* older versions of ardour used floating point samples_per_pixel */
2385                 reset_zoom (llrintf (z));
2386         } else {
2387                 reset_zoom (samples_per_pixel);
2388         }
2389
2390         int32_t cnt;
2391         if (node.get_property ("visible-track-count", cnt)) {
2392                 set_visible_track_count (cnt);
2393         }
2394
2395         GridType grid_type;
2396         if (!node.get_property ("grid-type", grid_type)) {
2397                 grid_type = _grid_type;
2398         }
2399         set_grid_to (grid_type);
2400
2401         SnapMode sm;
2402         if (node.get_property ("snap-mode", sm)) {
2403                 snap_mode_selection_done(sm);
2404                 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2405                  * snap_mode_selection_done() will only mark an already active item as active
2406                  * which does not trigger set_text().
2407                  */
2408                 set_snap_mode (sm);
2409         } else {
2410                 set_snap_mode (_snap_mode);
2411         }
2412
2413         node.get_property ("internal-grid-type", internal_grid_type);
2414         node.get_property ("internal-snap-mode", internal_snap_mode);
2415         node.get_property ("pre-internal-grid-type", pre_internal_grid_type);
2416         node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2417
2418         std::string mm_str;
2419         if (node.get_property ("mouse-mode", mm_str)) {
2420                 MouseMode m = str2mousemode(mm_str);
2421                 set_mouse_mode (m, true);
2422         } else {
2423                 set_mouse_mode (MouseObject, true);
2424         }
2425
2426         samplepos_t lf_pos;
2427         if (node.get_property ("left-frame", lf_pos)) {
2428                 if (lf_pos < 0) {
2429                         lf_pos = 0;
2430                 }
2431                 reset_x_origin (lf_pos);
2432         }
2433
2434         double y_origin;
2435         if (node.get_property ("y-origin", y_origin)) {
2436                 reset_y_origin (y_origin);
2437         }
2438
2439         yn = false;
2440         node.get_property ("join-object-range", yn);
2441         {
2442                 RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2443                 /* do it twice to force the change */
2444                 tact->set_active (!yn);
2445                 tact->set_active (yn);
2446                 set_mouse_mode(mouse_mode, true);
2447         }
2448
2449         EditPoint ep;
2450         if (node.get_property ("edit-point", ep)) {
2451                 set_edit_point_preference (ep, true);
2452         } else {
2453                 set_edit_point_preference (_edit_point);
2454         }
2455
2456         if (node.get_property ("follow-playhead", yn)) {
2457                 set_follow_playhead (yn);
2458         }
2459
2460         if (node.get_property ("stationary-playhead", yn)) {
2461                 set_stationary_playhead (yn);
2462         }
2463
2464         RegionListSortType sort_type;
2465         if (node.get_property ("region-list-sort-type", sort_type)) {
2466                 _regions->reset_sort_type (sort_type, true);
2467         }
2468
2469         yn = false;
2470         node.get_property ("show-editor-mixer", yn);
2471         {
2472                 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-mixer"));
2473                 /* do it twice to force the change */
2474                 tact->set_active (!yn);
2475                 tact->set_active (yn);
2476         }
2477
2478         yn = false;
2479         node.get_property ("show-editor-list", yn);
2480         {
2481                 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-list"));
2482                 /* do it twice to force the change */
2483                 tact->set_active (!yn);
2484                 tact->set_active (yn);
2485         }
2486
2487         int32_t el_page;
2488         if (node.get_property (X_("editor-list-page"), el_page)) {
2489                 _the_notebook.set_current_page (el_page);
2490         }
2491
2492         yn = false;
2493         node.get_property (X_("show-marker-lines"), yn);
2494         {
2495                 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-marker-lines"));
2496                 /* do it twice to force the change */
2497                 tact->set_active (!yn);
2498                 tact->set_active (yn);
2499         }
2500
2501         XMLNodeList children = node.children ();
2502         for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2503                 selection->set_state (**i, Stateful::current_state_version);
2504                 _regions->set_state (**i);
2505                 _locations->set_state (**i);
2506         }
2507
2508         if (node.get_property ("maximised", yn)) {
2509                 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Common"), X_("ToggleMaximalEditor"));
2510                 bool fs = tact->get_active();
2511                 if (yn ^ fs) {
2512                         ActionManager::do_action ("Common", "ToggleMaximalEditor");
2513                 }
2514         }
2515
2516         samplepos_t nudge_clock_value;
2517         if (node.get_property ("nudge-clock-value", nudge_clock_value)) {
2518                 nudge_clock->set (nudge_clock_value);
2519         } else {
2520                 nudge_clock->set_mode (AudioClock::Timecode);
2521                 nudge_clock->set (_session->sample_rate() * 5, true);
2522         }
2523
2524         {
2525                 /* apply state
2526                  * Not all properties may have been in XML, but
2527                  * those that are linked to a private variable may need changing
2528                  */
2529                 RefPtr<ToggleAction> tact;
2530
2531                 tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-follow-playhead"));
2532                 yn = _follow_playhead;
2533                 if (tact->get_active() != yn) {
2534                         tact->set_active (yn);
2535                 }
2536
2537                 tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-stationary-playhead"));
2538                 yn = _stationary_playhead;
2539                 if (tact->get_active() != yn) {
2540                         tact->set_active (yn);
2541                 }
2542         }
2543
2544         return 0;
2545 }
2546
2547 XMLNode&
2548 Editor::get_state ()
2549 {
2550         XMLNode* node = new XMLNode (X_("Editor"));
2551
2552         node->set_property ("id", id().to_s ());
2553
2554         node->add_child_nocopy (Tabbable::get_state());
2555
2556         node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ());
2557         node->set_property("notebook-shrunk", _notebook_shrunk);
2558         node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider());
2559
2560         maybe_add_mixer_strip_width (*node);
2561
2562         node->set_property ("zoom-focus", zoom_focus);
2563
2564         node->set_property ("zoom", samples_per_pixel);
2565         node->set_property ("grid-type", _grid_type);
2566         node->set_property ("snap-mode", _snap_mode);
2567         node->set_property ("internal-grid-type", internal_grid_type);
2568         node->set_property ("internal-snap-mode", internal_snap_mode);
2569         node->set_property ("pre-internal-grid-type", pre_internal_grid_type);
2570         node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2571         node->set_property ("edit-point", _edit_point);
2572         node->set_property ("visible-track-count", _visible_track_count);
2573
2574         node->set_property ("playhead", playhead_cursor->current_sample ());
2575         node->set_property ("left-frame", _leftmost_sample);
2576         node->set_property ("y-origin", vertical_adjustment.get_value ());
2577
2578         node->set_property ("maximised", _maximised);
2579         node->set_property ("follow-playhead", _follow_playhead);
2580         node->set_property ("stationary-playhead", _stationary_playhead);
2581         node->set_property ("region-list-sort-type", _regions->sort_type ());
2582         node->set_property ("mouse-mode", mouse_mode);
2583         node->set_property ("join-object-range", smart_mode_action->get_active ());
2584
2585         Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-mixer"));
2586         node->set_property (X_("show-editor-mixer"), tact->get_active());
2587
2588         tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-list"));
2589         node->set_property (X_("show-editor-list"), tact->get_active());
2590
2591         node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
2592
2593         if (button_bindings) {
2594                 XMLNode* bb = new XMLNode (X_("Buttons"));
2595                 button_bindings->save (*bb);
2596                 node->add_child_nocopy (*bb);
2597         }
2598
2599         node->set_property (X_("show-marker-lines"), _show_marker_lines);
2600
2601         node->add_child_nocopy (selection->get_state ());
2602         node->add_child_nocopy (_regions->get_state ());
2603
2604         node->set_property ("nudge-clock-value", nudge_clock->current_duration());
2605
2606         node->add_child_nocopy (_locations->get_state ());
2607
2608         return *node;
2609 }
2610
2611 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2612  *  if @param trackview_relative_offset is false, @param y y is a global canvas *  coordinate, in pixel units
2613  *
2614  *  @return pair: TimeAxisView that y is over, layer index.
2615  *
2616  *  TimeAxisView may be 0.  Layer index is the layer number if the TimeAxisView is valid and is
2617  *  in stacked or expanded region display mode, otherwise 0.
2618  */
2619 std::pair<TimeAxisView *, double>
2620 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2621 {
2622         if (!trackview_relative_offset) {
2623                 y -= _trackview_group->canvas_origin().y;
2624         }
2625
2626         if (y < 0) {
2627                 return std::make_pair ((TimeAxisView *) 0, 0);
2628         }
2629
2630         for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2631
2632                 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2633
2634                 if (r.first) {
2635                         return r;
2636                 }
2637         }
2638
2639         return std::make_pair ((TimeAxisView *) 0, 0);
2640 }
2641
2642 void
2643 Editor::set_snapped_cursor_position (samplepos_t pos)
2644 {
2645         if (_edit_point == EditAtMouse) {
2646                 snapped_cursor->set_position(pos);
2647         }
2648 }
2649
2650
2651 /** Snap a position to the grid, if appropriate, taking into account current
2652  *  grid settings and also the state of any snap modifier keys that may be pressed.
2653  *  @param start Position to snap.
2654  *  @param event Event to get current key modifier information from, or 0.
2655  */
2656 void
2657 Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, RoundMode direction, SnapPref pref)
2658 {
2659         if (!_session || !event) {
2660                 return;
2661         }
2662
2663         if (ArdourKeyboard::indicates_snap (event->button.state)) {
2664                 if (_snap_mode == SnapOff) {
2665                         snap_to_internal (start, direction, pref);
2666                 } else {
2667                         start.set (start.sample, 0);
2668                 }
2669         } else {
2670                 if (_snap_mode != SnapOff) {
2671                         snap_to_internal (start, direction, pref);
2672                 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2673                         /* SnapOff, but we pressed the snap_delta modifier */
2674                         snap_to_internal (start, direction, pref);
2675                 } else {
2676                         start.set (start.sample, 0);
2677                 }
2678         }
2679 }
2680
2681 void
2682 Editor::snap_to (MusicSample& start, RoundMode direction, SnapPref pref, bool ensure_snap)
2683 {
2684         if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2685                 start.set (start.sample, 0);
2686                 return;
2687         }
2688
2689         snap_to_internal (start, direction, pref, ensure_snap);
2690 }
2691
2692 void
2693 check_best_snap (samplepos_t presnap, samplepos_t &test, samplepos_t &dist, samplepos_t &best)
2694 {
2695         samplepos_t diff = abs (test - presnap);
2696         if (diff < dist) {
2697                 dist = diff;
2698                 best = test;
2699         }
2700
2701         test = max_samplepos; // reset this so it doesn't get accidentally reused
2702 }
2703
2704 MusicSample
2705 Editor::snap_to_timecode (MusicSample presnap, RoundMode direction, SnapPref gpref)
2706 {
2707         samplepos_t start = presnap.sample;
2708         const samplepos_t one_timecode_second = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2709         samplepos_t one_timecode_minute = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2710
2711         TimecodeRulerScale scale = (gpref != SnapToGrid_Unscaled) ? timecode_ruler_scale : timecode_show_samples;
2712
2713         switch (scale) {
2714         case timecode_show_bits:
2715         case timecode_show_samples:
2716                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2717                     fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2718                         /* start is already on a whole timecode frame, do nothing */
2719                 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2720                         start = (samplepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2721                 } else {
2722                         start = (samplepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) *  _session->samples_per_timecode_frame());
2723                 }
2724                 break;
2725
2726         case timecode_show_seconds:
2727                 if (_session->config.get_timecode_offset_negative()) {
2728                         start += _session->config.get_timecode_offset ();
2729                 } else {
2730                         start -= _session->config.get_timecode_offset ();
2731                 }
2732                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2733                     (start % one_timecode_second == 0)) {
2734                         /* start is already on a whole second, do nothing */
2735                 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2736                         start = (samplepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2737                 } else {
2738                         start = (samplepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2739                 }
2740
2741                 if (_session->config.get_timecode_offset_negative()) {
2742                         start -= _session->config.get_timecode_offset ();
2743                 } else {
2744                         start += _session->config.get_timecode_offset ();
2745                 }
2746                 break;
2747
2748         case timecode_show_minutes:
2749         case timecode_show_hours:
2750         case timecode_show_many_hours:
2751                 if (_session->config.get_timecode_offset_negative()) {
2752                         start += _session->config.get_timecode_offset ();
2753                 } else {
2754                         start -= _session->config.get_timecode_offset ();
2755                 }
2756                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2757                     (start % one_timecode_minute == 0)) {
2758                         /* start is already on a whole minute, do nothing */
2759                 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2760                         start = (samplepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2761                 } else {
2762                         start = (samplepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2763                 }
2764                 if (_session->config.get_timecode_offset_negative()) {
2765                         start -= _session->config.get_timecode_offset ();
2766                 } else {
2767                         start += _session->config.get_timecode_offset ();
2768                 }
2769                 break;
2770         default:
2771                 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2772         }
2773
2774         MusicSample ret(start,0);
2775         return ret;
2776 }
2777
2778 MusicSample
2779 Editor::snap_to_minsec (MusicSample presnap, RoundMode direction, SnapPref gpref)
2780 {
2781         MusicSample ret(presnap);
2782
2783         const samplepos_t one_second = _session->sample_rate();
2784         const samplepos_t one_minute = one_second * 60;
2785         const samplepos_t one_hour = one_minute * 60;
2786
2787         MinsecRulerScale scale = (gpref != SnapToGrid_Unscaled) ? minsec_ruler_scale : minsec_show_seconds;
2788
2789         switch (scale) {
2790                 case minsec_show_msecs:
2791                 case minsec_show_seconds: {
2792                         if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2793                                 presnap.sample % one_second == 0) {
2794                                 /* start is already on a whole second, do nothing */
2795                         } else if (((direction == 0) && (presnap.sample % one_second > one_second / 2)) || (direction > 0)) {
2796                                 ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_second) * one_second;
2797                         } else {
2798                                 ret.sample = (samplepos_t) floor ((double) presnap.sample / one_second) * one_second;
2799                         }
2800                 } break;
2801
2802                 case minsec_show_minutes: {
2803                         if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2804                                 presnap.sample % one_minute == 0) {
2805                                 /* start is already on a whole minute, do nothing */
2806                         } else if (((direction == 0) && (presnap.sample % one_minute > one_minute / 2)) || (direction > 0)) {
2807                                 ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_minute) * one_minute;
2808                         } else {
2809                                 ret.sample = (samplepos_t) floor ((double) presnap.sample / one_minute) * one_minute;
2810                         }
2811                 } break;
2812
2813                 default: {
2814                         if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2815                                 presnap.sample % one_hour == 0) {
2816                                 /* start is already on a whole hour, do nothing */
2817                         } else if (((direction == 0) && (presnap.sample % one_hour > one_hour / 2)) || (direction > 0)) {
2818                                 ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_hour) * one_hour;
2819                         } else {
2820                                 ret.sample = (samplepos_t) floor ((double) presnap.sample / one_hour) * one_hour;
2821                         }
2822                 } break;
2823         }
2824
2825         return ret;
2826 }
2827
2828 MusicSample
2829 Editor::snap_to_cd_frames (MusicSample presnap, RoundMode direction, SnapPref gpref)
2830 {
2831         if ((gpref != SnapToGrid_Unscaled) && (minsec_ruler_scale != minsec_show_msecs)) {
2832                 return snap_to_minsec (presnap, direction, gpref);
2833         }
2834
2835         const samplepos_t one_second = _session->sample_rate();
2836
2837         MusicSample ret(presnap);
2838
2839         if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2840                 presnap.sample % (one_second/75) == 0) {
2841                 /* start is already on a whole CD sample, do nothing */
2842         } else if (((direction == 0) && (presnap.sample % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2843                 ret.sample = (samplepos_t) ceil ((double) presnap.sample / (one_second / 75)) * (one_second / 75);
2844         } else {
2845                 ret.sample = (samplepos_t) floor ((double) presnap.sample / (one_second / 75)) * (one_second / 75);
2846         }
2847
2848         return ret;
2849 }
2850
2851 MusicSample
2852 Editor::snap_to_bbt (MusicSample presnap, RoundMode direction, SnapPref gpref)
2853 {
2854         MusicSample ret(presnap);
2855
2856         if (gpref != SnapToGrid_Unscaled) { // use the visual grid lines which are limited by the zoom scale that the user selected
2857
2858                 int divisor = 2;
2859                 switch (_grid_type) {
2860                 case GridTypeBeatDiv3:
2861                 case GridTypeBeatDiv6:
2862                 case GridTypeBeatDiv12:
2863                 case GridTypeBeatDiv24:
2864                         divisor = 3;
2865                         break;
2866                 case GridTypeBeatDiv5:
2867                 case GridTypeBeatDiv10:
2868                 case GridTypeBeatDiv20:
2869                         divisor = 5;
2870                         break;
2871                 case GridTypeBeatDiv7:
2872                 case GridTypeBeatDiv14:
2873                 case GridTypeBeatDiv28:
2874                         divisor = 7;
2875                         break;
2876                 default:
2877                         divisor = 2;
2878                 };
2879
2880                 BBTRulerScale scale = bbt_ruler_scale;
2881                 switch (scale) {
2882                         case bbt_show_many:
2883                         case bbt_show_64:
2884                         case bbt_show_16:
2885                         case bbt_show_4:
2886                         case bbt_show_1:
2887                                 ret = _session->tempo_map().round_to_bar (presnap.sample, direction);
2888                                 break;
2889                         case bbt_show_quarters:
2890                                 ret = _session->tempo_map().round_to_beat (presnap.sample, direction);
2891                                 break;
2892                         case bbt_show_eighths:
2893                                 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 1 * divisor, direction);
2894                                 break;
2895                         case bbt_show_sixteenths:
2896                                 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 2 * divisor, direction);
2897                                 break;
2898                         case bbt_show_thirtyseconds:
2899                                 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 4 * divisor, direction);
2900                                 break;
2901                 }
2902         } else {
2903                 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, get_grid_beat_divisions(_grid_type), direction);
2904         }
2905
2906         return ret;
2907 }
2908
2909 ARDOUR::MusicSample
2910 Editor::snap_to_grid (MusicSample presnap, RoundMode direction, SnapPref gpref)
2911 {
2912         MusicSample ret(presnap);
2913
2914         if (grid_musical()) {
2915                 ret = snap_to_bbt (presnap, direction, gpref);
2916         }
2917
2918         switch (_grid_type) {
2919                 case GridTypeTimecode:
2920                         ret = snap_to_timecode(presnap, direction, gpref);
2921                         break;
2922                 case GridTypeMinSec:
2923                         ret = snap_to_minsec(presnap, direction, gpref);
2924                         break;
2925                 case GridTypeCDFrame:
2926                         ret = snap_to_cd_frames(presnap, direction, gpref);
2927                         break;
2928                 default:
2929                         {}
2930         };
2931
2932         return ret;
2933 }
2934
2935 samplepos_t
2936 Editor::snap_to_marker (samplepos_t presnap, RoundMode direction)
2937 {
2938         samplepos_t before;
2939         samplepos_t after;
2940         samplepos_t test;
2941
2942         _session->locations()->marks_either_side (presnap, before, after);
2943
2944         if (before == max_samplepos && after == max_samplepos) {
2945                 /* No marks to snap to, so just don't snap */
2946                 return presnap;
2947         } else if (before == max_samplepos) {
2948                 test = after;
2949         } else if (after == max_samplepos) {
2950                 test = before;
2951         } else  {
2952                 if ((direction == RoundUpMaybe || direction == RoundUpAlways)) {
2953                         test = after;
2954                 } else if ((direction == RoundDownMaybe || direction == RoundDownAlways)) {
2955                         test = before;
2956                 } else if (direction ==  0) {
2957                         if ((presnap - before) < (after - presnap)) {
2958                                 test = before;
2959                         } else {
2960                                 test = after;
2961                         }
2962                 }
2963         }
2964
2965         return test;
2966 }
2967
2968 void
2969 Editor::snap_to_internal (MusicSample& start, RoundMode direction, SnapPref pref, bool ensure_snap)
2970 {
2971         const samplepos_t presnap = start.sample;
2972
2973         samplepos_t test = max_samplepos; // for each snap, we'll use this value
2974         samplepos_t dist = max_samplepos; // this records the distance of the best snap result we've found so far
2975         samplepos_t best = max_samplepos; // this records the best snap-result we've found so far
2976
2977         /* check snap-to-marker */
2978         if ((pref == SnapToAny_Visual) && UIConfiguration::instance().get_snap_to_marks()) {
2979                 test = snap_to_marker (presnap, direction);
2980                 check_best_snap(presnap, test, dist, best);
2981         }
2982
2983         /* check snap-to-region-{start/end/sync} */
2984         if (
2985                 (pref == SnapToAny_Visual) &&
2986                 (UIConfiguration::instance().get_snap_to_region_start() || UIConfiguration::instance().get_snap_to_region_end() || UIConfiguration::instance().get_snap_to_region_sync())
2987                 ) {
2988                 if (!region_boundary_cache.empty()) {
2989
2990                         vector<samplepos_t>::iterator prev = region_boundary_cache.begin();
2991                         vector<samplepos_t>::iterator next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
2992                         if (next != region_boundary_cache.begin ()) {
2993                                 prev = next;
2994                                 prev--;
2995                         }
2996
2997                         if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2998                                 test = *next;
2999                         else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
3000                                 test = *prev;
3001                         else if (direction ==  0) {
3002                                 if ((presnap - *prev) < (*next - presnap)) {
3003                                         test = *prev;
3004                                 } else {
3005                                         test = *next;
3006                                 }
3007                         }
3008
3009                 }
3010
3011                 check_best_snap(presnap, test, dist, best);
3012         }
3013
3014         /* check Grid */
3015         if (UIConfiguration::instance().get_snap_to_grid() && (_grid_type != GridTypeNone)) {
3016                 MusicSample pre(presnap, 0);
3017                 MusicSample post = snap_to_grid (pre, direction, pref);
3018                 check_best_snap(presnap, post.sample, dist, best);
3019         }
3020
3021         /* now check "magnetic" state: is the grid within reasonable on-screen distance to trigger a snap?
3022          * this also helps to avoid snapping to somewhere the user can't see.  (i.e.: I clicked on a region and it disappeared!!)
3023          * ToDo: Perhaps this should only occur if EditPointMouse?
3024          */
3025         int snap_threshold_s = pixel_to_sample(UIConfiguration::instance().get_snap_threshold());
3026         if (ensure_snap) {
3027                 start.set (best, 0);
3028                 return;
3029         } else if (presnap > best) {
3030                 if (presnap > (best+ snap_threshold_s)) {
3031                         best = presnap;
3032                 }
3033         } else if (presnap < best) {
3034                 if (presnap < (best - snap_threshold_s)) {
3035                          best = presnap;
3036                 }
3037         }
3038
3039         start.set (best, 0);
3040 }
3041
3042
3043 void
3044 Editor::setup_toolbar ()
3045 {
3046         HBox* mode_box = manage(new HBox);
3047         mode_box->set_border_width (2);
3048         mode_box->set_spacing(2);
3049
3050         HBox* mouse_mode_box = manage (new HBox);
3051         HBox* mouse_mode_hbox = manage (new HBox);
3052         VBox* mouse_mode_vbox = manage (new VBox);
3053         Alignment* mouse_mode_align = manage (new Alignment);
3054
3055         Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3056         mouse_mode_size_group->add_widget (smart_mode_button);
3057         mouse_mode_size_group->add_widget (mouse_move_button);
3058         if (!Profile->get_mixbus()) {
3059                 mouse_mode_size_group->add_widget (mouse_cut_button);
3060         }
3061         mouse_mode_size_group->add_widget (mouse_select_button);
3062         mouse_mode_size_group->add_widget (mouse_timefx_button);
3063         if (!Profile->get_mixbus()) {
3064                 mouse_mode_size_group->add_widget (mouse_audition_button);
3065         }
3066         mouse_mode_size_group->add_widget (mouse_draw_button);
3067         mouse_mode_size_group->add_widget (mouse_content_button);
3068
3069         if (!Profile->get_mixbus()) {
3070                 mouse_mode_size_group->add_widget (zoom_in_button);
3071                 mouse_mode_size_group->add_widget (zoom_out_button);
3072                 mouse_mode_size_group->add_widget (zoom_out_full_button);
3073                 mouse_mode_size_group->add_widget (zoom_focus_selector);
3074                 mouse_mode_size_group->add_widget (tav_shrink_button);
3075                 mouse_mode_size_group->add_widget (tav_expand_button);
3076         } else {
3077                 mouse_mode_size_group->add_widget (zoom_preset_selector);
3078                 mouse_mode_size_group->add_widget (visible_tracks_selector);
3079         }
3080
3081         mouse_mode_size_group->add_widget (grid_type_selector);
3082         mouse_mode_size_group->add_widget (snap_mode_button);
3083
3084         mouse_mode_size_group->add_widget (edit_point_selector);
3085         mouse_mode_size_group->add_widget (edit_mode_selector);
3086
3087         mouse_mode_size_group->add_widget (*nudge_clock);
3088         mouse_mode_size_group->add_widget (nudge_forward_button);
3089         mouse_mode_size_group->add_widget (nudge_backward_button);
3090
3091         mouse_mode_hbox->set_spacing (2);
3092
3093         if (!ARDOUR::Profile->get_trx()) {
3094                 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3095         }
3096
3097         mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3098         mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3099
3100         if (!ARDOUR::Profile->get_mixbus()) {
3101                 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3102                 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3103         }
3104
3105         if (!ARDOUR::Profile->get_trx()) {
3106                 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3107                 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3108                 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3109         }
3110
3111         mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3112
3113         mouse_mode_align->add (*mouse_mode_vbox);
3114         mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3115
3116         mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3117
3118         edit_mode_selector.set_name ("mouse mode button");
3119
3120         if (!ARDOUR::Profile->get_trx()) {
3121                 mode_box->pack_start (edit_mode_selector, false, false);
3122                 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3123                 mode_box->pack_start (edit_point_selector, false, false);
3124                 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3125         }
3126
3127         mode_box->pack_start (*mouse_mode_box, false, false);
3128
3129         /* Zoom */
3130
3131         _zoom_box.set_spacing (2);
3132         _zoom_box.set_border_width (2);
3133
3134         RefPtr<Action> act;
3135
3136         zoom_preset_selector.set_name ("zoom button");
3137         zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3138
3139         zoom_in_button.set_name ("zoom button");
3140         zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3141         act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3142         zoom_in_button.set_related_action (act);
3143
3144         zoom_out_button.set_name ("zoom button");
3145         zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3146         act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3147         zoom_out_button.set_related_action (act);
3148
3149         zoom_out_full_button.set_name ("zoom button");
3150         zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3151         act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3152         zoom_out_full_button.set_related_action (act);
3153
3154         zoom_focus_selector.set_name ("zoom button");
3155
3156         if (ARDOUR::Profile->get_mixbus()) {
3157                 _zoom_box.pack_start (zoom_preset_selector, false, false);
3158         } else if (ARDOUR::Profile->get_trx()) {
3159                 mode_box->pack_start (zoom_out_button, false, false);
3160                 mode_box->pack_start (zoom_in_button, false, false);
3161         } else {
3162                 _zoom_box.pack_start (zoom_out_button, false, false);
3163                 _zoom_box.pack_start (zoom_in_button, false, false);
3164                 _zoom_box.pack_start (zoom_out_full_button, false, false);
3165                 _zoom_box.pack_start (zoom_focus_selector, false, false);
3166         }
3167
3168         /* Track zoom buttons */
3169         _track_box.set_spacing (2);
3170         _track_box.set_border_width (2);
3171
3172         visible_tracks_selector.set_name ("zoom button");
3173         if (Profile->get_mixbus()) {
3174                 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3175         } else {
3176                 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3177         }
3178
3179         tav_expand_button.set_name ("zoom button");
3180         tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3181         act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3182         tav_expand_button.set_related_action (act);
3183
3184         tav_shrink_button.set_name ("zoom button");
3185         tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3186         act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3187         tav_shrink_button.set_related_action (act);
3188
3189         if (ARDOUR::Profile->get_mixbus()) {
3190                 _track_box.pack_start (visible_tracks_selector);
3191         } else if (ARDOUR::Profile->get_trx()) {
3192                 _track_box.pack_start (tav_shrink_button);
3193                 _track_box.pack_start (tav_expand_button);
3194         } else {
3195                 _track_box.pack_start (visible_tracks_selector);
3196                 _track_box.pack_start (tav_shrink_button);
3197                 _track_box.pack_start (tav_expand_button);
3198         }
3199
3200         snap_box.set_spacing (2);
3201         snap_box.set_border_width (2);
3202
3203         grid_type_selector.set_name ("mouse mode button");
3204
3205         snap_mode_button.set_name ("mouse mode button");
3206
3207         edit_point_selector.set_name ("mouse mode button");
3208
3209         snap_box.pack_start (snap_mode_button, false, false);
3210         snap_box.pack_start (grid_type_selector, false, false);
3211
3212         /* Nudge */
3213
3214         HBox *nudge_box = manage (new HBox);
3215         nudge_box->set_spacing (2);
3216         nudge_box->set_border_width (2);
3217
3218         nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3219         nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3220
3221         nudge_box->pack_start (nudge_backward_button, false, false);
3222         nudge_box->pack_start (nudge_forward_button, false, false);
3223         nudge_box->pack_start (*nudge_clock, false, false);
3224
3225
3226         /* Pack everything in... */
3227
3228         toolbar_hbox.set_spacing (2);
3229         toolbar_hbox.set_border_width (2);
3230
3231         ArdourWidgets::ArdourDropShadow *tool_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
3232         tool_shadow->set_size_request (4, -1);
3233         tool_shadow->show();
3234
3235         ebox_hpacker.pack_start (*tool_shadow, false, false);
3236         ebox_hpacker.pack_start(ebox_vpacker, true, true);
3237
3238         Gtk::EventBox* spacer = manage (new Gtk::EventBox); // extra space under the mouse toolbar, for aesthetics
3239         spacer->set_name("EditorWindow");
3240         spacer->set_size_request(-1,4);
3241         spacer->show();
3242
3243         ebox_vpacker.pack_start(toolbar_hbox, false, false);
3244         ebox_vpacker.pack_start(*spacer, false, false);
3245         ebox_vpacker.show();
3246
3247         toolbar_hbox.pack_start (*mode_box, false, false);
3248
3249         if (!ARDOUR::Profile->get_trx()) {
3250
3251                 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3252
3253                 toolbar_hbox.pack_start (snap_box, false, false);
3254
3255                 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3256
3257                 toolbar_hbox.pack_start (*nudge_box, false, false);
3258
3259                 toolbar_hbox.pack_end (_zoom_box, false, false, 2);
3260
3261                 toolbar_hbox.pack_end (*(manage (new ArdourVSpacer ())), false, false, 3);
3262
3263                 toolbar_hbox.pack_end (_track_box, false, false);
3264
3265         }
3266
3267         toolbar_hbox.show_all ();
3268 }
3269
3270 void
3271 Editor::build_edit_point_menu ()
3272 {
3273         using namespace Menu_Helpers;
3274
3275         edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3276         if(!Profile->get_mixbus())
3277                 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3278         edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3279
3280         set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3281 }
3282
3283 void
3284 Editor::build_edit_mode_menu ()
3285 {
3286         using namespace Menu_Helpers;
3287
3288         edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3289         edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3290         edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode)  Lock)));
3291         /* Note: Splice was removed */
3292
3293         set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3294 }
3295
3296 void
3297 Editor::build_grid_type_menu ()
3298 {
3299         using namespace Menu_Helpers;
3300
3301         /* main grid: bars, quarter-notes, etc */
3302         grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeNone],      sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeNone)));
3303         grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBar],       sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBar)));
3304         grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeat],      sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeat)));
3305         grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv2],  sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv2)));
3306         grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv4],  sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv4)));
3307         grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv8],  sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv8)));
3308         grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv16)));
3309         grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv32)));
3310
3311         /* triplet grid */
3312         grid_type_selector.AddMenuElem(SeparatorElem());
3313         Gtk::Menu *_triplet_menu = manage (new Menu);
3314         MenuList& triplet_items (_triplet_menu->items());
3315         {
3316                 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv3],  sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv3)));
3317                 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv6],  sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv6)));
3318                 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv12)));
3319                 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv24)));
3320         }
3321         grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Triplets"), *_triplet_menu));
3322
3323         /* quintuplet grid */
3324         Gtk::Menu *_quintuplet_menu = manage (new Menu);
3325         MenuList& quintuplet_items (_quintuplet_menu->items());
3326         {
3327                 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv5],  sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv5)));
3328                 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv10)));
3329                 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv20)));
3330         }
3331         grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Quintuplets"), *_quintuplet_menu));
3332
3333         /* septuplet grid */
3334         Gtk::Menu *_septuplet_menu = manage (new Menu);
3335         MenuList& septuplet_items (_septuplet_menu->items());
3336         {
3337                 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv7],  sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv7)));
3338                 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv14)));
3339                 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv28)));
3340         }
3341         grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Septuplets"), *_septuplet_menu));
3342
3343         grid_type_selector.AddMenuElem(SeparatorElem());
3344         grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeTimecode], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeTimecode)));
3345         grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeMinSec], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeMinSec)));
3346         grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeCDFrame)));
3347 }
3348
3349 void
3350 Editor::setup_tooltips ()
3351 {
3352         set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3353         set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3354         set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3355         set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3356         set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3357         set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3358         set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3359         set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3360         set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3361         set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3362         set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3363         set_tooltip (zoom_in_button, _("Zoom In"));
3364         set_tooltip (zoom_out_button, _("Zoom Out"));
3365         set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3366         set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3367         set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3368         set_tooltip (tav_expand_button, _("Expand Tracks"));
3369         set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3370         set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3371         set_tooltip (grid_type_selector, _("Grid Mode"));
3372         set_tooltip (snap_mode_button, _("Snap Mode\n\nRight-click to visit Snap preferences."));
3373         set_tooltip (edit_point_selector, _("Edit Point"));
3374         set_tooltip (edit_mode_selector, _("Edit Mode"));
3375         set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3376 }
3377
3378 int
3379 Editor::convert_drop_to_paths (
3380                 vector<string>&                paths,
3381                 const RefPtr<Gdk::DragContext>& /*context*/,
3382                 gint                            /*x*/,
3383                 gint                            /*y*/,
3384                 const SelectionData&            data,
3385                 guint                           /*info*/,
3386                 guint                           /*time*/)
3387 {
3388         if (_session == 0) {
3389                 return -1;
3390         }
3391
3392         vector<string> uris = data.get_uris();
3393
3394         if (uris.empty()) {
3395
3396                 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3397                    are actually URI lists. So do it by hand.
3398                 */
3399
3400                 if (data.get_target() != "text/plain") {
3401                         return -1;
3402                 }
3403
3404                 /* Parse the "uri-list" format that Nautilus provides,
3405                    where each pathname is delimited by \r\n.
3406
3407                    THERE MAY BE NO NULL TERMINATING CHAR!!!
3408                 */
3409
3410                 string txt = data.get_text();
3411                 char* p;
3412                 const char* q;
3413
3414                 p = (char *) malloc (txt.length() + 1);
3415                 txt.copy (p, txt.length(), 0);
3416                 p[txt.length()] = '\0';
3417
3418                 while (p)
3419                 {
3420                         if (*p != '#')
3421                         {
3422                                 while (g_ascii_isspace (*p))
3423                                         p++;
3424
3425                                 q = p;
3426                                 while (*q && (*q != '\n') && (*q != '\r')) {
3427                                         q++;
3428                                 }
3429
3430                                 if (q > p)
3431                                 {
3432                                         q--;
3433                                         while (q > p && g_ascii_isspace (*q))
3434                                                 q--;
3435
3436                                         if (q > p)
3437                                         {
3438                                                 uris.push_back (string (p, q - p + 1));
3439                                         }
3440                                 }
3441                         }
3442                         p = strchr (p, '\n');
3443                         if (p)
3444                                 p++;
3445                 }
3446
3447                 free ((void*)p);
3448
3449                 if (uris.empty()) {
3450                         return -1;
3451                 }
3452         }
3453
3454         for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3455                 if ((*i).substr (0,7) == "file://") {
3456                         paths.push_back (Glib::filename_from_uri (*i));
3457                 }
3458         }
3459
3460         return 0;
3461 }
3462
3463 void
3464 Editor::new_tempo_section ()
3465 {
3466 }
3467
3468 void
3469 Editor::map_transport_state ()
3470 {
3471         ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3472
3473         if (_session && _session->transport_stopped()) {
3474                 have_pending_keyboard_selection = false;
3475         }
3476
3477         update_loop_range_view ();
3478 }
3479
3480 void
3481 Editor::transport_looped ()
3482 {
3483         /* reset Playhead position interpolation.
3484          * see Editor::super_rapid_screen_update
3485          */
3486         _last_update_time = 0;
3487 }
3488
3489 /* UNDO/REDO */
3490
3491 void
3492 Editor::begin_selection_op_history ()
3493 {
3494         selection_op_cmd_depth = 0;
3495         selection_op_history_it = 0;
3496
3497         while(!selection_op_history.empty()) {
3498                 delete selection_op_history.front();
3499                 selection_op_history.pop_front();
3500         }
3501
3502         selection_undo_action->set_sensitive (false);
3503         selection_redo_action->set_sensitive (false);
3504         selection_op_history.push_front (&_selection_memento->get_state ());
3505 }
3506
3507 void
3508 Editor::begin_reversible_selection_op (string name)
3509 {
3510         if (_session) {
3511                 //cerr << name << endl;
3512                 /* begin/commit pairs can be nested */
3513                 selection_op_cmd_depth++;
3514         }
3515 }
3516
3517 void
3518 Editor::commit_reversible_selection_op ()
3519 {
3520         if (_session) {
3521                 if (selection_op_cmd_depth == 1) {
3522
3523                         if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3524                                 /* The user has undone some selection ops and then made a new one,
3525                                  * making anything earlier in the list invalid.
3526                                  */
3527
3528                                 list<XMLNode *>::iterator it = selection_op_history.begin();
3529                                 list<XMLNode *>::iterator e_it = it;
3530                                 advance (e_it, selection_op_history_it);
3531
3532                                 for (; it != e_it; ++it) {
3533                                         delete *it;
3534                                 }
3535                                 selection_op_history.erase (selection_op_history.begin(), e_it);
3536                         }
3537
3538                         selection_op_history.push_front (&_selection_memento->get_state ());
3539                         selection_op_history_it = 0;
3540
3541                         selection_undo_action->set_sensitive (true);
3542                         selection_redo_action->set_sensitive (false);
3543                 }
3544
3545                 if (selection_op_cmd_depth > 0) {
3546                         selection_op_cmd_depth--;
3547                 }
3548         }
3549 }
3550
3551 void
3552 Editor::undo_selection_op ()
3553 {
3554         if (_session) {
3555                 selection_op_history_it++;
3556                 uint32_t n = 0;
3557                 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3558                         if (n == selection_op_history_it) {
3559                                 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3560                                 selection_redo_action->set_sensitive (true);
3561                         }
3562                         ++n;
3563                 }
3564                 /* is there an earlier entry? */
3565                 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3566                         selection_undo_action->set_sensitive (false);
3567                 }
3568         }
3569 }
3570
3571 void
3572 Editor::redo_selection_op ()
3573 {
3574         if (_session) {
3575                 if (selection_op_history_it > 0) {
3576                         selection_op_history_it--;
3577                 }
3578                 uint32_t n = 0;
3579                 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3580                         if (n == selection_op_history_it) {
3581                                 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3582                                 selection_undo_action->set_sensitive (true);
3583                         }
3584                         ++n;
3585                 }
3586
3587                 if (selection_op_history_it == 0) {
3588                         selection_redo_action->set_sensitive (false);
3589                 }
3590         }
3591 }
3592
3593 void
3594 Editor::begin_reversible_command (string name)
3595 {
3596         if (_session) {
3597                 before.push_back (&_selection_memento->get_state ());
3598                 _session->begin_reversible_command (name);
3599         }
3600 }
3601
3602 void
3603 Editor::begin_reversible_command (GQuark q)
3604 {
3605         if (_session) {
3606                 before.push_back (&_selection_memento->get_state ());
3607                 _session->begin_reversible_command (q);
3608         }
3609 }
3610
3611 void
3612 Editor::abort_reversible_command ()
3613 {
3614         if (_session) {
3615                 while(!before.empty()) {
3616                         delete before.front();
3617                         before.pop_front();
3618                 }
3619                 _session->abort_reversible_command ();
3620         }
3621 }
3622
3623 void
3624 Editor::commit_reversible_command ()
3625 {
3626         if (_session) {
3627                 if (before.size() == 1) {
3628                         _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3629                         redo_action->set_sensitive(false);
3630                         undo_action->set_sensitive(true);
3631                         begin_selection_op_history ();
3632                 }
3633
3634                 if (before.empty()) {
3635                         cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3636                 } else {
3637                         before.pop_back();
3638                 }
3639
3640                 _session->commit_reversible_command ();
3641         }
3642 }
3643
3644 void
3645 Editor::history_changed ()
3646 {
3647         string label;
3648
3649         if (undo_action && _session) {
3650                 if (_session->undo_depth() == 0) {
3651                         label = S_("Command|Undo");
3652                 } else {
3653                         label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3654                 }
3655                 undo_action->property_label() = label;
3656         }
3657
3658         if (redo_action && _session) {
3659                 if (_session->redo_depth() == 0) {
3660                         label = _("Redo");
3661                         redo_action->set_sensitive (false);
3662                 } else {
3663                         label = string_compose(_("Redo (%1)"), _session->next_redo());
3664                         redo_action->set_sensitive (true);
3665                 }
3666                 redo_action->property_label() = label;
3667         }
3668 }
3669
3670 void
3671 Editor::duplicate_range (bool with_dialog)
3672 {
3673         float times = 1.0f;
3674
3675         RegionSelection rs = get_regions_from_selection_and_entered ();
3676
3677         if (selection->time.length() == 0 && rs.empty()) {
3678                 return;
3679         }
3680
3681         if (with_dialog) {
3682
3683                 ArdourDialog win (_("Duplicate"));
3684                 Label label (_("Number of duplications:"));
3685                 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3686                 SpinButton spinner (adjustment, 0.0, 1);
3687                 HBox hbox;
3688
3689                 win.get_vbox()->set_spacing (12);
3690                 win.get_vbox()->pack_start (hbox);
3691                 hbox.set_border_width (6);
3692                 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3693
3694                 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3695                    place, visually. so do this by hand.
3696                 */
3697
3698                 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3699                 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3700                 spinner.grab_focus();
3701
3702                 hbox.show ();
3703                 label.show ();
3704                 spinner.show ();
3705
3706                 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3707                 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3708                 win.set_default_response (RESPONSE_ACCEPT);
3709
3710                 spinner.grab_focus ();
3711
3712                 switch (win.run ()) {
3713                 case RESPONSE_ACCEPT:
3714                         break;
3715                 default:
3716                         return;
3717                 }
3718
3719                 times = adjustment.get_value();
3720         }
3721
3722         if ((current_mouse_mode() == MouseRange)) {
3723                 if (selection->time.length()) {
3724                         duplicate_selection (times);
3725                 }
3726         } else if (get_smart_mode()) {
3727                 if (selection->time.length()) {
3728                         duplicate_selection (times);
3729                 } else
3730                         duplicate_some_regions (rs, times);
3731         } else {
3732                 duplicate_some_regions (rs, times);
3733         }
3734 }
3735
3736 void
3737 Editor::set_edit_mode (EditMode m)
3738 {
3739         Config->set_edit_mode (m);
3740 }
3741
3742 void
3743 Editor::cycle_edit_mode ()
3744 {
3745         switch (Config->get_edit_mode()) {
3746         case Slide:
3747                 Config->set_edit_mode (Ripple);
3748                 break;
3749         case Splice:
3750         case Ripple:
3751                 Config->set_edit_mode (Lock);
3752                 break;
3753         case Lock:
3754                 Config->set_edit_mode (Slide);
3755                 break;
3756         }
3757 }
3758
3759 void
3760 Editor::edit_mode_selection_done (EditMode m)
3761 {
3762         Config->set_edit_mode (m);
3763 }
3764
3765 void
3766 Editor::grid_type_selection_done (GridType gridtype)
3767 {
3768         RefPtr<RadioAction> ract = grid_type_action (gridtype);
3769         if (ract) {
3770                 ract->set_active ();
3771         }
3772 }
3773
3774 void
3775 Editor::snap_mode_selection_done (SnapMode mode)
3776 {
3777         RefPtr<RadioAction> ract = snap_mode_action (mode);
3778
3779         if (ract) {
3780                 ract->set_active (true);
3781         }
3782 }
3783
3784 void
3785 Editor::cycle_edit_point (bool with_marker)
3786 {
3787         if(Profile->get_mixbus())
3788                 with_marker = false;
3789
3790         switch (_edit_point) {
3791         case EditAtMouse:
3792                 set_edit_point_preference (EditAtPlayhead);
3793                 break;
3794         case EditAtPlayhead:
3795                 if (with_marker) {
3796                         set_edit_point_preference (EditAtSelectedMarker);
3797                 } else {
3798                         set_edit_point_preference (EditAtMouse);
3799                 }
3800                 break;
3801         case EditAtSelectedMarker:
3802                 set_edit_point_preference (EditAtMouse);
3803                 break;
3804         }
3805 }
3806
3807 void
3808 Editor::edit_point_selection_done (EditPoint ep)
3809 {
3810         set_edit_point_preference (ep);
3811 }
3812
3813 void
3814 Editor::build_zoom_focus_menu ()
3815 {
3816         using namespace Menu_Helpers;
3817
3818         zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3819         zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3820         zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3821         zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3822         zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3823         zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3824
3825         set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3826 }
3827
3828 void
3829 Editor::zoom_focus_selection_done (ZoomFocus f)
3830 {
3831         RefPtr<RadioAction> ract = zoom_focus_action (f);
3832         if (ract) {
3833                 ract->set_active ();
3834         }
3835 }
3836
3837 void
3838 Editor::build_track_count_menu ()
3839 {
3840         using namespace Menu_Helpers;
3841
3842         if (!Profile->get_mixbus()) {
3843                 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3844                 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3845                 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3846                 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3847                 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3848                 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3849                 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3850                 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3851                 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3852                 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3853                 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3854                 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3855                 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3856         } else {
3857                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3858                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3859                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3860                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3861                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3862                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3863                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3864                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3865                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3866                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3867
3868                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3869                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3870                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3871                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3872                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3873                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3874                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3875                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3876                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3877                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3878                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Extents"), sigc::mem_fun(*this, &Editor::temporal_zoom_extents)));
3879                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3880         }
3881 }
3882
3883 void
3884 Editor::set_zoom_preset (int64_t ms)
3885 {
3886         if (ms <= 0) {
3887                 temporal_zoom_session();
3888                 return;
3889         }
3890
3891         ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3892         temporal_zoom ((sample_rate * ms / 1000) / _visible_canvas_width);
3893 }
3894
3895 void
3896 Editor::set_visible_track_count (int32_t n)
3897 {
3898         _visible_track_count = n;
3899
3900         /* if the canvas hasn't really been allocated any size yet, just
3901            record the desired number of visible tracks and return. when canvas
3902            allocation happens, we will get called again and then we can do the
3903            real work.
3904         */
3905
3906         if (_visible_canvas_height <= 1) {
3907                 return;
3908         }
3909
3910         int h;
3911         string str;
3912         DisplaySuspender ds;
3913
3914         if (_visible_track_count > 0) {
3915                 h = trackviews_height() / _visible_track_count;
3916                 std::ostringstream s;
3917                 s << _visible_track_count;
3918                 str = s.str();
3919         } else if (_visible_track_count == 0) {
3920                 uint32_t n = 0;
3921                 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
3922                         if ((*i)->marked_for_display()) {
3923                                 ++n;
3924                                 TimeAxisView::Children cl ((*i)->get_child_list ());
3925                                 for (TimeAxisView::Children::const_iterator j = cl.begin(); j != cl.end(); ++j) {
3926                                         if ((*j)->marked_for_display()) {
3927                                                 ++n;
3928                                         }
3929                                 }
3930                         }
3931                 }
3932                 if (n == 0) {
3933                         visible_tracks_selector.set_text (X_("*"));
3934                         return;
3935                 }
3936                 h = trackviews_height() / n;
3937                 str = _("All");
3938         } else {
3939                 /* negative value means that the visible track count has
3940                    been overridden by explicit track height changes.
3941                 */
3942                 visible_tracks_selector.set_text (X_("*"));
3943                 return;
3944         }
3945
3946         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3947                 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3948         }
3949
3950         if (str != visible_tracks_selector.get_text()) {
3951                 visible_tracks_selector.set_text (str);
3952         }
3953 }
3954
3955 void
3956 Editor::override_visible_track_count ()
3957 {
3958         _visible_track_count = -1;
3959         visible_tracks_selector.set_text (_("*"));
3960 }
3961
3962 bool
3963 Editor::edit_controls_button_release (GdkEventButton* ev)
3964 {
3965         if (Keyboard::is_context_menu_event (ev)) {
3966                 ARDOUR_UI::instance()->add_route ();
3967         } else if (ev->button == 1) {
3968                 selection->clear_tracks ();
3969         }
3970
3971         return true;
3972 }
3973
3974 bool
3975 Editor::mouse_select_button_release (GdkEventButton* ev)
3976 {
3977         /* this handles just right-clicks */
3978
3979         if (ev->button != 3) {
3980                 return false;
3981         }
3982
3983         return true;
3984 }
3985
3986 void
3987 Editor::set_zoom_focus (ZoomFocus f)
3988 {
3989         string str = zoom_focus_strings[(int)f];
3990
3991         if (str != zoom_focus_selector.get_text()) {
3992                 zoom_focus_selector.set_text (str);
3993         }
3994
3995         if (zoom_focus != f) {
3996                 zoom_focus = f;
3997                 instant_save ();
3998         }
3999 }
4000
4001 void
4002 Editor::cycle_zoom_focus ()
4003 {
4004         switch (zoom_focus) {
4005         case ZoomFocusLeft:
4006                 set_zoom_focus (ZoomFocusRight);
4007                 break;
4008         case ZoomFocusRight:
4009                 set_zoom_focus (ZoomFocusCenter);
4010                 break;
4011         case ZoomFocusCenter:
4012                 set_zoom_focus (ZoomFocusPlayhead);
4013                 break;
4014         case ZoomFocusPlayhead:
4015                 set_zoom_focus (ZoomFocusMouse);
4016                 break;
4017         case ZoomFocusMouse:
4018                 set_zoom_focus (ZoomFocusEdit);
4019                 break;
4020         case ZoomFocusEdit:
4021                 set_zoom_focus (ZoomFocusLeft);
4022                 break;
4023         }
4024 }
4025
4026 void
4027 Editor::update_grid ()
4028 {
4029         if (grid_musical()) {
4030                 std::vector<TempoMap::BBTPoint> grid;
4031                 if (bbt_ruler_scale != bbt_show_many) {
4032                         compute_current_bbt_points (grid, _leftmost_sample, _leftmost_sample + current_page_samples());
4033                 }
4034                 maybe_draw_grid_lines ();
4035         } else if (grid_nonmusical()) {
4036                 maybe_draw_grid_lines ();
4037         } else {
4038                 hide_grid_lines ();
4039         }
4040 }
4041
4042 void
4043 Editor::toggle_follow_playhead ()
4044 {
4045         RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-follow-playhead"));
4046         set_follow_playhead (tact->get_active());
4047 }
4048
4049 /** @param yn true to follow playhead, otherwise false.
4050  *  @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4051  */
4052 void
4053 Editor::set_follow_playhead (bool yn, bool catch_up)
4054 {
4055         if (_follow_playhead != yn) {
4056                 if ((_follow_playhead = yn) == true && catch_up) {
4057                         /* catch up */
4058                         reset_x_origin_to_follow_playhead ();
4059                 }
4060                 instant_save ();
4061         }
4062 }
4063
4064 void
4065 Editor::toggle_stationary_playhead ()
4066 {
4067         RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-stationary-playhead"));
4068         set_stationary_playhead (tact->get_active());
4069 }
4070
4071 void
4072 Editor::set_stationary_playhead (bool yn)
4073 {
4074         if (_stationary_playhead != yn) {
4075                 if ((_stationary_playhead = yn) == true) {
4076                         /* catch up -- FIXME need a 3.0 equivalent of this 2.X call */
4077                         // update_current_screen ();
4078                 }
4079                 instant_save ();
4080         }
4081 }
4082
4083 PlaylistSelector&
4084 Editor::playlist_selector () const
4085 {
4086         return *_playlist_selector;
4087 }
4088
4089 samplecnt_t
4090 Editor::get_paste_offset (samplepos_t pos, unsigned paste_count, samplecnt_t duration)
4091 {
4092         if (paste_count == 0) {
4093                 /* don't bother calculating an offset that will be zero anyway */
4094                 return 0;
4095         }
4096
4097         /* calculate basic unsnapped multi-paste offset */
4098         samplecnt_t offset = paste_count * duration;
4099
4100         /* snap offset so pos + offset is aligned to the grid */
4101         MusicSample offset_pos (pos + offset, 0);
4102         snap_to(offset_pos, RoundUpMaybe);
4103         offset = offset_pos.sample - pos;
4104
4105         return offset;
4106 }
4107
4108 unsigned
4109 Editor::get_grid_beat_divisions(samplepos_t position)
4110 {
4111         switch (_grid_type) {
4112         case GridTypeBeatDiv32:  return 32;
4113         case GridTypeBeatDiv28:  return 28;
4114         case GridTypeBeatDiv24:  return 24;
4115         case GridTypeBeatDiv20:  return 20;
4116         case GridTypeBeatDiv16:  return 16;
4117         case GridTypeBeatDiv14:  return 14;
4118         case GridTypeBeatDiv12:  return 12;
4119         case GridTypeBeatDiv10:  return 10;
4120         case GridTypeBeatDiv8:   return 8;
4121         case GridTypeBeatDiv7:   return 7;
4122         case GridTypeBeatDiv6:   return 6;
4123         case GridTypeBeatDiv5:   return 5;
4124         case GridTypeBeatDiv4:   return 4;
4125         case GridTypeBeatDiv3:   return 3;
4126         case GridTypeBeatDiv2:   return 2;
4127         case GridTypeBeat:       return 1;
4128         case GridTypeBar:        return 1;
4129
4130         case GridTypeNone:       return 0;
4131         case GridTypeTimecode:   return 0;
4132         case GridTypeMinSec:     return 0;
4133         case GridTypeCDFrame:    return 0;
4134         default:                 return 0;
4135         }
4136         return 0;
4137 }
4138
4139 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4140     if the grid is non-musical, returns 0.
4141     if the grid is snapped to bars, returns -1.
4142     @param event_state the current keyboard modifier mask.
4143 */
4144 int32_t
4145 Editor::get_grid_music_divisions (uint32_t event_state)
4146 {
4147         if (snap_mode() == SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4148                 return 0;
4149         }
4150
4151         if (snap_mode() != SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4152                 return 0;
4153         }
4154
4155         switch (_grid_type) {
4156         case GridTypeBeatDiv32:  return 32;
4157         case GridTypeBeatDiv28:  return 28;
4158         case GridTypeBeatDiv24:  return 24;
4159         case GridTypeBeatDiv20:  return 20;
4160         case GridTypeBeatDiv16:  return 16;
4161         case GridTypeBeatDiv14:  return 14;
4162         case GridTypeBeatDiv12:  return 12;
4163         case GridTypeBeatDiv10:  return 10;
4164         case GridTypeBeatDiv8:   return 8;
4165         case GridTypeBeatDiv7:   return 7;
4166         case GridTypeBeatDiv6:   return 6;
4167         case GridTypeBeatDiv5:   return 5;
4168         case GridTypeBeatDiv4:   return 4;
4169         case GridTypeBeatDiv3:   return 3;
4170         case GridTypeBeatDiv2:   return 2;
4171         case GridTypeBeat:       return 1;
4172         case GridTypeBar :       return -1;
4173
4174         case GridTypeNone:       return 0;
4175         case GridTypeTimecode:   return 0;
4176         case GridTypeMinSec:     return 0;
4177         case GridTypeCDFrame:    return 0;
4178         }
4179         return 0;
4180 }
4181
4182 Temporal::Beats
4183 Editor::get_grid_type_as_beats (bool& success, samplepos_t position)
4184 {
4185         success = true;
4186
4187         const unsigned divisions = get_grid_beat_divisions(position);
4188         if (divisions) {
4189                 return Temporal::Beats(1.0 / (double)get_grid_beat_divisions(position));
4190         }
4191
4192         switch (_grid_type) {
4193         case GridTypeBeat:
4194                 return Temporal::Beats(4.0 / _session->tempo_map().meter_at_sample (position).note_divisor());
4195         case GridTypeBar:
4196                 if (_session) {
4197                         const Meter& m = _session->tempo_map().meter_at_sample (position);
4198                         return Temporal::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4199                 }
4200                 break;
4201         default:
4202                 success = false;
4203                 break;
4204         }
4205
4206         return Temporal::Beats();
4207 }
4208
4209 samplecnt_t
4210 Editor::get_nudge_distance (samplepos_t pos, samplecnt_t& next)
4211 {
4212         samplecnt_t ret;
4213
4214         ret = nudge_clock->current_duration (pos);
4215         next = ret + 1; /* XXXX fix me */
4216
4217         return ret;
4218 }
4219
4220 int
4221 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4222 {
4223         ArdourDialog dialog (_("Playlist Deletion"));
4224         Label  label (string_compose (_("Playlist %1 is currently unused.\n"
4225                                         "If it is kept, its audio files will not be cleaned.\n"
4226                                         "If it is deleted, audio files used by it alone will be cleaned."),
4227                                       pl->name()));
4228
4229         dialog.set_position (WIN_POS_CENTER);
4230         dialog.get_vbox()->pack_start (label);
4231
4232         label.show ();
4233
4234         dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4235         dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4236         Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4237         dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4238         dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4239
4240         /* by default gtk uses the left most button */
4241         keep->grab_focus ();
4242
4243         switch (dialog.run ()) {
4244         case RESPONSE_NO:
4245                 /* keep this and all remaining ones */
4246                 return -2;
4247                 break;
4248
4249         case RESPONSE_YES:
4250                 /* delete this and all others */
4251                 return 2;
4252                 break;
4253
4254         case RESPONSE_ACCEPT:
4255                 /* delete the playlist */
4256                 return 1;
4257                 break;
4258
4259         case RESPONSE_REJECT:
4260                 /* keep the playlist */
4261                 return 0;
4262                 break;
4263
4264         default:
4265                 break;
4266         }
4267
4268         return -1;
4269 }
4270
4271 bool
4272 Editor::audio_region_selection_covers (samplepos_t where)
4273 {
4274         for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4275                 if ((*a)->region()->covers (where)) {
4276                         return true;
4277                 }
4278         }
4279
4280         return false;
4281 }
4282
4283 void
4284 Editor::prepare_for_cleanup ()
4285 {
4286         cut_buffer->clear_regions ();
4287         cut_buffer->clear_playlists ();
4288
4289         selection->clear_regions ();
4290         selection->clear_playlists ();
4291
4292         _regions->suspend_redisplay ();
4293 }
4294
4295 void
4296 Editor::finish_cleanup ()
4297 {
4298         _regions->resume_redisplay ();
4299 }
4300
4301 Location*
4302 Editor::transport_loop_location()
4303 {
4304         if (_session) {
4305                 return _session->locations()->auto_loop_location();
4306         } else {
4307                 return 0;
4308         }
4309 }
4310
4311 Location*
4312 Editor::transport_punch_location()
4313 {
4314         if (_session) {
4315                 return _session->locations()->auto_punch_location();
4316         } else {
4317                 return 0;
4318         }
4319 }
4320
4321 bool
4322 Editor::control_layout_scroll (GdkEventScroll* ev)
4323 {
4324         /* Just forward to the normal canvas scroll method. The coordinate
4325            systems are different but since the canvas is always larger than the
4326            track headers, and aligned with the trackview area, this will work.
4327
4328            In the not too distant future this layout is going away anyway and
4329            headers will be on the canvas.
4330         */
4331         return canvas_scroll_event (ev, false);
4332 }
4333
4334 void
4335 Editor::session_state_saved (string)
4336 {
4337         update_title ();
4338         _snapshots->redisplay ();
4339 }
4340
4341 void
4342 Editor::maximise_editing_space ()
4343 {
4344         if (_maximised) {
4345                 return;
4346         }
4347
4348         Gtk::Window* toplevel = current_toplevel();
4349
4350         if (toplevel) {
4351                 toplevel->fullscreen ();
4352                 _maximised = true;
4353         }
4354 }
4355
4356 void
4357 Editor::restore_editing_space ()
4358 {
4359         if (!_maximised) {
4360                 return;
4361         }
4362
4363         Gtk::Window* toplevel = current_toplevel();
4364
4365         if (toplevel) {
4366                 toplevel->unfullscreen();
4367                 _maximised = false;
4368         }
4369 }
4370
4371 /**
4372  *  Make new playlists for a given track and also any others that belong
4373  *  to the same active route group with the `select' property.
4374  *  @param v Track.
4375  */
4376
4377 void
4378 Editor::new_playlists (TimeAxisView* v)
4379 {
4380         begin_reversible_command (_("new playlists"));
4381         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4382         _session->playlists()->get (playlists);
4383         mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4384         commit_reversible_command ();
4385 }
4386
4387 /**
4388  *  Use a copy of the current playlist for a given track and also any others that belong
4389  *  to the same active route group with the `select' property.
4390  *  @param v Track.
4391  */
4392
4393 void
4394 Editor::copy_playlists (TimeAxisView* v)
4395 {
4396         begin_reversible_command (_("copy playlists"));
4397         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4398         _session->playlists()->get (playlists);
4399         mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4400         commit_reversible_command ();
4401 }
4402
4403 /** Clear the current playlist for a given track and also any others that belong
4404  *  to the same active route group with the `select' property.
4405  *  @param v Track.
4406  */
4407
4408 void
4409 Editor::clear_playlists (TimeAxisView* v)
4410 {
4411         begin_reversible_command (_("clear playlists"));
4412         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4413         _session->playlists()->get (playlists);
4414         mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4415         commit_reversible_command ();
4416 }
4417
4418 void
4419 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4420 {
4421         atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4422 }
4423
4424 void
4425 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4426 {
4427         atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4428 }
4429
4430 void
4431 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4432 {
4433         atv.clear_playlist ();
4434 }
4435
4436 double
4437 Editor::get_y_origin () const
4438 {
4439         return vertical_adjustment.get_value ();
4440 }
4441
4442 /** Queue up a change to the viewport x origin.
4443  *  @param sample New x origin.
4444  */
4445 void
4446 Editor::reset_x_origin (samplepos_t sample)
4447 {
4448         pending_visual_change.add (VisualChange::TimeOrigin);
4449         pending_visual_change.time_origin = sample;
4450         ensure_visual_change_idle_handler ();
4451 }
4452
4453 void
4454 Editor::reset_y_origin (double y)
4455 {
4456         pending_visual_change.add (VisualChange::YOrigin);
4457         pending_visual_change.y_origin = y;
4458         ensure_visual_change_idle_handler ();
4459 }
4460
4461 void
4462 Editor::reset_zoom (samplecnt_t spp)
4463 {
4464         if (spp == samples_per_pixel) {
4465                 return;
4466         }
4467
4468         pending_visual_change.add (VisualChange::ZoomLevel);
4469         pending_visual_change.samples_per_pixel = spp;
4470         ensure_visual_change_idle_handler ();
4471 }
4472
4473 void
4474 Editor::reposition_and_zoom (samplepos_t sample, double fpu)
4475 {
4476         reset_x_origin (sample);
4477         reset_zoom (fpu);
4478
4479         if (!no_save_visual) {
4480                 undo_visual_stack.push_back (current_visual_state(false));
4481         }
4482 }
4483
4484 Editor::VisualState::VisualState (bool with_tracks)
4485         : gui_state (with_tracks ? new GUIObjectState : 0)
4486 {
4487 }
4488
4489 Editor::VisualState::~VisualState ()
4490 {
4491         delete gui_state;
4492 }
4493
4494 Editor::VisualState*
4495 Editor::current_visual_state (bool with_tracks)
4496 {
4497         VisualState* vs = new VisualState (with_tracks);
4498         vs->y_position = vertical_adjustment.get_value();
4499         vs->samples_per_pixel = samples_per_pixel;
4500         vs->_leftmost_sample = _leftmost_sample;
4501         vs->zoom_focus = zoom_focus;
4502
4503         if (with_tracks) {
4504                 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4505         }
4506
4507         return vs;
4508 }
4509
4510 void
4511 Editor::undo_visual_state ()
4512 {
4513         if (undo_visual_stack.empty()) {
4514                 return;
4515         }
4516
4517         VisualState* vs = undo_visual_stack.back();
4518         undo_visual_stack.pop_back();
4519
4520
4521         redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4522
4523         if (vs) {
4524                 use_visual_state (*vs);
4525         }
4526 }
4527
4528 void
4529 Editor::redo_visual_state ()
4530 {
4531         if (redo_visual_stack.empty()) {
4532                 return;
4533         }
4534
4535         VisualState* vs = redo_visual_stack.back();
4536         redo_visual_stack.pop_back();
4537
4538         /* XXX: can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack? */
4539         undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4540
4541         if (vs) {
4542                 use_visual_state (*vs);
4543         }
4544 }
4545
4546 void
4547 Editor::swap_visual_state ()
4548 {
4549         if (undo_visual_stack.empty()) {
4550                 redo_visual_state ();
4551         } else {
4552                 undo_visual_state ();
4553         }
4554 }
4555
4556 void
4557 Editor::use_visual_state (VisualState& vs)
4558 {
4559         PBD::Unwinder<bool> nsv (no_save_visual, true);
4560         DisplaySuspender ds;
4561
4562         vertical_adjustment.set_value (vs.y_position);
4563
4564         set_zoom_focus (vs.zoom_focus);
4565         reposition_and_zoom (vs._leftmost_sample, vs.samples_per_pixel);
4566
4567         if (vs.gui_state) {
4568                 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4569
4570                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4571                         (*i)->clear_property_cache();
4572                         (*i)->reset_visual_state ();
4573                 }
4574         }
4575
4576         _routes->update_visibility ();
4577 }
4578
4579 /** This is the core function that controls the zoom level of the canvas. It is called
4580  *  whenever one or more calls are made to reset_zoom().  It executes in an idle handler.
4581  *  @param spp new number of samples per pixel
4582  */
4583 void
4584 Editor::set_samples_per_pixel (samplecnt_t spp)
4585 {
4586         if (spp < 1) {
4587                 return;
4588         }
4589
4590         const samplecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->sample_rate() : 48000);
4591         const samplecnt_t lots_of_pixels = 4000;
4592
4593         /* if the zoom level is greater than what you'd get trying to display 3
4594          * days of audio on a really big screen, then it's too big.
4595          */
4596
4597         if (spp * lots_of_pixels > three_days) {
4598                 return;
4599         }
4600
4601         samples_per_pixel = spp;
4602 }
4603
4604 void
4605 Editor::on_samples_per_pixel_changed ()
4606 {
4607         bool const showing_time_selection = selection->time.length() > 0;
4608
4609         if (showing_time_selection && selection->time.start () != selection->time.end_sample ()) {
4610                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4611                         (*i)->reshow_selection (selection->time);
4612                 }
4613         }
4614
4615         ZoomChanged (); /* EMIT_SIGNAL */
4616
4617         ArdourCanvas::GtkCanvasViewport* c;
4618
4619         c = get_track_canvas();
4620         if (c) {
4621                 c->canvas()->zoomed ();
4622         }
4623
4624         if (playhead_cursor) {
4625                 playhead_cursor->set_position (playhead_cursor->current_sample ());
4626         }
4627
4628         refresh_location_display();
4629         _summary->set_overlays_dirty ();
4630
4631         update_marker_labels ();
4632
4633         instant_save ();
4634 }
4635
4636 samplepos_t
4637 Editor::playhead_cursor_sample () const
4638 {
4639         return playhead_cursor->current_sample();
4640 }
4641
4642 void
4643 Editor::queue_visual_videotimeline_update ()
4644 {
4645         pending_visual_change.add (VisualChange::VideoTimeline);
4646         ensure_visual_change_idle_handler ();
4647 }
4648
4649 void
4650 Editor::ensure_visual_change_idle_handler ()
4651 {
4652         if (pending_visual_change.idle_handler_id < 0) {
4653                 /* see comment in add_to_idle_resize above. */
4654                 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4655                 pending_visual_change.being_handled = false;
4656         }
4657 }
4658
4659 int
4660 Editor::_idle_visual_changer (void* arg)
4661 {
4662         return static_cast<Editor*>(arg)->idle_visual_changer ();
4663 }
4664
4665 void
4666 Editor::pre_render ()
4667 {
4668         visual_change_queued = false;
4669
4670         if (pending_visual_change.pending != 0) {
4671                 ensure_visual_change_idle_handler();
4672         }
4673 }
4674
4675 int
4676 Editor::idle_visual_changer ()
4677 {
4678         pending_visual_change.idle_handler_id = -1;
4679
4680         if (pending_visual_change.pending == 0) {
4681                 return 0;
4682         }
4683
4684         /* set_horizontal_position() below (and maybe other calls) call
4685            gtk_main_iteration(), so it's possible that a signal will be handled
4686            half-way through this method.  If this signal wants an
4687            idle_visual_changer we must schedule another one after this one, so
4688            mark the idle_handler_id as -1 here to allow that.  Also make a note
4689            that we are doing the visual change, so that changes in response to
4690            super-rapid-screen-update can be dropped if we are still processing
4691            the last one.
4692         */
4693
4694         if (visual_change_queued) {
4695                 return 0;
4696         }
4697
4698         pending_visual_change.being_handled = true;
4699
4700         VisualChange vc = pending_visual_change;
4701
4702         pending_visual_change.pending = (VisualChange::Type) 0;
4703
4704         visual_changer (vc);
4705
4706         pending_visual_change.being_handled = false;
4707
4708         visual_change_queued = true;
4709
4710         return 0; /* this is always a one-shot call */
4711 }
4712
4713 void
4714 Editor::visual_changer (const VisualChange& vc)
4715 {
4716         /**
4717          * Changed first so the correct horizontal canvas position is calculated in
4718          * Editor::set_horizontal_position
4719          */
4720         if (vc.pending & VisualChange::ZoomLevel) {
4721                 set_samples_per_pixel (vc.samples_per_pixel);
4722         }
4723
4724         if (vc.pending & VisualChange::TimeOrigin) {
4725                 double new_time_origin = sample_to_pixel_unrounded (vc.time_origin);
4726                 set_horizontal_position (new_time_origin);
4727         }
4728
4729         if (vc.pending & VisualChange::YOrigin) {
4730                 vertical_adjustment.set_value (vc.y_origin);
4731         }
4732
4733         /**
4734          * Now the canvas is in the final state before render the canvas items that
4735          * support the Item::prepare_for_render interface can calculate the correct
4736          * item to visible canvas intersection.
4737          */
4738         if (vc.pending & VisualChange::ZoomLevel) {
4739                 on_samples_per_pixel_changed ();
4740
4741                 compute_fixed_ruler_scale ();
4742
4743                 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4744                 update_tempo_based_rulers ();
4745         }
4746
4747         if (!(vc.pending & VisualChange::ZoomLevel)) {
4748                 /* If the canvas is not being zoomed then the canvas items will not change
4749                  * and cause Item::prepare_for_render to be called so do it here manually.
4750                  * Not ideal, but I can't think of a better solution atm.
4751                  */
4752                 _track_canvas->prepare_for_render();
4753         }
4754
4755         /* If we are only scrolling vertically there is no need to update these */
4756         if (vc.pending != VisualChange::YOrigin) {
4757                 update_fixed_rulers ();
4758                 redisplay_grid (true);
4759
4760                 /* video frames & position need to be updated for zoom, horiz-scroll
4761                  * and (explicitly) VisualChange::VideoTimeline.
4762                  */
4763                 update_video_timeline();
4764         }
4765
4766         _summary->set_overlays_dirty ();
4767 }
4768
4769 struct EditorOrderTimeAxisSorter {
4770     bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4771             return a->order () < b->order ();
4772     }
4773 };
4774
4775 void
4776 Editor::sort_track_selection (TrackViewList& sel)
4777 {
4778         EditorOrderTimeAxisSorter cmp;
4779         sel.sort (cmp);
4780 }
4781
4782 samplepos_t
4783 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4784 {
4785         bool ignored;
4786         samplepos_t where = 0;
4787         EditPoint ep = _edit_point;
4788
4789         if (Profile->get_mixbus()) {
4790                 if (ep == EditAtSelectedMarker) {
4791                         ep = EditAtPlayhead;
4792                 }
4793         }
4794
4795         if (from_outside_canvas && (ep == EditAtMouse)) {
4796                 ep = EditAtPlayhead;
4797         } else if (from_context_menu && (ep == EditAtMouse)) {
4798                 return canvas_event_sample (&context_click_event, 0, 0);
4799         }
4800
4801         if (entered_marker) {
4802                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4803                 return entered_marker->position();
4804         }
4805
4806         if ((ignore == EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4807                 ep = EditAtSelectedMarker;
4808         }
4809
4810         if ((ignore == EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4811                 ep = EditAtPlayhead;
4812         }
4813
4814         MusicSample snap_mf (0, 0);
4815
4816         switch (ep) {
4817         case EditAtPlayhead:
4818                 if (_dragging_playhead) {
4819                         /* NOTE: since the user is dragging with the mouse, this operation will implicitly be Snapped */
4820                         where = playhead_cursor->current_sample();
4821                 } else {
4822                         where = _session->audible_sample();
4823                 }
4824                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4825                 break;
4826
4827         case EditAtSelectedMarker:
4828                 if (!selection->markers.empty()) {
4829                         bool is_start;
4830                         Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4831                         if (loc) {
4832                                 if (is_start) {
4833                                         where =  loc->start();
4834                                 } else {
4835                                         where = loc->end();
4836                                 }
4837                                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4838                                 break;
4839                         }
4840                 }
4841                 /* fallthru */
4842
4843         default:
4844         case EditAtMouse:
4845                 if (!mouse_sample (where, ignored)) {
4846                         /* XXX not right but what can we do ? */
4847                         return 0;
4848                 }
4849                 snap_mf.sample = where;
4850                 snap_to (snap_mf);
4851                 where = snap_mf.sample;
4852                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4853                 break;
4854         }
4855
4856         return where;
4857 }
4858
4859 void
4860 Editor::set_loop_range (samplepos_t start, samplepos_t end, string cmd)
4861 {
4862         if (!_session) return;
4863
4864         begin_reversible_command (cmd);
4865
4866         Location* tll;
4867
4868         if ((tll = transport_loop_location()) == 0) {
4869                 Location* loc = new Location (*_session, start, end, _("Loop"),  Location::IsAutoLoop, get_grid_music_divisions(0));
4870                 XMLNode &before = _session->locations()->get_state();
4871                 _session->locations()->add (loc, true);
4872                 _session->set_auto_loop_location (loc);
4873                 XMLNode &after = _session->locations()->get_state();
4874                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4875         } else {
4876                 XMLNode &before = tll->get_state();
4877                 tll->set_hidden (false, this);
4878                 tll->set (start, end);
4879                 XMLNode &after = tll->get_state();
4880                 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4881         }
4882
4883         commit_reversible_command ();
4884 }
4885
4886 void
4887 Editor::set_punch_range (samplepos_t start, samplepos_t end, string cmd)
4888 {
4889         if (!_session) return;
4890
4891         begin_reversible_command (cmd);
4892
4893         Location* tpl;
4894
4895         if ((tpl = transport_punch_location()) == 0) {
4896                 Location* loc = new Location (*_session, start, end, _("Punch"),  Location::IsAutoPunch, get_grid_music_divisions(0));
4897                 XMLNode &before = _session->locations()->get_state();
4898                 _session->locations()->add (loc, true);
4899                 _session->set_auto_punch_location (loc);
4900                 XMLNode &after = _session->locations()->get_state();
4901                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4902         } else {
4903                 XMLNode &before = tpl->get_state();
4904                 tpl->set_hidden (false, this);
4905                 tpl->set (start, end);
4906                 XMLNode &after = tpl->get_state();
4907                 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4908         }
4909
4910         commit_reversible_command ();
4911 }
4912
4913 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4914  *  @param rs List to which found regions are added.
4915  *  @param where Time to look at.
4916  *  @param ts Tracks to look on; if this is empty, all tracks are examined.
4917  */
4918 void
4919 Editor::get_regions_at (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4920 {
4921         const TrackViewList* tracks;
4922
4923         if (ts.empty()) {
4924                 tracks = &track_views;
4925         } else {
4926                 tracks = &ts;
4927         }
4928
4929         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4930
4931                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4932
4933                 if (rtv) {
4934                         boost::shared_ptr<Track> tr;
4935                         boost::shared_ptr<Playlist> pl;
4936
4937                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4938
4939                                 boost::shared_ptr<RegionList> regions = pl->regions_at (where);
4940
4941                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4942                                         RegionView* rv = rtv->view()->find_view (*i);
4943                                         if (rv) {
4944                                                 rs.add (rv);
4945                                         }
4946                                 }
4947                         }
4948                 }
4949         }
4950 }
4951
4952 void
4953 Editor::get_regions_after (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4954 {
4955         const TrackViewList* tracks;
4956
4957         if (ts.empty()) {
4958                 tracks = &track_views;
4959         } else {
4960                 tracks = &ts;
4961         }
4962
4963         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4964                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4965                 if (rtv) {
4966                         boost::shared_ptr<Track> tr;
4967                         boost::shared_ptr<Playlist> pl;
4968
4969                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4970
4971                                 boost::shared_ptr<RegionList> regions = pl->regions_touched (where, max_samplepos);
4972
4973                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4974
4975                                         RegionView* rv = rtv->view()->find_view (*i);
4976
4977                                         if (rv) {
4978                                                 rs.add (rv);
4979                                         }
4980                                 }
4981                         }
4982                 }
4983         }
4984 }
4985
4986 /** Get regions using the following method:
4987  *
4988  *  Make a region list using:
4989  *   (a) any selected regions
4990  *   (b) the intersection of any selected tracks and the edit point(*)
4991  *   (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4992  *
4993  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4994  *
4995  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4996  */
4997
4998 RegionSelection
4999 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
5000 {
5001         RegionSelection regions;
5002
5003         if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
5004                 regions.add (entered_regionview);
5005         } else {
5006                 regions = selection->regions;
5007         }
5008
5009         if (regions.empty()) {
5010                 TrackViewList tracks = selection->tracks;
5011
5012                 if (!tracks.empty()) {
5013                         /* no region selected or entered, but some selected tracks:
5014                          * act on all regions on the selected tracks at the edit point
5015                          */
5016                         samplepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
5017                         get_regions_at(regions, where, tracks);
5018                 }
5019         }
5020
5021         return regions;
5022 }
5023
5024 /** Get regions using the following method:
5025  *
5026  *  Make a region list using:
5027  *   (a) any selected regions
5028  *   (b) the intersection of any selected tracks and the edit point(*)
5029  *   (c) if neither exists, then whatever region is under the mouse
5030  *
5031  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
5032  *
5033  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
5034  */
5035 RegionSelection
5036 Editor::get_regions_from_selection_and_mouse (samplepos_t pos)
5037 {
5038         RegionSelection regions;
5039
5040         if (entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
5041                 regions.add (entered_regionview);
5042         } else {
5043                 regions = selection->regions;
5044         }
5045
5046         if (regions.empty()) {
5047                 TrackViewList tracks = selection->tracks;
5048
5049                 if (!tracks.empty()) {
5050                         /* no region selected or entered, but some selected tracks:
5051                          * act on all regions on the selected tracks at the edit point
5052                          */
5053                         get_regions_at(regions, pos, tracks);
5054                 }
5055         }
5056
5057         return regions;
5058 }
5059
5060 /** Start with regions that are selected, or the entered regionview if none are selected.
5061  *  Then add equivalent regions on tracks in the same active edit-enabled route group as any
5062  *  of the regions that we started with.
5063  */
5064
5065 RegionSelection
5066 Editor::get_regions_from_selection_and_entered () const
5067 {
5068         RegionSelection regions = selection->regions;
5069
5070         if (regions.empty() && entered_regionview) {
5071                 regions.add (entered_regionview);
5072         }
5073
5074         return regions;
5075 }
5076
5077 void
5078 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
5079 {
5080         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5081                 RouteTimeAxisView* rtav;
5082
5083                 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5084                         boost::shared_ptr<Playlist> pl;
5085                         std::vector<boost::shared_ptr<Region> > results;
5086                         boost::shared_ptr<Track> tr;
5087
5088                         if ((tr = rtav->track()) == 0) {
5089                                 /* bus */
5090                                 continue;
5091                         }
5092
5093                         if ((pl = (tr->playlist())) != 0) {
5094                                 boost::shared_ptr<Region> r = pl->region_by_id (id);
5095                                 if (r) {
5096                                         RegionView* rv = rtav->view()->find_view (r);
5097                                         if (rv) {
5098                                                 regions.push_back (rv);
5099                                         }
5100                                 }
5101                         }
5102                 }
5103         }
5104 }
5105
5106 void
5107 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > > &selection) const
5108 {
5109
5110         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5111                 MidiTimeAxisView* mtav;
5112
5113                 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5114
5115                         mtav->get_per_region_note_selection (selection);
5116                 }
5117         }
5118
5119 }
5120
5121 void
5122 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5123 {
5124         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5125
5126                 RouteTimeAxisView* tatv;
5127
5128                 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5129
5130                         boost::shared_ptr<Playlist> pl;
5131                         vector<boost::shared_ptr<Region> > results;
5132                         RegionView* marv;
5133                         boost::shared_ptr<Track> tr;
5134
5135                         if ((tr = tatv->track()) == 0) {
5136                                 /* bus */
5137                                 continue;
5138                         }
5139
5140                         if ((pl = (tr->playlist())) != 0) {
5141                                 if (src_comparison) {
5142                                         pl->get_source_equivalent_regions (region, results);
5143                                 } else {
5144                                         pl->get_region_list_equivalent_regions (region, results);
5145                                 }
5146                         }
5147
5148                         for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5149                                 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5150                                         regions.push_back (marv);
5151                                 }
5152                         }
5153
5154                 }
5155         }
5156 }
5157
5158 RegionView*
5159 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5160 {
5161         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5162                 RouteTimeAxisView* tatv;
5163                 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5164                         if (!tatv->track()) {
5165                                 continue;
5166                         }
5167                         RegionView* marv = tatv->view()->find_view (region);
5168                         if (marv) {
5169                                 return marv;
5170                         }
5171                 }
5172         }
5173         return NULL;
5174 }
5175
5176 RouteTimeAxisView*
5177 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5178 {
5179         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5180                 RouteTimeAxisView* rtav;
5181                 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5182                         if (rtav->route() == route) {
5183                                 return rtav;
5184                         }
5185                 }
5186         }
5187         return NULL;
5188 }
5189
5190 void
5191 Editor::show_rhythm_ferret ()
5192 {
5193         if (rhythm_ferret == 0) {
5194                 rhythm_ferret = new RhythmFerret(*this);
5195         }
5196
5197         rhythm_ferret->set_session (_session);
5198         rhythm_ferret->show ();
5199         rhythm_ferret->present ();
5200 }
5201
5202 void
5203 Editor::first_idle ()
5204 {
5205         MessageDialog* dialog = 0;
5206
5207         if (track_views.size() > 1) {
5208                 Timers::TimerSuspender t;
5209                 dialog = new MessageDialog (
5210                         string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5211                         true
5212                         );
5213                 dialog->present ();
5214                 ARDOUR_UI::instance()->flush_pending (60);
5215         }
5216
5217         for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5218                 (*t)->first_idle();
5219         }
5220
5221         /* now that all regionviews should exist, setup region selection */
5222
5223         RegionSelection rs;
5224
5225         for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5226                 /* this is cumulative: rs is NOT cleared each time */
5227                 get_regionviews_by_id (*pr, rs);
5228         }
5229
5230         selection->set (rs);
5231
5232         /* first idle adds route children (automation tracks), so we need to redisplay here */
5233         _routes->redisplay ();
5234
5235         delete dialog;
5236
5237         if (_session->undo_depth() == 0) {
5238                 undo_action->set_sensitive(false);
5239         }
5240         redo_action->set_sensitive(false);
5241         begin_selection_op_history ();
5242
5243         _have_idled = true;
5244 }
5245
5246 gboolean
5247 Editor::_idle_resize (gpointer arg)
5248 {
5249         return ((Editor*)arg)->idle_resize ();
5250 }
5251
5252 void
5253 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5254 {
5255         if (resize_idle_id < 0) {
5256                 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5257                  * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5258                  * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5259                  */
5260                 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5261                 _pending_resize_amount = 0;
5262         }
5263
5264         /* make a note of the smallest resulting height, so that we can clamp the
5265            lower limit at TimeAxisView::hSmall */
5266
5267         int32_t min_resulting = INT32_MAX;
5268
5269         _pending_resize_amount += h;
5270         _pending_resize_view = view;
5271
5272         min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5273
5274         if (selection->tracks.contains (_pending_resize_view)) {
5275                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5276                         min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5277                 }
5278         }
5279
5280         if (min_resulting < 0) {
5281                 min_resulting = 0;
5282         }
5283
5284         /* clamp */
5285         if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5286                 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5287         }
5288 }
5289
5290 /** Handle pending resizing of tracks */
5291 bool
5292 Editor::idle_resize ()
5293 {
5294         _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5295
5296         if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5297             selection->tracks.contains (_pending_resize_view)) {
5298
5299                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5300                         if (*i != _pending_resize_view) {
5301                                 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5302                         }
5303                 }
5304         }
5305
5306         _pending_resize_amount = 0;
5307         _group_tabs->set_dirty ();
5308         resize_idle_id = -1;
5309
5310         return false;
5311 }
5312
5313 void
5314 Editor::located ()
5315 {
5316         ENSURE_GUI_THREAD (*this, &Editor::located);
5317
5318         if (_session) {
5319                 playhead_cursor->set_position (_session->audible_sample ());
5320                 if (_follow_playhead && !_pending_initial_locate) {
5321                         reset_x_origin_to_follow_playhead ();
5322                 }
5323         }
5324
5325         _pending_locate_request = false;
5326         _pending_initial_locate = false;
5327         _last_update_time = 0;
5328 }
5329
5330 void
5331 Editor::region_view_added (RegionView * rv)
5332 {
5333         MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5334         if (mrv) {
5335                 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5336                 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5337                         if (rv->region()->id () == (*rnote).first) {
5338                                 mrv->select_notes ((*rnote).second);
5339                                 selection->pending_midi_note_selection.erase(rnote);
5340                                 break;
5341                         }
5342                 }
5343         }
5344
5345         _summary->set_background_dirty ();
5346
5347         mark_region_boundary_cache_dirty ();
5348 }
5349
5350 void
5351 Editor::region_view_removed ()
5352 {
5353         _summary->set_background_dirty ();
5354
5355         mark_region_boundary_cache_dirty ();
5356 }
5357
5358 AxisView*
5359 Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
5360 {
5361         for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5362                 if ((*j)->stripable() == s) {
5363                         return *j;
5364                 }
5365         }
5366
5367         return 0;
5368 }
5369
5370 AxisView*
5371 Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
5372 {
5373         for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5374                 if ((*j)->control() == c) {
5375                         return *j;
5376                 }
5377
5378                 TimeAxisView::Children kids = (*j)->get_child_list ();
5379
5380                 for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) {
5381                         if ((*k)->control() == c) {
5382                                 return (*k).get();
5383                         }
5384                 }
5385         }
5386
5387         return 0;
5388 }
5389
5390 TrackViewList
5391 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5392 {
5393         TrackViewList t;
5394
5395         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5396                 TimeAxisView* tv = time_axis_view_from_stripable (*i);
5397                 if (tv) {
5398                         t.push_back (tv);
5399                 }
5400         }
5401
5402         return t;
5403 }
5404
5405 void
5406 Editor::suspend_route_redisplay ()
5407 {
5408         if (_routes) {
5409                 _routes->suspend_redisplay();
5410         }
5411 }
5412
5413 void
5414 Editor::resume_route_redisplay ()
5415 {
5416         if (_routes) {
5417                 _routes->redisplay(); // queue redisplay
5418                 _routes->resume_redisplay();
5419         }
5420 }
5421
5422 void
5423 Editor::add_vcas (VCAList& vlist)
5424 {
5425         StripableList sl;
5426
5427         for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5428                 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5429         }
5430
5431         add_stripables (sl);
5432 }
5433
5434 void
5435 Editor::add_routes (RouteList& rlist)
5436 {
5437         StripableList sl;
5438
5439         for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5440                 sl.push_back (*r);
5441         }
5442
5443         add_stripables (sl);
5444 }
5445
5446 void
5447 Editor::add_stripables (StripableList& sl)
5448 {
5449         list<TimeAxisView*> new_views;
5450         boost::shared_ptr<VCA> v;
5451         boost::shared_ptr<Route> r;
5452         TrackViewList new_selection;
5453         bool from_scratch = (track_views.size() == 0);
5454
5455         sl.sort (Stripable::Sorter());
5456
5457         for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5458
5459                 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5460
5461                         VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5462                         vtv->set_vca (v);
5463                         new_views.push_back (vtv);
5464
5465                 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5466
5467                         if (r->is_auditioner() || r->is_monitor()) {
5468                                 continue;
5469                         }
5470
5471                         RouteTimeAxisView* rtv;
5472                         DataType dt = r->input()->default_type();
5473
5474                         if (dt == ARDOUR::DataType::AUDIO) {
5475                                 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5476                                 rtv->set_route (r);
5477                         } else if (dt == ARDOUR::DataType::MIDI) {
5478                                 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5479                                 rtv->set_route (r);
5480                         } else {
5481                                 throw unknown_type();
5482                         }
5483
5484                         new_views.push_back (rtv);
5485                         track_views.push_back (rtv);
5486                         new_selection.push_back (rtv);
5487
5488                         rtv->effective_gain_display ();
5489
5490                         rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5491                         rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5492                 }
5493         }
5494
5495         if (new_views.size() > 0) {
5496                 _routes->time_axis_views_added (new_views);
5497                 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5498         }
5499
5500         /* note: !new_selection.empty() means that we got some routes rather
5501          * than just VCAs
5502          */
5503
5504         if (!from_scratch && !new_selection.empty()) {
5505                 selection->set (new_selection);
5506                 begin_selection_op_history();
5507         }
5508
5509         if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5510                 show_editor_mixer (true);
5511         }
5512
5513         editor_list_button.set_sensitive (true);
5514 }
5515
5516 void
5517 Editor::timeaxisview_deleted (TimeAxisView *tv)
5518 {
5519         if (tv == entered_track) {
5520                 entered_track = 0;
5521         }
5522
5523         if (_session && _session->deletion_in_progress()) {
5524                 /* the situation is under control */
5525                 return;
5526         }
5527
5528         ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5529
5530         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5531
5532         _routes->route_removed (tv);
5533
5534         TimeAxisView::Children c = tv->get_child_list ();
5535         for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5536                 if (entered_track == i->get()) {
5537                         entered_track = 0;
5538                 }
5539         }
5540
5541         /* remove it from the list of track views */
5542
5543         TrackViewList::iterator i;
5544
5545         if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5546                 i = track_views.erase (i);
5547         }
5548
5549         /* update whatever the current mixer strip is displaying, if revelant */
5550
5551         boost::shared_ptr<Route> route;
5552
5553         if (rtav) {
5554                 route = rtav->route ();
5555         }
5556
5557         if (current_mixer_strip && current_mixer_strip->route() == route) {
5558
5559                 TimeAxisView* next_tv;
5560
5561                 if (track_views.empty()) {
5562                         next_tv = 0;
5563                 } else if (i == track_views.end()) {
5564                         next_tv = track_views.front();
5565                 } else {
5566                         next_tv = (*i);
5567                 }
5568
5569                 // skip VCAs (cannot be selected, n/a in editor-mixer)
5570                 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5571                         /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5572                         next_tv = track_views.front();
5573                 }
5574                 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5575                         /* just in case: no master, only a VCA remains */
5576                         next_tv = 0;
5577                 }
5578
5579
5580                 if (next_tv) {
5581                         set_selected_mixer_strip (*next_tv);
5582                 } else {
5583                         /* make the editor mixer strip go away setting the
5584                          * button to inactive (which also unticks the menu option)
5585                          */
5586
5587                         ActionManager::uncheck_toggleaction ("Editor/show-editor-mixer");
5588                 }
5589         }
5590 }
5591
5592 void
5593 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5594 {
5595         if (!tv) {
5596                 return;
5597         }
5598
5599         DisplaySuspender ds;
5600         PresentationInfo::ChangeSuspender cs;
5601
5602         if (apply_to_selection) {
5603                 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end();) {
5604
5605                         TrackSelection::iterator j = i;
5606                         ++j;
5607
5608                         hide_track_in_display (*i, false);
5609
5610                         i = j;
5611                 }
5612         } else {
5613                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5614
5615                 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5616                         /* this will hide the mixer strip */
5617                         set_selected_mixer_strip (*tv);
5618                 }
5619
5620                 _routes->hide_track_in_display (*tv);
5621         }
5622 }
5623
5624 void
5625 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5626 {
5627         if (!tv) {
5628                 return;
5629         }
5630         _routes->show_track_in_display (*tv);
5631         if (move_into_view) {
5632                 ensure_time_axis_view_is_visible (*tv, false);
5633         }
5634 }
5635
5636 bool
5637 Editor::sync_track_view_list_and_routes ()
5638 {
5639         track_views = TrackViewList (_routes->views ());
5640
5641         _summary->set_background_dirty();
5642         _group_tabs->set_dirty ();
5643
5644         return false; // do not call again (until needed)
5645 }
5646
5647 void
5648 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5649 {
5650         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5651                 theslot (**i);
5652         }
5653 }
5654
5655 /** Find a StripableTimeAxisView by the ID of its stripable */
5656 StripableTimeAxisView*
5657 Editor::get_stripable_time_axis_by_id (const PBD::ID& id) const
5658 {
5659         StripableTimeAxisView* v;
5660
5661         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5662                 if((v = dynamic_cast<StripableTimeAxisView*>(*i)) != 0) {
5663                         if(v->stripable()->id() == id) {
5664                                 return v;
5665                         }
5666                 }
5667         }
5668
5669         return 0;
5670 }
5671
5672 void
5673 Editor::fit_route_group (RouteGroup *g)
5674 {
5675         TrackViewList ts = axis_views_from_routes (g->route_list ());
5676         fit_tracks (ts);
5677 }
5678
5679 void
5680 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5681 {
5682         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5683
5684         if (r == 0) {
5685                 _session->cancel_audition ();
5686                 return;
5687         }
5688
5689         if (_session->is_auditioning()) {
5690                 _session->cancel_audition ();
5691                 if (r == last_audition_region) {
5692                         return;
5693                 }
5694         }
5695
5696         _session->audition_region (r);
5697         last_audition_region = r;
5698 }
5699
5700
5701 void
5702 Editor::hide_a_region (boost::shared_ptr<Region> r)
5703 {
5704         r->set_hidden (true);
5705 }
5706
5707 void
5708 Editor::show_a_region (boost::shared_ptr<Region> r)
5709 {
5710         r->set_hidden (false);
5711 }
5712
5713 void
5714 Editor::audition_region_from_region_list ()
5715 {
5716         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5717 }
5718
5719 void
5720 Editor::hide_region_from_region_list ()
5721 {
5722         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5723 }
5724
5725 void
5726 Editor::show_region_in_region_list ()
5727 {
5728         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5729 }
5730
5731 void
5732 Editor::step_edit_status_change (bool yn)
5733 {
5734         if (yn) {
5735                 start_step_editing ();
5736         } else {
5737                 stop_step_editing ();
5738         }
5739 }
5740
5741 void
5742 Editor::start_step_editing ()
5743 {
5744         step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5745 }
5746
5747 void
5748 Editor::stop_step_editing ()
5749 {
5750         step_edit_connection.disconnect ();
5751 }
5752
5753 bool
5754 Editor::check_step_edit ()
5755 {
5756         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5757                 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5758                 if (mtv) {
5759                         mtv->check_step_edit ();
5760                 }
5761         }
5762
5763         return true; // do it again, till we stop
5764 }
5765
5766 bool
5767 Editor::scroll_press (Direction dir)
5768 {
5769         ++_scroll_callbacks;
5770
5771         if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5772                 /* delay the first auto-repeat */
5773                 return true;
5774         }
5775
5776         switch (dir) {
5777         case LEFT:
5778                 scroll_backward (1);
5779                 break;
5780
5781         case RIGHT:
5782                 scroll_forward (1);
5783                 break;
5784
5785         case UP:
5786                 scroll_up_one_track ();
5787                 break;
5788
5789         case DOWN:
5790                 scroll_down_one_track ();
5791                 break;
5792         }
5793
5794         /* do hacky auto-repeat */
5795         if (!_scroll_connection.connected ()) {
5796
5797                 _scroll_connection = Glib::signal_timeout().connect (
5798                         sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5799                         );
5800
5801                 _scroll_callbacks = 0;
5802         }
5803
5804         return true;
5805 }
5806
5807 void
5808 Editor::scroll_release ()
5809 {
5810         _scroll_connection.disconnect ();
5811 }
5812
5813 /** Queue a change for the Editor viewport x origin to follow the playhead */
5814 void
5815 Editor::reset_x_origin_to_follow_playhead ()
5816 {
5817         samplepos_t const sample = playhead_cursor->current_sample ();
5818
5819         if (sample < _leftmost_sample || sample > _leftmost_sample + current_page_samples()) {
5820
5821                 if (_session->transport_speed() < 0) {
5822
5823                         if (sample > (current_page_samples() / 2)) {
5824                                 center_screen (sample-(current_page_samples()/2));
5825                         } else {
5826                                 center_screen (current_page_samples()/2);
5827                         }
5828
5829                 } else {
5830
5831                         samplepos_t l = 0;
5832
5833                         if (sample < _leftmost_sample) {
5834                                 /* moving left */
5835                                 if (_session->transport_rolling()) {
5836                                         /* rolling; end up with the playhead at the right of the page */
5837                                         l = sample - current_page_samples ();
5838                                 } else {
5839                                         /* not rolling: end up with the playhead 1/4 of the way along the page */
5840                                         l = sample - current_page_samples() / 4;
5841                                 }
5842                         } else {
5843                                 /* moving right */
5844                                 if (_session->transport_rolling()) {
5845                                         /* rolling: end up with the playhead on the left of the page */
5846                                         l = sample;
5847                                 } else {
5848                                         /* not rolling: end up with the playhead 3/4 of the way along the page */
5849                                         l = sample - 3 * current_page_samples() / 4;
5850                                 }
5851                         }
5852
5853                         if (l < 0) {
5854                                 l = 0;
5855                         }
5856
5857                         center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5858                 }
5859         }
5860 }
5861
5862 void
5863 Editor::super_rapid_screen_update ()
5864 {
5865         if (!_session || !_session->engine().running()) {
5866                 return;
5867         }
5868
5869         /* METERING / MIXER STRIPS */
5870
5871         /* update track meters, if required */
5872         if (contents().is_mapped() && meters_running) {
5873                 RouteTimeAxisView* rtv;
5874                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5875                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5876                                 rtv->fast_update ();
5877                         }
5878                 }
5879         }
5880
5881         /* and any current mixer strip */
5882         if (current_mixer_strip) {
5883                 current_mixer_strip->fast_update ();
5884         }
5885
5886         bool latent_locate = false;
5887         samplepos_t sample = _session->audible_sample (&latent_locate);
5888         const int64_t now = g_get_monotonic_time ();
5889         double err = 0;
5890
5891         if (_session->exporting ()) {
5892                 /* freewheel/export may be faster or slower than transport_speed() / SR.
5893                  * Also exporting multiple ranges locates/jumps without a _pending_locate_request.
5894                  */
5895                 _last_update_time = 0;
5896         }
5897
5898         if (!_session->transport_rolling () || _session->is_auditioning ()) {
5899                 /* Do not interpolate the playhead position; just set it */
5900                 _last_update_time = 0;
5901         }
5902
5903         if (_last_update_time > 0) {
5904                 /* interpolate and smoothen playhead position */
5905                 const double ds =  (now - _last_update_time) * _session->transport_speed() * _session->nominal_sample_rate () * 1e-6;
5906                 samplepos_t guess = playhead_cursor->current_sample () + rint (ds);
5907                 err = sample - guess;
5908
5909                 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5910                 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5911
5912 #if 0 // DEBUG
5913                 printf ("eng: %ld  gui:%ld (%+6.1f)  diff: %6.1f (err: %7.2f)\n",
5914                                 sample, guess, ds,
5915                                 err, _err_screen_engine);
5916 #endif
5917
5918                 sample = guess;
5919         } else {
5920                 _err_screen_engine = 0;
5921         }
5922
5923         if (err > 8192 || latent_locate) {
5924                 // in case of x-runs or freewheeling
5925                 _last_update_time = 0;
5926                 sample = _session->audible_sample ();
5927         } else {
5928                 _last_update_time = now;
5929         }
5930
5931         /* snapped cursor stuff (the snapped_cursor shows where an operation is going to occur) */
5932         bool ignored;
5933         MusicSample where (sample, 0);
5934         if (!UIConfiguration::instance().get_show_snapped_cursor()) {
5935                 snapped_cursor->hide ();
5936         } else if (_edit_point == EditAtPlayhead && !_dragging_playhead) {
5937                 /* EditAtPlayhead does not snap */
5938         } else if (_edit_point == EditAtSelectedMarker) {
5939                 /* NOTE: I don't think EditAtSelectedMarker should snap. They are what they are.
5940                  * however, the current editing code -does- snap so I'll draw it that way for now.
5941                  */
5942                 if (!selection->markers.empty()) {
5943                         MusicSample ms (selection->markers.front()->position(), 0);
5944                         snap_to (ms); // should use snap_to_with_modifier?
5945                         snapped_cursor->set_position (ms.sample);
5946                         snapped_cursor->show ();
5947                 }
5948         } else if (mouse_sample (where.sample, ignored)) { // cursor is in the editing canvas. show it.
5949                 snapped_cursor->show ();
5950         } else { // mouse is out of the editing canvas. hide the snapped_cursor
5951                 snapped_cursor->hide ();
5952         }
5953
5954         /* There are a few reasons why we might not update the playhead / viewport stuff:
5955          *
5956          * 1.  we don't update things when there's a pending locate request, otherwise
5957          *     when the editor requests a locate there is a chance that this method
5958          *     will move the playhead before the locate request is processed, causing
5959          *     a visual glitch.
5960          * 2.  if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5961          * 3.  if we're still at the same frame that we were last time, there's nothing to do.
5962          */
5963         if (_pending_locate_request) {
5964                 _last_update_time = 0;
5965                 return;
5966         }
5967
5968         if (_dragging_playhead) {
5969                 _last_update_time = 0;
5970                 return;
5971         }
5972
5973         if (playhead_cursor->current_sample () == sample) {
5974                 return;
5975         }
5976
5977         playhead_cursor->set_position (sample);
5978
5979         if (_session->requested_return_sample() >= 0) {
5980                 _last_update_time = 0;
5981                 return;
5982         }
5983
5984         if (!_follow_playhead || pending_visual_change.being_handled) {
5985                 /* We only do this if we aren't already
5986                  * handling a visual change (ie if
5987                  * pending_visual_change.being_handled is
5988                  * false) so that these requests don't stack
5989                  * up there are too many of them to handle in
5990                  * time.
5991                  */
5992                 return;
5993         }
5994
5995         if (!_stationary_playhead) {
5996                 reset_x_origin_to_follow_playhead ();
5997         } else {
5998                 samplepos_t const sample = playhead_cursor->current_sample ();
5999                 double target = ((double)sample - (double)current_page_samples() / 2.0);
6000                 if (target <= 0.0) {
6001                         target = 0.0;
6002                 }
6003                 /* compare to EditorCursor::set_position() */
6004                 double const old_pos = sample_to_pixel_unrounded (_leftmost_sample);
6005                 double const new_pos = sample_to_pixel_unrounded (target);
6006                 if (rint (new_pos) != rint (old_pos)) {
6007                         reset_x_origin (pixel_to_sample (new_pos));
6008                 }
6009         }
6010 }
6011
6012
6013 void
6014 Editor::session_going_away ()
6015 {
6016         _have_idled = false;
6017
6018         _session_connections.drop_connections ();
6019
6020         super_rapid_screen_update_connection.disconnect ();
6021
6022         selection->clear ();
6023         cut_buffer->clear ();
6024
6025         clicked_regionview = 0;
6026         clicked_axisview = 0;
6027         clicked_routeview = 0;
6028         entered_regionview = 0;
6029         entered_track = 0;
6030         _last_update_time = 0;
6031         _drags->abort ();
6032
6033         playhead_cursor->hide ();
6034
6035         /* rip everything out of the list displays */
6036
6037         _regions->clear ();
6038         _routes->clear ();
6039         _route_groups->clear ();
6040
6041         /* do this first so that deleting a track doesn't reset cms to null
6042            and thus cause a leak.
6043         */
6044
6045         if (current_mixer_strip) {
6046                 if (current_mixer_strip->get_parent() != 0) {
6047                         global_hpacker.remove (*current_mixer_strip);
6048                 }
6049                 delete current_mixer_strip;
6050                 current_mixer_strip = 0;
6051         }
6052
6053         /* delete all trackviews */
6054
6055         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6056                 delete *i;
6057         }
6058         track_views.clear ();
6059
6060         nudge_clock->set_session (0);
6061
6062         editor_list_button.set_active(false);
6063         editor_list_button.set_sensitive(false);
6064
6065         /* clear tempo/meter rulers */
6066         remove_metric_marks ();
6067         clear_marker_display ();
6068
6069         hide_grid_lines ();
6070         delete grid_lines;
6071         grid_lines = 0;
6072
6073         stop_step_editing ();
6074
6075         if (own_window()) {
6076
6077                 /* get rid of any existing editor mixer strip */
6078
6079                 WindowTitle title(Glib::get_application_name());
6080                 title += _("Editor");
6081
6082                 own_window()->set_title (title.get_string());
6083         }
6084
6085         SessionHandlePtr::session_going_away ();
6086 }
6087
6088 void
6089 Editor::trigger_script (int i)
6090 {
6091         LuaInstance::instance()-> call_action (i);
6092 }
6093
6094 void
6095 Editor::show_editor_list (bool yn)
6096 {
6097         if (yn) {
6098                 _editor_list_vbox.show ();
6099         } else {
6100                 _editor_list_vbox.hide ();
6101         }
6102 }
6103
6104 void
6105 Editor::change_region_layering_order (bool from_context_menu)
6106 {
6107         const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
6108
6109         if (!clicked_routeview) {
6110                 if (layering_order_editor) {
6111                         layering_order_editor->hide ();
6112                 }
6113                 return;
6114         }
6115
6116         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
6117
6118         if (!track) {
6119                 return;
6120         }
6121
6122         boost::shared_ptr<Playlist> pl = track->playlist();
6123
6124         if (!pl) {
6125                 return;
6126         }
6127
6128         if (layering_order_editor == 0) {
6129                 layering_order_editor = new RegionLayeringOrderEditor (*this);
6130         }
6131
6132         layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
6133         layering_order_editor->maybe_present ();
6134 }
6135
6136 void
6137 Editor::update_region_layering_order_editor ()
6138 {
6139         if (layering_order_editor && layering_order_editor->is_visible ()) {
6140                 change_region_layering_order (true);
6141         }
6142 }
6143
6144 void
6145 Editor::setup_fade_images ()
6146 {
6147         _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
6148         _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
6149         _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
6150         _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
6151         _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
6152
6153         _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
6154         _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
6155         _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
6156         _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
6157         _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
6158
6159 }
6160
6161 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
6162 Gtk::MenuItem&
6163 Editor::action_menu_item (std::string const & name)
6164 {
6165         Glib::RefPtr<Action> a = editor_actions->get_action (name);
6166         assert (a);
6167
6168         return *manage (a->create_menu_item ());
6169 }
6170
6171 void
6172 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6173 {
6174         EventBox* b = manage (new EventBox);
6175         b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6176         Label* l = manage (new Label (name));
6177         l->set_angle (-90);
6178         b->add (*l);
6179         b->show_all ();
6180         _the_notebook.append_page (widget, *b);
6181 }
6182
6183 bool
6184 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6185 {
6186         if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6187                 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6188         }
6189
6190         if (ev->type == GDK_2BUTTON_PRESS) {
6191
6192                 /* double-click on a notebook tab shrinks or expands the notebook */
6193
6194                 if (_notebook_shrunk) {
6195                         if (pre_notebook_shrink_pane_width) {
6196                                 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6197                         }
6198                         _notebook_shrunk = false;
6199                 } else {
6200                         pre_notebook_shrink_pane_width = edit_pane.get_divider();
6201
6202                         /* this expands the LHS of the edit pane to cover the notebook
6203                            PAGE but leaves the tabs visible.
6204                          */
6205                         edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6206                         _notebook_shrunk = true;
6207                 }
6208         }
6209
6210         return true;
6211 }
6212
6213 void
6214 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6215 {
6216         using namespace Menu_Helpers;
6217
6218         MenuList& items = _control_point_context_menu.items ();
6219         items.clear ();
6220
6221         items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6222         items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6223         if (!can_remove_control_point (item)) {
6224                 items.back().set_sensitive (false);
6225         }
6226
6227         _control_point_context_menu.popup (event->button.button, event->button.time);
6228 }
6229
6230 void
6231 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6232 {
6233         using namespace Menu_Helpers;
6234
6235         NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6236         if (!note) {
6237                 return;
6238         }
6239
6240         /* We need to get the selection here and pass it to the operations, since
6241            popping up the menu will cause a region leave event which clears
6242            entered_regionview. */
6243
6244         MidiRegionView&       mrv = note->region_view();
6245         const RegionSelection rs  = get_regions_from_selection_and_entered ();
6246         const uint32_t sel_size = mrv.selection_size ();
6247
6248         MenuList& items = _note_context_menu.items();
6249         items.clear();
6250
6251         if (sel_size > 0) {
6252                 items.push_back(MenuElem(_("Delete"),
6253                                          sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6254         }
6255
6256         items.push_back(MenuElem(_("Edit..."),
6257                                  sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6258         if (sel_size != 1) {
6259                 items.back().set_sensitive (false);
6260         }
6261
6262         items.push_back(MenuElem(_("Transpose..."),
6263                                  sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6264
6265
6266         items.push_back(MenuElem(_("Legatize"),
6267                                  sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6268         if (sel_size < 2) {
6269                 items.back().set_sensitive (false);
6270         }
6271
6272         items.push_back(MenuElem(_("Quantize..."),
6273                                  sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6274
6275         items.push_back(MenuElem(_("Remove Overlap"),
6276                                  sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6277         if (sel_size < 2) {
6278                 items.back().set_sensitive (false);
6279         }
6280
6281         items.push_back(MenuElem(_("Transform..."),
6282                                  sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6283
6284         _note_context_menu.popup (event->button.button, event->button.time);
6285 }
6286
6287 void
6288 Editor::zoom_vertical_modifier_released()
6289 {
6290         _stepping_axis_view = 0;
6291 }
6292
6293 void
6294 Editor::ui_parameter_changed (string parameter)
6295 {
6296         if (parameter == "icon-set") {
6297                 while (!_cursor_stack.empty()) {
6298                         _cursor_stack.pop_back();
6299                 }
6300                 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6301                 _cursor_stack.push_back(_cursors->grabber);
6302                 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6303                 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6304
6305         } else if (parameter == "draggable-playhead") {
6306                 if (_verbose_cursor) {
6307                         playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6308                 }
6309         } else if (parameter == "use-note-bars-for-velocity") {
6310                 ArdourCanvas::Note::set_show_velocity_bars (UIConfiguration::instance().get_use_note_bars_for_velocity());
6311                 _track_canvas->request_redraw (_track_canvas->visible_area());
6312         } else if (parameter == "use-note-color-for-velocity") {
6313                 /* handled individually by each MidiRegionView */
6314         }
6315 }
6316
6317 Gtk::Window*
6318 Editor::use_own_window (bool and_fill_it)
6319 {
6320         bool new_window = !own_window();
6321
6322         Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6323
6324         if (win && new_window) {
6325                 win->set_name ("EditorWindow");
6326
6327                 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6328
6329                 // win->signal_realize().connect (*this, &Editor::on_realize);
6330                 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6331                 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6332                 win->set_data ("ardour-bindings", bindings);
6333
6334                 update_title ();
6335         }
6336
6337         DisplaySuspender ds;
6338         contents().show_all ();
6339
6340         /* XXX: this is a bit unfortunate; it would probably
6341            be nicer if we could just call show () above rather
6342            than needing the show_all ()
6343         */
6344
6345         /* re-hide stuff if necessary */
6346         editor_list_button_toggled ();
6347         parameter_changed ("show-summary");
6348         parameter_changed ("show-group-tabs");
6349         parameter_changed ("show-zoom-tools");
6350
6351         /* now reset all audio_time_axis heights, because widgets might need
6352            to be re-hidden
6353         */
6354
6355         TimeAxisView *tv;
6356
6357         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6358                 tv = (static_cast<TimeAxisView*>(*i));
6359                 tv->reset_height ();
6360         }
6361
6362         if (current_mixer_strip) {
6363                 current_mixer_strip->hide_things ();
6364                 current_mixer_strip->parameter_changed ("mixer-element-visibility");
6365         }
6366
6367         return win;
6368 }