e4d2a126a1c9b1ccabfede99d55236b14d85da47
[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                 _locations->set_state (**i);
2556         }
2557
2558         if ((prop = node.property ("maximised"))) {
2559                 bool yn = string_is_affirmative (prop->value());
2560                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2561                 assert (act);
2562                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2563                 bool fs = tact && tact->get_active();
2564                 if (yn ^ fs) {
2565                         ActionManager::do_action ("Common", "ToggleMaximalEditor");
2566                 }
2567         }
2568
2569         if ((prop = node.property ("nudge-clock-value"))) {
2570                 framepos_t f;
2571                 sscanf (prop->value().c_str(), "%" PRId64, &f);
2572                 nudge_clock->set (f);
2573         } else {
2574                 nudge_clock->set_mode (AudioClock::Timecode);
2575                 nudge_clock->set (_session->frame_rate() * 5, true);
2576         }
2577
2578         {
2579                 /* apply state
2580                  * Not all properties may have been in XML, but
2581                  * those that are linked to a private variable may need changing
2582                  */
2583                 RefPtr<Action> act;
2584                 bool yn;
2585
2586                 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2587                 if (act) {
2588                         yn = _show_measures;
2589                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2590                         /* do it twice to force the change */
2591                         tact->set_active (!yn);
2592                         tact->set_active (yn);
2593                 }
2594
2595                 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2596                 yn = _follow_playhead;
2597                 if (act) {
2598                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2599                         if (tact->get_active() != yn) {
2600                                 tact->set_active (yn);
2601                         }
2602                 }
2603
2604                 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2605                 yn = _stationary_playhead;
2606                 if (act) {
2607                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2608                         if (tact->get_active() != yn) {
2609                                 tact->set_active (yn);
2610                         }
2611                 }
2612         }
2613
2614         return LuaInstance::instance()->set_state(node);
2615 }
2616
2617 XMLNode&
2618 Editor::get_state ()
2619 {
2620         XMLNode* node = new XMLNode (X_("Editor"));
2621         char buf[32];
2622         LocaleGuard lg;
2623
2624         id().print (buf, sizeof (buf));
2625         node->add_property ("id", buf);
2626
2627         node->add_child_nocopy (Tabbable::get_state());
2628
2629         snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ());
2630         node->add_property("edit-horizontal-pane-pos", string(buf));
2631         node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2632         snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider());
2633         node->add_property("edit-vertical-pane-pos", string(buf));
2634
2635         maybe_add_mixer_strip_width (*node);
2636
2637         node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2638
2639         snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2640         node->add_property ("zoom", buf);
2641         node->add_property ("snap-to", enum_2_string (_snap_type));
2642         node->add_property ("snap-mode", enum_2_string (_snap_mode));
2643         node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2644         node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2645         node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2646         node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2647         node->add_property ("edit-point", enum_2_string (_edit_point));
2648         snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2649         node->add_property ("visible-track-count", buf);
2650
2651         snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2652         node->add_property ("playhead", buf);
2653         snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2654         node->add_property ("left-frame", buf);
2655         snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2656         node->add_property ("y-origin", buf);
2657
2658         node->add_property ("show-measures", _show_measures ? "yes" : "no");
2659         node->add_property ("maximised", _maximised ? "yes" : "no");
2660         node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2661         node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2662         node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2663         node->add_property ("mouse-mode", enum2str(mouse_mode));
2664         node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2665
2666         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2667         if (act) {
2668                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2669                 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2670         }
2671
2672         act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2673         if (act) {
2674                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2675                 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2676         }
2677
2678         snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2679         node->add_property (X_("editor-list-page"), buf);
2680
2681         if (button_bindings) {
2682                 XMLNode* bb = new XMLNode (X_("Buttons"));
2683                 button_bindings->save (*bb);
2684                 node->add_child_nocopy (*bb);
2685         }
2686
2687         node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2688
2689         node->add_child_nocopy (selection->get_state ());
2690         node->add_child_nocopy (_regions->get_state ());
2691
2692         snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2693         node->add_property ("nudge-clock-value", buf);
2694
2695         node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2696         node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2697         node->add_child_nocopy (_locations->get_state ());
2698
2699         return *node;
2700 }
2701
2702 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2703  *  if @param trackview_relative_offset is false, @param y y is a global canvas *  coordinate, in pixel units
2704  *
2705  *  @return pair: TimeAxisView that y is over, layer index.
2706  *
2707  *  TimeAxisView may be 0.  Layer index is the layer number if the TimeAxisView is valid and is
2708  *  in stacked or expanded region display mode, otherwise 0.
2709  */
2710 std::pair<TimeAxisView *, double>
2711 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2712 {
2713         if (!trackview_relative_offset) {
2714                 y -= _trackview_group->canvas_origin().y;
2715         }
2716
2717         if (y < 0) {
2718                 return std::make_pair ( (TimeAxisView *) 0, 0);
2719         }
2720
2721         for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2722
2723                 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2724
2725                 if (r.first) {
2726                         return r;
2727                 }
2728         }
2729
2730         return std::make_pair ( (TimeAxisView *) 0, 0);
2731 }
2732
2733 /** Snap a position to the grid, if appropriate, taking into account current
2734  *  grid settings and also the state of any snap modifier keys that may be pressed.
2735  *  @param start Position to snap.
2736  *  @param event Event to get current key modifier information from, or 0.
2737  */
2738 void
2739 Editor::snap_to_with_modifier (MusicFrame& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2740 {
2741         if (!_session || !event) {
2742                 return;
2743         }
2744
2745         if (ArdourKeyboard::indicates_snap (event->button.state)) {
2746                 if (_snap_mode == SnapOff) {
2747                         snap_to_internal (start, direction, for_mark);
2748                 } else {
2749                         start.set (start.frame, 0);
2750                 }
2751         } else {
2752                 if (_snap_mode != SnapOff) {
2753                         snap_to_internal (start, direction, for_mark);
2754                 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2755                         /* SnapOff, but we pressed the snap_delta modifier */
2756                         snap_to_internal (start, direction, for_mark);
2757                 } else {
2758                         start.set (start.frame, 0);
2759                 }
2760         }
2761 }
2762
2763 void
2764 Editor::snap_to (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2765 {
2766         if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2767                 start.set (start.frame, 0);
2768                 return;
2769         }
2770
2771         snap_to_internal (start, direction, for_mark, ensure_snap);
2772 }
2773
2774 void
2775 Editor::timecode_snap_to_internal (MusicFrame& pos, RoundMode direction, bool /*for_mark*/)
2776 {
2777         framepos_t start = pos.frame;
2778         const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2779         framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2780
2781         switch (_snap_type) {
2782         case SnapToTimecodeFrame:
2783                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2784                     fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2785                         /* start is already on a whole timecode frame, do nothing */
2786                 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2787                         start = (framepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2788                 } else {
2789                         start = (framepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) *  _session->samples_per_timecode_frame());
2790                 }
2791                 break;
2792
2793         case SnapToTimecodeSeconds:
2794                 if (_session->config.get_timecode_offset_negative()) {
2795                         start += _session->config.get_timecode_offset ();
2796                 } else {
2797                         start -= _session->config.get_timecode_offset ();
2798                 }
2799                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2800                     (start % one_timecode_second == 0)) {
2801                         /* start is already on a whole second, do nothing */
2802                 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2803                         start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2804                 } else {
2805                         start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2806                 }
2807
2808                 if (_session->config.get_timecode_offset_negative()) {
2809                         start -= _session->config.get_timecode_offset ();
2810                 } else {
2811                         start += _session->config.get_timecode_offset ();
2812                 }
2813                 break;
2814
2815         case SnapToTimecodeMinutes:
2816                 if (_session->config.get_timecode_offset_negative()) {
2817                         start += _session->config.get_timecode_offset ();
2818                 } else {
2819                         start -= _session->config.get_timecode_offset ();
2820                 }
2821                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2822                     (start % one_timecode_minute == 0)) {
2823                         /* start is already on a whole minute, do nothing */
2824                 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2825                         start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2826                 } else {
2827                         start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2828                 }
2829                 if (_session->config.get_timecode_offset_negative()) {
2830                         start -= _session->config.get_timecode_offset ();
2831                 } else {
2832                         start += _session->config.get_timecode_offset ();
2833                 }
2834                 break;
2835         default:
2836                 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2837                 abort(); /*NOTREACHED*/
2838         }
2839
2840         pos.set (start, 0);
2841 }
2842
2843 void
2844 Editor::snap_to_internal (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2845 {
2846         const framepos_t one_second = _session->frame_rate();
2847         const framepos_t one_minute = _session->frame_rate() * 60;
2848         framepos_t presnap = start.frame;
2849         framepos_t before;
2850         framepos_t after;
2851
2852         switch (_snap_type) {
2853         case SnapToTimecodeFrame:
2854         case SnapToTimecodeSeconds:
2855         case SnapToTimecodeMinutes:
2856                 return timecode_snap_to_internal (start, direction, for_mark);
2857
2858         case SnapToCDFrame:
2859                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2860                     start.frame % (one_second/75) == 0) {
2861                         /* start is already on a whole CD frame, do nothing */
2862                 } else if (((direction == 0) && (start.frame % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2863                         start.frame = (framepos_t) ceil ((double) start.frame / (one_second / 75)) * (one_second / 75);
2864                 } else {
2865                         start.frame = (framepos_t) floor ((double) start.frame / (one_second / 75)) * (one_second / 75);
2866                 }
2867
2868                 start.set (start.frame, 0);
2869
2870                 break;
2871
2872         case SnapToSeconds:
2873                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2874                     start.frame % one_second == 0) {
2875                         /* start is already on a whole second, do nothing */
2876                 } else if (((direction == 0) && (start.frame % one_second > one_second / 2)) || (direction > 0)) {
2877                         start.frame = (framepos_t) ceil ((double) start.frame / one_second) * one_second;
2878                 } else {
2879                         start.frame = (framepos_t) floor ((double) start.frame / one_second) * one_second;
2880                 }
2881
2882                 start.set (start.frame, 0);
2883
2884                 break;
2885
2886         case SnapToMinutes:
2887                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2888                     start.frame % one_minute == 0) {
2889                         /* start is already on a whole minute, do nothing */
2890                 } else if (((direction == 0) && (start.frame % one_minute > one_minute / 2)) || (direction > 0)) {
2891                         start.frame = (framepos_t) ceil ((double) start.frame / one_minute) * one_minute;
2892                 } else {
2893                         start.frame = (framepos_t) floor ((double) start.frame / one_minute) * one_minute;
2894                 }
2895
2896                 start.set (start.frame, 0);
2897
2898                 break;
2899
2900         case SnapToBar:
2901                 start = _session->tempo_map().round_to_bar (start.frame, direction);
2902                 break;
2903
2904         case SnapToBeat:
2905                 start = _session->tempo_map().round_to_beat (start.frame, direction);
2906                 break;
2907
2908         case SnapToBeatDiv128:
2909                 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 128, direction);
2910                 break;
2911         case SnapToBeatDiv64:
2912                 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 64, direction);
2913                 break;
2914         case SnapToBeatDiv32:
2915                 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 32, direction);
2916                 break;
2917         case SnapToBeatDiv28:
2918                 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 28, direction);
2919                 break;
2920         case SnapToBeatDiv24:
2921                 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 24, direction);
2922                 break;
2923         case SnapToBeatDiv20:
2924                 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 20, direction);
2925                 break;
2926         case SnapToBeatDiv16:
2927                 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 16, direction);
2928                 break;
2929         case SnapToBeatDiv14:
2930                 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 14, direction);
2931                 break;
2932         case SnapToBeatDiv12:
2933                 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 12, direction);
2934                 break;
2935         case SnapToBeatDiv10:
2936                 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 10, direction);
2937                 break;
2938         case SnapToBeatDiv8:
2939                 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 8, direction);
2940                 break;
2941         case SnapToBeatDiv7:
2942                 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 7, direction);
2943                 break;
2944         case SnapToBeatDiv6:
2945                 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 6, direction);
2946                 break;
2947         case SnapToBeatDiv5:
2948                 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 5, direction);
2949                 break;
2950         case SnapToBeatDiv4:
2951                 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 4, direction);
2952                 break;
2953         case SnapToBeatDiv3:
2954                 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 3, direction);
2955                 break;
2956         case SnapToBeatDiv2:
2957                 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 2, direction);
2958                 break;
2959
2960         case SnapToMark:
2961                 if (for_mark) {
2962                         return;
2963                 }
2964
2965                 _session->locations()->marks_either_side (start.frame, before, after);
2966
2967                 if (before == max_framepos && after == max_framepos) {
2968                         /* No marks to snap to, so just don't snap */
2969                         return;
2970                 } else if (before == max_framepos) {
2971                         start.frame = after;
2972                 } else if (after == max_framepos) {
2973                         start.frame = before;
2974                 } else if (before != max_framepos && after != max_framepos) {
2975                         if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2976                                 start.frame = after;
2977                         else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2978                                 start.frame = before;
2979                         else if (direction ==  0 ) {
2980                                 if ((start.frame - before) < (after - start.frame)) {
2981                                         start.frame = before;
2982                                 } else {
2983                                         start.frame = after;
2984                                 }
2985                         }
2986                 }
2987
2988                 start.set (start.frame, 0);
2989
2990                 break;
2991
2992         case SnapToRegionStart:
2993         case SnapToRegionEnd:
2994         case SnapToRegionSync:
2995         case SnapToRegionBoundary:
2996                 if (!region_boundary_cache.empty()) {
2997
2998                         vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2999                         vector<framepos_t>::iterator next = region_boundary_cache.end ();
3000
3001                         if (direction > 0) {
3002                                 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
3003                         } else {
3004                                 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
3005                         }
3006
3007                         if (next != region_boundary_cache.begin ()) {
3008                                 prev = next;
3009                                 prev--;
3010                         }
3011
3012                         framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
3013                         framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
3014
3015                         if (start.frame > (p + n) / 2) {
3016                                 start.frame = n;
3017                         } else {
3018                                 start.frame = p;
3019                         }
3020                 }
3021
3022                 start.set (start.frame, 0);
3023
3024                 break;
3025         }
3026
3027         switch (_snap_mode) {
3028         case SnapNormal:
3029                 return;
3030
3031         case SnapMagnetic:
3032
3033                 if (ensure_snap) {
3034                         return;
3035                 }
3036
3037                 if (presnap > start.frame) {
3038                         if (presnap > (start.frame + pixel_to_sample(snap_threshold))) {
3039                                 start.set (presnap, 0);
3040                         }
3041
3042                 } else if (presnap < start.frame) {
3043                         if (presnap < (start.frame - pixel_to_sample(snap_threshold))) {
3044                                 start.set (presnap, 0);
3045                         }
3046                 }
3047
3048         default:
3049                 /* handled at entry */
3050                 return;
3051         }
3052 }
3053
3054
3055 void
3056 Editor::setup_toolbar ()
3057 {
3058         HBox* mode_box = manage(new HBox);
3059         mode_box->set_border_width (2);
3060         mode_box->set_spacing(2);
3061
3062         HBox* mouse_mode_box = manage (new HBox);
3063         HBox* mouse_mode_hbox = manage (new HBox);
3064         VBox* mouse_mode_vbox = manage (new VBox);
3065         Alignment* mouse_mode_align = manage (new Alignment);
3066
3067         Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3068         mouse_mode_size_group->add_widget (smart_mode_button);
3069         mouse_mode_size_group->add_widget (mouse_move_button);
3070         mouse_mode_size_group->add_widget (mouse_cut_button);
3071         mouse_mode_size_group->add_widget (mouse_select_button);
3072         mouse_mode_size_group->add_widget (mouse_timefx_button);
3073         mouse_mode_size_group->add_widget (mouse_audition_button);
3074         mouse_mode_size_group->add_widget (mouse_draw_button);
3075         mouse_mode_size_group->add_widget (mouse_content_button);
3076
3077         if (!Profile->get_mixbus()) {
3078                 mouse_mode_size_group->add_widget (zoom_in_button);
3079                 mouse_mode_size_group->add_widget (zoom_out_button);
3080                 mouse_mode_size_group->add_widget (zoom_out_full_button);
3081                 mouse_mode_size_group->add_widget (zoom_focus_selector);
3082                 mouse_mode_size_group->add_widget (tav_shrink_button);
3083                 mouse_mode_size_group->add_widget (tav_expand_button);
3084         } else {
3085                 mouse_mode_size_group->add_widget (zoom_preset_selector);
3086                 mouse_mode_size_group->add_widget (visible_tracks_selector);
3087         }
3088
3089         mouse_mode_size_group->add_widget (snap_type_selector);
3090         mouse_mode_size_group->add_widget (snap_mode_selector);
3091
3092         mouse_mode_size_group->add_widget (edit_point_selector);
3093         mouse_mode_size_group->add_widget (edit_mode_selector);
3094
3095         mouse_mode_size_group->add_widget (*nudge_clock);
3096         mouse_mode_size_group->add_widget (nudge_forward_button);
3097         mouse_mode_size_group->add_widget (nudge_backward_button);
3098
3099         mouse_mode_hbox->set_spacing (2);
3100
3101         if (!ARDOUR::Profile->get_trx()) {
3102                 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3103         }
3104
3105         mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3106         mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3107
3108         if (!ARDOUR::Profile->get_mixbus()) {
3109                 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3110         }
3111
3112         if (!ARDOUR::Profile->get_trx()) {
3113                 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3114                 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3115                 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3116                 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3117         }
3118
3119         mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3120
3121         mouse_mode_align->add (*mouse_mode_vbox);
3122         mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3123
3124         mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3125
3126         edit_mode_selector.set_name ("mouse mode button");
3127
3128         if (!ARDOUR::Profile->get_trx()) {
3129                 mode_box->pack_start (edit_mode_selector, false, false);
3130         }
3131
3132         mode_box->pack_start (*mouse_mode_box, false, false);
3133
3134         /* Zoom */
3135
3136         _zoom_box.set_spacing (2);
3137         _zoom_box.set_border_width (2);
3138
3139         RefPtr<Action> act;
3140
3141         zoom_preset_selector.set_name ("zoom button");
3142         zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3143
3144         zoom_in_button.set_name ("zoom button");
3145         zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3146         act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3147         zoom_in_button.set_related_action (act);
3148
3149         zoom_out_button.set_name ("zoom button");
3150         zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3151         act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3152         zoom_out_button.set_related_action (act);
3153
3154         zoom_out_full_button.set_name ("zoom button");
3155         zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3156         act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3157         zoom_out_full_button.set_related_action (act);
3158
3159         zoom_focus_selector.set_name ("zoom button");
3160
3161         if (ARDOUR::Profile->get_mixbus()) {
3162                 _zoom_box.pack_start (zoom_preset_selector, false, false);
3163         } else if (ARDOUR::Profile->get_trx()) {
3164                 mode_box->pack_start (zoom_out_button, false, false);
3165                 mode_box->pack_start (zoom_in_button, false, false);
3166         } else {
3167                 _zoom_box.pack_start (zoom_out_button, false, false);
3168                 _zoom_box.pack_start (zoom_in_button, false, false);
3169                 _zoom_box.pack_start (zoom_out_full_button, false, false);
3170                 _zoom_box.pack_start (zoom_focus_selector, false, false);
3171         }
3172
3173         /* Track zoom buttons */
3174         _track_box.set_spacing (2);
3175         _track_box.set_border_width (2);
3176
3177         visible_tracks_selector.set_name ("zoom button");
3178         if (Profile->get_mixbus()) {
3179                 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3180         } else {
3181                 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3182         }
3183
3184         tav_expand_button.set_name ("zoom button");
3185         tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3186         act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3187         tav_expand_button.set_related_action (act);
3188
3189         tav_shrink_button.set_name ("zoom button");
3190         tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3191         act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3192         tav_shrink_button.set_related_action (act);
3193
3194         if (ARDOUR::Profile->get_mixbus()) {
3195                 _track_box.pack_start (visible_tracks_selector);
3196         } else if (ARDOUR::Profile->get_trx()) {
3197                 _track_box.pack_start (tav_shrink_button);
3198                 _track_box.pack_start (tav_expand_button);
3199         } else {
3200                 _track_box.pack_start (visible_tracks_selector);
3201                 _track_box.pack_start (tav_shrink_button);
3202                 _track_box.pack_start (tav_expand_button);
3203         }
3204
3205         snap_box.set_spacing (2);
3206         snap_box.set_border_width (2);
3207
3208         snap_type_selector.set_name ("mouse mode button");
3209
3210         snap_mode_selector.set_name ("mouse mode button");
3211
3212         edit_point_selector.set_name ("mouse mode button");
3213
3214         snap_box.pack_start (snap_mode_selector, false, false);
3215         snap_box.pack_start (snap_type_selector, false, false);
3216
3217         /* Edit Point*/
3218         HBox *ep_box = manage (new HBox);
3219         ep_box->set_spacing (2);
3220         ep_box->set_border_width (2);
3221
3222         ep_box->pack_start (edit_point_selector, false, false);
3223
3224         /* Nudge */
3225
3226         HBox *nudge_box = manage (new HBox);
3227         nudge_box->set_spacing (2);
3228         nudge_box->set_border_width (2);
3229
3230         nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3231         nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3232
3233         nudge_box->pack_start (nudge_backward_button, false, false);
3234         nudge_box->pack_start (nudge_forward_button, false, false);
3235         nudge_box->pack_start (*nudge_clock, false, false);
3236
3237
3238         /* Pack everything in... */
3239
3240         toolbar_hbox.set_spacing (2);
3241         toolbar_hbox.set_border_width (2);
3242
3243         toolbar_hbox.pack_start (*mode_box, false, false);
3244
3245         if (!ARDOUR::Profile->get_trx()) {
3246
3247                 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3248
3249                 toolbar_hbox.pack_start (_zoom_box, false, false);
3250
3251                 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3252
3253                 toolbar_hbox.pack_start (_track_box, false, false);
3254
3255                 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3256
3257                 toolbar_hbox.pack_start (snap_box, false, false);
3258
3259                 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3260
3261                 toolbar_hbox.pack_start (*ep_box, false, false);
3262
3263                 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3264
3265                 toolbar_hbox.pack_start (*nudge_box, false, false);
3266         }
3267
3268         toolbar_hbox.show_all ();
3269 }
3270
3271 void
3272 Editor::build_edit_point_menu ()
3273 {
3274         using namespace Menu_Helpers;
3275
3276         edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3277         if(!Profile->get_mixbus())
3278                 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3279         edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3280
3281         set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3282 }
3283
3284 void
3285 Editor::build_edit_mode_menu ()
3286 {
3287         using namespace Menu_Helpers;
3288
3289         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3290 //      edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3291         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3292         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode)  Lock)));
3293
3294         set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3295 }
3296
3297 void
3298 Editor::build_snap_mode_menu ()
3299 {
3300         using namespace Menu_Helpers;
3301
3302         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3303         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3304         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3305
3306         set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3307 }
3308
3309 void
3310 Editor::build_snap_type_menu ()
3311 {
3312         using namespace Menu_Helpers;
3313
3314         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3315         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3316         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3317         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3318         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3319         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3320         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3321         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3322         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3323         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3324         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3325         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3326         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3327         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3328         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3329         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3330         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3331         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3332         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3333         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3334         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3335         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3336         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3337         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3338         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3339         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3340         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3341         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3342         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3343         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3344
3345         set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3346
3347 }
3348
3349 void
3350 Editor::setup_tooltips ()
3351 {
3352         set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3353         set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3354         set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3355         set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3356         set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3357         set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3358         set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3359         set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3360         set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3361         set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3362         set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3363         set_tooltip (zoom_in_button, _("Zoom In"));
3364         set_tooltip (zoom_out_button, _("Zoom Out"));
3365         set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3366         set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3367         set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3368         set_tooltip (tav_expand_button, _("Expand Tracks"));
3369         set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3370         set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3371         set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3372         set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3373         set_tooltip (edit_point_selector, _("Edit Point"));
3374         set_tooltip (edit_mode_selector, _("Edit Mode"));
3375         set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3376 }
3377
3378 int
3379 Editor::convert_drop_to_paths (
3380                 vector<string>&                paths,
3381                 const RefPtr<Gdk::DragContext>& /*context*/,
3382                 gint                            /*x*/,
3383                 gint                            /*y*/,
3384                 const SelectionData&            data,
3385                 guint                           /*info*/,
3386                 guint                           /*time*/)
3387 {
3388         if (_session == 0) {
3389                 return -1;
3390         }
3391
3392         vector<string> uris = data.get_uris();
3393
3394         if (uris.empty()) {
3395
3396                 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3397                    are actually URI lists. So do it by hand.
3398                 */
3399
3400                 if (data.get_target() != "text/plain") {
3401                         return -1;
3402                 }
3403
3404                 /* Parse the "uri-list" format that Nautilus provides,
3405                    where each pathname is delimited by \r\n.
3406
3407                    THERE MAY BE NO NULL TERMINATING CHAR!!!
3408                 */
3409
3410                 string txt = data.get_text();
3411                 char* p;
3412                 const char* q;
3413
3414                 p = (char *) malloc (txt.length() + 1);
3415                 txt.copy (p, txt.length(), 0);
3416                 p[txt.length()] = '\0';
3417
3418                 while (p)
3419                 {
3420                         if (*p != '#')
3421                         {
3422                                 while (g_ascii_isspace (*p))
3423                                         p++;
3424
3425                                 q = p;
3426                                 while (*q && (*q != '\n') && (*q != '\r')) {
3427                                         q++;
3428                                 }
3429
3430                                 if (q > p)
3431                                 {
3432                                         q--;
3433                                         while (q > p && g_ascii_isspace (*q))
3434                                                 q--;
3435
3436                                         if (q > p)
3437                                         {
3438                                                 uris.push_back (string (p, q - p + 1));
3439                                         }
3440                                 }
3441                         }
3442                         p = strchr (p, '\n');
3443                         if (p)
3444                                 p++;
3445                 }
3446
3447                 free ((void*)p);
3448
3449                 if (uris.empty()) {
3450                         return -1;
3451                 }
3452         }
3453
3454         for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3455                 if ((*i).substr (0,7) == "file://") {
3456                         paths.push_back (Glib::filename_from_uri (*i));
3457                 }
3458         }
3459
3460         return 0;
3461 }
3462
3463 void
3464 Editor::new_tempo_section ()
3465 {
3466 }
3467
3468 void
3469 Editor::map_transport_state ()
3470 {
3471         ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3472
3473         if (_session && _session->transport_stopped()) {
3474                 have_pending_keyboard_selection = false;
3475         }
3476
3477         update_loop_range_view ();
3478 }
3479
3480 /* UNDO/REDO */
3481
3482 void
3483 Editor::begin_selection_op_history ()
3484 {
3485         selection_op_cmd_depth = 0;
3486         selection_op_history_it = 0;
3487
3488         while(!selection_op_history.empty()) {
3489                 delete selection_op_history.front();
3490                 selection_op_history.pop_front();
3491         }
3492
3493         selection_undo_action->set_sensitive (false);
3494         selection_redo_action->set_sensitive (false);
3495         selection_op_history.push_front (&_selection_memento->get_state ());
3496 }
3497
3498 void
3499 Editor::begin_reversible_selection_op (string name)
3500 {
3501         if (_session) {
3502                 //cerr << name << endl;
3503                 /* begin/commit pairs can be nested */
3504                 selection_op_cmd_depth++;
3505         }
3506 }
3507
3508 void
3509 Editor::commit_reversible_selection_op ()
3510 {
3511         if (_session) {
3512                 if (selection_op_cmd_depth == 1) {
3513
3514                         if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3515                                 /**
3516                                     The user has undone some selection ops and then made a new one,
3517                                     making anything earlier in the list invalid.
3518                                 */
3519
3520                                 list<XMLNode *>::iterator it = selection_op_history.begin();
3521                                 list<XMLNode *>::iterator e_it = it;
3522                                 advance (e_it, selection_op_history_it);
3523
3524                                 for ( ; it != e_it; ++it) {
3525                                         delete *it;
3526                                 }
3527                                 selection_op_history.erase (selection_op_history.begin(), e_it);
3528                         }
3529
3530                         selection_op_history.push_front (&_selection_memento->get_state ());
3531                         selection_op_history_it = 0;
3532
3533                         selection_undo_action->set_sensitive (true);
3534                         selection_redo_action->set_sensitive (false);
3535                 }
3536
3537                 if (selection_op_cmd_depth > 0) {
3538                         selection_op_cmd_depth--;
3539                 }
3540         }
3541 }
3542
3543 void
3544 Editor::undo_selection_op ()
3545 {
3546         if (_session) {
3547                 selection_op_history_it++;
3548                 uint32_t n = 0;
3549                 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3550                         if (n == selection_op_history_it) {
3551                                 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3552                                 selection_redo_action->set_sensitive (true);
3553                         }
3554                         ++n;
3555                 }
3556                 /* is there an earlier entry? */
3557                 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3558                         selection_undo_action->set_sensitive (false);
3559                 }
3560         }
3561 }
3562
3563 void
3564 Editor::redo_selection_op ()
3565 {
3566         if (_session) {
3567                 if (selection_op_history_it > 0) {
3568                         selection_op_history_it--;
3569                 }
3570                 uint32_t n = 0;
3571                 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3572                         if (n == selection_op_history_it) {
3573                                 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3574                                 selection_undo_action->set_sensitive (true);
3575                         }
3576                         ++n;
3577                 }
3578
3579                 if (selection_op_history_it == 0) {
3580                         selection_redo_action->set_sensitive (false);
3581                 }
3582         }
3583 }
3584
3585 void
3586 Editor::begin_reversible_command (string name)
3587 {
3588         if (_session) {
3589                 before.push_back (&_selection_memento->get_state ());
3590                 _session->begin_reversible_command (name);
3591         }
3592 }
3593
3594 void
3595 Editor::begin_reversible_command (GQuark q)
3596 {
3597         if (_session) {
3598                 before.push_back (&_selection_memento->get_state ());
3599                 _session->begin_reversible_command (q);
3600         }
3601 }
3602
3603 void
3604 Editor::abort_reversible_command ()
3605 {
3606         if (_session) {
3607                 while(!before.empty()) {
3608                         delete before.front();
3609                         before.pop_front();
3610                 }
3611                 _session->abort_reversible_command ();
3612         }
3613 }
3614
3615 void
3616 Editor::commit_reversible_command ()
3617 {
3618         if (_session) {
3619                 if (before.size() == 1) {
3620                         _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3621                         redo_action->set_sensitive(false);
3622                         undo_action->set_sensitive(true);
3623                         begin_selection_op_history ();
3624                 }
3625
3626                 if (before.empty()) {
3627                         cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3628                 } else {
3629                         before.pop_back();
3630                 }
3631
3632                 _session->commit_reversible_command ();
3633         }
3634 }
3635
3636 void
3637 Editor::history_changed ()
3638 {
3639         string label;
3640
3641         if (undo_action && _session) {
3642                 if (_session->undo_depth() == 0) {
3643                         label = S_("Command|Undo");
3644                 } else {
3645                         label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3646                 }
3647                 undo_action->property_label() = label;
3648         }
3649
3650         if (redo_action && _session) {
3651                 if (_session->redo_depth() == 0) {
3652                         label = _("Redo");
3653                         redo_action->set_sensitive (false);
3654                 } else {
3655                         label = string_compose(_("Redo (%1)"), _session->next_redo());
3656                         redo_action->set_sensitive (true);
3657                 }
3658                 redo_action->property_label() = label;
3659         }
3660 }
3661
3662 void
3663 Editor::duplicate_range (bool with_dialog)
3664 {
3665         float times = 1.0f;
3666
3667         RegionSelection rs = get_regions_from_selection_and_entered ();
3668
3669         if ( selection->time.length() == 0 && rs.empty()) {
3670                 return;
3671         }
3672
3673         if (with_dialog) {
3674
3675                 ArdourDialog win (_("Duplicate"));
3676                 Label label (_("Number of duplications:"));
3677                 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3678                 SpinButton spinner (adjustment, 0.0, 1);
3679                 HBox hbox;
3680
3681                 win.get_vbox()->set_spacing (12);
3682                 win.get_vbox()->pack_start (hbox);
3683                 hbox.set_border_width (6);
3684                 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3685
3686                 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3687                    place, visually. so do this by hand.
3688                 */
3689
3690                 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3691                 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3692                 spinner.grab_focus();
3693
3694                 hbox.show ();
3695                 label.show ();
3696                 spinner.show ();
3697
3698                 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3699                 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3700                 win.set_default_response (RESPONSE_ACCEPT);
3701
3702                 spinner.grab_focus ();
3703
3704                 switch (win.run ()) {
3705                 case RESPONSE_ACCEPT:
3706                         break;
3707                 default:
3708                         return;
3709                 }
3710
3711                 times = adjustment.get_value();
3712         }
3713
3714         if ((current_mouse_mode() == Editing::MouseRange)) {
3715                 if (selection->time.length()) {
3716                         duplicate_selection (times);
3717                 }
3718         } else if (get_smart_mode()) {
3719                 if (selection->time.length()) {
3720                         duplicate_selection (times);
3721                 } else
3722                         duplicate_some_regions (rs, times);
3723         } else {
3724                 duplicate_some_regions (rs, times);
3725         }
3726 }
3727
3728 void
3729 Editor::set_edit_mode (EditMode m)
3730 {
3731         Config->set_edit_mode (m);
3732 }
3733
3734 void
3735 Editor::cycle_edit_mode ()
3736 {
3737         switch (Config->get_edit_mode()) {
3738         case Slide:
3739                 Config->set_edit_mode (Ripple);
3740                 break;
3741         case Splice:
3742         case Ripple:
3743                 Config->set_edit_mode (Lock);
3744                 break;
3745         case Lock:
3746                 Config->set_edit_mode (Slide);
3747                 break;
3748         }
3749 }
3750
3751 void
3752 Editor::edit_mode_selection_done ( EditMode m )
3753 {
3754         Config->set_edit_mode ( m );
3755 }
3756
3757 void
3758 Editor::snap_type_selection_done (SnapType snaptype)
3759 {
3760         RefPtr<RadioAction> ract = snap_type_action (snaptype);
3761         if (ract) {
3762                 ract->set_active ();
3763         }
3764 }
3765
3766 void
3767 Editor::snap_mode_selection_done (SnapMode mode)
3768 {
3769         RefPtr<RadioAction> ract = snap_mode_action (mode);
3770
3771         if (ract) {
3772                 ract->set_active (true);
3773         }
3774 }
3775
3776 void
3777 Editor::cycle_edit_point (bool with_marker)
3778 {
3779         if(Profile->get_mixbus())
3780                 with_marker = false;
3781
3782         switch (_edit_point) {
3783         case EditAtMouse:
3784                 set_edit_point_preference (EditAtPlayhead);
3785                 break;
3786         case EditAtPlayhead:
3787                 if (with_marker) {
3788                         set_edit_point_preference (EditAtSelectedMarker);
3789                 } else {
3790                         set_edit_point_preference (EditAtMouse);
3791                 }
3792                 break;
3793         case EditAtSelectedMarker:
3794                 set_edit_point_preference (EditAtMouse);
3795                 break;
3796         }
3797 }
3798
3799 void
3800 Editor::edit_point_selection_done (EditPoint ep)
3801 {
3802         set_edit_point_preference ( ep );
3803 }
3804
3805 void
3806 Editor::build_zoom_focus_menu ()
3807 {
3808         using namespace Menu_Helpers;
3809
3810         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3811         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3812         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3813         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3814         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3815         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3816
3817         set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3818 }
3819
3820 void
3821 Editor::zoom_focus_selection_done ( ZoomFocus f )
3822 {
3823         RefPtr<RadioAction> ract = zoom_focus_action (f);
3824         if (ract) {
3825                 ract->set_active ();
3826         }
3827 }
3828
3829 void
3830 Editor::build_track_count_menu ()
3831 {
3832         using namespace Menu_Helpers;
3833
3834         if (!Profile->get_mixbus()) {
3835                 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3836                 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3837                 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3838                 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3839                 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3840                 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3841                 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3842                 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3843                 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3844                 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3845                 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3846                 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3847                 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3848         } else {
3849                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3850                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3851                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3852                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3853                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3854                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3855                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3856                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3857                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3858                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3859
3860                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3861                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3862                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3863                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3864                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3865                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3866                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3867                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3868                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3869                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3870                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3871         }
3872 }
3873
3874 void
3875 Editor::set_zoom_preset (int64_t ms)
3876 {
3877         if ( ms <= 0 ) {
3878                 temporal_zoom_session();
3879                 return;
3880         }
3881
3882         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3883         temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3884 }
3885
3886 void
3887 Editor::set_visible_track_count (int32_t n)
3888 {
3889         _visible_track_count = n;
3890
3891         /* if the canvas hasn't really been allocated any size yet, just
3892            record the desired number of visible tracks and return. when canvas
3893            allocation happens, we will get called again and then we can do the
3894            real work.
3895         */
3896
3897         if (_visible_canvas_height <= 1) {
3898                 return;
3899         }
3900
3901         int h;
3902         string str;
3903         DisplaySuspender ds;
3904
3905         if (_visible_track_count > 0) {
3906                 h = trackviews_height() / _visible_track_count;
3907                 std::ostringstream s;
3908                 s << _visible_track_count;
3909                 str = s.str();
3910         } else if (_visible_track_count == 0) {
3911                 uint32_t n = 0;
3912                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3913                         if ((*i)->marked_for_display()) {
3914                                 ++n;
3915                         }
3916                 }
3917                 h = trackviews_height() / n;
3918                 str = _("All");
3919         } else {
3920                 /* negative value means that the visible track count has
3921                    been overridden by explicit track height changes.
3922                 */
3923                 visible_tracks_selector.set_text (X_("*"));
3924                 return;
3925         }
3926
3927         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3928                 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3929         }
3930
3931         if (str != visible_tracks_selector.get_text()) {
3932                 visible_tracks_selector.set_text (str);
3933         }
3934 }
3935
3936 void
3937 Editor::override_visible_track_count ()
3938 {
3939         _visible_track_count = -1;
3940         visible_tracks_selector.set_text ( _("*") );
3941 }
3942
3943 bool
3944 Editor::edit_controls_button_release (GdkEventButton* ev)
3945 {
3946         if (Keyboard::is_context_menu_event (ev)) {
3947                 ARDOUR_UI::instance()->add_route ();
3948         } else if (ev->button == 1) {
3949                 selection->clear_tracks ();
3950         }
3951
3952         return true;
3953 }
3954
3955 bool
3956 Editor::mouse_select_button_release (GdkEventButton* ev)
3957 {
3958         /* this handles just right-clicks */
3959
3960         if (ev->button != 3) {
3961                 return false;
3962         }
3963
3964         return true;
3965 }
3966
3967 void
3968 Editor::set_zoom_focus (ZoomFocus f)
3969 {
3970         string str = zoom_focus_strings[(int)f];
3971
3972         if (str != zoom_focus_selector.get_text()) {
3973                 zoom_focus_selector.set_text (str);
3974         }
3975
3976         if (zoom_focus != f) {
3977                 zoom_focus = f;
3978                 instant_save ();
3979         }
3980 }
3981
3982 void
3983 Editor::cycle_zoom_focus ()
3984 {
3985         switch (zoom_focus) {
3986         case ZoomFocusLeft:
3987                 set_zoom_focus (ZoomFocusRight);
3988                 break;
3989         case ZoomFocusRight:
3990                 set_zoom_focus (ZoomFocusCenter);
3991                 break;
3992         case ZoomFocusCenter:
3993                 set_zoom_focus (ZoomFocusPlayhead);
3994                 break;
3995         case ZoomFocusPlayhead:
3996                 set_zoom_focus (ZoomFocusMouse);
3997                 break;
3998         case ZoomFocusMouse:
3999                 set_zoom_focus (ZoomFocusEdit);
4000                 break;
4001         case ZoomFocusEdit:
4002                 set_zoom_focus (ZoomFocusLeft);
4003                 break;
4004         }
4005 }
4006
4007 void
4008 Editor::set_show_measures (bool yn)
4009 {
4010         if (_show_measures != yn) {
4011                 hide_measures ();
4012
4013                 if ((_show_measures = yn) == true) {
4014                         if (tempo_lines) {
4015                                 tempo_lines->show();
4016                         }
4017
4018                         std::vector<TempoMap::BBTPoint> grid;
4019                         compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
4020                         draw_measures (grid);
4021                 }
4022
4023                 instant_save ();
4024         }
4025 }
4026
4027 void
4028 Editor::toggle_follow_playhead ()
4029 {
4030         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
4031         if (act) {
4032                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4033                 set_follow_playhead (tact->get_active());
4034         }
4035 }
4036
4037 /** @param yn true to follow playhead, otherwise false.
4038  *  @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4039  */
4040 void
4041 Editor::set_follow_playhead (bool yn, bool catch_up)
4042 {
4043         if (_follow_playhead != yn) {
4044                 if ((_follow_playhead = yn) == true && catch_up) {
4045                         /* catch up */
4046                         reset_x_origin_to_follow_playhead ();
4047                 }
4048                 instant_save ();
4049         }
4050 }
4051
4052 void
4053 Editor::toggle_stationary_playhead ()
4054 {
4055         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4056         if (act) {
4057                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4058                 set_stationary_playhead (tact->get_active());
4059         }
4060 }
4061
4062 void
4063 Editor::set_stationary_playhead (bool yn)
4064 {
4065         if (_stationary_playhead != yn) {
4066                 if ((_stationary_playhead = yn) == true) {
4067                         /* catch up */
4068                         // FIXME need a 3.0 equivalent of this 2.X call
4069                         // update_current_screen ();
4070                 }
4071                 instant_save ();
4072         }
4073 }
4074
4075 PlaylistSelector&
4076 Editor::playlist_selector () const
4077 {
4078         return *_playlist_selector;
4079 }
4080
4081 framecnt_t
4082 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4083 {
4084         if (paste_count == 0) {
4085                 /* don't bother calculating an offset that will be zero anyway */
4086                 return 0;
4087         }
4088
4089         /* calculate basic unsnapped multi-paste offset */
4090         framecnt_t offset = paste_count * duration;
4091
4092         /* snap offset so pos + offset is aligned to the grid */
4093         MusicFrame offset_pos (pos + offset, 0);
4094         snap_to(offset_pos, RoundUpMaybe);
4095         offset = offset_pos.frame - pos;
4096
4097         return offset;
4098 }
4099
4100 unsigned
4101 Editor::get_grid_beat_divisions(framepos_t position)
4102 {
4103         switch (_snap_type) {
4104         case SnapToBeatDiv128: return 128;
4105         case SnapToBeatDiv64:  return 64;
4106         case SnapToBeatDiv32:  return 32;
4107         case SnapToBeatDiv28:  return 28;
4108         case SnapToBeatDiv24:  return 24;
4109         case SnapToBeatDiv20:  return 20;
4110         case SnapToBeatDiv16:  return 16;
4111         case SnapToBeatDiv14:  return 14;
4112         case SnapToBeatDiv12:  return 12;
4113         case SnapToBeatDiv10:  return 10;
4114         case SnapToBeatDiv8:   return 8;
4115         case SnapToBeatDiv7:   return 7;
4116         case SnapToBeatDiv6:   return 6;
4117         case SnapToBeatDiv5:   return 5;
4118         case SnapToBeatDiv4:   return 4;
4119         case SnapToBeatDiv3:   return 3;
4120         case SnapToBeatDiv2:   return 2;
4121         default:               return 0;
4122         }
4123         return 0;
4124 }
4125
4126 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4127     if the grid is non-musical, returns 0.
4128     if the grid is snapped to bars, returns -1.
4129     @param event_state the current keyboard modifier mask.
4130 */
4131 int32_t
4132 Editor::get_grid_music_divisions (uint32_t event_state)
4133 {
4134         if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4135                 return 0;
4136         }
4137
4138         if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4139                 return 0;
4140         }
4141
4142         switch (_snap_type) {
4143         case SnapToBeatDiv128: return 128;
4144         case SnapToBeatDiv64:  return 64;
4145         case SnapToBeatDiv32:  return 32;
4146         case SnapToBeatDiv28:  return 28;
4147         case SnapToBeatDiv24:  return 24;
4148         case SnapToBeatDiv20:  return 20;
4149         case SnapToBeatDiv16:  return 16;
4150         case SnapToBeatDiv14:  return 14;
4151         case SnapToBeatDiv12:  return 12;
4152         case SnapToBeatDiv10:  return 10;
4153         case SnapToBeatDiv8:   return 8;
4154         case SnapToBeatDiv7:   return 7;
4155         case SnapToBeatDiv6:   return 6;
4156         case SnapToBeatDiv5:   return 5;
4157         case SnapToBeatDiv4:   return 4;
4158         case SnapToBeatDiv3:   return 3;
4159         case SnapToBeatDiv2:   return 2;
4160         case SnapToBeat:       return 1;
4161         case SnapToBar :       return -1;
4162         default:               return 0;
4163         }
4164         return 0;
4165 }
4166
4167 Evoral::Beats
4168 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4169 {
4170         success = true;
4171
4172         const unsigned divisions = get_grid_beat_divisions(position);
4173         if (divisions) {
4174                 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4175         }
4176
4177         switch (_snap_type) {
4178         case SnapToBeat:
4179                 return Evoral::Beats(4.0 / _session->tempo_map().meter_at_frame (position).note_divisor());
4180         case SnapToBar:
4181                 if (_session) {
4182                         const Meter& m = _session->tempo_map().meter_at_frame (position);
4183                         return Evoral::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4184                 }
4185                 break;
4186         default:
4187                 success = false;
4188                 break;
4189         }
4190
4191         return Evoral::Beats();
4192 }
4193
4194 framecnt_t
4195 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4196 {
4197         framecnt_t ret;
4198
4199         ret = nudge_clock->current_duration (pos);
4200         next = ret + 1; /* XXXX fix me */
4201
4202         return ret;
4203 }
4204
4205 int
4206 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4207 {
4208         ArdourDialog dialog (_("Playlist Deletion"));
4209         Label  label (string_compose (_("Playlist %1 is currently unused.\n"
4210                                         "If it is kept, its audio files will not be cleaned.\n"
4211                                         "If it is deleted, audio files used by it alone will be cleaned."),
4212                                       pl->name()));
4213
4214         dialog.set_position (WIN_POS_CENTER);
4215         dialog.get_vbox()->pack_start (label);
4216
4217         label.show ();
4218
4219         dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4220         dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4221         Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4222         dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4223         dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4224
4225         // by default gtk uses the left most button
4226         keep->grab_focus ();
4227
4228         switch (dialog.run ()) {
4229         case RESPONSE_NO:
4230                 /* keep this and all remaining ones */
4231                 return -2;
4232                 break;
4233
4234         case RESPONSE_YES:
4235                 /* delete this and all others */
4236                 return 2;
4237                 break;
4238
4239         case RESPONSE_ACCEPT:
4240                 /* delete the playlist */
4241                 return 1;
4242                 break;
4243
4244         case RESPONSE_REJECT:
4245                 /* keep the playlist */
4246                 return 0;
4247                 break;
4248
4249         default:
4250                 break;
4251         }
4252
4253         return -1;
4254 }
4255
4256 bool
4257 Editor::audio_region_selection_covers (framepos_t where)
4258 {
4259         for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4260                 if ((*a)->region()->covers (where)) {
4261                         return true;
4262                 }
4263         }
4264
4265         return false;
4266 }
4267
4268 void
4269 Editor::prepare_for_cleanup ()
4270 {
4271         cut_buffer->clear_regions ();
4272         cut_buffer->clear_playlists ();
4273
4274         selection->clear_regions ();
4275         selection->clear_playlists ();
4276
4277         _regions->suspend_redisplay ();
4278 }
4279
4280 void
4281 Editor::finish_cleanup ()
4282 {
4283         _regions->resume_redisplay ();
4284 }
4285
4286 Location*
4287 Editor::transport_loop_location()
4288 {
4289         if (_session) {
4290                 return _session->locations()->auto_loop_location();
4291         } else {
4292                 return 0;
4293         }
4294 }
4295
4296 Location*
4297 Editor::transport_punch_location()
4298 {
4299         if (_session) {
4300                 return _session->locations()->auto_punch_location();
4301         } else {
4302                 return 0;
4303         }
4304 }
4305
4306 bool
4307 Editor::control_layout_scroll (GdkEventScroll* ev)
4308 {
4309         /* Just forward to the normal canvas scroll method. The coordinate
4310            systems are different but since the canvas is always larger than the
4311            track headers, and aligned with the trackview area, this will work.
4312
4313            In the not too distant future this layout is going away anyway and
4314            headers will be on the canvas.
4315         */
4316         return canvas_scroll_event (ev, false);
4317 }
4318
4319 void
4320 Editor::session_state_saved (string)
4321 {
4322         update_title ();
4323         _snapshots->redisplay ();
4324 }
4325
4326 void
4327 Editor::maximise_editing_space ()
4328 {
4329         if (_maximised) {
4330                 return;
4331         }
4332
4333         Gtk::Window* toplevel = current_toplevel();
4334
4335         if (toplevel) {
4336                 toplevel->fullscreen ();
4337                 _maximised = true;
4338         }
4339 }
4340
4341 void
4342 Editor::restore_editing_space ()
4343 {
4344         if (!_maximised) {
4345                 return;
4346         }
4347
4348         Gtk::Window* toplevel = current_toplevel();
4349
4350         if (toplevel) {
4351                 toplevel->unfullscreen();
4352                 _maximised = false;
4353         }
4354 }
4355
4356 /**
4357  *  Make new playlists for a given track and also any others that belong
4358  *  to the same active route group with the `select' property.
4359  *  @param v Track.
4360  */
4361
4362 void
4363 Editor::new_playlists (TimeAxisView* v)
4364 {
4365         begin_reversible_command (_("new playlists"));
4366         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4367         _session->playlists->get (playlists);
4368         mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4369         commit_reversible_command ();
4370 }
4371
4372 /**
4373  *  Use a copy of the current playlist for a given track and also any others that belong
4374  *  to the same active route group with the `select' property.
4375  *  @param v Track.
4376  */
4377
4378 void
4379 Editor::copy_playlists (TimeAxisView* v)
4380 {
4381         begin_reversible_command (_("copy playlists"));
4382         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4383         _session->playlists->get (playlists);
4384         mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4385         commit_reversible_command ();
4386 }
4387
4388 /** Clear the current playlist for a given track and also any others that belong
4389  *  to the same active route group with the `select' property.
4390  *  @param v Track.
4391  */
4392
4393 void
4394 Editor::clear_playlists (TimeAxisView* v)
4395 {
4396         begin_reversible_command (_("clear playlists"));
4397         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4398         _session->playlists->get (playlists);
4399         mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4400         commit_reversible_command ();
4401 }
4402
4403 void
4404 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4405 {
4406         atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4407 }
4408
4409 void
4410 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4411 {
4412         atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4413 }
4414
4415 void
4416 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4417 {
4418         atv.clear_playlist ();
4419 }
4420
4421 double
4422 Editor::get_y_origin () const
4423 {
4424         return vertical_adjustment.get_value ();
4425 }
4426
4427 /** Queue up a change to the viewport x origin.
4428  *  @param frame New x origin.
4429  */
4430 void
4431 Editor::reset_x_origin (framepos_t frame)
4432 {
4433         pending_visual_change.add (VisualChange::TimeOrigin);
4434         pending_visual_change.time_origin = frame;
4435         ensure_visual_change_idle_handler ();
4436 }
4437
4438 void
4439 Editor::reset_y_origin (double y)
4440 {
4441         pending_visual_change.add (VisualChange::YOrigin);
4442         pending_visual_change.y_origin = y;
4443         ensure_visual_change_idle_handler ();
4444 }
4445
4446 void
4447 Editor::reset_zoom (framecnt_t spp)
4448 {
4449         if (spp == samples_per_pixel) {
4450                 return;
4451         }
4452
4453         pending_visual_change.add (VisualChange::ZoomLevel);
4454         pending_visual_change.samples_per_pixel = spp;
4455         ensure_visual_change_idle_handler ();
4456 }
4457
4458 void
4459 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4460 {
4461         reset_x_origin (frame);
4462         reset_zoom (fpu);
4463
4464         if (!no_save_visual) {
4465                 undo_visual_stack.push_back (current_visual_state(false));
4466         }
4467 }
4468
4469 Editor::VisualState::VisualState (bool with_tracks)
4470         : gui_state (with_tracks ? new GUIObjectState : 0)
4471 {
4472 }
4473
4474 Editor::VisualState::~VisualState ()
4475 {
4476         delete gui_state;
4477 }
4478
4479 Editor::VisualState*
4480 Editor::current_visual_state (bool with_tracks)
4481 {
4482         VisualState* vs = new VisualState (with_tracks);
4483         vs->y_position = vertical_adjustment.get_value();
4484         vs->samples_per_pixel = samples_per_pixel;
4485         vs->leftmost_frame = leftmost_frame;
4486         vs->zoom_focus = zoom_focus;
4487
4488         if (with_tracks) {
4489                 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4490         }
4491
4492         return vs;
4493 }
4494
4495 void
4496 Editor::undo_visual_state ()
4497 {
4498         if (undo_visual_stack.empty()) {
4499                 return;
4500         }
4501
4502         VisualState* vs = undo_visual_stack.back();
4503         undo_visual_stack.pop_back();
4504
4505
4506         redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4507
4508         if (vs) {
4509                 use_visual_state (*vs);
4510         }
4511 }
4512
4513 void
4514 Editor::redo_visual_state ()
4515 {
4516         if (redo_visual_stack.empty()) {
4517                 return;
4518         }
4519
4520         VisualState* vs = redo_visual_stack.back();
4521         redo_visual_stack.pop_back();
4522
4523         // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4524         // why do we check here?
4525         undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4526
4527         if (vs) {
4528                 use_visual_state (*vs);
4529         }
4530 }
4531
4532 void
4533 Editor::swap_visual_state ()
4534 {
4535         if (undo_visual_stack.empty()) {
4536                 redo_visual_state ();
4537         } else {
4538                 undo_visual_state ();
4539         }
4540 }
4541
4542 void
4543 Editor::use_visual_state (VisualState& vs)
4544 {
4545         PBD::Unwinder<bool> nsv (no_save_visual, true);
4546         DisplaySuspender ds;
4547
4548         vertical_adjustment.set_value (vs.y_position);
4549
4550         set_zoom_focus (vs.zoom_focus);
4551         reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4552
4553         if (vs.gui_state) {
4554                 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4555
4556                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4557                         (*i)->clear_property_cache();
4558                         (*i)->reset_visual_state ();
4559                 }
4560         }
4561
4562         _routes->update_visibility ();
4563 }
4564
4565 /** This is the core function that controls the zoom level of the canvas. It is called
4566  *  whenever one or more calls are made to reset_zoom().  It executes in an idle handler.
4567  *  @param spp new number of samples per pixel
4568  */
4569 void
4570 Editor::set_samples_per_pixel (framecnt_t spp)
4571 {
4572         if (spp < 1) {
4573                 return;
4574         }
4575
4576         const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4577         const framecnt_t lots_of_pixels = 4000;
4578
4579         /* if the zoom level is greater than what you'd get trying to display 3
4580          * days of audio on a really big screen, then it's too big.
4581          */
4582
4583         if (spp * lots_of_pixels > three_days) {
4584                 return;
4585         }
4586
4587         samples_per_pixel = spp;
4588
4589         if (tempo_lines) {
4590                 tempo_lines->tempo_map_changed();
4591         }
4592
4593         bool const showing_time_selection = selection->time.length() > 0;
4594
4595         if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4596                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4597                         (*i)->reshow_selection (selection->time);
4598                 }
4599         }
4600
4601         ZoomChanged (); /* EMIT_SIGNAL */
4602
4603         ArdourCanvas::GtkCanvasViewport* c;
4604
4605         c = get_track_canvas();
4606         if (c) {
4607                 c->canvas()->zoomed ();
4608         }
4609
4610         if (playhead_cursor) {
4611                 playhead_cursor->set_position (playhead_cursor->current_frame ());
4612         }
4613
4614         refresh_location_display();
4615         _summary->set_overlays_dirty ();
4616
4617         update_marker_labels ();
4618
4619         instant_save ();
4620 }
4621
4622 framepos_t
4623 Editor::playhead_cursor_sample () const
4624 {
4625         return playhead_cursor->current_frame();
4626 }
4627
4628 void
4629 Editor::queue_visual_videotimeline_update ()
4630 {
4631         /* TODO:
4632          * pending_visual_change.add (VisualChange::VideoTimeline);
4633          * or maybe even more specific: which videotimeline-image
4634          * currently it calls update_video_timeline() to update
4635          * _all outdated_ images on the video-timeline.
4636          * see 'exposeimg()' in video_image_frame.cc
4637          */
4638         ensure_visual_change_idle_handler ();
4639 }
4640
4641 void
4642 Editor::ensure_visual_change_idle_handler ()
4643 {
4644         if (pending_visual_change.idle_handler_id < 0) {
4645                 // see comment in add_to_idle_resize above.
4646                 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4647                 pending_visual_change.being_handled = false;
4648         }
4649 }
4650
4651 int
4652 Editor::_idle_visual_changer (void* arg)
4653 {
4654         return static_cast<Editor*>(arg)->idle_visual_changer ();
4655 }
4656
4657 int
4658 Editor::idle_visual_changer ()
4659 {
4660         /* set_horizontal_position() below (and maybe other calls) call
4661            gtk_main_iteration(), so it's possible that a signal will be handled
4662            half-way through this method.  If this signal wants an
4663            idle_visual_changer we must schedule another one after this one, so
4664            mark the idle_handler_id as -1 here to allow that.  Also make a note
4665            that we are doing the visual change, so that changes in response to
4666            super-rapid-screen-update can be dropped if we are still processing
4667            the last one.
4668         */
4669
4670         pending_visual_change.idle_handler_id = -1;
4671         pending_visual_change.being_handled = true;
4672
4673         VisualChange vc = pending_visual_change;
4674
4675         pending_visual_change.pending = (VisualChange::Type) 0;
4676
4677         visual_changer (vc);
4678
4679         pending_visual_change.being_handled = false;
4680
4681         return 0; /* this is always a one-shot call */
4682 }
4683
4684 void
4685 Editor::visual_changer (const VisualChange& vc)
4686 {
4687         double const last_time_origin = horizontal_position ();
4688
4689         if (vc.pending & VisualChange::ZoomLevel) {
4690                 set_samples_per_pixel (vc.samples_per_pixel);
4691
4692                 compute_fixed_ruler_scale ();
4693
4694                 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4695                 update_tempo_based_rulers ();
4696
4697                 update_video_timeline();
4698         }
4699
4700         if (vc.pending & VisualChange::TimeOrigin) {
4701                 set_horizontal_position (vc.time_origin / samples_per_pixel);
4702         }
4703
4704         if (vc.pending & VisualChange::YOrigin) {
4705                 vertical_adjustment.set_value (vc.y_origin);
4706         }
4707
4708         if (last_time_origin == horizontal_position ()) {
4709                 /* changed signal not emitted */
4710                 update_fixed_rulers ();
4711                 redisplay_tempo (true);
4712         }
4713
4714         if (!(vc.pending & VisualChange::ZoomLevel)) {
4715                 update_video_timeline();
4716         }
4717
4718         _summary->set_overlays_dirty ();
4719 }
4720
4721 struct EditorOrderTimeAxisSorter {
4722     bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4723             return a->order () < b->order ();
4724     }
4725 };
4726
4727 void
4728 Editor::sort_track_selection (TrackViewList& sel)
4729 {
4730         EditorOrderTimeAxisSorter cmp;
4731         sel.sort (cmp);
4732 }
4733
4734 framepos_t
4735 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4736 {
4737         bool ignored;
4738         framepos_t where = 0;
4739         EditPoint ep = _edit_point;
4740
4741         if (Profile->get_mixbus()) {
4742                 if (ep == EditAtSelectedMarker) {
4743                         ep = EditAtPlayhead;
4744                 }
4745         }
4746
4747         if (from_outside_canvas && (ep == EditAtMouse)) {
4748                 ep = EditAtPlayhead;
4749         } else if (from_context_menu && (ep == EditAtMouse)) {
4750                 return  canvas_event_sample (&context_click_event, 0, 0);
4751         }
4752
4753         if (entered_marker) {
4754                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4755                 return entered_marker->position();
4756         }
4757
4758         if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4759                 ep = EditAtSelectedMarker;
4760         }
4761
4762         if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4763                 ep = EditAtPlayhead;
4764         }
4765
4766         MusicFrame snap_mf (0, 0);
4767
4768         switch (ep) {
4769         case EditAtPlayhead:
4770                 if (_dragging_playhead) {
4771                         where = *_control_scroll_target;
4772                 } else {
4773                         where = _session->audible_frame();
4774                 }
4775                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4776                 break;
4777
4778         case EditAtSelectedMarker:
4779                 if (!selection->markers.empty()) {
4780                         bool is_start;
4781                         Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4782                         if (loc) {
4783                                 if (is_start) {
4784                                         where =  loc->start();
4785                                 } else {
4786                                         where = loc->end();
4787                                 }
4788                                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4789                                 break;
4790                         }
4791                 }
4792                 /* fallthru */
4793
4794         default:
4795         case EditAtMouse:
4796                 if (!mouse_frame (where, ignored)) {
4797                         /* XXX not right but what can we do ? */
4798                         return 0;
4799                 }
4800                 snap_mf.frame = where;
4801                 snap_to (snap_mf);
4802                 where = snap_mf.frame;
4803                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4804                 break;
4805         }
4806
4807         return where;
4808 }
4809
4810 void
4811 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4812 {
4813         if (!_session) return;
4814
4815         begin_reversible_command (cmd);
4816
4817         Location* tll;
4818
4819         if ((tll = transport_loop_location()) == 0) {
4820                 Location* loc = new Location (*_session, start, end, _("Loop"),  Location::IsAutoLoop, get_grid_music_divisions(0));
4821                 XMLNode &before = _session->locations()->get_state();
4822                 _session->locations()->add (loc, true);
4823                 _session->set_auto_loop_location (loc);
4824                 XMLNode &after = _session->locations()->get_state();
4825                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4826         } else {
4827                 XMLNode &before = tll->get_state();
4828                 tll->set_hidden (false, this);
4829                 tll->set (start, end);
4830                 XMLNode &after = tll->get_state();
4831                 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4832         }
4833
4834         commit_reversible_command ();
4835 }
4836
4837 void
4838 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4839 {
4840         if (!_session) return;
4841
4842         begin_reversible_command (cmd);
4843
4844         Location* tpl;
4845
4846         if ((tpl = transport_punch_location()) == 0) {
4847                 Location* loc = new Location (*_session, start, end, _("Punch"),  Location::IsAutoPunch, get_grid_music_divisions(0));
4848                 XMLNode &before = _session->locations()->get_state();
4849                 _session->locations()->add (loc, true);
4850                 _session->set_auto_punch_location (loc);
4851                 XMLNode &after = _session->locations()->get_state();
4852                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4853         } else {
4854                 XMLNode &before = tpl->get_state();
4855                 tpl->set_hidden (false, this);
4856                 tpl->set (start, end);
4857                 XMLNode &after = tpl->get_state();
4858                 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4859         }
4860
4861         commit_reversible_command ();
4862 }
4863
4864 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4865  *  @param rs List to which found regions are added.
4866  *  @param where Time to look at.
4867  *  @param ts Tracks to look on; if this is empty, all tracks are examined.
4868  */
4869 void
4870 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4871 {
4872         const TrackViewList* tracks;
4873
4874         if (ts.empty()) {
4875                 tracks = &track_views;
4876         } else {
4877                 tracks = &ts;
4878         }
4879
4880         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4881
4882                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4883
4884                 if (rtv) {
4885                         boost::shared_ptr<Track> tr;
4886                         boost::shared_ptr<Playlist> pl;
4887
4888                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4889
4890                                 boost::shared_ptr<RegionList> regions = pl->regions_at (
4891                                                 (framepos_t) floor ( (double) where * tr->speed()));
4892
4893                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4894                                         RegionView* rv = rtv->view()->find_view (*i);
4895                                         if (rv) {
4896                                                 rs.add (rv);
4897                                         }
4898                                 }
4899                         }
4900                 }
4901         }
4902 }
4903
4904 void
4905 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4906 {
4907         const TrackViewList* tracks;
4908
4909         if (ts.empty()) {
4910                 tracks = &track_views;
4911         } else {
4912                 tracks = &ts;
4913         }
4914
4915         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4916                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4917                 if (rtv) {
4918                         boost::shared_ptr<Track> tr;
4919                         boost::shared_ptr<Playlist> pl;
4920
4921                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4922
4923                                 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4924                                         (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4925
4926                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4927
4928                                         RegionView* rv = rtv->view()->find_view (*i);
4929
4930                                         if (rv) {
4931                                                 rs.add (rv);
4932                                         }
4933                                 }
4934                         }
4935                 }
4936         }
4937 }
4938
4939 /** Get regions using the following method:
4940  *
4941  *  Make a region list using:
4942  *   (a) any selected regions
4943  *   (b) the intersection of any selected tracks and the edit point(*)
4944  *   (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4945  *
4946  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4947  *
4948  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4949  */
4950
4951 RegionSelection
4952 Editor::get_regions_from_selection_and_edit_point ()
4953 {
4954         RegionSelection regions;
4955
4956         if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4957                 regions.add (entered_regionview);
4958         } else {
4959                 regions = selection->regions;
4960         }
4961
4962         if ( regions.empty() ) {
4963                 TrackViewList tracks = selection->tracks;
4964
4965                 if (!tracks.empty()) {
4966                         /* no region selected or entered, but some selected tracks:
4967                          * act on all regions on the selected tracks at the edit point
4968                          */
4969                         framepos_t const where = get_preferred_edit_position ();
4970                         get_regions_at(regions, where, tracks);
4971                 }
4972         }
4973
4974         return regions;
4975 }
4976
4977 /** Get regions using the following method:
4978  *
4979  *  Make a region list using:
4980  *   (a) any selected regions
4981  *   (b) the intersection of any selected tracks and the edit point(*)
4982  *   (c) if neither exists, then whatever region is under the mouse
4983  *
4984  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4985  *
4986  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4987  */
4988 RegionSelection
4989 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4990 {
4991         RegionSelection regions;
4992
4993         if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4994                 regions.add (entered_regionview);
4995         } else {
4996                 regions = selection->regions;
4997         }
4998
4999         if ( regions.empty() ) {
5000                 TrackViewList tracks = selection->tracks;
5001
5002                 if (!tracks.empty()) {
5003                         /* no region selected or entered, but some selected tracks:
5004                          * act on all regions on the selected tracks at the edit point
5005                          */
5006                         get_regions_at(regions, pos, tracks);
5007                 }
5008         }
5009
5010         return regions;
5011 }
5012
5013 /** Start with regions that are selected, or the entered regionview if none are selected.
5014  *  Then add equivalent regions on tracks in the same active edit-enabled route group as any
5015  *  of the regions that we started with.
5016  */
5017
5018 RegionSelection
5019 Editor::get_regions_from_selection_and_entered () const
5020 {
5021         RegionSelection regions = selection->regions;
5022
5023         if (regions.empty() && entered_regionview) {
5024                 regions.add (entered_regionview);
5025         }
5026
5027         return regions;
5028 }
5029
5030 void
5031 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
5032 {
5033         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5034                 RouteTimeAxisView* rtav;
5035
5036                 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5037                         boost::shared_ptr<Playlist> pl;
5038                         std::vector<boost::shared_ptr<Region> > results;
5039                         boost::shared_ptr<Track> tr;
5040
5041                         if ((tr = rtav->track()) == 0) {
5042                                 /* bus */
5043                                 continue;
5044                         }
5045
5046                         if ((pl = (tr->playlist())) != 0) {
5047                                 boost::shared_ptr<Region> r = pl->region_by_id (id);
5048                                 if (r) {
5049                                         RegionView* rv = rtav->view()->find_view (r);
5050                                         if (rv) {
5051                                                 regions.push_back (rv);
5052                                         }
5053                                 }
5054                         }
5055                 }
5056         }
5057 }
5058
5059 void
5060 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5061 {
5062
5063         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5064                 MidiTimeAxisView* mtav;
5065
5066                 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5067
5068                         mtav->get_per_region_note_selection (selection);
5069                 }
5070         }
5071
5072 }
5073
5074 void
5075 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5076 {
5077         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5078
5079                 RouteTimeAxisView* tatv;
5080
5081                 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5082
5083                         boost::shared_ptr<Playlist> pl;
5084                         vector<boost::shared_ptr<Region> > results;
5085                         RegionView* marv;
5086                         boost::shared_ptr<Track> tr;
5087
5088                         if ((tr = tatv->track()) == 0) {
5089                                 /* bus */
5090                                 continue;
5091                         }
5092
5093                         if ((pl = (tr->playlist())) != 0) {
5094                                 if (src_comparison) {
5095                                         pl->get_source_equivalent_regions (region, results);
5096                                 } else {
5097                                         pl->get_region_list_equivalent_regions (region, results);
5098                                 }
5099                         }
5100
5101                         for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5102                                 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5103                                         regions.push_back (marv);
5104                                 }
5105                         }
5106
5107                 }
5108         }
5109 }
5110
5111 void
5112 Editor::show_rhythm_ferret ()
5113 {
5114         if (rhythm_ferret == 0) {
5115                 rhythm_ferret = new RhythmFerret(*this);
5116         }
5117
5118         rhythm_ferret->set_session (_session);
5119         rhythm_ferret->show ();
5120         rhythm_ferret->present ();
5121 }
5122
5123 void
5124 Editor::first_idle ()
5125 {
5126         MessageDialog* dialog = 0;
5127
5128         if (track_views.size() > 1) {
5129                 Timers::TimerSuspender t;
5130                 dialog = new MessageDialog (
5131                         string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5132                         true
5133                         );
5134                 dialog->present ();
5135                 ARDOUR_UI::instance()->flush_pending (60);
5136         }
5137
5138         for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5139                 (*t)->first_idle();
5140         }
5141
5142         // first idle adds route children (automation tracks), so we need to redisplay here
5143         _routes->redisplay ();
5144
5145         delete dialog;
5146
5147         if (_session->undo_depth() == 0) {
5148                 undo_action->set_sensitive(false);
5149         }
5150         redo_action->set_sensitive(false);
5151         begin_selection_op_history ();
5152
5153         _have_idled = true;
5154 }
5155
5156 gboolean
5157 Editor::_idle_resize (gpointer arg)
5158 {
5159         return ((Editor*)arg)->idle_resize ();
5160 }
5161
5162 void
5163 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5164 {
5165         if (resize_idle_id < 0) {
5166                 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5167                  * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5168                  * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5169                  */
5170                 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5171                 _pending_resize_amount = 0;
5172         }
5173
5174         /* make a note of the smallest resulting height, so that we can clamp the
5175            lower limit at TimeAxisView::hSmall */
5176
5177         int32_t min_resulting = INT32_MAX;
5178
5179         _pending_resize_amount += h;
5180         _pending_resize_view = view;
5181
5182         min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5183
5184         if (selection->tracks.contains (_pending_resize_view)) {
5185                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5186                         min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5187                 }
5188         }
5189
5190         if (min_resulting < 0) {
5191                 min_resulting = 0;
5192         }
5193
5194         /* clamp */
5195         if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5196                 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5197         }
5198 }
5199
5200 /** Handle pending resizing of tracks */
5201 bool
5202 Editor::idle_resize ()
5203 {
5204         _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5205
5206         if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5207             selection->tracks.contains (_pending_resize_view)) {
5208
5209                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5210                         if (*i != _pending_resize_view) {
5211                                 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5212                         }
5213                 }
5214         }
5215
5216         _pending_resize_amount = 0;
5217         _group_tabs->set_dirty ();
5218         resize_idle_id = -1;
5219
5220         return false;
5221 }
5222
5223 void
5224 Editor::located ()
5225 {
5226         ENSURE_GUI_THREAD (*this, &Editor::located);
5227
5228         if (_session) {
5229                 playhead_cursor->set_position (_session->audible_frame ());
5230                 if (_follow_playhead && !_pending_initial_locate) {
5231                         reset_x_origin_to_follow_playhead ();
5232                 }
5233         }
5234
5235         _pending_locate_request = false;
5236         _pending_initial_locate = false;
5237 }
5238
5239 void
5240 Editor::region_view_added (RegionView * rv)
5241 {
5242         for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5243                 if (rv->region ()->id () == (*pr)) {
5244                         selection->add (rv);
5245                         selection->regions.pending.erase (pr);
5246                         break;
5247                 }
5248         }
5249
5250         MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5251         if (mrv) {
5252                 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5253                 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5254                         if (rv->region()->id () == (*rnote).first) {
5255                                 mrv->select_notes ((*rnote).second);
5256                                 selection->pending_midi_note_selection.erase(rnote);
5257                                 break;
5258                         }
5259                 }
5260         }
5261
5262         _summary->set_background_dirty ();
5263 }
5264
5265 void
5266 Editor::region_view_removed ()
5267 {
5268         _summary->set_background_dirty ();
5269 }
5270
5271 TimeAxisView*
5272 Editor::axis_view_from_stripable (boost::shared_ptr<Stripable> s) const
5273 {
5274         for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5275                 if ((*j)->stripable() == s) {
5276                         return *j;
5277                 }
5278         }
5279
5280         return 0;
5281 }
5282
5283
5284 TrackViewList
5285 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5286 {
5287         TrackViewList t;
5288
5289         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5290                 TimeAxisView* tv = axis_view_from_stripable (*i);
5291                 if (tv) {
5292                         t.push_back (tv);
5293                 }
5294         }
5295
5296         return t;
5297 }
5298
5299 void
5300 Editor::suspend_route_redisplay ()
5301 {
5302         if (_routes) {
5303                 _routes->suspend_redisplay();
5304         }
5305 }
5306
5307 void
5308 Editor::resume_route_redisplay ()
5309 {
5310         if (_routes) {
5311                 _routes->redisplay(); // queue redisplay
5312                 _routes->resume_redisplay();
5313         }
5314 }
5315
5316 void
5317 Editor::add_vcas (VCAList& vlist)
5318 {
5319         StripableList sl;
5320
5321         for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5322                 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5323         }
5324
5325         add_stripables (sl);
5326 }
5327
5328 void
5329 Editor::add_routes (RouteList& rlist)
5330 {
5331         StripableList sl;
5332
5333         for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5334                 sl.push_back (*r);
5335         }
5336
5337         add_stripables (sl);
5338 }
5339
5340 void
5341 Editor::add_stripables (StripableList& sl)
5342 {
5343         list<TimeAxisView*> new_views;
5344         boost::shared_ptr<VCA> v;
5345         boost::shared_ptr<Route> r;
5346         TrackViewList new_selection;
5347         bool from_scratch = (track_views.size() == 0);
5348
5349         sl.sort (StripablePresentationInfoSorter());
5350
5351         for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5352
5353                 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5354
5355                         VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5356                         vtv->set_vca (v);
5357                         new_views.push_back (vtv);
5358
5359                 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5360
5361                         if (r->is_auditioner() || r->is_monitor()) {
5362                                 continue;
5363                         }
5364
5365                         RouteTimeAxisView* rtv;
5366                         DataType dt = r->input()->default_type();
5367
5368                         if (dt == ARDOUR::DataType::AUDIO) {
5369                                 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5370                                 rtv->set_route (r);
5371                         } else if (dt == ARDOUR::DataType::MIDI) {
5372                                 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5373                                 rtv->set_route (r);
5374                         } else {
5375                                 throw unknown_type();
5376                         }
5377
5378                         new_views.push_back (rtv);
5379                         track_views.push_back (rtv);
5380                         new_selection.push_back (rtv);
5381
5382                         rtv->effective_gain_display ();
5383
5384                         rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5385                         rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5386                 }
5387         }
5388
5389         if (new_views.size() > 0) {
5390                 _routes->time_axis_views_added (new_views);
5391                 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5392         }
5393
5394         /* note: !new_selection.empty() means that we got some routes rather
5395          * than just VCAs
5396          */
5397
5398         if (!from_scratch && !new_selection.empty()) {
5399                 selection->tracks.clear();
5400                 selection->add (new_selection);
5401                 begin_selection_op_history();
5402         }
5403
5404         if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5405                 show_editor_mixer (true);
5406         }
5407
5408         editor_list_button.set_sensitive (true);
5409 }
5410
5411 void
5412 Editor::timeaxisview_deleted (TimeAxisView *tv)
5413 {
5414         if (tv == entered_track) {
5415                 entered_track = 0;
5416         }
5417
5418         if (_session && _session->deletion_in_progress()) {
5419                 /* the situation is under control */
5420                 return;
5421         }
5422
5423         ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5424
5425         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5426
5427         _routes->route_removed (tv);
5428
5429         TimeAxisView::Children c = tv->get_child_list ();
5430         for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5431                 if (entered_track == i->get()) {
5432                         entered_track = 0;
5433                 }
5434         }
5435
5436         /* remove it from the list of track views */
5437
5438         TrackViewList::iterator i;
5439
5440         if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5441                 i = track_views.erase (i);
5442         }
5443
5444         /* update whatever the current mixer strip is displaying, if revelant */
5445
5446         boost::shared_ptr<Route> route;
5447
5448         if (rtav) {
5449                 route = rtav->route ();
5450         }
5451
5452         if (current_mixer_strip && current_mixer_strip->route() == route) {
5453
5454                 TimeAxisView* next_tv;
5455
5456                 if (track_views.empty()) {
5457                         next_tv = 0;
5458                 } else if (i == track_views.end()) {
5459                         next_tv = track_views.front();
5460                 } else {
5461                         next_tv = (*i);
5462                 }
5463
5464                 // skip VCAs (cannot be selected, n/a in editor-mixer)
5465                 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5466                         /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5467                         next_tv = track_views.front();
5468                 }
5469                 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5470                         /* just in case: no master, only a VCA remains */
5471                         next_tv = 0;
5472                 }
5473
5474
5475                 if (next_tv) {
5476                         set_selected_mixer_strip (*next_tv);
5477                 } else {
5478                         /* make the editor mixer strip go away setting the
5479                          * button to inactive (which also unticks the menu option)
5480                          */
5481
5482                         ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5483                 }
5484         }
5485 }
5486
5487 void
5488 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5489 {
5490         if (apply_to_selection) {
5491                 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5492
5493                         TrackSelection::iterator j = i;
5494                         ++j;
5495
5496                         hide_track_in_display (*i, false);
5497
5498                         i = j;
5499                 }
5500         } else {
5501                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5502
5503                 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5504                         // this will hide the mixer strip
5505                         set_selected_mixer_strip (*tv);
5506                 }
5507
5508                 _routes->hide_track_in_display (*tv);
5509         }
5510 }
5511
5512 bool
5513 Editor::sync_track_view_list_and_routes ()
5514 {
5515         track_views = TrackViewList (_routes->views ());
5516
5517         _summary->set_background_dirty();
5518         _group_tabs->set_dirty ();
5519
5520         return false; // do not call again (until needed)
5521 }
5522
5523 void
5524 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5525 {
5526         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5527                 theslot (**i);
5528         }
5529 }
5530
5531 /** Find a RouteTimeAxisView by the ID of its route */
5532 RouteTimeAxisView*
5533 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5534 {
5535         RouteTimeAxisView* v;
5536
5537         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5538                 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5539                         if(v->route()->id() == id) {
5540                                 return v;
5541                         }
5542                 }
5543         }
5544
5545         return 0;
5546 }
5547
5548 void
5549 Editor::fit_route_group (RouteGroup *g)
5550 {
5551         TrackViewList ts = axis_views_from_routes (g->route_list ());
5552         fit_tracks (ts);
5553 }
5554
5555 void
5556 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5557 {
5558         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5559
5560         if (r == 0) {
5561                 _session->cancel_audition ();
5562                 return;
5563         }
5564
5565         if (_session->is_auditioning()) {
5566                 _session->cancel_audition ();
5567                 if (r == last_audition_region) {
5568                         return;
5569                 }
5570         }
5571
5572         _session->audition_region (r);
5573         last_audition_region = r;
5574 }
5575
5576
5577 void
5578 Editor::hide_a_region (boost::shared_ptr<Region> r)
5579 {
5580         r->set_hidden (true);
5581 }
5582
5583 void
5584 Editor::show_a_region (boost::shared_ptr<Region> r)
5585 {
5586         r->set_hidden (false);
5587 }
5588
5589 void
5590 Editor::audition_region_from_region_list ()
5591 {
5592         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5593 }
5594
5595 void
5596 Editor::hide_region_from_region_list ()
5597 {
5598         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5599 }
5600
5601 void
5602 Editor::show_region_in_region_list ()
5603 {
5604         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5605 }
5606
5607 void
5608 Editor::step_edit_status_change (bool yn)
5609 {
5610         if (yn) {
5611                 start_step_editing ();
5612         } else {
5613                 stop_step_editing ();
5614         }
5615 }
5616
5617 void
5618 Editor::start_step_editing ()
5619 {
5620         step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5621 }
5622
5623 void
5624 Editor::stop_step_editing ()
5625 {
5626         step_edit_connection.disconnect ();
5627 }
5628
5629 bool
5630 Editor::check_step_edit ()
5631 {
5632         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5633                 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5634                 if (mtv) {
5635                         mtv->check_step_edit ();
5636                 }
5637         }
5638
5639         return true; // do it again, till we stop
5640 }
5641
5642 bool
5643 Editor::scroll_press (Direction dir)
5644 {
5645         ++_scroll_callbacks;
5646
5647         if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5648                 /* delay the first auto-repeat */
5649                 return true;
5650         }
5651
5652         switch (dir) {
5653         case LEFT:
5654                 scroll_backward (1);
5655                 break;
5656
5657         case RIGHT:
5658                 scroll_forward (1);
5659                 break;
5660
5661         case UP:
5662                 scroll_up_one_track ();
5663                 break;
5664
5665         case DOWN:
5666                 scroll_down_one_track ();
5667                 break;
5668         }
5669
5670         /* do hacky auto-repeat */
5671         if (!_scroll_connection.connected ()) {
5672
5673                 _scroll_connection = Glib::signal_timeout().connect (
5674                         sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5675                         );
5676
5677                 _scroll_callbacks = 0;
5678         }
5679
5680         return true;
5681 }
5682
5683 void
5684 Editor::scroll_release ()
5685 {
5686         _scroll_connection.disconnect ();
5687 }
5688
5689 /** Queue a change for the Editor viewport x origin to follow the playhead */
5690 void
5691 Editor::reset_x_origin_to_follow_playhead ()
5692 {
5693         framepos_t const frame = playhead_cursor->current_frame ();
5694
5695         if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5696
5697                 if (_session->transport_speed() < 0) {
5698
5699                         if (frame > (current_page_samples() / 2)) {
5700                                 center_screen (frame-(current_page_samples()/2));
5701                         } else {
5702                                 center_screen (current_page_samples()/2);
5703                         }
5704
5705                 } else {
5706
5707                         framepos_t l = 0;
5708
5709                         if (frame < leftmost_frame) {
5710                                 /* moving left */
5711                                 if (_session->transport_rolling()) {
5712                                         /* rolling; end up with the playhead at the right of the page */
5713                                         l = frame - current_page_samples ();
5714                                 } else {
5715                                         /* not rolling: end up with the playhead 1/4 of the way along the page */
5716                                         l = frame - current_page_samples() / 4;
5717                                 }
5718                         } else {
5719                                 /* moving right */
5720                                 if (_session->transport_rolling()) {
5721                                         /* rolling: end up with the playhead on the left of the page */
5722                                         l = frame;
5723                                 } else {
5724                                         /* not rolling: end up with the playhead 3/4 of the way along the page */
5725                                         l = frame - 3 * current_page_samples() / 4;
5726                                 }
5727                         }
5728
5729                         if (l < 0) {
5730                                 l = 0;
5731                         }
5732
5733                         center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5734                 }
5735         }
5736 }
5737
5738 void
5739 Editor::super_rapid_screen_update ()
5740 {
5741         if (!_session || !_session->engine().running()) {
5742                 return;
5743         }
5744
5745         /* METERING / MIXER STRIPS */
5746
5747         /* update track meters, if required */
5748         if (contents().is_mapped() && meters_running) {
5749                 RouteTimeAxisView* rtv;
5750                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5751                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5752                                 rtv->fast_update ();
5753                         }
5754                 }
5755         }
5756
5757         /* and any current mixer strip */
5758         if (current_mixer_strip) {
5759                 current_mixer_strip->fast_update ();
5760         }
5761
5762         /* PLAYHEAD AND VIEWPORT */
5763
5764         framepos_t const frame = _session->audible_frame();
5765
5766         /* There are a few reasons why we might not update the playhead / viewport stuff:
5767          *
5768          * 1.  we don't update things when there's a pending locate request, otherwise
5769          *     when the editor requests a locate there is a chance that this method
5770          *     will move the playhead before the locate request is processed, causing
5771          *     a visual glitch.
5772          * 2.  if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5773          * 3.  if we're still at the same frame that we were last time, there's nothing to do.
5774          */
5775
5776         if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5777
5778                 last_update_frame = frame;
5779
5780                 if (!_dragging_playhead) {
5781                         playhead_cursor->set_position (frame);
5782                 }
5783
5784                 if (!_stationary_playhead) {
5785
5786                         if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5787                                 /* We only do this if we aren't already
5788                                    handling a visual change (ie if
5789                                    pending_visual_change.being_handled is
5790                                    false) so that these requests don't stack
5791                                    up there are too many of them to handle in
5792                                    time.
5793                                 */
5794                                 reset_x_origin_to_follow_playhead ();
5795                         }
5796
5797                 } else {
5798
5799                         if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5800                                 framepos_t const frame = playhead_cursor->current_frame ();
5801                                 double target = ((double)frame - (double)current_page_samples()/2.0);
5802                                 if (target <= 0.0) {
5803                                         target = 0.0;
5804                                 }
5805                                 // compare to EditorCursor::set_position()
5806                                 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5807                                 double const new_pos = sample_to_pixel_unrounded (target);
5808                                 if (rint (new_pos) != rint (old_pos)) {
5809                                         reset_x_origin (pixel_to_sample (floor (new_pos)));
5810                                 }
5811                         }
5812
5813                 }
5814
5815         }
5816 }
5817
5818
5819 void
5820 Editor::session_going_away ()
5821 {
5822         _have_idled = false;
5823
5824         _session_connections.drop_connections ();
5825
5826         super_rapid_screen_update_connection.disconnect ();
5827
5828         selection->clear ();
5829         cut_buffer->clear ();
5830
5831         clicked_regionview = 0;
5832         clicked_axisview = 0;
5833         clicked_routeview = 0;
5834         entered_regionview = 0;
5835         entered_track = 0;
5836         last_update_frame = 0;
5837         _drags->abort ();
5838
5839         playhead_cursor->hide ();
5840
5841         /* rip everything out of the list displays */
5842
5843         _regions->clear ();
5844         _routes->clear ();
5845         _route_groups->clear ();
5846
5847         /* do this first so that deleting a track doesn't reset cms to null
5848            and thus cause a leak.
5849         */
5850
5851         if (current_mixer_strip) {
5852                 if (current_mixer_strip->get_parent() != 0) {
5853                         global_hpacker.remove (*current_mixer_strip);
5854                 }
5855                 delete current_mixer_strip;
5856                 current_mixer_strip = 0;
5857         }
5858
5859         /* delete all trackviews */
5860
5861         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5862                 delete *i;
5863         }
5864         track_views.clear ();
5865
5866         nudge_clock->set_session (0);
5867
5868         editor_list_button.set_active(false);
5869         editor_list_button.set_sensitive(false);
5870
5871         /* clear tempo/meter rulers */
5872         remove_metric_marks ();
5873         hide_measures ();
5874         clear_marker_display ();
5875
5876         stop_step_editing ();
5877
5878         if (own_window()) {
5879
5880                 /* get rid of any existing editor mixer strip */
5881
5882                 WindowTitle title(Glib::get_application_name());
5883                 title += _("Editor");
5884
5885                 own_window()->set_title (title.get_string());
5886         }
5887
5888         SessionHandlePtr::session_going_away ();
5889 }
5890
5891 void
5892 Editor::trigger_script (int i)
5893 {
5894         LuaInstance::instance()-> call_action (i);
5895 }
5896
5897 void
5898 Editor::set_script_action_name (int i, const std::string& n)
5899 {
5900         string const a = string_compose (X_("script-action-%1"), i + 1);
5901         Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5902         assert (act);
5903         if (n.empty ()) {
5904                 act->set_label (string_compose (_("Unset #%1"), i + 1));
5905                 act->set_tooltip (_("no action bound"));
5906                 act->set_sensitive (false);
5907         } else {
5908                 act->set_label (n);
5909                 act->set_tooltip (n);
5910                 act->set_sensitive (true);
5911         }
5912         KeyEditor::UpdateBindings ();
5913 }
5914
5915 void
5916 Editor::show_editor_list (bool yn)
5917 {
5918         if (yn) {
5919                 _editor_list_vbox.show ();
5920         } else {
5921                 _editor_list_vbox.hide ();
5922         }
5923 }
5924
5925 void
5926 Editor::change_region_layering_order (bool from_context_menu)
5927 {
5928         const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5929
5930         if (!clicked_routeview) {
5931                 if (layering_order_editor) {
5932                         layering_order_editor->hide ();
5933                 }
5934                 return;
5935         }
5936
5937         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5938
5939         if (!track) {
5940                 return;
5941         }
5942
5943         boost::shared_ptr<Playlist> pl = track->playlist();
5944
5945         if (!pl) {
5946                 return;
5947         }
5948
5949         if (layering_order_editor == 0) {
5950                 layering_order_editor = new RegionLayeringOrderEditor (*this);
5951         }
5952
5953         layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5954         layering_order_editor->maybe_present ();
5955 }
5956
5957 void
5958 Editor::update_region_layering_order_editor ()
5959 {
5960         if (layering_order_editor && layering_order_editor->is_visible ()) {
5961                 change_region_layering_order (true);
5962         }
5963 }
5964
5965 void
5966 Editor::setup_fade_images ()
5967 {
5968         _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5969         _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5970         _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5971         _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5972         _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5973
5974         _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5975         _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5976         _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5977         _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5978         _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5979
5980 }
5981
5982 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5983 Gtk::MenuItem&
5984 Editor::action_menu_item (std::string const & name)
5985 {
5986         Glib::RefPtr<Action> a = editor_actions->get_action (name);
5987         assert (a);
5988
5989         return *manage (a->create_menu_item ());
5990 }
5991
5992 void
5993 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5994 {
5995         EventBox* b = manage (new EventBox);
5996         b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5997         Label* l = manage (new Label (name));
5998         l->set_angle (-90);
5999         b->add (*l);
6000         b->show_all ();
6001         _the_notebook.append_page (widget, *b);
6002 }
6003
6004 bool
6005 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6006 {
6007         if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6008                 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6009         }
6010
6011         if (ev->type == GDK_2BUTTON_PRESS) {
6012
6013                 /* double-click on a notebook tab shrinks or expands the notebook */
6014
6015                 if (_notebook_shrunk) {
6016                         if (pre_notebook_shrink_pane_width) {
6017                                 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6018                         }
6019                         _notebook_shrunk = false;
6020                 } else {
6021                         pre_notebook_shrink_pane_width = edit_pane.get_divider();
6022
6023                         /* this expands the LHS of the edit pane to cover the notebook
6024                            PAGE but leaves the tabs visible.
6025                          */
6026                         edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6027                         _notebook_shrunk = true;
6028                 }
6029         }
6030
6031         return true;
6032 }
6033
6034 void
6035 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6036 {
6037         using namespace Menu_Helpers;
6038
6039         MenuList& items = _control_point_context_menu.items ();
6040         items.clear ();
6041
6042         items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6043         items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6044         if (!can_remove_control_point (item)) {
6045                 items.back().set_sensitive (false);
6046         }
6047
6048         _control_point_context_menu.popup (event->button.button, event->button.time);
6049 }
6050
6051 void
6052 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6053 {
6054         using namespace Menu_Helpers;
6055
6056         NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6057         if (!note) {
6058                 return;
6059         }
6060
6061         /* We need to get the selection here and pass it to the operations, since
6062            popping up the menu will cause a region leave event which clears
6063            entered_regionview. */
6064
6065         MidiRegionView&       mrv = note->region_view();
6066         const RegionSelection rs  = get_regions_from_selection_and_entered ();
6067         const uint32_t sel_size = mrv.selection_size ();
6068
6069         MenuList& items = _note_context_menu.items();
6070         items.clear();
6071
6072         if (sel_size > 0) {
6073                 items.push_back(MenuElem(_("Delete"),
6074                                          sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6075         }
6076
6077         items.push_back(MenuElem(_("Edit..."),
6078                                  sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6079         if (sel_size != 1) {
6080                 items.back().set_sensitive (false);
6081         }
6082
6083         items.push_back(MenuElem(_("Transpose..."),
6084                                  sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6085
6086
6087         items.push_back(MenuElem(_("Legatize"),
6088                                  sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6089         if (sel_size < 2) {
6090                 items.back().set_sensitive (false);
6091         }
6092
6093         items.push_back(MenuElem(_("Quantize..."),
6094                                  sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6095
6096         items.push_back(MenuElem(_("Remove Overlap"),
6097                                  sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6098         if (sel_size < 2) {
6099                 items.back().set_sensitive (false);
6100         }
6101
6102         items.push_back(MenuElem(_("Transform..."),
6103                                  sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6104
6105         _note_context_menu.popup (event->button.button, event->button.time);
6106 }
6107
6108 void
6109 Editor::zoom_vertical_modifier_released()
6110 {
6111         _stepping_axis_view = 0;
6112 }
6113
6114 void
6115 Editor::ui_parameter_changed (string parameter)
6116 {
6117         if (parameter == "icon-set") {
6118                 while (!_cursor_stack.empty()) {
6119                         _cursor_stack.pop_back();
6120                 }
6121                 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6122                 _cursor_stack.push_back(_cursors->grabber);
6123                 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6124                 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6125
6126         } else if (parameter == "draggable-playhead") {
6127                 if (_verbose_cursor) {
6128                         playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6129                 }
6130         }
6131 }
6132
6133 Gtk::Window*
6134 Editor::use_own_window (bool and_fill_it)
6135 {
6136         bool new_window = !own_window();
6137
6138         Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6139
6140         if (win && new_window) {
6141                 win->set_name ("EditorWindow");
6142
6143                 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6144
6145                 // win->signal_realize().connect (*this, &Editor::on_realize);
6146                 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6147                 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6148                 win->set_data ("ardour-bindings", bindings);
6149
6150                 update_title ();
6151         }
6152
6153         DisplaySuspender ds;
6154         contents().show_all ();
6155
6156         /* XXX: this is a bit unfortunate; it would probably
6157            be nicer if we could just call show () above rather
6158            than needing the show_all ()
6159         */
6160
6161         /* re-hide stuff if necessary */
6162         editor_list_button_toggled ();
6163         parameter_changed ("show-summary");
6164         parameter_changed ("show-group-tabs");
6165         parameter_changed ("show-zoom-tools");
6166
6167         /* now reset all audio_time_axis heights, because widgets might need
6168            to be re-hidden
6169         */
6170
6171         TimeAxisView *tv;
6172
6173         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6174                 tv = (static_cast<TimeAxisView*>(*i));
6175                 tv->reset_height ();
6176         }
6177
6178         if (current_mixer_strip) {
6179                 current_mixer_strip->hide_things ();
6180                 current_mixer_strip->parameter_changed ("mixer-element-visibility");
6181         }
6182
6183         return win;
6184 }