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