Reinstate the ability to split regions while dragging playhead. I think this was...
[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(true);
2272
2273                 ruler_cd_marker_action->set_active(true);
2274                 ruler_samples_action->set_active(false);
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) {
4678                         /* NOTE: since the user is dragging with the mouse, this operation will implicitly be Snapped */
4679                         where = playhead_cursor->current_sample();
4680                 } else {
4681                         where = _session->audible_sample();
4682                 }
4683                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4684                 break;
4685
4686         case EditAtSelectedMarker:
4687                 if (!selection->markers.empty()) {
4688                         bool is_start;
4689                         Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4690                         if (loc) {
4691                                 if (is_start) {
4692                                         where =  loc->start();
4693                                 } else {
4694                                         where = loc->end();
4695                                 }
4696                                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4697                                 break;
4698                         }
4699                 }
4700                 /* fallthru */
4701
4702         default:
4703         case EditAtMouse:
4704                 if (!mouse_sample (where, ignored)) {
4705                         /* XXX not right but what can we do ? */
4706                         return 0;
4707                 }
4708                 snap_mf.sample = where;
4709                 snap_to (snap_mf);
4710                 where = snap_mf.sample;
4711                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4712                 break;
4713         }
4714
4715         return where;
4716 }
4717
4718 void
4719 Editor::set_loop_range (samplepos_t start, samplepos_t end, string cmd)
4720 {
4721         if (!_session) return;
4722
4723         begin_reversible_command (cmd);
4724
4725         Location* tll;
4726
4727         if ((tll = transport_loop_location()) == 0) {
4728                 Location* loc = new Location (*_session, start, end, _("Loop"),  Location::IsAutoLoop, get_grid_music_divisions(0));
4729                 XMLNode &before = _session->locations()->get_state();
4730                 _session->locations()->add (loc, true);
4731                 _session->set_auto_loop_location (loc);
4732                 XMLNode &after = _session->locations()->get_state();
4733                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4734         } else {
4735                 XMLNode &before = tll->get_state();
4736                 tll->set_hidden (false, this);
4737                 tll->set (start, end);
4738                 XMLNode &after = tll->get_state();
4739                 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4740         }
4741
4742         commit_reversible_command ();
4743 }
4744
4745 void
4746 Editor::set_punch_range (samplepos_t start, samplepos_t end, string cmd)
4747 {
4748         if (!_session) return;
4749
4750         begin_reversible_command (cmd);
4751
4752         Location* tpl;
4753
4754         if ((tpl = transport_punch_location()) == 0) {
4755                 Location* loc = new Location (*_session, start, end, _("Punch"),  Location::IsAutoPunch, get_grid_music_divisions(0));
4756                 XMLNode &before = _session->locations()->get_state();
4757                 _session->locations()->add (loc, true);
4758                 _session->set_auto_punch_location (loc);
4759                 XMLNode &after = _session->locations()->get_state();
4760                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4761         } else {
4762                 XMLNode &before = tpl->get_state();
4763                 tpl->set_hidden (false, this);
4764                 tpl->set (start, end);
4765                 XMLNode &after = tpl->get_state();
4766                 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4767         }
4768
4769         commit_reversible_command ();
4770 }
4771
4772 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4773  *  @param rs List to which found regions are added.
4774  *  @param where Time to look at.
4775  *  @param ts Tracks to look on; if this is empty, all tracks are examined.
4776  */
4777 void
4778 Editor::get_regions_at (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4779 {
4780         const TrackViewList* tracks;
4781
4782         if (ts.empty()) {
4783                 tracks = &track_views;
4784         } else {
4785                 tracks = &ts;
4786         }
4787
4788         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4789
4790                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4791
4792                 if (rtv) {
4793                         boost::shared_ptr<Track> tr;
4794                         boost::shared_ptr<Playlist> pl;
4795
4796                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4797
4798                                 boost::shared_ptr<RegionList> regions = pl->regions_at (where);
4799
4800                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4801                                         RegionView* rv = rtv->view()->find_view (*i);
4802                                         if (rv) {
4803                                                 rs.add (rv);
4804                                         }
4805                                 }
4806                         }
4807                 }
4808         }
4809 }
4810
4811 void
4812 Editor::get_regions_after (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4813 {
4814         const TrackViewList* tracks;
4815
4816         if (ts.empty()) {
4817                 tracks = &track_views;
4818         } else {
4819                 tracks = &ts;
4820         }
4821
4822         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4823                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4824                 if (rtv) {
4825                         boost::shared_ptr<Track> tr;
4826                         boost::shared_ptr<Playlist> pl;
4827
4828                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4829
4830                                 boost::shared_ptr<RegionList> regions = pl->regions_touched (where, max_samplepos);
4831
4832                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4833
4834                                         RegionView* rv = rtv->view()->find_view (*i);
4835
4836                                         if (rv) {
4837                                                 rs.add (rv);
4838                                         }
4839                                 }
4840                         }
4841                 }
4842         }
4843 }
4844
4845 /** Get regions using the following method:
4846  *
4847  *  Make a region list using:
4848  *   (a) any selected regions
4849  *   (b) the intersection of any selected tracks and the edit point(*)
4850  *   (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4851  *
4852  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4853  *
4854  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4855  */
4856
4857 RegionSelection
4858 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4859 {
4860         RegionSelection regions;
4861
4862         if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
4863                 regions.add (entered_regionview);
4864         } else {
4865                 regions = selection->regions;
4866         }
4867
4868         if (regions.empty()) {
4869                 TrackViewList tracks = selection->tracks;
4870
4871                 if (!tracks.empty()) {
4872                         /* no region selected or entered, but some selected tracks:
4873                          * act on all regions on the selected tracks at the edit point
4874                          */
4875                         samplepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
4876                         get_regions_at(regions, where, tracks);
4877                 }
4878         }
4879
4880         return regions;
4881 }
4882
4883 /** Get regions using the following method:
4884  *
4885  *  Make a region list using:
4886  *   (a) any selected regions
4887  *   (b) the intersection of any selected tracks and the edit point(*)
4888  *   (c) if neither exists, then whatever region is under the mouse
4889  *
4890  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4891  *
4892  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4893  */
4894 RegionSelection
4895 Editor::get_regions_from_selection_and_mouse (samplepos_t pos)
4896 {
4897         RegionSelection regions;
4898
4899         if (entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
4900                 regions.add (entered_regionview);
4901         } else {
4902                 regions = selection->regions;
4903         }
4904
4905         if (regions.empty()) {
4906                 TrackViewList tracks = selection->tracks;
4907
4908                 if (!tracks.empty()) {
4909                         /* no region selected or entered, but some selected tracks:
4910                          * act on all regions on the selected tracks at the edit point
4911                          */
4912                         get_regions_at(regions, pos, tracks);
4913                 }
4914         }
4915
4916         return regions;
4917 }
4918
4919 /** Start with regions that are selected, or the entered regionview if none are selected.
4920  *  Then add equivalent regions on tracks in the same active edit-enabled route group as any
4921  *  of the regions that we started with.
4922  */
4923
4924 RegionSelection
4925 Editor::get_regions_from_selection_and_entered () const
4926 {
4927         RegionSelection regions = selection->regions;
4928
4929         if (regions.empty() && entered_regionview) {
4930                 regions.add (entered_regionview);
4931         }
4932
4933         return regions;
4934 }
4935
4936 void
4937 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4938 {
4939         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4940                 RouteTimeAxisView* rtav;
4941
4942                 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4943                         boost::shared_ptr<Playlist> pl;
4944                         std::vector<boost::shared_ptr<Region> > results;
4945                         boost::shared_ptr<Track> tr;
4946
4947                         if ((tr = rtav->track()) == 0) {
4948                                 /* bus */
4949                                 continue;
4950                         }
4951
4952                         if ((pl = (tr->playlist())) != 0) {
4953                                 boost::shared_ptr<Region> r = pl->region_by_id (id);
4954                                 if (r) {
4955                                         RegionView* rv = rtav->view()->find_view (r);
4956                                         if (rv) {
4957                                                 regions.push_back (rv);
4958                                         }
4959                                 }
4960                         }
4961                 }
4962         }
4963 }
4964
4965 void
4966 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > > &selection) const
4967 {
4968
4969         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4970                 MidiTimeAxisView* mtav;
4971
4972                 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4973
4974                         mtav->get_per_region_note_selection (selection);
4975                 }
4976         }
4977
4978 }
4979
4980 void
4981 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4982 {
4983         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4984
4985                 RouteTimeAxisView* tatv;
4986
4987                 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4988
4989                         boost::shared_ptr<Playlist> pl;
4990                         vector<boost::shared_ptr<Region> > results;
4991                         RegionView* marv;
4992                         boost::shared_ptr<Track> tr;
4993
4994                         if ((tr = tatv->track()) == 0) {
4995                                 /* bus */
4996                                 continue;
4997                         }
4998
4999                         if ((pl = (tr->playlist())) != 0) {
5000                                 if (src_comparison) {
5001                                         pl->get_source_equivalent_regions (region, results);
5002                                 } else {
5003                                         pl->get_region_list_equivalent_regions (region, results);
5004                                 }
5005                         }
5006
5007                         for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5008                                 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5009                                         regions.push_back (marv);
5010                                 }
5011                         }
5012
5013                 }
5014         }
5015 }
5016
5017 RegionView*
5018 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5019 {
5020         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5021                 RouteTimeAxisView* tatv;
5022                 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5023                         if (!tatv->track()) {
5024                                 continue;
5025                         }
5026                         RegionView* marv = tatv->view()->find_view (region);
5027                         if (marv) {
5028                                 return marv;
5029                         }
5030                 }
5031         }
5032         return NULL;
5033 }
5034
5035 RouteTimeAxisView*
5036 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5037 {
5038         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5039                 RouteTimeAxisView* rtav;
5040                 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5041                         if (rtav->route() == route) {
5042                                 return rtav;
5043                         }
5044                 }
5045         }
5046         return NULL;
5047 }
5048
5049 void
5050 Editor::show_rhythm_ferret ()
5051 {
5052         if (rhythm_ferret == 0) {
5053                 rhythm_ferret = new RhythmFerret(*this);
5054         }
5055
5056         rhythm_ferret->set_session (_session);
5057         rhythm_ferret->show ();
5058         rhythm_ferret->present ();
5059 }
5060
5061 void
5062 Editor::first_idle ()
5063 {
5064         MessageDialog* dialog = 0;
5065
5066         if (track_views.size() > 1) {
5067                 Timers::TimerSuspender t;
5068                 dialog = new MessageDialog (
5069                         string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5070                         true
5071                         );
5072                 dialog->present ();
5073                 ARDOUR_UI::instance()->flush_pending (60);
5074         }
5075
5076         for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5077                 (*t)->first_idle();
5078         }
5079
5080         /* now that all regionviews should exist, setup region selection */
5081
5082         RegionSelection rs;
5083
5084         for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5085                 /* this is cumulative: rs is NOT cleared each time */
5086                 get_regionviews_by_id (*pr, rs);
5087         }
5088
5089         selection->set (rs);
5090
5091         /* first idle adds route children (automation tracks), so we need to redisplay here */
5092         _routes->redisplay ();
5093
5094         delete dialog;
5095
5096         if (_session->undo_depth() == 0) {
5097                 undo_action->set_sensitive(false);
5098         }
5099         redo_action->set_sensitive(false);
5100         begin_selection_op_history ();
5101
5102         _have_idled = true;
5103 }
5104
5105 gboolean
5106 Editor::_idle_resize (gpointer arg)
5107 {
5108         return ((Editor*)arg)->idle_resize ();
5109 }
5110
5111 void
5112 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5113 {
5114         if (resize_idle_id < 0) {
5115                 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5116                  * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5117                  * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5118                  */
5119                 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5120                 _pending_resize_amount = 0;
5121         }
5122
5123         /* make a note of the smallest resulting height, so that we can clamp the
5124            lower limit at TimeAxisView::hSmall */
5125
5126         int32_t min_resulting = INT32_MAX;
5127
5128         _pending_resize_amount += h;
5129         _pending_resize_view = view;
5130
5131         min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5132
5133         if (selection->tracks.contains (_pending_resize_view)) {
5134                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5135                         min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5136                 }
5137         }
5138
5139         if (min_resulting < 0) {
5140                 min_resulting = 0;
5141         }
5142
5143         /* clamp */
5144         if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5145                 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5146         }
5147 }
5148
5149 /** Handle pending resizing of tracks */
5150 bool
5151 Editor::idle_resize ()
5152 {
5153         _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5154
5155         if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5156             selection->tracks.contains (_pending_resize_view)) {
5157
5158                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5159                         if (*i != _pending_resize_view) {
5160                                 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5161                         }
5162                 }
5163         }
5164
5165         _pending_resize_amount = 0;
5166         _group_tabs->set_dirty ();
5167         resize_idle_id = -1;
5168
5169         return false;
5170 }
5171
5172 void
5173 Editor::located ()
5174 {
5175         ENSURE_GUI_THREAD (*this, &Editor::located);
5176
5177         if (_session) {
5178                 playhead_cursor->set_position (_session->audible_sample ());
5179                 if (_follow_playhead && !_pending_initial_locate) {
5180                         reset_x_origin_to_follow_playhead ();
5181                 }
5182         }
5183
5184         _pending_locate_request = false;
5185         _pending_initial_locate = false;
5186         _last_update_time = 0;
5187 }
5188
5189 void
5190 Editor::region_view_added (RegionView * rv)
5191 {
5192         MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5193         if (mrv) {
5194                 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5195                 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5196                         if (rv->region()->id () == (*rnote).first) {
5197                                 mrv->select_notes ((*rnote).second);
5198                                 selection->pending_midi_note_selection.erase(rnote);
5199                                 break;
5200                         }
5201                 }
5202         }
5203
5204         _summary->set_background_dirty ();
5205
5206         mark_region_boundary_cache_dirty ();
5207 }
5208
5209 void
5210 Editor::region_view_removed ()
5211 {
5212         _summary->set_background_dirty ();
5213
5214         mark_region_boundary_cache_dirty ();
5215 }
5216
5217 AxisView*
5218 Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
5219 {
5220         for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5221                 if ((*j)->stripable() == s) {
5222                         return *j;
5223                 }
5224         }
5225
5226         return 0;
5227 }
5228
5229 AxisView*
5230 Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
5231 {
5232         for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5233                 if ((*j)->control() == c) {
5234                         return *j;
5235                 }
5236
5237                 TimeAxisView::Children kids = (*j)->get_child_list ();
5238
5239                 for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) {
5240                         if ((*k)->control() == c) {
5241                                 return (*k).get();
5242                         }
5243                 }
5244         }
5245
5246         return 0;
5247 }
5248
5249 TrackViewList
5250 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5251 {
5252         TrackViewList t;
5253
5254         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5255                 TimeAxisView* tv = time_axis_view_from_stripable (*i);
5256                 if (tv) {
5257                         t.push_back (tv);
5258                 }
5259         }
5260
5261         return t;
5262 }
5263
5264 void
5265 Editor::suspend_route_redisplay ()
5266 {
5267         if (_routes) {
5268                 _routes->suspend_redisplay();
5269         }
5270 }
5271
5272 void
5273 Editor::resume_route_redisplay ()
5274 {
5275         if (_routes) {
5276                 _routes->redisplay(); // queue redisplay
5277                 _routes->resume_redisplay();
5278         }
5279 }
5280
5281 void
5282 Editor::add_vcas (VCAList& vlist)
5283 {
5284         StripableList sl;
5285
5286         for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5287                 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5288         }
5289
5290         add_stripables (sl);
5291 }
5292
5293 void
5294 Editor::add_routes (RouteList& rlist)
5295 {
5296         StripableList sl;
5297
5298         for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5299                 sl.push_back (*r);
5300         }
5301
5302         add_stripables (sl);
5303 }
5304
5305 void
5306 Editor::add_stripables (StripableList& sl)
5307 {
5308         list<TimeAxisView*> new_views;
5309         boost::shared_ptr<VCA> v;
5310         boost::shared_ptr<Route> r;
5311         TrackViewList new_selection;
5312         bool from_scratch = (track_views.size() == 0);
5313
5314         sl.sort (Stripable::Sorter());
5315
5316         for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5317
5318                 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5319
5320                         VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5321                         vtv->set_vca (v);
5322                         new_views.push_back (vtv);
5323
5324                 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5325
5326                         if (r->is_auditioner() || r->is_monitor()) {
5327                                 continue;
5328                         }
5329
5330                         RouteTimeAxisView* rtv;
5331                         DataType dt = r->input()->default_type();
5332
5333                         if (dt == ARDOUR::DataType::AUDIO) {
5334                                 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5335                                 rtv->set_route (r);
5336                         } else if (dt == ARDOUR::DataType::MIDI) {
5337                                 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5338                                 rtv->set_route (r);
5339                         } else {
5340                                 throw unknown_type();
5341                         }
5342
5343                         new_views.push_back (rtv);
5344                         track_views.push_back (rtv);
5345                         new_selection.push_back (rtv);
5346
5347                         rtv->effective_gain_display ();
5348
5349                         rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5350                         rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5351                 }
5352         }
5353
5354         if (new_views.size() > 0) {
5355                 _routes->time_axis_views_added (new_views);
5356                 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5357         }
5358
5359         /* note: !new_selection.empty() means that we got some routes rather
5360          * than just VCAs
5361          */
5362
5363         if (!from_scratch && !new_selection.empty()) {
5364                 selection->set (new_selection);
5365                 begin_selection_op_history();
5366         }
5367
5368         if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5369                 show_editor_mixer (true);
5370         }
5371
5372         editor_list_button.set_sensitive (true);
5373 }
5374
5375 void
5376 Editor::timeaxisview_deleted (TimeAxisView *tv)
5377 {
5378         if (tv == entered_track) {
5379                 entered_track = 0;
5380         }
5381
5382         if (_session && _session->deletion_in_progress()) {
5383                 /* the situation is under control */
5384                 return;
5385         }
5386
5387         ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5388
5389         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5390
5391         _routes->route_removed (tv);
5392
5393         TimeAxisView::Children c = tv->get_child_list ();
5394         for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5395                 if (entered_track == i->get()) {
5396                         entered_track = 0;
5397                 }
5398         }
5399
5400         /* remove it from the list of track views */
5401
5402         TrackViewList::iterator i;
5403
5404         if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5405                 i = track_views.erase (i);
5406         }
5407
5408         /* update whatever the current mixer strip is displaying, if revelant */
5409
5410         boost::shared_ptr<Route> route;
5411
5412         if (rtav) {
5413                 route = rtav->route ();
5414         }
5415
5416         if (current_mixer_strip && current_mixer_strip->route() == route) {
5417
5418                 TimeAxisView* next_tv;
5419
5420                 if (track_views.empty()) {
5421                         next_tv = 0;
5422                 } else if (i == track_views.end()) {
5423                         next_tv = track_views.front();
5424                 } else {
5425                         next_tv = (*i);
5426                 }
5427
5428                 // skip VCAs (cannot be selected, n/a in editor-mixer)
5429                 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5430                         /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5431                         next_tv = track_views.front();
5432                 }
5433                 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5434                         /* just in case: no master, only a VCA remains */
5435                         next_tv = 0;
5436                 }
5437
5438
5439                 if (next_tv) {
5440                         set_selected_mixer_strip (*next_tv);
5441                 } else {
5442                         /* make the editor mixer strip go away setting the
5443                          * button to inactive (which also unticks the menu option)
5444                          */
5445
5446                         ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5447                 }
5448         }
5449 }
5450
5451 void
5452 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5453 {
5454         if (!tv) {
5455                 return;
5456         }
5457
5458         DisplaySuspender ds;
5459         PresentationInfo::ChangeSuspender cs;
5460
5461         if (apply_to_selection) {
5462                 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end();) {
5463
5464                         TrackSelection::iterator j = i;
5465                         ++j;
5466
5467                         hide_track_in_display (*i, false);
5468
5469                         i = j;
5470                 }
5471         } else {
5472                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5473
5474                 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5475                         /* this will hide the mixer strip */
5476                         set_selected_mixer_strip (*tv);
5477                 }
5478
5479                 _routes->hide_track_in_display (*tv);
5480         }
5481 }
5482
5483 void
5484 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5485 {
5486         if (!tv) {
5487                 return;
5488         }
5489         _routes->show_track_in_display (*tv);
5490         if (move_into_view) {
5491                 ensure_time_axis_view_is_visible (*tv, false);
5492         }
5493 }
5494
5495 bool
5496 Editor::sync_track_view_list_and_routes ()
5497 {
5498         track_views = TrackViewList (_routes->views ());
5499
5500         _summary->set_background_dirty();
5501         _group_tabs->set_dirty ();
5502
5503         return false; // do not call again (until needed)
5504 }
5505
5506 void
5507 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5508 {
5509         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5510                 theslot (**i);
5511         }
5512 }
5513
5514 /** Find a StripableTimeAxisView by the ID of its stripable */
5515 StripableTimeAxisView*
5516 Editor::get_stripable_time_axis_by_id (const PBD::ID& id) const
5517 {
5518         StripableTimeAxisView* v;
5519
5520         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5521                 if((v = dynamic_cast<StripableTimeAxisView*>(*i)) != 0) {
5522                         if(v->stripable()->id() == id) {
5523                                 return v;
5524                         }
5525                 }
5526         }
5527
5528         return 0;
5529 }
5530
5531 void
5532 Editor::fit_route_group (RouteGroup *g)
5533 {
5534         TrackViewList ts = axis_views_from_routes (g->route_list ());
5535         fit_tracks (ts);
5536 }
5537
5538 void
5539 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5540 {
5541         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5542
5543         if (r == 0) {
5544                 _session->cancel_audition ();
5545                 return;
5546         }
5547
5548         if (_session->is_auditioning()) {
5549                 _session->cancel_audition ();
5550                 if (r == last_audition_region) {
5551                         return;
5552                 }
5553         }
5554
5555         _session->audition_region (r);
5556         last_audition_region = r;
5557 }
5558
5559
5560 void
5561 Editor::hide_a_region (boost::shared_ptr<Region> r)
5562 {
5563         r->set_hidden (true);
5564 }
5565
5566 void
5567 Editor::show_a_region (boost::shared_ptr<Region> r)
5568 {
5569         r->set_hidden (false);
5570 }
5571
5572 void
5573 Editor::audition_region_from_region_list ()
5574 {
5575         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5576 }
5577
5578 void
5579 Editor::hide_region_from_region_list ()
5580 {
5581         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5582 }
5583
5584 void
5585 Editor::show_region_in_region_list ()
5586 {
5587         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5588 }
5589
5590 void
5591 Editor::step_edit_status_change (bool yn)
5592 {
5593         if (yn) {
5594                 start_step_editing ();
5595         } else {
5596                 stop_step_editing ();
5597         }
5598 }
5599
5600 void
5601 Editor::start_step_editing ()
5602 {
5603         step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5604 }
5605
5606 void
5607 Editor::stop_step_editing ()
5608 {
5609         step_edit_connection.disconnect ();
5610 }
5611
5612 bool
5613 Editor::check_step_edit ()
5614 {
5615         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5616                 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5617                 if (mtv) {
5618                         mtv->check_step_edit ();
5619                 }
5620         }
5621
5622         return true; // do it again, till we stop
5623 }
5624
5625 bool
5626 Editor::scroll_press (Direction dir)
5627 {
5628         ++_scroll_callbacks;
5629
5630         if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5631                 /* delay the first auto-repeat */
5632                 return true;
5633         }
5634
5635         switch (dir) {
5636         case LEFT:
5637                 scroll_backward (1);
5638                 break;
5639
5640         case RIGHT:
5641                 scroll_forward (1);
5642                 break;
5643
5644         case UP:
5645                 scroll_up_one_track ();
5646                 break;
5647
5648         case DOWN:
5649                 scroll_down_one_track ();
5650                 break;
5651         }
5652
5653         /* do hacky auto-repeat */
5654         if (!_scroll_connection.connected ()) {
5655
5656                 _scroll_connection = Glib::signal_timeout().connect (
5657                         sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5658                         );
5659
5660                 _scroll_callbacks = 0;
5661         }
5662
5663         return true;
5664 }
5665
5666 void
5667 Editor::scroll_release ()
5668 {
5669         _scroll_connection.disconnect ();
5670 }
5671
5672 /** Queue a change for the Editor viewport x origin to follow the playhead */
5673 void
5674 Editor::reset_x_origin_to_follow_playhead ()
5675 {
5676         samplepos_t const sample = playhead_cursor->current_sample ();
5677
5678         if (sample < _leftmost_sample || sample > _leftmost_sample + current_page_samples()) {
5679
5680                 if (_session->transport_speed() < 0) {
5681
5682                         if (sample > (current_page_samples() / 2)) {
5683                                 center_screen (sample-(current_page_samples()/2));
5684                         } else {
5685                                 center_screen (current_page_samples()/2);
5686                         }
5687
5688                 } else {
5689
5690                         samplepos_t l = 0;
5691
5692                         if (sample < _leftmost_sample) {
5693                                 /* moving left */
5694                                 if (_session->transport_rolling()) {
5695                                         /* rolling; end up with the playhead at the right of the page */
5696                                         l = sample - current_page_samples ();
5697                                 } else {
5698                                         /* not rolling: end up with the playhead 1/4 of the way along the page */
5699                                         l = sample - current_page_samples() / 4;
5700                                 }
5701                         } else {
5702                                 /* moving right */
5703                                 if (_session->transport_rolling()) {
5704                                         /* rolling: end up with the playhead on the left of the page */
5705                                         l = sample;
5706                                 } else {
5707                                         /* not rolling: end up with the playhead 3/4 of the way along the page */
5708                                         l = sample - 3 * current_page_samples() / 4;
5709                                 }
5710                         }
5711
5712                         if (l < 0) {
5713                                 l = 0;
5714                         }
5715
5716                         center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5717                 }
5718         }
5719 }
5720
5721 void
5722 Editor::super_rapid_screen_update ()
5723 {
5724         if (!_session || !_session->engine().running()) {
5725                 return;
5726         }
5727
5728         /* METERING / MIXER STRIPS */
5729
5730         /* update track meters, if required */
5731         if (contents().is_mapped() && meters_running) {
5732                 RouteTimeAxisView* rtv;
5733                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5734                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5735                                 rtv->fast_update ();
5736                         }
5737                 }
5738         }
5739
5740         /* and any current mixer strip */
5741         if (current_mixer_strip) {
5742                 current_mixer_strip->fast_update ();
5743         }
5744
5745         bool latent_locate = false;
5746         samplepos_t sample = _session->audible_sample (&latent_locate);
5747         const int64_t now = g_get_monotonic_time ();
5748         double err = 0;
5749
5750         if (_session->exporting ()) {
5751                 /* freewheel/export may be faster or slower than transport_speed() / SR.
5752                  * Also exporting multiple ranges locates/jumps without a _pending_locate_request.
5753                  */
5754                 _last_update_time = 0;
5755         }
5756
5757         if (!_session->transport_rolling ()) {
5758                 /* Do not interpolate the playhead position; just set it */
5759                 _last_update_time = 0;
5760         }
5761
5762         if (_last_update_time > 0) {
5763                 /* interpolate and smoothen playhead position */
5764                 const double ds =  (now - _last_update_time) * _session->transport_speed() * _session->nominal_sample_rate () * 1e-6;
5765                 samplepos_t guess = playhead_cursor->current_sample () + rint (ds);
5766                 err = sample - guess;
5767
5768                 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5769                 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5770
5771 #if 0 // DEBUG
5772                 printf ("eng: %ld  gui:%ld (%+6.1f)  diff: %6.1f (err: %7.2f)\n",
5773                                 sample, guess, ds,
5774                                 err, _err_screen_engine);
5775 #endif
5776
5777                 sample = guess;
5778         } else {
5779                 _err_screen_engine = 0;
5780         }
5781
5782         if (err > 8192 || latent_locate) {
5783                 // in case of x-runs or freewheeling
5784                 _last_update_time = 0;
5785                 sample = _session->audible_sample ();
5786         } else {
5787                 _last_update_time = now;
5788         }
5789
5790         /* snapped cursor stuff (the snapped_cursor shows where an operation is going to occur) */
5791         bool ignored;
5792         MusicSample where (sample, 0);
5793         if (!UIConfiguration::instance().get_show_snapped_cursor()) {
5794                 snapped_cursor->hide ();
5795         } else if (_edit_point == EditAtPlayhead && !_dragging_playhead) {
5796                 /* EditAtPlayhead does not snap */
5797         } else if (_edit_point == EditAtSelectedMarker) {
5798                 /* NOTE: I don't think EditAtSelectedMarker should snap. They are what they are.
5799                  * however, the current editing code -does- snap so I'll draw it that way for now.
5800                  */
5801                 if (!selection->markers.empty()) {
5802                         MusicSample ms (selection->markers.front()->position(), 0);
5803                         snap_to (ms); // should use snap_to_with_modifier?
5804                         snapped_cursor->set_position (ms.sample);
5805                         snapped_cursor->show ();
5806                 }
5807         } else if (mouse_sample (where.sample, ignored)) { // cursor is in the editing canvas. show it.
5808                 snapped_cursor->show ();
5809         } else { // mouse is out of the editing canvas. hide the snapped_cursor
5810                 snapped_cursor->hide ();
5811         }
5812
5813         /* There are a few reasons why we might not update the playhead / viewport stuff:
5814          *
5815          * 1.  we don't update things when there's a pending locate request, otherwise
5816          *     when the editor requests a locate there is a chance that this method
5817          *     will move the playhead before the locate request is processed, causing
5818          *     a visual glitch.
5819          * 2.  if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5820          * 3.  if we're still at the same frame that we were last time, there's nothing to do.
5821          */
5822         if (_pending_locate_request) {
5823                 _last_update_time = 0;
5824                 return;
5825         }
5826
5827         if (_dragging_playhead) {
5828                 _last_update_time = 0;
5829                 return;
5830         }
5831
5832         if (playhead_cursor->current_sample () == sample) {
5833                 return;
5834         }
5835
5836         playhead_cursor->set_position (sample);
5837
5838         if (_session->requested_return_sample() >= 0) {
5839                 _last_update_time = 0;
5840                 return;
5841         }
5842
5843         if (!_follow_playhead || pending_visual_change.being_handled) {
5844                 /* We only do this if we aren't already
5845                  * handling a visual change (ie if
5846                  * pending_visual_change.being_handled is
5847                  * false) so that these requests don't stack
5848                  * up there are too many of them to handle in
5849                  * time.
5850                  */
5851                 return;
5852         }
5853
5854         if (!_stationary_playhead) {
5855                 reset_x_origin_to_follow_playhead ();
5856         } else {
5857                 samplepos_t const sample = playhead_cursor->current_sample ();
5858                 double target = ((double)sample - (double)current_page_samples() / 2.0);
5859                 if (target <= 0.0) {
5860                         target = 0.0;
5861                 }
5862                 /* compare to EditorCursor::set_position() */
5863                 double const old_pos = sample_to_pixel_unrounded (_leftmost_sample);
5864                 double const new_pos = sample_to_pixel_unrounded (target);
5865                 if (rint (new_pos) != rint (old_pos)) {
5866                         reset_x_origin (pixel_to_sample (new_pos));
5867                 }
5868         }
5869 }
5870
5871
5872 void
5873 Editor::session_going_away ()
5874 {
5875         _have_idled = false;
5876
5877         _session_connections.drop_connections ();
5878
5879         super_rapid_screen_update_connection.disconnect ();
5880
5881         selection->clear ();
5882         cut_buffer->clear ();
5883
5884         clicked_regionview = 0;
5885         clicked_axisview = 0;
5886         clicked_routeview = 0;
5887         entered_regionview = 0;
5888         entered_track = 0;
5889         _last_update_time = 0;
5890         _drags->abort ();
5891
5892         playhead_cursor->hide ();
5893
5894         /* rip everything out of the list displays */
5895
5896         _regions->clear ();
5897         _routes->clear ();
5898         _route_groups->clear ();
5899
5900         /* do this first so that deleting a track doesn't reset cms to null
5901            and thus cause a leak.
5902         */
5903
5904         if (current_mixer_strip) {
5905                 if (current_mixer_strip->get_parent() != 0) {
5906                         global_hpacker.remove (*current_mixer_strip);
5907                 }
5908                 delete current_mixer_strip;
5909                 current_mixer_strip = 0;
5910         }
5911
5912         /* delete all trackviews */
5913
5914         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5915                 delete *i;
5916         }
5917         track_views.clear ();
5918
5919         nudge_clock->set_session (0);
5920
5921         editor_list_button.set_active(false);
5922         editor_list_button.set_sensitive(false);
5923
5924         /* clear tempo/meter rulers */
5925         remove_metric_marks ();
5926         clear_marker_display ();
5927
5928         hide_grid_lines ();
5929         delete grid_lines;
5930         grid_lines = 0;
5931
5932         stop_step_editing ();
5933
5934         if (own_window()) {
5935
5936                 /* get rid of any existing editor mixer strip */
5937
5938                 WindowTitle title(Glib::get_application_name());
5939                 title += _("Editor");
5940
5941                 own_window()->set_title (title.get_string());
5942         }
5943
5944         SessionHandlePtr::session_going_away ();
5945 }
5946
5947 void
5948 Editor::trigger_script (int i)
5949 {
5950         LuaInstance::instance()-> call_action (i);
5951 }
5952
5953 void
5954 Editor::show_editor_list (bool yn)
5955 {
5956         if (yn) {
5957                 _editor_list_vbox.show ();
5958         } else {
5959                 _editor_list_vbox.hide ();
5960         }
5961 }
5962
5963 void
5964 Editor::change_region_layering_order (bool from_context_menu)
5965 {
5966         const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5967
5968         if (!clicked_routeview) {
5969                 if (layering_order_editor) {
5970                         layering_order_editor->hide ();
5971                 }
5972                 return;
5973         }
5974
5975         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5976
5977         if (!track) {
5978                 return;
5979         }
5980
5981         boost::shared_ptr<Playlist> pl = track->playlist();
5982
5983         if (!pl) {
5984                 return;
5985         }
5986
5987         if (layering_order_editor == 0) {
5988                 layering_order_editor = new RegionLayeringOrderEditor (*this);
5989         }
5990
5991         layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5992         layering_order_editor->maybe_present ();
5993 }
5994
5995 void
5996 Editor::update_region_layering_order_editor ()
5997 {
5998         if (layering_order_editor && layering_order_editor->is_visible ()) {
5999                 change_region_layering_order (true);
6000         }
6001 }
6002
6003 void
6004 Editor::setup_fade_images ()
6005 {
6006         _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
6007         _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
6008         _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
6009         _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
6010         _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
6011
6012         _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
6013         _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
6014         _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
6015         _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
6016         _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
6017
6018 }
6019
6020 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
6021 Gtk::MenuItem&
6022 Editor::action_menu_item (std::string const & name)
6023 {
6024         Glib::RefPtr<Action> a = editor_actions->get_action (name);
6025         assert (a);
6026
6027         return *manage (a->create_menu_item ());
6028 }
6029
6030 void
6031 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6032 {
6033         EventBox* b = manage (new EventBox);
6034         b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6035         Label* l = manage (new Label (name));
6036         l->set_angle (-90);
6037         b->add (*l);
6038         b->show_all ();
6039         _the_notebook.append_page (widget, *b);
6040 }
6041
6042 bool
6043 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6044 {
6045         if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6046                 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6047         }
6048
6049         if (ev->type == GDK_2BUTTON_PRESS) {
6050
6051                 /* double-click on a notebook tab shrinks or expands the notebook */
6052
6053                 if (_notebook_shrunk) {
6054                         if (pre_notebook_shrink_pane_width) {
6055                                 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6056                         }
6057                         _notebook_shrunk = false;
6058                 } else {
6059                         pre_notebook_shrink_pane_width = edit_pane.get_divider();
6060
6061                         /* this expands the LHS of the edit pane to cover the notebook
6062                            PAGE but leaves the tabs visible.
6063                          */
6064                         edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6065                         _notebook_shrunk = true;
6066                 }
6067         }
6068
6069         return true;
6070 }
6071
6072 void
6073 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6074 {
6075         using namespace Menu_Helpers;
6076
6077         MenuList& items = _control_point_context_menu.items ();
6078         items.clear ();
6079
6080         items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6081         items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6082         if (!can_remove_control_point (item)) {
6083                 items.back().set_sensitive (false);
6084         }
6085
6086         _control_point_context_menu.popup (event->button.button, event->button.time);
6087 }
6088
6089 void
6090 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6091 {
6092         using namespace Menu_Helpers;
6093
6094         NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6095         if (!note) {
6096                 return;
6097         }
6098
6099         /* We need to get the selection here and pass it to the operations, since
6100            popping up the menu will cause a region leave event which clears
6101            entered_regionview. */
6102
6103         MidiRegionView&       mrv = note->region_view();
6104         const RegionSelection rs  = get_regions_from_selection_and_entered ();
6105         const uint32_t sel_size = mrv.selection_size ();
6106
6107         MenuList& items = _note_context_menu.items();
6108         items.clear();
6109
6110         if (sel_size > 0) {
6111                 items.push_back(MenuElem(_("Delete"),
6112                                          sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6113         }
6114
6115         items.push_back(MenuElem(_("Edit..."),
6116                                  sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6117         if (sel_size != 1) {
6118                 items.back().set_sensitive (false);
6119         }
6120
6121         items.push_back(MenuElem(_("Transpose..."),
6122                                  sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6123
6124
6125         items.push_back(MenuElem(_("Legatize"),
6126                                  sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6127         if (sel_size < 2) {
6128                 items.back().set_sensitive (false);
6129         }
6130
6131         items.push_back(MenuElem(_("Quantize..."),
6132                                  sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6133
6134         items.push_back(MenuElem(_("Remove Overlap"),
6135                                  sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6136         if (sel_size < 2) {
6137                 items.back().set_sensitive (false);
6138         }
6139
6140         items.push_back(MenuElem(_("Transform..."),
6141                                  sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6142
6143         _note_context_menu.popup (event->button.button, event->button.time);
6144 }
6145
6146 void
6147 Editor::zoom_vertical_modifier_released()
6148 {
6149         _stepping_axis_view = 0;
6150 }
6151
6152 void
6153 Editor::ui_parameter_changed (string parameter)
6154 {
6155         if (parameter == "icon-set") {
6156                 while (!_cursor_stack.empty()) {
6157                         _cursor_stack.pop_back();
6158                 }
6159                 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6160                 _cursor_stack.push_back(_cursors->grabber);
6161                 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6162                 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6163
6164         } else if (parameter == "draggable-playhead") {
6165                 if (_verbose_cursor) {
6166                         playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6167                 }
6168         }
6169 }
6170
6171 Gtk::Window*
6172 Editor::use_own_window (bool and_fill_it)
6173 {
6174         bool new_window = !own_window();
6175
6176         Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6177
6178         if (win && new_window) {
6179                 win->set_name ("EditorWindow");
6180
6181                 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6182
6183                 // win->signal_realize().connect (*this, &Editor::on_realize);
6184                 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6185                 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6186                 win->set_data ("ardour-bindings", bindings);
6187
6188                 update_title ();
6189         }
6190
6191         DisplaySuspender ds;
6192         contents().show_all ();
6193
6194         /* XXX: this is a bit unfortunate; it would probably
6195            be nicer if we could just call show () above rather
6196            than needing the show_all ()
6197         */
6198
6199         /* re-hide stuff if necessary */
6200         editor_list_button_toggled ();
6201         parameter_changed ("show-summary");
6202         parameter_changed ("show-group-tabs");
6203         parameter_changed ("show-zoom-tools");
6204
6205         /* now reset all audio_time_axis heights, because widgets might need
6206            to be re-hidden
6207         */
6208
6209         TimeAxisView *tv;
6210
6211         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6212                 tv = (static_cast<TimeAxisView*>(*i));
6213                 tv->reset_height ();
6214         }
6215
6216         if (current_mixer_strip) {
6217                 current_mixer_strip->hide_things ();
6218                 current_mixer_strip->parameter_changed ("mixer-element-visibility");
6219         }
6220
6221         return win;
6222 }