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