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