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