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