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