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