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