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