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