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