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