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