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