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