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