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