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