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