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