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