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