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