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