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