Tempo ramps - switch MusicLocked tempos to beat-based dragging. fix various bugs...
[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         case SnapToBeat:
2161         case SnapToBar:
2162                 return true;
2163         default:
2164                 break;
2165         }
2166
2167         return false;
2168 }
2169
2170 SnapMode
2171 Editor::snap_mode() const
2172 {
2173         return _snap_mode;
2174 }
2175
2176 void
2177 Editor::set_snap_to (SnapType st)
2178 {
2179         unsigned int snap_ind = (unsigned int)st;
2180
2181         if (internal_editing()) {
2182                 internal_snap_type = st;
2183         } else {
2184                 pre_internal_snap_type = st;
2185         }
2186
2187         _snap_type = st;
2188
2189         if (snap_ind > snap_type_strings.size() - 1) {
2190                 snap_ind = 0;
2191                 _snap_type = (SnapType)snap_ind;
2192         }
2193
2194         string str = snap_type_strings[snap_ind];
2195
2196         if (str != snap_type_selector.get_text()) {
2197                 snap_type_selector.set_text (str);
2198         }
2199
2200         instant_save ();
2201
2202         switch (_snap_type) {
2203         case SnapToBeatDiv128:
2204         case SnapToBeatDiv64:
2205         case SnapToBeatDiv32:
2206         case SnapToBeatDiv28:
2207         case SnapToBeatDiv24:
2208         case SnapToBeatDiv20:
2209         case SnapToBeatDiv16:
2210         case SnapToBeatDiv14:
2211         case SnapToBeatDiv12:
2212         case SnapToBeatDiv10:
2213         case SnapToBeatDiv8:
2214         case SnapToBeatDiv7:
2215         case SnapToBeatDiv6:
2216         case SnapToBeatDiv5:
2217         case SnapToBeatDiv4:
2218         case SnapToBeatDiv3:
2219         case SnapToBeatDiv2: {
2220                 std::vector<TempoMap::BBTPoint> grid;
2221                 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
2222                 compute_bbt_ruler_scale (grid, leftmost_frame, leftmost_frame + current_page_samples());
2223                 update_tempo_based_rulers (grid);
2224                 break;
2225         }
2226
2227         case SnapToRegionStart:
2228         case SnapToRegionEnd:
2229         case SnapToRegionSync:
2230         case SnapToRegionBoundary:
2231                 build_region_boundary_cache ();
2232                 break;
2233
2234         default:
2235                 /* relax */
2236                 break;
2237         }
2238
2239         redisplay_tempo (false);
2240
2241         SnapChanged (); /* EMIT SIGNAL */
2242 }
2243
2244 void
2245 Editor::set_snap_mode (SnapMode mode)
2246 {
2247         string str = snap_mode_strings[(int)mode];
2248
2249         if (internal_editing()) {
2250                 internal_snap_mode = mode;
2251         } else {
2252                 pre_internal_snap_mode = mode;
2253         }
2254
2255         _snap_mode = mode;
2256
2257         if (str != snap_mode_selector.get_text ()) {
2258                 snap_mode_selector.set_text (str);
2259         }
2260
2261         instant_save ();
2262 }
2263
2264 void
2265 Editor::set_edit_point_preference (EditPoint ep, bool force)
2266 {
2267         bool changed = (_edit_point != ep);
2268
2269         _edit_point = ep;
2270         if (Profile->get_mixbus())
2271                 if (ep == EditAtSelectedMarker)
2272                         ep = EditAtPlayhead;
2273
2274         string str = edit_point_strings[(int)ep];
2275         if (str != edit_point_selector.get_text ()) {
2276                 edit_point_selector.set_text (str);
2277         }
2278
2279         update_all_enter_cursors();
2280
2281         if (!force && !changed) {
2282                 return;
2283         }
2284
2285         const char* action=NULL;
2286
2287         switch (_edit_point) {
2288         case EditAtPlayhead:
2289                 action = "edit-at-playhead";
2290                 break;
2291         case EditAtSelectedMarker:
2292                 action = "edit-at-marker";
2293                 break;
2294         case EditAtMouse:
2295                 action = "edit-at-mouse";
2296                 break;
2297         }
2298
2299         Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2300         if (act) {
2301                 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2302         }
2303
2304         framepos_t foo;
2305         bool in_track_canvas;
2306
2307         if (!mouse_frame (foo, in_track_canvas)) {
2308                 in_track_canvas = false;
2309         }
2310
2311         reset_canvas_action_sensitivity (in_track_canvas);
2312
2313         instant_save ();
2314 }
2315
2316 int
2317 Editor::set_state (const XMLNode& node, int version)
2318 {
2319         XMLProperty const * prop;
2320         set_id (node);
2321         PBD::Unwinder<bool> nsi (no_save_instant, true);
2322
2323         Tabbable::set_state (node, version);
2324
2325         if (_session && (prop = node.property ("playhead"))) {
2326                 framepos_t pos;
2327                 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2328                 if (pos >= 0) {
2329                         playhead_cursor->set_position (pos);
2330                 } else {
2331                         warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2332                         playhead_cursor->set_position (0);
2333                 }
2334         } else {
2335                 playhead_cursor->set_position (0);
2336         }
2337
2338         if ((prop = node.property ("mixer-width"))) {
2339                 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2340         }
2341
2342         if ((prop = node.property ("zoom-focus"))) {
2343                 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2344         }
2345
2346         if ((prop = node.property ("zoom"))) {
2347                 /* older versions of ardour used floating point samples_per_pixel */
2348                 double f = PBD::atof (prop->value());
2349                 reset_zoom (llrintf (f));
2350         } else {
2351                 reset_zoom (samples_per_pixel);
2352         }
2353
2354         if ((prop = node.property ("visible-track-count"))) {
2355                 set_visible_track_count (PBD::atoi (prop->value()));
2356         }
2357
2358         if ((prop = node.property ("snap-to"))) {
2359                 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2360                 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2361         }
2362
2363         if ((prop = node.property ("snap-mode"))) {
2364                 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2365                 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2366                  * snap_mode_selection_done() will only mark an already active item as active
2367                  * which does not trigger set_text().
2368                  */
2369                 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2370         }
2371
2372         if ((prop = node.property ("internal-snap-to"))) {
2373                 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2374         }
2375
2376         if ((prop = node.property ("internal-snap-mode"))) {
2377                 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2378         }
2379
2380         if ((prop = node.property ("pre-internal-snap-to"))) {
2381                 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2382         }
2383
2384         if ((prop = node.property ("pre-internal-snap-mode"))) {
2385                 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2386         }
2387
2388         if ((prop = node.property ("mouse-mode"))) {
2389                 MouseMode m = str2mousemode(prop->value());
2390                 set_mouse_mode (m, true);
2391         } else {
2392                 set_mouse_mode (MouseObject, true);
2393         }
2394
2395         if ((prop = node.property ("left-frame")) != 0) {
2396                 framepos_t pos;
2397                 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2398                         if (pos < 0) {
2399                                 pos = 0;
2400                         }
2401                         reset_x_origin (pos);
2402                 }
2403         }
2404
2405         if ((prop = node.property ("y-origin")) != 0) {
2406                 reset_y_origin (atof (prop->value ()));
2407         }
2408
2409         if ((prop = node.property ("join-object-range"))) {
2410                 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2411                 bool yn = string_is_affirmative (prop->value());
2412                 if (act) {
2413                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2414                         tact->set_active (!yn);
2415                         tact->set_active (yn);
2416                 }
2417                 set_mouse_mode(mouse_mode, true);
2418         }
2419
2420         if ((prop = node.property ("edit-point"))) {
2421                 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2422         }
2423
2424         if ((prop = node.property ("show-measures"))) {
2425                 bool yn = string_is_affirmative (prop->value());
2426                 _show_measures = yn;
2427         }
2428
2429         if ((prop = node.property ("follow-playhead"))) {
2430                 bool yn = string_is_affirmative (prop->value());
2431                 set_follow_playhead (yn);
2432         }
2433
2434         if ((prop = node.property ("stationary-playhead"))) {
2435                 bool yn = string_is_affirmative (prop->value());
2436                 set_stationary_playhead (yn);
2437         }
2438
2439         if ((prop = node.property ("region-list-sort-type"))) {
2440                 RegionListSortType st;
2441                 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2442         }
2443
2444         if ((prop = node.property ("show-editor-mixer"))) {
2445
2446                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2447                 assert (act);
2448
2449                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2450                 bool yn = string_is_affirmative (prop->value());
2451
2452                 /* do it twice to force the change */
2453
2454                 tact->set_active (!yn);
2455                 tact->set_active (yn);
2456         }
2457
2458         if ((prop = node.property ("show-editor-list"))) {
2459
2460                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2461                 assert (act);
2462
2463                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2464                 bool yn = string_is_affirmative (prop->value());
2465
2466                 /* do it twice to force the change */
2467
2468                 tact->set_active (!yn);
2469                 tact->set_active (yn);
2470         }
2471
2472         if ((prop = node.property (X_("editor-list-page")))) {
2473                 _the_notebook.set_current_page (atoi (prop->value ()));
2474         }
2475
2476         if ((prop = node.property (X_("show-marker-lines")))) {
2477                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2478                 assert (act);
2479                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2480                 bool yn = string_is_affirmative (prop->value ());
2481
2482                 tact->set_active (!yn);
2483                 tact->set_active (yn);
2484         }
2485
2486         XMLNodeList children = node.children ();
2487         for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2488                 selection->set_state (**i, Stateful::current_state_version);
2489                 _regions->set_state (**i);
2490         }
2491
2492         if ((prop = node.property ("maximised"))) {
2493                 bool yn = string_is_affirmative (prop->value());
2494                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2495                 assert (act);
2496                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2497                 bool fs = tact && tact->get_active();
2498                 if (yn ^ fs) {
2499                         ActionManager::do_action ("Common", "ToggleMaximalEditor");
2500                 }
2501         }
2502
2503         if ((prop = node.property ("nudge-clock-value"))) {
2504                 framepos_t f;
2505                 sscanf (prop->value().c_str(), "%" PRId64, &f);
2506                 nudge_clock->set (f);
2507         } else {
2508                 nudge_clock->set_mode (AudioClock::Timecode);
2509                 nudge_clock->set (_session->frame_rate() * 5, true);
2510         }
2511
2512         {
2513                 /* apply state
2514                  * Not all properties may have been in XML, but
2515                  * those that are linked to a private variable may need changing
2516                  */
2517                 RefPtr<Action> act;
2518                 bool yn;
2519
2520                 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2521                 if (act) {
2522                         yn = _show_measures;
2523                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2524                         /* do it twice to force the change */
2525                         tact->set_active (!yn);
2526                         tact->set_active (yn);
2527                 }
2528
2529                 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2530                 yn = _follow_playhead;
2531                 if (act) {
2532                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2533                         if (tact->get_active() != yn) {
2534                                 tact->set_active (yn);
2535                         }
2536                 }
2537
2538                 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2539                 yn = _stationary_playhead;
2540                 if (act) {
2541                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2542                         if (tact->get_active() != yn) {
2543                                 tact->set_active (yn);
2544                         }
2545                 }
2546         }
2547
2548         return LuaInstance::instance()->set_state(node);
2549 }
2550
2551 XMLNode&
2552 Editor::get_state ()
2553 {
2554         XMLNode* node = new XMLNode (X_("Editor"));
2555         char buf[32];
2556
2557         id().print (buf, sizeof (buf));
2558         node->add_property ("id", buf);
2559
2560         node->add_child_nocopy (Tabbable::get_state());
2561
2562         snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2563         node->add_property("edit-horizontal-pane-pos", string(buf));
2564         node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2565         snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2566         node->add_property("edit-vertical-pane-pos", string(buf));
2567
2568         maybe_add_mixer_strip_width (*node);
2569
2570         node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2571
2572         snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2573         node->add_property ("zoom", buf);
2574         node->add_property ("snap-to", enum_2_string (_snap_type));
2575         node->add_property ("snap-mode", enum_2_string (_snap_mode));
2576         node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2577         node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2578         node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2579         node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2580         node->add_property ("edit-point", enum_2_string (_edit_point));
2581         snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2582         node->add_property ("visible-track-count", buf);
2583
2584         snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2585         node->add_property ("playhead", buf);
2586         snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2587         node->add_property ("left-frame", buf);
2588         snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2589         node->add_property ("y-origin", buf);
2590
2591         node->add_property ("show-measures", _show_measures ? "yes" : "no");
2592         node->add_property ("maximised", _maximised ? "yes" : "no");
2593         node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2594         node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2595         node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2596         node->add_property ("mouse-mode", enum2str(mouse_mode));
2597         node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2598
2599         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2600         if (act) {
2601                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2602                 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2603         }
2604
2605         act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2606         if (act) {
2607                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2608                 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2609         }
2610
2611         snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2612         node->add_property (X_("editor-list-page"), buf);
2613
2614         if (button_bindings) {
2615                 XMLNode* bb = new XMLNode (X_("Buttons"));
2616                 button_bindings->save (*bb);
2617                 node->add_child_nocopy (*bb);
2618         }
2619
2620         node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2621
2622         node->add_child_nocopy (selection->get_state ());
2623         node->add_child_nocopy (_regions->get_state ());
2624
2625         snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2626         node->add_property ("nudge-clock-value", buf);
2627
2628         node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2629         node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2630
2631         return *node;
2632 }
2633
2634 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2635  *  if @param trackview_relative_offset is false, @param y y is a global canvas *  coordinate, in pixel units
2636  *
2637  *  @return pair: TimeAxisView that y is over, layer index.
2638  *
2639  *  TimeAxisView may be 0.  Layer index is the layer number if the TimeAxisView is valid and is
2640  *  in stacked or expanded region display mode, otherwise 0.
2641  */
2642 std::pair<TimeAxisView *, double>
2643 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2644 {
2645         if (!trackview_relative_offset) {
2646                 y -= _trackview_group->canvas_origin().y;
2647         }
2648
2649         if (y < 0) {
2650                 return std::make_pair ( (TimeAxisView *) 0, 0);
2651         }
2652
2653         for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2654
2655                 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2656
2657                 if (r.first) {
2658                         return r;
2659                 }
2660         }
2661
2662         return std::make_pair ( (TimeAxisView *) 0, 0);
2663 }
2664
2665 /** Snap a position to the grid, if appropriate, taking into account current
2666  *  grid settings and also the state of any snap modifier keys that may be pressed.
2667  *  @param start Position to snap.
2668  *  @param event Event to get current key modifier information from, or 0.
2669  */
2670 void
2671 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2672 {
2673         if (!_session || !event) {
2674                 return;
2675         }
2676
2677         if (ArdourKeyboard::indicates_snap (event->button.state)) {
2678                 if (_snap_mode == SnapOff) {
2679                         snap_to_internal (start, direction, for_mark);
2680                 }
2681         } else {
2682                 if (_snap_mode != SnapOff) {
2683                         snap_to_internal (start, direction, for_mark);
2684                 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2685                         /* SnapOff, but we pressed the snap_delta modifier */
2686                         snap_to_internal (start, direction, for_mark);
2687                 }
2688         }
2689 }
2690
2691 void
2692 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2693 {
2694         if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2695                 return;
2696         }
2697
2698         snap_to_internal (start, direction, for_mark, ensure_snap);
2699 }
2700
2701 void
2702 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2703 {
2704         const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2705         framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2706
2707         switch (_snap_type) {
2708         case SnapToTimecodeFrame:
2709                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2710                     fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2711                         /* start is already on a whole timecode frame, do nothing */
2712                 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2713                         start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2714                 } else {
2715                         start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) *  _session->frames_per_timecode_frame());
2716                 }
2717                 break;
2718
2719         case SnapToTimecodeSeconds:
2720                 if (_session->config.get_timecode_offset_negative()) {
2721                         start += _session->config.get_timecode_offset ();
2722                 } else {
2723                         start -= _session->config.get_timecode_offset ();
2724                 }
2725                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2726                     (start % one_timecode_second == 0)) {
2727                         /* start is already on a whole second, do nothing */
2728                 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2729                         start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2730                 } else {
2731                         start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2732                 }
2733
2734                 if (_session->config.get_timecode_offset_negative()) {
2735                         start -= _session->config.get_timecode_offset ();
2736                 } else {
2737                         start += _session->config.get_timecode_offset ();
2738                 }
2739                 break;
2740
2741         case SnapToTimecodeMinutes:
2742                 if (_session->config.get_timecode_offset_negative()) {
2743                         start += _session->config.get_timecode_offset ();
2744                 } else {
2745                         start -= _session->config.get_timecode_offset ();
2746                 }
2747                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2748                     (start % one_timecode_minute == 0)) {
2749                         /* start is already on a whole minute, do nothing */
2750                 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2751                         start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2752                 } else {
2753                         start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2754                 }
2755                 if (_session->config.get_timecode_offset_negative()) {
2756                         start -= _session->config.get_timecode_offset ();
2757                 } else {
2758                         start += _session->config.get_timecode_offset ();
2759                 }
2760                 break;
2761         default:
2762                 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2763                 abort(); /*NOTREACHED*/
2764         }
2765 }
2766
2767 void
2768 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2769 {
2770         const framepos_t one_second = _session->frame_rate();
2771         const framepos_t one_minute = _session->frame_rate() * 60;
2772         framepos_t presnap = start;
2773         framepos_t before;
2774         framepos_t after;
2775
2776         switch (_snap_type) {
2777         case SnapToTimecodeFrame:
2778         case SnapToTimecodeSeconds:
2779         case SnapToTimecodeMinutes:
2780                 return timecode_snap_to_internal (start, direction, for_mark);
2781
2782         case SnapToCDFrame:
2783                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2784                     start % (one_second/75) == 0) {
2785                         /* start is already on a whole CD frame, do nothing */
2786                 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2787                         start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2788                 } else {
2789                         start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2790                 }
2791                 break;
2792
2793         case SnapToSeconds:
2794                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2795                     start % one_second == 0) {
2796                         /* start is already on a whole second, do nothing */
2797                 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2798                         start = (framepos_t) ceil ((double) start / one_second) * one_second;
2799                 } else {
2800                         start = (framepos_t) floor ((double) start / one_second) * one_second;
2801                 }
2802                 break;
2803
2804         case SnapToMinutes:
2805                 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2806                     start % one_minute == 0) {
2807                         /* start is already on a whole minute, do nothing */
2808                 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2809                         start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2810                 } else {
2811                         start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2812                 }
2813                 break;
2814
2815         case SnapToBar:
2816                 start = _session->tempo_map().round_to_bar (start, direction);
2817                 break;
2818
2819         case SnapToBeat:
2820                 start = _session->tempo_map().round_to_beat (start, direction);
2821                 break;
2822
2823         case SnapToBeatDiv128:
2824                 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2825                 break;
2826         case SnapToBeatDiv64:
2827                 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2828                 break;
2829         case SnapToBeatDiv32:
2830                 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2831                 break;
2832         case SnapToBeatDiv28:
2833                 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2834                 break;
2835         case SnapToBeatDiv24:
2836                 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2837                 break;
2838         case SnapToBeatDiv20:
2839                 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2840                 break;
2841         case SnapToBeatDiv16:
2842                 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2843                 break;
2844         case SnapToBeatDiv14:
2845                 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2846                 break;
2847         case SnapToBeatDiv12:
2848                 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2849                 break;
2850         case SnapToBeatDiv10:
2851                 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2852                 break;
2853         case SnapToBeatDiv8:
2854                 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2855                 break;
2856         case SnapToBeatDiv7:
2857                 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2858                 break;
2859         case SnapToBeatDiv6:
2860                 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2861                 break;
2862         case SnapToBeatDiv5:
2863                 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2864                 break;
2865         case SnapToBeatDiv4:
2866                 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2867                 break;
2868         case SnapToBeatDiv3:
2869                 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2870                 break;
2871         case SnapToBeatDiv2:
2872                 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2873                 break;
2874
2875         case SnapToMark:
2876                 if (for_mark) {
2877                         return;
2878                 }
2879
2880                 _session->locations()->marks_either_side (start, before, after);
2881
2882                 if (before == max_framepos && after == max_framepos) {
2883                         /* No marks to snap to, so just don't snap */
2884                         return;
2885                 } else if (before == max_framepos) {
2886                         start = after;
2887                 } else if (after == max_framepos) {
2888                         start = before;
2889                 } else if (before != max_framepos && after != max_framepos) {
2890                         /* have before and after */
2891                         if ((start - before) < (after - start)) {
2892                                 start = before;
2893                         } else {
2894                                 start = after;
2895                         }
2896                 }
2897
2898                 break;
2899
2900         case SnapToRegionStart:
2901         case SnapToRegionEnd:
2902         case SnapToRegionSync:
2903         case SnapToRegionBoundary:
2904                 if (!region_boundary_cache.empty()) {
2905
2906                         vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2907                         vector<framepos_t>::iterator next = region_boundary_cache.end ();
2908
2909                         if (direction > 0) {
2910                                 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2911                         } else {
2912                                 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2913                         }
2914
2915                         if (next != region_boundary_cache.begin ()) {
2916                                 prev = next;
2917                                 prev--;
2918                         }
2919
2920                         framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2921                         framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2922
2923                         if (start > (p + n) / 2) {
2924                                 start = n;
2925                         } else {
2926                                 start = p;
2927                         }
2928                 }
2929                 break;
2930         }
2931
2932         switch (_snap_mode) {
2933         case SnapNormal:
2934                 return;
2935
2936         case SnapMagnetic:
2937
2938                 if (ensure_snap) {
2939                         return;
2940                 }
2941
2942                 if (presnap > start) {
2943                         if (presnap > (start + pixel_to_sample(snap_threshold))) {
2944                                 start = presnap;
2945                         }
2946
2947                 } else if (presnap < start) {
2948                         if (presnap < (start - pixel_to_sample(snap_threshold))) {
2949                                 start = presnap;
2950                         }
2951                 }
2952
2953         default:
2954                 /* handled at entry */
2955                 return;
2956
2957         }
2958 }
2959
2960
2961 void
2962 Editor::setup_toolbar ()
2963 {
2964         HBox* mode_box = manage(new HBox);
2965         mode_box->set_border_width (2);
2966         mode_box->set_spacing(2);
2967
2968         HBox* mouse_mode_box = manage (new HBox);
2969         HBox* mouse_mode_hbox = manage (new HBox);
2970         VBox* mouse_mode_vbox = manage (new VBox);
2971         Alignment* mouse_mode_align = manage (new Alignment);
2972
2973         Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2974         mouse_mode_size_group->add_widget (smart_mode_button);
2975         mouse_mode_size_group->add_widget (mouse_move_button);
2976         mouse_mode_size_group->add_widget (mouse_cut_button);
2977         mouse_mode_size_group->add_widget (mouse_select_button);
2978         mouse_mode_size_group->add_widget (mouse_timefx_button);
2979         mouse_mode_size_group->add_widget (mouse_audition_button);
2980         mouse_mode_size_group->add_widget (mouse_draw_button);
2981         mouse_mode_size_group->add_widget (mouse_content_button);
2982
2983         mouse_mode_size_group->add_widget (zoom_in_button);
2984         mouse_mode_size_group->add_widget (zoom_out_button);
2985         mouse_mode_size_group->add_widget (zoom_preset_selector);
2986         mouse_mode_size_group->add_widget (zoom_out_full_button);
2987         mouse_mode_size_group->add_widget (zoom_focus_selector);
2988
2989         mouse_mode_size_group->add_widget (tav_shrink_button);
2990         mouse_mode_size_group->add_widget (tav_expand_button);
2991         mouse_mode_size_group->add_widget (visible_tracks_selector);
2992
2993         mouse_mode_size_group->add_widget (snap_type_selector);
2994         mouse_mode_size_group->add_widget (snap_mode_selector);
2995
2996         mouse_mode_size_group->add_widget (edit_point_selector);
2997         mouse_mode_size_group->add_widget (edit_mode_selector);
2998
2999         mouse_mode_size_group->add_widget (*nudge_clock);
3000         mouse_mode_size_group->add_widget (nudge_forward_button);
3001         mouse_mode_size_group->add_widget (nudge_backward_button);
3002
3003         mouse_mode_hbox->set_spacing (2);
3004
3005         if (!ARDOUR::Profile->get_trx()) {
3006                 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3007         }
3008
3009         mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3010         mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3011
3012         if (!ARDOUR::Profile->get_mixbus()) {
3013                 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3014         }
3015
3016         if (!ARDOUR::Profile->get_trx()) {
3017                 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3018                 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3019                 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3020                 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3021         }
3022
3023         mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3024
3025         mouse_mode_align->add (*mouse_mode_vbox);
3026         mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3027
3028         mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3029
3030         edit_mode_selector.set_name ("mouse mode button");
3031
3032         if (!ARDOUR::Profile->get_trx()) {
3033                 mode_box->pack_start (edit_mode_selector, false, false);
3034         }
3035
3036         mode_box->pack_start (*mouse_mode_box, false, false);
3037
3038         /* Zoom */
3039
3040         _zoom_box.set_spacing (2);
3041         _zoom_box.set_border_width (2);
3042
3043         RefPtr<Action> act;
3044
3045         zoom_preset_selector.set_name ("zoom button");
3046         zoom_preset_selector.set_image(::get_icon ("time_exp"));
3047         zoom_preset_selector.set_size_request (42, -1);
3048
3049         zoom_in_button.set_name ("zoom button");
3050         zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3051         act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3052         zoom_in_button.set_related_action (act);
3053
3054         zoom_out_button.set_name ("zoom button");
3055         zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3056         act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3057         zoom_out_button.set_related_action (act);
3058
3059         zoom_out_full_button.set_name ("zoom button");
3060         zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3061         act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3062         zoom_out_full_button.set_related_action (act);
3063
3064         zoom_focus_selector.set_name ("zoom button");
3065
3066         if (ARDOUR::Profile->get_mixbus()) {
3067                 _zoom_box.pack_start (zoom_preset_selector, false, false);
3068         } else if (ARDOUR::Profile->get_trx()) {
3069                 mode_box->pack_start (zoom_out_button, false, false);
3070                 mode_box->pack_start (zoom_in_button, false, false);
3071         } else {
3072                 _zoom_box.pack_start (zoom_out_button, false, false);
3073                 _zoom_box.pack_start (zoom_in_button, false, false);
3074                 _zoom_box.pack_start (zoom_out_full_button, false, false);
3075                 _zoom_box.pack_start (zoom_focus_selector, false, false);
3076         }
3077
3078         /* Track zoom buttons */
3079         visible_tracks_selector.set_name ("zoom button");
3080         if (Profile->get_mixbus()) {
3081                 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3082                 visible_tracks_selector.set_size_request (42, -1);
3083         } else {
3084                 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3085         }
3086
3087         tav_expand_button.set_name ("zoom button");
3088         tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3089         act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3090         tav_expand_button.set_related_action (act);
3091
3092         tav_shrink_button.set_name ("zoom button");
3093         tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3094         act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3095         tav_shrink_button.set_related_action (act);
3096
3097         if (ARDOUR::Profile->get_mixbus()) {
3098                 _zoom_box.pack_start (visible_tracks_selector);
3099         } else if (ARDOUR::Profile->get_trx()) {
3100                 _zoom_box.pack_start (tav_shrink_button);
3101                 _zoom_box.pack_start (tav_expand_button);
3102         } else {
3103                 _zoom_box.pack_start (visible_tracks_selector);
3104                 _zoom_box.pack_start (tav_shrink_button);
3105                 _zoom_box.pack_start (tav_expand_button);
3106         }
3107
3108         snap_box.set_spacing (2);
3109         snap_box.set_border_width (2);
3110
3111         snap_type_selector.set_name ("mouse mode button");
3112
3113         snap_mode_selector.set_name ("mouse mode button");
3114
3115         edit_point_selector.set_name ("mouse mode button");
3116
3117         snap_box.pack_start (snap_mode_selector, false, false);
3118         snap_box.pack_start (snap_type_selector, false, false);
3119         snap_box.pack_start (edit_point_selector, false, false);
3120
3121         /* Nudge */
3122
3123         HBox *nudge_box = manage (new HBox);
3124         nudge_box->set_spacing (2);
3125         nudge_box->set_border_width (2);
3126
3127         nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3128         nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3129
3130         nudge_box->pack_start (nudge_backward_button, false, false);
3131         nudge_box->pack_start (nudge_forward_button, false, false);
3132         nudge_box->pack_start (*nudge_clock, false, false);
3133
3134
3135         /* Pack everything in... */
3136
3137         HBox* hbox = manage (new HBox);
3138         hbox->set_spacing(2);
3139
3140         toolbar_hbox.set_spacing (2);
3141         toolbar_hbox.set_border_width (1);
3142
3143         toolbar_hbox.pack_start (*mode_box, false, false);
3144         if (!ARDOUR::Profile->get_trx()) {
3145                 toolbar_hbox.pack_start (_zoom_box, false, false);
3146                 toolbar_hbox.pack_start (*hbox, false, false);
3147         }
3148
3149         if (!ARDOUR::Profile->get_trx()) {
3150                 hbox->pack_start (snap_box, false, false);
3151                 hbox->pack_start (*nudge_box, false, false);
3152         }
3153
3154         hbox->show_all ();
3155
3156         toolbar_base.set_name ("ToolBarBase");
3157         toolbar_base.add (toolbar_hbox);
3158
3159         _toolbar_viewport.add (toolbar_base);
3160         /* stick to the required height but allow width to vary if there's not enough room */
3161         _toolbar_viewport.set_size_request (1, -1);
3162
3163         toolbar_frame.set_shadow_type (SHADOW_OUT);
3164         toolbar_frame.set_name ("BaseFrame");
3165         toolbar_frame.add (_toolbar_viewport);
3166 }
3167
3168 void
3169 Editor::build_edit_point_menu ()
3170 {
3171         using namespace Menu_Helpers;
3172
3173         edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3174         if(!Profile->get_mixbus())
3175                 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3176         edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3177
3178         set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3179 }
3180
3181 void
3182 Editor::build_edit_mode_menu ()
3183 {
3184         using namespace Menu_Helpers;
3185
3186         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3187 //      edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3188         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3189         edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode)  Lock)));
3190
3191         set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3192 }
3193
3194 void
3195 Editor::build_snap_mode_menu ()
3196 {
3197         using namespace Menu_Helpers;
3198
3199         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3200         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3201         snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3202
3203         set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3204 }
3205
3206 void
3207 Editor::build_snap_type_menu ()
3208 {
3209         using namespace Menu_Helpers;
3210
3211         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3212         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3213         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3214         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3215         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3216         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3217         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3218         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3219         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3220         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3221         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3222         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3223         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3224         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3225         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3226         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3227         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3228         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3229         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3230         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3231         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3232         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3233         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3234         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3235         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3236         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3237         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3238         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3239         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3240         snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3241
3242         set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3243
3244 }
3245
3246 void
3247 Editor::setup_tooltips ()
3248 {
3249         set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3250         set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3251         set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3252         set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3253         set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3254         set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3255         set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3256         set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3257         set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3258         set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3259         set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3260         set_tooltip (zoom_in_button, _("Zoom In"));
3261         set_tooltip (zoom_out_button, _("Zoom Out"));
3262         set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3263         set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3264         set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3265         set_tooltip (tav_expand_button, _("Expand Tracks"));
3266         set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3267         set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3268         set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3269         set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3270         set_tooltip (edit_point_selector, _("Edit Point"));
3271         set_tooltip (edit_mode_selector, _("Edit Mode"));
3272         set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3273 }
3274
3275 int
3276 Editor::convert_drop_to_paths (
3277                 vector<string>&                paths,
3278                 const RefPtr<Gdk::DragContext>& /*context*/,
3279                 gint                            /*x*/,
3280                 gint                            /*y*/,
3281                 const SelectionData&            data,
3282                 guint                           /*info*/,
3283                 guint                           /*time*/)
3284 {
3285         if (_session == 0) {
3286                 return -1;
3287         }
3288
3289         vector<string> uris = data.get_uris();
3290
3291         if (uris.empty()) {
3292
3293                 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3294                    are actually URI lists. So do it by hand.
3295                 */
3296
3297                 if (data.get_target() != "text/plain") {
3298                         return -1;
3299                 }
3300
3301                 /* Parse the "uri-list" format that Nautilus provides,
3302                    where each pathname is delimited by \r\n.
3303
3304                    THERE MAY BE NO NULL TERMINATING CHAR!!!
3305                 */
3306
3307                 string txt = data.get_text();
3308                 char* p;
3309                 const char* q;
3310
3311                 p = (char *) malloc (txt.length() + 1);
3312                 txt.copy (p, txt.length(), 0);
3313                 p[txt.length()] = '\0';
3314
3315                 while (p)
3316                 {
3317                         if (*p != '#')
3318                         {
3319                                 while (g_ascii_isspace (*p))
3320                                         p++;
3321
3322                                 q = p;
3323                                 while (*q && (*q != '\n') && (*q != '\r')) {
3324                                         q++;
3325                                 }
3326
3327                                 if (q > p)
3328                                 {
3329                                         q--;
3330                                         while (q > p && g_ascii_isspace (*q))
3331                                                 q--;
3332
3333                                         if (q > p)
3334                                         {
3335                                                 uris.push_back (string (p, q - p + 1));
3336                                         }
3337                                 }
3338                         }
3339                         p = strchr (p, '\n');
3340                         if (p)
3341                                 p++;
3342                 }
3343
3344                 free ((void*)p);
3345
3346                 if (uris.empty()) {
3347                         return -1;
3348                 }
3349         }
3350
3351         for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3352                 if ((*i).substr (0,7) == "file://") {
3353                         paths.push_back (Glib::filename_from_uri (*i));
3354                 }
3355         }
3356
3357         return 0;
3358 }
3359
3360 void
3361 Editor::new_tempo_section ()
3362 {
3363 }
3364
3365 void
3366 Editor::map_transport_state ()
3367 {
3368         ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3369
3370         if (_session && _session->transport_stopped()) {
3371                 have_pending_keyboard_selection = false;
3372         }
3373
3374         update_loop_range_view ();
3375 }
3376
3377 /* UNDO/REDO */
3378
3379 void
3380 Editor::begin_selection_op_history ()
3381 {
3382         selection_op_cmd_depth = 0;
3383         selection_op_history_it = 0;
3384
3385         while(!selection_op_history.empty()) {
3386                 delete selection_op_history.front();
3387                 selection_op_history.pop_front();
3388         }
3389
3390         selection_undo_action->set_sensitive (false);
3391         selection_redo_action->set_sensitive (false);
3392         selection_op_history.push_front (&_selection_memento->get_state ());
3393 }
3394
3395 void
3396 Editor::begin_reversible_selection_op (string name)
3397 {
3398         if (_session) {
3399                 //cerr << name << endl;
3400                 /* begin/commit pairs can be nested */
3401                 selection_op_cmd_depth++;
3402         }
3403 }
3404
3405 void
3406 Editor::commit_reversible_selection_op ()
3407 {
3408         if (_session) {
3409                 if (selection_op_cmd_depth == 1) {
3410
3411                         if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3412                                 /**
3413                                     The user has undone some selection ops and then made a new one,
3414                                     making anything earlier in the list invalid.
3415                                 */
3416
3417                                 list<XMLNode *>::iterator it = selection_op_history.begin();
3418                                 list<XMLNode *>::iterator e_it = it;
3419                                 advance (e_it, selection_op_history_it);
3420
3421                                 for ( ; it != e_it; ++it) {
3422                                         delete *it;
3423                                 }
3424                                 selection_op_history.erase (selection_op_history.begin(), e_it);
3425                         }
3426
3427                         selection_op_history.push_front (&_selection_memento->get_state ());
3428                         selection_op_history_it = 0;
3429
3430                         selection_undo_action->set_sensitive (true);
3431                         selection_redo_action->set_sensitive (false);
3432                 }
3433
3434                 if (selection_op_cmd_depth > 0) {
3435                         selection_op_cmd_depth--;
3436                 }
3437         }
3438 }
3439
3440 void
3441 Editor::undo_selection_op ()
3442 {
3443         if (_session) {
3444                 selection_op_history_it++;
3445                 uint32_t n = 0;
3446                 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3447                         if (n == selection_op_history_it) {
3448                                 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3449                                 selection_redo_action->set_sensitive (true);
3450                         }
3451                         ++n;
3452                 }
3453                 /* is there an earlier entry? */
3454                 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3455                         selection_undo_action->set_sensitive (false);
3456                 }
3457         }
3458 }
3459
3460 void
3461 Editor::redo_selection_op ()
3462 {
3463         if (_session) {
3464                 if (selection_op_history_it > 0) {
3465                         selection_op_history_it--;
3466                 }
3467                 uint32_t n = 0;
3468                 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3469                         if (n == selection_op_history_it) {
3470                                 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3471                                 selection_undo_action->set_sensitive (true);
3472                         }
3473                         ++n;
3474                 }
3475
3476                 if (selection_op_history_it == 0) {
3477                         selection_redo_action->set_sensitive (false);
3478                 }
3479         }
3480 }
3481
3482 void
3483 Editor::begin_reversible_command (string name)
3484 {
3485         if (_session) {
3486                 before.push_back (&_selection_memento->get_state ());
3487                 _session->begin_reversible_command (name);
3488         }
3489 }
3490
3491 void
3492 Editor::begin_reversible_command (GQuark q)
3493 {
3494         if (_session) {
3495                 before.push_back (&_selection_memento->get_state ());
3496                 _session->begin_reversible_command (q);
3497         }
3498 }
3499
3500 void
3501 Editor::abort_reversible_command ()
3502 {
3503         if (_session) {
3504                 while(!before.empty()) {
3505                         delete before.front();
3506                         before.pop_front();
3507                 }
3508                 _session->abort_reversible_command ();
3509         }
3510 }
3511
3512 void
3513 Editor::commit_reversible_command ()
3514 {
3515         if (_session) {
3516                 if (before.size() == 1) {
3517                         _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3518                         redo_action->set_sensitive(false);
3519                         undo_action->set_sensitive(true);
3520                         begin_selection_op_history ();
3521                 }
3522
3523                 if (before.empty()) {
3524                         cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3525                 } else {
3526                         before.pop_back();
3527                 }
3528
3529                 _session->commit_reversible_command ();
3530         }
3531 }
3532
3533 void
3534 Editor::history_changed ()
3535 {
3536         string label;
3537
3538         if (undo_action && _session) {
3539                 if (_session->undo_depth() == 0) {
3540                         label = S_("Command|Undo");
3541                 } else {
3542                         label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3543                 }
3544                 undo_action->property_label() = label;
3545         }
3546
3547         if (redo_action && _session) {
3548                 if (_session->redo_depth() == 0) {
3549                         label = _("Redo");
3550                         redo_action->set_sensitive (false);
3551                 } else {
3552                         label = string_compose(_("Redo (%1)"), _session->next_redo());
3553                         redo_action->set_sensitive (true);
3554                 }
3555                 redo_action->property_label() = label;
3556         }
3557 }
3558
3559 void
3560 Editor::duplicate_range (bool with_dialog)
3561 {
3562         float times = 1.0f;
3563
3564         RegionSelection rs = get_regions_from_selection_and_entered ();
3565
3566         if ( selection->time.length() == 0 && rs.empty()) {
3567                 return;
3568         }
3569
3570         if (with_dialog) {
3571
3572                 ArdourDialog win (_("Duplicate"));
3573                 Label label (_("Number of duplications:"));
3574                 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3575                 SpinButton spinner (adjustment, 0.0, 1);
3576                 HBox hbox;
3577
3578                 win.get_vbox()->set_spacing (12);
3579                 win.get_vbox()->pack_start (hbox);
3580                 hbox.set_border_width (6);
3581                 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3582
3583                 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3584                    place, visually. so do this by hand.
3585                 */
3586
3587                 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3588                 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3589                 spinner.grab_focus();
3590
3591                 hbox.show ();
3592                 label.show ();
3593                 spinner.show ();
3594
3595                 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3596                 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3597                 win.set_default_response (RESPONSE_ACCEPT);
3598
3599                 spinner.grab_focus ();
3600
3601                 switch (win.run ()) {
3602                 case RESPONSE_ACCEPT:
3603                         break;
3604                 default:
3605                         return;
3606                 }
3607
3608                 times = adjustment.get_value();
3609         }
3610
3611         if ((current_mouse_mode() == Editing::MouseRange)) {
3612                 if (selection->time.length()) {
3613                         duplicate_selection (times);
3614                 }
3615         } else if (get_smart_mode()) {
3616                 if (selection->time.length()) {
3617                         duplicate_selection (times);
3618                 } else
3619                         duplicate_some_regions (rs, times);
3620         } else {
3621                 duplicate_some_regions (rs, times);
3622         }
3623 }
3624
3625 void
3626 Editor::set_edit_mode (EditMode m)
3627 {
3628         Config->set_edit_mode (m);
3629 }
3630
3631 void
3632 Editor::cycle_edit_mode ()
3633 {
3634         switch (Config->get_edit_mode()) {
3635         case Slide:
3636                 Config->set_edit_mode (Ripple);
3637                 break;
3638         case Splice:
3639         case Ripple:
3640                 Config->set_edit_mode (Lock);
3641                 break;
3642         case Lock:
3643                 Config->set_edit_mode (Slide);
3644                 break;
3645         }
3646 }
3647
3648 void
3649 Editor::edit_mode_selection_done ( EditMode m )
3650 {
3651         Config->set_edit_mode ( m );
3652 }
3653
3654 void
3655 Editor::snap_type_selection_done (SnapType snaptype)
3656 {
3657         RefPtr<RadioAction> ract = snap_type_action (snaptype);
3658         if (ract) {
3659                 ract->set_active ();
3660         }
3661 }
3662
3663 void
3664 Editor::snap_mode_selection_done (SnapMode mode)
3665 {
3666         RefPtr<RadioAction> ract = snap_mode_action (mode);
3667
3668         if (ract) {
3669                 ract->set_active (true);
3670         }
3671 }
3672
3673 void
3674 Editor::cycle_edit_point (bool with_marker)
3675 {
3676         if(Profile->get_mixbus())
3677                 with_marker = false;
3678
3679         switch (_edit_point) {
3680         case EditAtMouse:
3681                 set_edit_point_preference (EditAtPlayhead);
3682                 break;
3683         case EditAtPlayhead:
3684                 if (with_marker) {
3685                         set_edit_point_preference (EditAtSelectedMarker);
3686                 } else {
3687                         set_edit_point_preference (EditAtMouse);
3688                 }
3689                 break;
3690         case EditAtSelectedMarker:
3691                 set_edit_point_preference (EditAtMouse);
3692                 break;
3693         }
3694 }
3695
3696 void
3697 Editor::edit_point_selection_done (EditPoint ep)
3698 {
3699         set_edit_point_preference ( ep );
3700 }
3701
3702 void
3703 Editor::build_zoom_focus_menu ()
3704 {
3705         using namespace Menu_Helpers;
3706
3707         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3708         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3709         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3710         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3711         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3712         zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3713
3714         set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3715 }
3716
3717 void
3718 Editor::zoom_focus_selection_done ( ZoomFocus f )
3719 {
3720         RefPtr<RadioAction> ract = zoom_focus_action (f);
3721         if (ract) {
3722                 ract->set_active ();
3723         }
3724 }
3725
3726 void
3727 Editor::build_track_count_menu ()
3728 {
3729         using namespace Menu_Helpers;
3730
3731         if (!Profile->get_mixbus()) {
3732                 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3733                 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3734                 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3735                 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3736                 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3737                 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3738                 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3739                 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3740                 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3741                 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3742                 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3743                 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3744                 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3745         } else {
3746                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3747                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3748                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3749                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3750                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3751                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3752                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3753                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3754                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3755                 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3756
3757                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3758                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3759                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3760                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3761                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3762                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3763                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3764                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3765                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3766                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3767                 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3768         }
3769 }
3770
3771 void
3772 Editor::set_zoom_preset (int64_t ms)
3773 {
3774         if ( ms <= 0 ) {
3775                 temporal_zoom_session();
3776                 return;
3777         }
3778
3779         ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3780         temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3781 }
3782
3783 void
3784 Editor::set_visible_track_count (int32_t n)
3785 {
3786         _visible_track_count = n;
3787
3788         /* if the canvas hasn't really been allocated any size yet, just
3789            record the desired number of visible tracks and return. when canvas
3790            allocation happens, we will get called again and then we can do the
3791            real work.
3792         */
3793
3794         if (_visible_canvas_height <= 1) {
3795                 return;
3796         }
3797
3798         int h;
3799         string str;
3800         DisplaySuspender ds;
3801
3802         if (_visible_track_count > 0) {
3803                 h = trackviews_height() / _visible_track_count;
3804                 std::ostringstream s;
3805                 s << _visible_track_count;
3806                 str = s.str();
3807         } else if (_visible_track_count == 0) {
3808                 uint32_t n = 0;
3809                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3810                         if ((*i)->marked_for_display()) {
3811                                 ++n;
3812                         }
3813                 }
3814                 h = trackviews_height() / n;
3815                 str = _("All");
3816         } else {
3817                 /* negative value means that the visible track count has
3818                    been overridden by explicit track height changes.
3819                 */
3820                 visible_tracks_selector.set_text (X_("*"));
3821                 return;
3822         }
3823
3824         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3825                 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3826         }
3827
3828         if (str != visible_tracks_selector.get_text()) {
3829                 visible_tracks_selector.set_text (str);
3830         }
3831 }
3832
3833 void
3834 Editor::override_visible_track_count ()
3835 {
3836         _visible_track_count = -1;
3837         visible_tracks_selector.set_text ( _("*") );
3838 }
3839
3840 bool
3841 Editor::edit_controls_button_release (GdkEventButton* ev)
3842 {
3843         if (Keyboard::is_context_menu_event (ev)) {
3844                 ARDOUR_UI::instance()->add_route ();
3845         } else if (ev->button == 1) {
3846                 selection->clear_tracks ();
3847         }
3848
3849         return true;
3850 }
3851
3852 bool
3853 Editor::mouse_select_button_release (GdkEventButton* ev)
3854 {
3855         /* this handles just right-clicks */
3856
3857         if (ev->button != 3) {
3858                 return false;
3859         }
3860
3861         return true;
3862 }
3863
3864 void
3865 Editor::set_zoom_focus (ZoomFocus f)
3866 {
3867         string str = zoom_focus_strings[(int)f];
3868
3869         if (str != zoom_focus_selector.get_text()) {
3870                 zoom_focus_selector.set_text (str);
3871         }
3872
3873         if (zoom_focus != f) {
3874                 zoom_focus = f;
3875                 instant_save ();
3876         }
3877 }
3878
3879 void
3880 Editor::cycle_zoom_focus ()
3881 {
3882         switch (zoom_focus) {
3883         case ZoomFocusLeft:
3884                 set_zoom_focus (ZoomFocusRight);
3885                 break;
3886         case ZoomFocusRight:
3887                 set_zoom_focus (ZoomFocusCenter);
3888                 break;
3889         case ZoomFocusCenter:
3890                 set_zoom_focus (ZoomFocusPlayhead);
3891                 break;
3892         case ZoomFocusPlayhead:
3893                 set_zoom_focus (ZoomFocusMouse);
3894                 break;
3895         case ZoomFocusMouse:
3896                 set_zoom_focus (ZoomFocusEdit);
3897                 break;
3898         case ZoomFocusEdit:
3899                 set_zoom_focus (ZoomFocusLeft);
3900                 break;
3901         }
3902 }
3903
3904 void
3905 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3906 {
3907         /* recover or initialize pane positions. do this here rather than earlier because
3908            we don't want the positions to change the child allocations, which they seem to do.
3909          */
3910
3911         int pos;
3912         XMLProperty const * prop;
3913         char buf[32];
3914         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3915
3916         enum Pane {
3917                 Horizontal = 0x1,
3918                 Vertical = 0x2
3919         };
3920
3921         static Pane done;
3922
3923         XMLNode* geometry = find_named_node (*node, "geometry");
3924
3925         if (which == static_cast<Paned*> (&edit_pane)) {
3926
3927                 if (done & Horizontal) {
3928                         return;
3929                 }
3930
3931                 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3932                         _notebook_shrunk = string_is_affirmative (prop->value ());
3933                 }
3934
3935                 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3936                         /* initial allocation is 90% to canvas, 10% to notebook */
3937                         pos = (int) floor (alloc.get_width() * 0.90f);
3938                         snprintf (buf, sizeof(buf), "%d", pos);
3939                 } else {
3940                         pos = atoi (prop->value());
3941                 }
3942
3943                 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3944                         edit_pane.set_position (pos);
3945                 }
3946
3947                 done = (Pane) (done | Horizontal);
3948
3949         } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3950
3951                 if (done & Vertical) {
3952                         return;
3953                 }
3954
3955                 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3956                         /* initial allocation is 90% to canvas, 10% to summary */
3957                         pos = (int) floor (alloc.get_height() * 0.90f);
3958                         snprintf (buf, sizeof(buf), "%d", pos);
3959                 } else {
3960
3961                         pos = atoi (prop->value());
3962                 }
3963
3964                 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3965                         editor_summary_pane.set_position (pos);
3966                 }
3967
3968                 done = (Pane) (done | Vertical);
3969         }
3970 }
3971
3972 void
3973 Editor::set_show_measures (bool yn)
3974 {
3975         if (_show_measures != yn) {
3976                 hide_measures ();
3977
3978                 if ((_show_measures = yn) == true) {
3979                         if (tempo_lines) {
3980                                 tempo_lines->show();
3981                         }
3982
3983                         std::vector<TempoMap::BBTPoint> grid;
3984                         compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3985                         draw_measures (grid);
3986                 }
3987
3988                 instant_save ();
3989         }
3990 }
3991
3992 void
3993 Editor::toggle_follow_playhead ()
3994 {
3995         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3996         if (act) {
3997                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3998                 set_follow_playhead (tact->get_active());
3999         }
4000 }
4001
4002 /** @param yn true to follow playhead, otherwise false.
4003  *  @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4004  */
4005 void
4006 Editor::set_follow_playhead (bool yn, bool catch_up)
4007 {
4008         if (_follow_playhead != yn) {
4009                 if ((_follow_playhead = yn) == true && catch_up) {
4010                         /* catch up */
4011                         reset_x_origin_to_follow_playhead ();
4012                 }
4013                 instant_save ();
4014         }
4015 }
4016
4017 void
4018 Editor::toggle_stationary_playhead ()
4019 {
4020         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4021         if (act) {
4022                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4023                 set_stationary_playhead (tact->get_active());
4024         }
4025 }
4026
4027 void
4028 Editor::set_stationary_playhead (bool yn)
4029 {
4030         if (_stationary_playhead != yn) {
4031                 if ((_stationary_playhead = yn) == true) {
4032                         /* catch up */
4033                         // FIXME need a 3.0 equivalent of this 2.X call
4034                         // update_current_screen ();
4035                 }
4036                 instant_save ();
4037         }
4038 }
4039
4040 PlaylistSelector&
4041 Editor::playlist_selector () const
4042 {
4043         return *_playlist_selector;
4044 }
4045
4046 framecnt_t
4047 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4048 {
4049         if (paste_count == 0) {
4050                 /* don't bother calculating an offset that will be zero anyway */
4051                 return 0;
4052         }
4053
4054         /* calculate basic unsnapped multi-paste offset */
4055         framecnt_t offset = paste_count * duration;
4056
4057         /* snap offset so pos + offset is aligned to the grid */
4058         framepos_t offset_pos = pos + offset;
4059         snap_to(offset_pos, RoundUpMaybe);
4060         offset = offset_pos - pos;
4061
4062         return offset;
4063 }
4064
4065 unsigned
4066 Editor::get_grid_beat_divisions(framepos_t position)
4067 {
4068         switch (_snap_type) {
4069         case SnapToBeatDiv128: return 128;
4070         case SnapToBeatDiv64:  return 64;
4071         case SnapToBeatDiv32:  return 32;
4072         case SnapToBeatDiv28:  return 28;
4073         case SnapToBeatDiv24:  return 24;
4074         case SnapToBeatDiv20:  return 20;
4075         case SnapToBeatDiv16:  return 16;
4076         case SnapToBeatDiv14:  return 14;
4077         case SnapToBeatDiv12:  return 12;
4078         case SnapToBeatDiv10:  return 10;
4079         case SnapToBeatDiv8:   return 8;
4080         case SnapToBeatDiv7:   return 7;
4081         case SnapToBeatDiv6:   return 6;
4082         case SnapToBeatDiv5:   return 5;
4083         case SnapToBeatDiv4:   return 4;
4084         case SnapToBeatDiv3:   return 3;
4085         case SnapToBeatDiv2:   return 2;
4086         default:               return 0;
4087         }
4088         return 0;
4089 }
4090
4091 Evoral::Beats
4092 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4093 {
4094         success = true;
4095
4096         const unsigned divisions = get_grid_beat_divisions(position);
4097         if (divisions) {
4098                 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4099         }
4100
4101         switch (_snap_type) {
4102         case SnapToBeat:
4103                 return Evoral::Beats(1.0);
4104         case SnapToBar:
4105                 if (_session) {
4106                         return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
4107                 }
4108                 break;
4109         default:
4110                 success = false;
4111                 break;
4112         }
4113
4114         return Evoral::Beats();
4115 }
4116
4117 framecnt_t
4118 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4119 {
4120         framecnt_t ret;
4121
4122         ret = nudge_clock->current_duration (pos);
4123         next = ret + 1; /* XXXX fix me */
4124
4125         return ret;
4126 }
4127
4128 int
4129 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4130 {
4131         ArdourDialog dialog (_("Playlist Deletion"));
4132         Label  label (string_compose (_("Playlist %1 is currently unused.\n"
4133                                         "If it is kept, its audio files will not be cleaned.\n"
4134                                         "If it is deleted, audio files used by it alone will be cleaned."),
4135                                       pl->name()));
4136
4137         dialog.set_position (WIN_POS_CENTER);
4138         dialog.get_vbox()->pack_start (label);
4139
4140         label.show ();
4141
4142         dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4143         dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4144         Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4145         dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4146         dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4147
4148         // by default gtk uses the left most button
4149         keep->grab_focus ();
4150
4151         switch (dialog.run ()) {
4152         case RESPONSE_NO:
4153                 /* keep this and all remaining ones */
4154                 return -2;
4155                 break;
4156
4157         case RESPONSE_YES:
4158                 /* delete this and all others */
4159                 return 2;
4160                 break;
4161
4162         case RESPONSE_ACCEPT:
4163                 /* delete the playlist */
4164                 return 1;
4165                 break;
4166
4167         case RESPONSE_REJECT:
4168                 /* keep the playlist */
4169                 return 0;
4170                 break;
4171
4172         default:
4173                 break;
4174         }
4175
4176         return -1;
4177 }
4178
4179 bool
4180 Editor::audio_region_selection_covers (framepos_t where)
4181 {
4182         for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4183                 if ((*a)->region()->covers (where)) {
4184                         return true;
4185                 }
4186         }
4187
4188         return false;
4189 }
4190
4191 void
4192 Editor::prepare_for_cleanup ()
4193 {
4194         cut_buffer->clear_regions ();
4195         cut_buffer->clear_playlists ();
4196
4197         selection->clear_regions ();
4198         selection->clear_playlists ();
4199
4200         _regions->suspend_redisplay ();
4201 }
4202
4203 void
4204 Editor::finish_cleanup ()
4205 {
4206         _regions->resume_redisplay ();
4207 }
4208
4209 Location*
4210 Editor::transport_loop_location()
4211 {
4212         if (_session) {
4213                 return _session->locations()->auto_loop_location();
4214         } else {
4215                 return 0;
4216         }
4217 }
4218
4219 Location*
4220 Editor::transport_punch_location()
4221 {
4222         if (_session) {
4223                 return _session->locations()->auto_punch_location();
4224         } else {
4225                 return 0;
4226         }
4227 }
4228
4229 bool
4230 Editor::control_layout_scroll (GdkEventScroll* ev)
4231 {
4232         /* Just forward to the normal canvas scroll method. The coordinate
4233            systems are different but since the canvas is always larger than the
4234            track headers, and aligned with the trackview area, this will work.
4235
4236            In the not too distant future this layout is going away anyway and
4237            headers will be on the canvas.
4238         */
4239         return canvas_scroll_event (ev, false);
4240 }
4241
4242 void
4243 Editor::session_state_saved (string)
4244 {
4245         update_title ();
4246         _snapshots->redisplay ();
4247 }
4248
4249 void
4250 Editor::maximise_editing_space ()
4251 {
4252         if (_maximised) {
4253                 return;
4254         }
4255
4256         Gtk::Window* toplevel = current_toplevel();
4257
4258         if (toplevel) {
4259                 toplevel->fullscreen ();
4260                 _maximised = true;
4261         }
4262 }
4263
4264 void
4265 Editor::restore_editing_space ()
4266 {
4267         if (!_maximised) {
4268                 return;
4269         }
4270
4271         Gtk::Window* toplevel = current_toplevel();
4272
4273         if (toplevel) {
4274                 toplevel->unfullscreen();
4275                 _maximised = false;
4276         }
4277 }
4278
4279 /**
4280  *  Make new playlists for a given track and also any others that belong
4281  *  to the same active route group with the `select' property.
4282  *  @param v Track.
4283  */
4284
4285 void
4286 Editor::new_playlists (TimeAxisView* v)
4287 {
4288         begin_reversible_command (_("new playlists"));
4289         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4290         _session->playlists->get (playlists);
4291         mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4292         commit_reversible_command ();
4293 }
4294
4295 /**
4296  *  Use a copy of the current playlist for a given track and also any others that belong
4297  *  to the same active route group with the `select' property.
4298  *  @param v Track.
4299  */
4300
4301 void
4302 Editor::copy_playlists (TimeAxisView* v)
4303 {
4304         begin_reversible_command (_("copy playlists"));
4305         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4306         _session->playlists->get (playlists);
4307         mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4308         commit_reversible_command ();
4309 }
4310
4311 /** Clear the current playlist for a given track and also any others that belong
4312  *  to the same active route group with the `select' property.
4313  *  @param v Track.
4314  */
4315
4316 void
4317 Editor::clear_playlists (TimeAxisView* v)
4318 {
4319         begin_reversible_command (_("clear playlists"));
4320         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4321         _session->playlists->get (playlists);
4322         mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4323         commit_reversible_command ();
4324 }
4325
4326 void
4327 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4328 {
4329         atv.use_new_playlist (sz > 1 ? false : true, playlists);
4330 }
4331
4332 void
4333 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4334 {
4335         atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4336 }
4337
4338 void
4339 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4340 {
4341         atv.clear_playlist ();
4342 }
4343
4344 double
4345 Editor::get_y_origin () const
4346 {
4347         return vertical_adjustment.get_value ();
4348 }
4349
4350 /** Queue up a change to the viewport x origin.
4351  *  @param frame New x origin.
4352  */
4353 void
4354 Editor::reset_x_origin (framepos_t frame)
4355 {
4356         pending_visual_change.add (VisualChange::TimeOrigin);
4357         pending_visual_change.time_origin = frame;
4358         ensure_visual_change_idle_handler ();
4359 }
4360
4361 void
4362 Editor::reset_y_origin (double y)
4363 {
4364         pending_visual_change.add (VisualChange::YOrigin);
4365         pending_visual_change.y_origin = y;
4366         ensure_visual_change_idle_handler ();
4367 }
4368
4369 void
4370 Editor::reset_zoom (framecnt_t spp)
4371 {
4372         if (spp == samples_per_pixel) {
4373                 return;
4374         }
4375
4376         pending_visual_change.add (VisualChange::ZoomLevel);
4377         pending_visual_change.samples_per_pixel = spp;
4378         ensure_visual_change_idle_handler ();
4379 }
4380
4381 void
4382 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4383 {
4384         reset_x_origin (frame);
4385         reset_zoom (fpu);
4386
4387         if (!no_save_visual) {
4388                 undo_visual_stack.push_back (current_visual_state(false));
4389         }
4390 }
4391
4392 Editor::VisualState::VisualState (bool with_tracks)
4393         : gui_state (with_tracks ? new GUIObjectState : 0)
4394 {
4395 }
4396
4397 Editor::VisualState::~VisualState ()
4398 {
4399         delete gui_state;
4400 }
4401
4402 Editor::VisualState*
4403 Editor::current_visual_state (bool with_tracks)
4404 {
4405         VisualState* vs = new VisualState (with_tracks);
4406         vs->y_position = vertical_adjustment.get_value();
4407         vs->samples_per_pixel = samples_per_pixel;
4408         vs->leftmost_frame = leftmost_frame;
4409         vs->zoom_focus = zoom_focus;
4410
4411         if (with_tracks) {
4412                 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4413         }
4414
4415         return vs;
4416 }
4417
4418 void
4419 Editor::undo_visual_state ()
4420 {
4421         if (undo_visual_stack.empty()) {
4422                 return;
4423         }
4424
4425         VisualState* vs = undo_visual_stack.back();
4426         undo_visual_stack.pop_back();
4427
4428
4429         redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4430
4431         if (vs) {
4432                 use_visual_state (*vs);
4433         }
4434 }
4435
4436 void
4437 Editor::redo_visual_state ()
4438 {
4439         if (redo_visual_stack.empty()) {
4440                 return;
4441         }
4442
4443         VisualState* vs = redo_visual_stack.back();
4444         redo_visual_stack.pop_back();
4445
4446         // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4447         // why do we check here?
4448         undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4449
4450         if (vs) {
4451                 use_visual_state (*vs);
4452         }
4453 }
4454
4455 void
4456 Editor::swap_visual_state ()
4457 {
4458         if (undo_visual_stack.empty()) {
4459                 redo_visual_state ();
4460         } else {
4461                 undo_visual_state ();
4462         }
4463 }
4464
4465 void
4466 Editor::use_visual_state (VisualState& vs)
4467 {
4468         PBD::Unwinder<bool> nsv (no_save_visual, true);
4469         DisplaySuspender ds;
4470
4471         vertical_adjustment.set_value (vs.y_position);
4472
4473         set_zoom_focus (vs.zoom_focus);
4474         reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4475
4476         if (vs.gui_state) {
4477                 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4478
4479                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4480                         (*i)->clear_property_cache();
4481                         (*i)->reset_visual_state ();
4482                 }
4483         }
4484
4485         _routes->update_visibility ();
4486 }
4487
4488 /** This is the core function that controls the zoom level of the canvas. It is called
4489  *  whenever one or more calls are made to reset_zoom().  It executes in an idle handler.
4490  *  @param spp new number of samples per pixel
4491  */
4492 void
4493 Editor::set_samples_per_pixel (framecnt_t spp)
4494 {
4495         if (spp < 1) {
4496                 return;
4497         }
4498
4499         const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4500         const framecnt_t lots_of_pixels = 4000;
4501
4502         /* if the zoom level is greater than what you'd get trying to display 3
4503          * days of audio on a really big screen, then it's too big.
4504          */
4505
4506         if (spp * lots_of_pixels > three_days) {
4507                 return;
4508         }
4509
4510         samples_per_pixel = spp;
4511
4512         if (tempo_lines) {
4513                 tempo_lines->tempo_map_changed();
4514         }
4515
4516         bool const showing_time_selection = selection->time.length() > 0;
4517
4518         if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4519                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4520                         (*i)->reshow_selection (selection->time);
4521                 }
4522         }
4523
4524         ZoomChanged (); /* EMIT_SIGNAL */
4525
4526         ArdourCanvas::GtkCanvasViewport* c;
4527
4528         c = get_track_canvas();
4529         if (c) {
4530                 c->canvas()->zoomed ();
4531         }
4532
4533         if (playhead_cursor) {
4534                 playhead_cursor->set_position (playhead_cursor->current_frame ());
4535         }
4536
4537         refresh_location_display();
4538         _summary->set_overlays_dirty ();
4539
4540         update_marker_labels ();
4541
4542         instant_save ();
4543 }
4544
4545 void
4546 Editor::queue_visual_videotimeline_update ()
4547 {
4548         /* TODO:
4549          * pending_visual_change.add (VisualChange::VideoTimeline);
4550          * or maybe even more specific: which videotimeline-image
4551          * currently it calls update_video_timeline() to update
4552          * _all outdated_ images on the video-timeline.
4553          * see 'exposeimg()' in video_image_frame.cc
4554          */
4555         ensure_visual_change_idle_handler ();
4556 }
4557
4558 void
4559 Editor::ensure_visual_change_idle_handler ()
4560 {
4561         if (pending_visual_change.idle_handler_id < 0) {
4562                 // see comment in add_to_idle_resize above.
4563                 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4564                 pending_visual_change.being_handled = false;
4565         }
4566 }
4567
4568 int
4569 Editor::_idle_visual_changer (void* arg)
4570 {
4571         return static_cast<Editor*>(arg)->idle_visual_changer ();
4572 }
4573
4574 int
4575 Editor::idle_visual_changer ()
4576 {
4577         /* set_horizontal_position() below (and maybe other calls) call
4578            gtk_main_iteration(), so it's possible that a signal will be handled
4579            half-way through this method.  If this signal wants an
4580            idle_visual_changer we must schedule another one after this one, so
4581            mark the idle_handler_id as -1 here to allow that.  Also make a note
4582            that we are doing the visual change, so that changes in response to
4583            super-rapid-screen-update can be dropped if we are still processing
4584            the last one.
4585         */
4586
4587         pending_visual_change.idle_handler_id = -1;
4588         pending_visual_change.being_handled = true;
4589
4590         VisualChange vc = pending_visual_change;
4591
4592         pending_visual_change.pending = (VisualChange::Type) 0;
4593
4594         visual_changer (vc);
4595
4596         pending_visual_change.being_handled = false;
4597
4598         return 0; /* this is always a one-shot call */
4599 }
4600
4601 void
4602 Editor::visual_changer (const VisualChange& vc)
4603 {
4604         double const last_time_origin = horizontal_position ();
4605
4606         if (vc.pending & VisualChange::ZoomLevel) {
4607                 set_samples_per_pixel (vc.samples_per_pixel);
4608
4609                 compute_fixed_ruler_scale ();
4610
4611                 std::vector<TempoMap::BBTPoint> grid;
4612                 compute_current_bbt_points (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4613                 compute_bbt_ruler_scale (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4614                 update_tempo_based_rulers (grid);
4615
4616                 update_video_timeline();
4617         }
4618
4619         if (vc.pending & VisualChange::TimeOrigin) {
4620                 set_horizontal_position (vc.time_origin / samples_per_pixel);
4621         }
4622
4623         if (vc.pending & VisualChange::YOrigin) {
4624                 vertical_adjustment.set_value (vc.y_origin);
4625         }
4626
4627         if (last_time_origin == horizontal_position ()) {
4628                 /* changed signal not emitted */
4629                 update_fixed_rulers ();
4630                 redisplay_tempo (true);
4631         }
4632
4633         if (!(vc.pending & VisualChange::ZoomLevel)) {
4634                 update_video_timeline();
4635         }
4636
4637         _summary->set_overlays_dirty ();
4638 }
4639
4640 struct EditorOrderTimeAxisSorter {
4641     bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4642             return a->order () < b->order ();
4643     }
4644 };
4645
4646 void
4647 Editor::sort_track_selection (TrackViewList& sel)
4648 {
4649         EditorOrderTimeAxisSorter cmp;
4650         sel.sort (cmp);
4651 }
4652
4653 framepos_t
4654 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4655 {
4656         bool ignored;
4657         framepos_t where = 0;
4658         EditPoint ep = _edit_point;
4659
4660         if (Profile->get_mixbus())
4661                 if (ep == EditAtSelectedMarker)
4662                         ep = EditAtPlayhead;
4663
4664         if (from_outside_canvas && (ep == EditAtMouse)) {
4665                 ep = EditAtPlayhead;
4666         } else if (from_context_menu && (ep == EditAtMouse)) {
4667                 return  canvas_event_sample (&context_click_event, 0, 0);
4668         }
4669
4670         if (entered_marker) {
4671                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4672                 return entered_marker->position();
4673         }
4674
4675         if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4676                 ep = EditAtSelectedMarker;
4677         }
4678
4679         if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4680                 ep = EditAtPlayhead;
4681         }
4682
4683         switch (ep) {
4684         case EditAtPlayhead:
4685                 if (_dragging_playhead) {
4686                         where = *_control_scroll_target;
4687                 } else {
4688                         where = _session->audible_frame();
4689                 }
4690                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4691                 break;
4692
4693         case EditAtSelectedMarker:
4694                 if (!selection->markers.empty()) {
4695                         bool is_start;
4696                         Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4697                         if (loc) {
4698                                 if (is_start) {
4699                                         where =  loc->start();
4700                                 } else {
4701                                         where = loc->end();
4702                                 }
4703                                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4704                                 break;
4705                         }
4706                 }
4707                 /* fallthru */
4708
4709         default:
4710         case EditAtMouse:
4711                 if (!mouse_frame (where, ignored)) {
4712                         /* XXX not right but what can we do ? */
4713                         return 0;
4714                 }
4715                 snap_to (where);
4716                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4717                 break;
4718         }
4719
4720         return where;
4721 }
4722
4723 void
4724 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4725 {
4726         if (!_session) return;
4727
4728         begin_reversible_command (cmd);
4729
4730         Location* tll;
4731
4732         if ((tll = transport_loop_location()) == 0) {
4733                 Location* loc = new Location (*_session, start, end, _("Loop"),  Location::IsAutoLoop);
4734                 XMLNode &before = _session->locations()->get_state();
4735                 _session->locations()->add (loc, true);
4736                 _session->set_auto_loop_location (loc);
4737                 XMLNode &after = _session->locations()->get_state();
4738                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4739         } else {
4740                 XMLNode &before = tll->get_state();
4741                 tll->set_hidden (false, this);
4742                 tll->set (start, end);
4743                 XMLNode &after = tll->get_state();
4744                 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4745         }
4746
4747         commit_reversible_command ();
4748 }
4749
4750 void
4751 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4752 {
4753         if (!_session) return;
4754
4755         begin_reversible_command (cmd);
4756
4757         Location* tpl;
4758
4759         if ((tpl = transport_punch_location()) == 0) {
4760                 Location* loc = new Location (*_session, start, end, _("Punch"),  Location::IsAutoPunch);
4761                 XMLNode &before = _session->locations()->get_state();
4762                 _session->locations()->add (loc, true);
4763                 _session->set_auto_punch_location (loc);
4764                 XMLNode &after = _session->locations()->get_state();
4765                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4766         } else {
4767                 XMLNode &before = tpl->get_state();
4768                 tpl->set_hidden (false, this);
4769                 tpl->set (start, end);
4770                 XMLNode &after = tpl->get_state();
4771                 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4772         }
4773
4774         commit_reversible_command ();
4775 }
4776
4777 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4778  *  @param rs List to which found regions are added.
4779  *  @param where Time to look at.
4780  *  @param ts Tracks to look on; if this is empty, all tracks are examined.
4781  */
4782 void
4783 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4784 {
4785         const TrackViewList* tracks;
4786
4787         if (ts.empty()) {
4788                 tracks = &track_views;
4789         } else {
4790                 tracks = &ts;
4791         }
4792
4793         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4794
4795                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4796
4797                 if (rtv) {
4798                         boost::shared_ptr<Track> tr;
4799                         boost::shared_ptr<Playlist> pl;
4800
4801                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4802
4803                                 boost::shared_ptr<RegionList> regions = pl->regions_at (
4804                                                 (framepos_t) floor ( (double) where * tr->speed()));
4805
4806                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4807                                         RegionView* rv = rtv->view()->find_view (*i);
4808                                         if (rv) {
4809                                                 rs.add (rv);
4810                                         }
4811                                 }
4812                         }
4813                 }
4814         }
4815 }
4816
4817 void
4818 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4819 {
4820         const TrackViewList* tracks;
4821
4822         if (ts.empty()) {
4823                 tracks = &track_views;
4824         } else {
4825                 tracks = &ts;
4826         }
4827
4828         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4829                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4830                 if (rtv) {
4831                         boost::shared_ptr<Track> tr;
4832                         boost::shared_ptr<Playlist> pl;
4833
4834                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4835
4836                                 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4837                                         (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4838
4839                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4840
4841                                         RegionView* rv = rtv->view()->find_view (*i);
4842
4843                                         if (rv) {
4844                                                 rs.add (rv);
4845                                         }
4846                                 }
4847                         }
4848                 }
4849         }
4850 }
4851
4852 /** Get regions using the following method:
4853  *
4854  *  Make a region list using:
4855  *   (a) any selected regions
4856  *   (b) the intersection of any selected tracks and the edit point(*)
4857  *   (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4858  *
4859  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4860  *
4861  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4862  */
4863
4864 RegionSelection
4865 Editor::get_regions_from_selection_and_edit_point ()
4866 {
4867         RegionSelection regions;
4868
4869         if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4870                 regions.add (entered_regionview);
4871         } else {
4872                 regions = selection->regions;
4873         }
4874
4875         if ( regions.empty() ) {
4876                 TrackViewList tracks = selection->tracks;
4877
4878                 if (!tracks.empty()) {
4879                         /* no region selected or entered, but some selected tracks:
4880                          * act on all regions on the selected tracks at the edit point
4881                          */
4882                         framepos_t const where = get_preferred_edit_position ();
4883                         get_regions_at(regions, where, tracks);
4884                 }
4885         }
4886
4887         return regions;
4888 }
4889
4890 /** Get regions using the following method:
4891  *
4892  *  Make a region list using:
4893  *   (a) any selected regions
4894  *   (b) the intersection of any selected tracks and the edit point(*)
4895  *   (c) if neither exists, then whatever region is under the mouse
4896  *
4897  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4898  *
4899  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4900  */
4901 RegionSelection
4902 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4903 {
4904         RegionSelection regions;
4905
4906         if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4907                 regions.add (entered_regionview);
4908         } else {
4909                 regions = selection->regions;
4910         }
4911
4912         if ( regions.empty() ) {
4913                 TrackViewList tracks = selection->tracks;
4914
4915                 if (!tracks.empty()) {
4916                         /* no region selected or entered, but some selected tracks:
4917                          * act on all regions on the selected tracks at the edit point
4918                          */
4919                         get_regions_at(regions, pos, tracks);
4920                 }
4921         }
4922
4923         return regions;
4924 }
4925
4926 /** Start with regions that are selected, or the entered regionview if none are selected.
4927  *  Then add equivalent regions on tracks in the same active edit-enabled route group as any
4928  *  of the regions that we started with.
4929  */
4930
4931 RegionSelection
4932 Editor::get_regions_from_selection_and_entered () const
4933 {
4934         RegionSelection regions = selection->regions;
4935
4936         if (regions.empty() && entered_regionview) {
4937                 regions.add (entered_regionview);
4938         }
4939
4940         return regions;
4941 }
4942
4943 void
4944 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4945 {
4946         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4947                 RouteTimeAxisView* rtav;
4948
4949                 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4950                         boost::shared_ptr<Playlist> pl;
4951                         std::vector<boost::shared_ptr<Region> > results;
4952                         boost::shared_ptr<Track> tr;
4953
4954                         if ((tr = rtav->track()) == 0) {
4955                                 /* bus */
4956                                 continue;
4957                         }
4958
4959                         if ((pl = (tr->playlist())) != 0) {
4960                                 boost::shared_ptr<Region> r = pl->region_by_id (id);
4961                                 if (r) {
4962                                         RegionView* rv = rtav->view()->find_view (r);
4963                                         if (rv) {
4964                                                 regions.push_back (rv);
4965                                         }
4966                                 }
4967                         }
4968                 }
4969         }
4970 }
4971
4972 void
4973 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4974 {
4975
4976         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4977                 MidiTimeAxisView* mtav;
4978
4979                 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4980
4981                         mtav->get_per_region_note_selection (selection);
4982                 }
4983         }
4984
4985 }
4986
4987 void
4988 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4989 {
4990         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4991
4992                 RouteTimeAxisView* tatv;
4993
4994                 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4995
4996                         boost::shared_ptr<Playlist> pl;
4997                         vector<boost::shared_ptr<Region> > results;
4998                         RegionView* marv;
4999                         boost::shared_ptr<Track> tr;
5000
5001                         if ((tr = tatv->track()) == 0) {
5002                                 /* bus */
5003                                 continue;
5004                         }
5005
5006                         if ((pl = (tr->playlist())) != 0) {
5007                                 if (src_comparison) {
5008                                         pl->get_source_equivalent_regions (region, results);
5009                                 } else {
5010                                         pl->get_region_list_equivalent_regions (region, results);
5011                                 }
5012                         }
5013
5014                         for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5015                                 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5016                                         regions.push_back (marv);
5017                                 }
5018                         }
5019
5020                 }
5021         }
5022 }
5023
5024 void
5025 Editor::show_rhythm_ferret ()
5026 {
5027         if (rhythm_ferret == 0) {
5028                 rhythm_ferret = new RhythmFerret(*this);
5029         }
5030
5031         rhythm_ferret->set_session (_session);
5032         rhythm_ferret->show ();
5033         rhythm_ferret->present ();
5034 }
5035
5036 void
5037 Editor::first_idle ()
5038 {
5039         MessageDialog* dialog = 0;
5040
5041         if (track_views.size() > 1) {
5042                 Timers::TimerSuspender t;
5043                 dialog = new MessageDialog (
5044                         string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5045                         true
5046                         );
5047                 dialog->present ();
5048                 ARDOUR_UI::instance()->flush_pending ();
5049         }
5050
5051         for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5052                 (*t)->first_idle();
5053         }
5054
5055         // first idle adds route children (automation tracks), so we need to redisplay here
5056         _routes->redisplay ();
5057
5058         delete dialog;
5059
5060         if (_session->undo_depth() == 0) {
5061                 undo_action->set_sensitive(false);
5062         }
5063         redo_action->set_sensitive(false);
5064         begin_selection_op_history ();
5065
5066         _have_idled = true;
5067 }
5068
5069 gboolean
5070 Editor::_idle_resize (gpointer arg)
5071 {
5072         return ((Editor*)arg)->idle_resize ();
5073 }
5074
5075 void
5076 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5077 {
5078         if (resize_idle_id < 0) {
5079                 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5080                  * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5081                  * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5082                  */
5083                 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5084                 _pending_resize_amount = 0;
5085         }
5086
5087         /* make a note of the smallest resulting height, so that we can clamp the
5088            lower limit at TimeAxisView::hSmall */
5089
5090         int32_t min_resulting = INT32_MAX;
5091
5092         _pending_resize_amount += h;
5093         _pending_resize_view = view;
5094
5095         min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5096
5097         if (selection->tracks.contains (_pending_resize_view)) {
5098                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5099                         min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5100                 }
5101         }
5102
5103         if (min_resulting < 0) {
5104                 min_resulting = 0;
5105         }
5106
5107         /* clamp */
5108         if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5109                 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5110         }
5111 }
5112
5113 /** Handle pending resizing of tracks */
5114 bool
5115 Editor::idle_resize ()
5116 {
5117         _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5118
5119         if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5120             selection->tracks.contains (_pending_resize_view)) {
5121
5122                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5123                         if (*i != _pending_resize_view) {
5124                                 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5125                         }
5126                 }
5127         }
5128
5129         _pending_resize_amount = 0;
5130         _group_tabs->set_dirty ();
5131         resize_idle_id = -1;
5132
5133         return false;
5134 }
5135
5136 void
5137 Editor::located ()
5138 {
5139         ENSURE_GUI_THREAD (*this, &Editor::located);
5140
5141         if (_session) {
5142                 playhead_cursor->set_position (_session->audible_frame ());
5143                 if (_follow_playhead && !_pending_initial_locate) {
5144                         reset_x_origin_to_follow_playhead ();
5145                 }
5146         }
5147
5148         _pending_locate_request = false;
5149         _pending_initial_locate = false;
5150 }
5151
5152 void
5153 Editor::region_view_added (RegionView * rv)
5154 {
5155         for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5156                 if (rv->region ()->id () == (*pr)) {
5157                         selection->add (rv);
5158                         selection->regions.pending.erase (pr);
5159                         break;
5160                 }
5161         }
5162
5163         MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5164         if (mrv) {
5165                 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5166                 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5167                         if (rv->region()->id () == (*rnote).first) {
5168                                 mrv->select_notes ((*rnote).second);
5169                                 selection->pending_midi_note_selection.erase(rnote);
5170                                 break;
5171                         }
5172                 }
5173         }
5174
5175         _summary->set_background_dirty ();
5176 }
5177
5178 void
5179 Editor::region_view_removed ()
5180 {
5181         _summary->set_background_dirty ();
5182 }
5183
5184 RouteTimeAxisView*
5185 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5186 {
5187         TrackViewList::const_iterator j = track_views.begin ();
5188         while (j != track_views.end()) {
5189                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5190                 if (rtv && rtv->route() == r) {
5191                         return rtv;
5192                 }
5193                 ++j;
5194         }
5195
5196         return 0;
5197 }
5198
5199
5200 TrackViewList
5201 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5202 {
5203         TrackViewList t;
5204
5205         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5206                 TimeAxisView* tv = axis_view_from_route (*i);
5207                 if (tv) {
5208                         t.push_back (tv);
5209                 }
5210         }
5211
5212         return t;
5213 }
5214
5215 void
5216 Editor::suspend_route_redisplay ()
5217 {
5218         if (_routes) {
5219                 _routes->suspend_redisplay();
5220         }
5221 }
5222
5223 void
5224 Editor::resume_route_redisplay ()
5225 {
5226         if (_routes) {
5227                 _routes->redisplay(); // queue redisplay
5228                 _routes->resume_redisplay();
5229         }
5230 }
5231
5232 void
5233 Editor::add_routes (RouteList& routes)
5234 {
5235         ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5236
5237         RouteTimeAxisView *rtv;
5238         list<RouteTimeAxisView*> new_views;
5239         TrackViewList new_selection;
5240         bool from_scratch = (track_views.size() == 0);
5241
5242         for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5243                 boost::shared_ptr<Route> route = (*x);
5244
5245                 if (route->is_auditioner() || route->is_monitor()) {
5246                         continue;
5247                 }
5248
5249                 DataType dt = route->input()->default_type();
5250
5251                 if (dt == ARDOUR::DataType::AUDIO) {
5252                         rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5253                         rtv->set_route (route);
5254                 } else if (dt == ARDOUR::DataType::MIDI) {
5255                         rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5256                         rtv->set_route (route);
5257                 } else {
5258                         throw unknown_type();
5259                 }
5260
5261                 new_views.push_back (rtv);
5262                 track_views.push_back (rtv);
5263                 new_selection.push_back (rtv);
5264
5265                 rtv->effective_gain_display ();
5266
5267                 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5268                 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5269         }
5270
5271         if (new_views.size() > 0) {
5272                 _routes->routes_added (new_views);
5273                 _summary->routes_added (new_views);
5274         }
5275
5276         if (!from_scratch) {
5277                 selection->tracks.clear();
5278                 selection->add (new_selection);
5279                 begin_selection_op_history();
5280         }
5281
5282         if (show_editor_mixer_when_tracks_arrive) {
5283                 show_editor_mixer (true);
5284         }
5285
5286         editor_list_button.set_sensitive (true);
5287 }
5288
5289 void
5290 Editor::timeaxisview_deleted (TimeAxisView *tv)
5291 {
5292         if (tv == entered_track) {
5293                 entered_track = 0;
5294         }
5295
5296         if (_session && _session->deletion_in_progress()) {
5297                 /* the situation is under control */
5298                 return;
5299         }
5300
5301         ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5302
5303         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5304
5305         _routes->route_removed (tv);
5306
5307         TimeAxisView::Children c = tv->get_child_list ();
5308         for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5309                 if (entered_track == i->get()) {
5310                         entered_track = 0;
5311                 }
5312         }
5313
5314         /* remove it from the list of track views */
5315
5316         TrackViewList::iterator i;
5317
5318         if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5319                 i = track_views.erase (i);
5320         }
5321
5322         /* update whatever the current mixer strip is displaying, if revelant */
5323
5324         boost::shared_ptr<Route> route;
5325
5326         if (rtav) {
5327                 route = rtav->route ();
5328         }
5329
5330         if (current_mixer_strip && current_mixer_strip->route() == route) {
5331
5332                 TimeAxisView* next_tv;
5333
5334                 if (track_views.empty()) {
5335                         next_tv = 0;
5336                 } else if (i == track_views.end()) {
5337                         next_tv = track_views.front();
5338                 } else {
5339                         next_tv = (*i);
5340                 }
5341
5342
5343                 if (next_tv) {
5344                         set_selected_mixer_strip (*next_tv);
5345                 } else {
5346                         /* make the editor mixer strip go away setting the
5347                          * button to inactive (which also unticks the menu option)
5348                          */
5349
5350                         ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5351                 }
5352         }
5353 }
5354
5355 void
5356 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5357 {
5358         if (apply_to_selection) {
5359                 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5360
5361                         TrackSelection::iterator j = i;
5362                         ++j;
5363
5364                         hide_track_in_display (*i, false);
5365
5366                         i = j;
5367                 }
5368         } else {
5369                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5370
5371                 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5372                         // this will hide the mixer strip
5373                         set_selected_mixer_strip (*tv);
5374                 }
5375
5376                 _routes->hide_track_in_display (*tv);
5377         }
5378 }
5379
5380 bool
5381 Editor::sync_track_view_list_and_routes ()
5382 {
5383         track_views = TrackViewList (_routes->views ());
5384
5385         _summary->set_background_dirty();
5386         _group_tabs->set_dirty ();
5387
5388         return false; // do not call again (until needed)
5389 }
5390
5391 void
5392 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5393 {
5394         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5395                 theslot (**i);
5396         }
5397 }
5398
5399 /** Find a RouteTimeAxisView by the ID of its route */
5400 RouteTimeAxisView*
5401 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5402 {
5403         RouteTimeAxisView* v;
5404
5405         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5406                 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5407                         if(v->route()->id() == id) {
5408                                 return v;
5409                         }
5410                 }
5411         }
5412
5413         return 0;
5414 }
5415
5416 void
5417 Editor::fit_route_group (RouteGroup *g)
5418 {
5419         TrackViewList ts = axis_views_from_routes (g->route_list ());
5420         fit_tracks (ts);
5421 }
5422
5423 void
5424 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5425 {
5426         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5427
5428         if (r == 0) {
5429                 _session->cancel_audition ();
5430                 return;
5431         }
5432
5433         if (_session->is_auditioning()) {
5434                 _session->cancel_audition ();
5435                 if (r == last_audition_region) {
5436                         return;
5437                 }
5438         }
5439
5440         _session->audition_region (r);
5441         last_audition_region = r;
5442 }
5443
5444
5445 void
5446 Editor::hide_a_region (boost::shared_ptr<Region> r)
5447 {
5448         r->set_hidden (true);
5449 }
5450
5451 void
5452 Editor::show_a_region (boost::shared_ptr<Region> r)
5453 {
5454         r->set_hidden (false);
5455 }
5456
5457 void
5458 Editor::audition_region_from_region_list ()
5459 {
5460         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5461 }
5462
5463 void
5464 Editor::hide_region_from_region_list ()
5465 {
5466         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5467 }
5468
5469 void
5470 Editor::show_region_in_region_list ()
5471 {
5472         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5473 }
5474
5475 void
5476 Editor::step_edit_status_change (bool yn)
5477 {
5478         if (yn) {
5479                 start_step_editing ();
5480         } else {
5481                 stop_step_editing ();
5482         }
5483 }
5484
5485 void
5486 Editor::start_step_editing ()
5487 {
5488         step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5489 }
5490
5491 void
5492 Editor::stop_step_editing ()
5493 {
5494         step_edit_connection.disconnect ();
5495 }
5496
5497 bool
5498 Editor::check_step_edit ()
5499 {
5500         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5501                 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5502                 if (mtv) {
5503                         mtv->check_step_edit ();
5504                 }
5505         }
5506
5507         return true; // do it again, till we stop
5508 }
5509
5510 bool
5511 Editor::scroll_press (Direction dir)
5512 {
5513         ++_scroll_callbacks;
5514
5515         if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5516                 /* delay the first auto-repeat */
5517                 return true;
5518         }
5519
5520         switch (dir) {
5521         case LEFT:
5522                 scroll_backward (1);
5523                 break;
5524
5525         case RIGHT:
5526                 scroll_forward (1);
5527                 break;
5528
5529         case UP:
5530                 scroll_up_one_track ();
5531                 break;
5532
5533         case DOWN:
5534                 scroll_down_one_track ();
5535                 break;
5536         }
5537
5538         /* do hacky auto-repeat */
5539         if (!_scroll_connection.connected ()) {
5540
5541                 _scroll_connection = Glib::signal_timeout().connect (
5542                         sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5543                         );
5544
5545                 _scroll_callbacks = 0;
5546         }
5547
5548         return true;
5549 }
5550
5551 void
5552 Editor::scroll_release ()
5553 {
5554         _scroll_connection.disconnect ();
5555 }
5556
5557 /** Queue a change for the Editor viewport x origin to follow the playhead */
5558 void
5559 Editor::reset_x_origin_to_follow_playhead ()
5560 {
5561         framepos_t const frame = playhead_cursor->current_frame ();
5562
5563         if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5564
5565                 if (_session->transport_speed() < 0) {
5566
5567                         if (frame > (current_page_samples() / 2)) {
5568                                 center_screen (frame-(current_page_samples()/2));
5569                         } else {
5570                                 center_screen (current_page_samples()/2);
5571                         }
5572
5573                 } else {
5574
5575                         framepos_t l = 0;
5576
5577                         if (frame < leftmost_frame) {
5578                                 /* moving left */
5579                                 if (_session->transport_rolling()) {
5580                                         /* rolling; end up with the playhead at the right of the page */
5581                                         l = frame - current_page_samples ();
5582                                 } else {
5583                                         /* not rolling: end up with the playhead 1/4 of the way along the page */
5584                                         l = frame - current_page_samples() / 4;
5585                                 }
5586                         } else {
5587                                 /* moving right */
5588                                 if (_session->transport_rolling()) {
5589                                         /* rolling: end up with the playhead on the left of the page */
5590                                         l = frame;
5591                                 } else {
5592                                         /* not rolling: end up with the playhead 3/4 of the way along the page */
5593                                         l = frame - 3 * current_page_samples() / 4;
5594                                 }
5595                         }
5596
5597                         if (l < 0) {
5598                                 l = 0;
5599                         }
5600
5601                         center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5602                 }
5603         }
5604 }
5605
5606 void
5607 Editor::super_rapid_screen_update ()
5608 {
5609         if (!_session || !_session->engine().running()) {
5610                 return;
5611         }
5612
5613         /* METERING / MIXER STRIPS */
5614
5615         /* update track meters, if required */
5616         if (contents().is_mapped() && meters_running) {
5617                 RouteTimeAxisView* rtv;
5618                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5619                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5620                                 rtv->fast_update ();
5621                         }
5622                 }
5623         }
5624
5625         /* and any current mixer strip */
5626         if (current_mixer_strip) {
5627                 current_mixer_strip->fast_update ();
5628         }
5629
5630         /* PLAYHEAD AND VIEWPORT */
5631
5632         framepos_t const frame = _session->audible_frame();
5633
5634         /* There are a few reasons why we might not update the playhead / viewport stuff:
5635          *
5636          * 1.  we don't update things when there's a pending locate request, otherwise
5637          *     when the editor requests a locate there is a chance that this method
5638          *     will move the playhead before the locate request is processed, causing
5639          *     a visual glitch.
5640          * 2.  if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5641          * 3.  if we're still at the same frame that we were last time, there's nothing to do.
5642          */
5643
5644         if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5645
5646                 last_update_frame = frame;
5647
5648                 if (!_dragging_playhead) {
5649                         playhead_cursor->set_position (frame);
5650                 }
5651
5652                 if (!_stationary_playhead) {
5653
5654                         if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5655                                 /* We only do this if we aren't already
5656                                    handling a visual change (ie if
5657                                    pending_visual_change.being_handled is
5658                                    false) so that these requests don't stack
5659                                    up there are too many of them to handle in
5660                                    time.
5661                                 */
5662                                 reset_x_origin_to_follow_playhead ();
5663                         }
5664
5665                 } else {
5666
5667                         if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5668                                 framepos_t const frame = playhead_cursor->current_frame ();
5669                                 double target = ((double)frame - (double)current_page_samples()/2.0);
5670                                 if (target <= 0.0) {
5671                                         target = 0.0;
5672                                 }
5673                                 // compare to EditorCursor::set_position()
5674                                 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5675                                 double const new_pos = sample_to_pixel_unrounded (target);
5676                                 if (rint (new_pos) != rint (old_pos)) {
5677                                         reset_x_origin (pixel_to_sample (floor (new_pos)));
5678                                 }
5679                         }
5680
5681                 }
5682
5683         }
5684 }
5685
5686
5687 void
5688 Editor::session_going_away ()
5689 {
5690         _have_idled = false;
5691
5692         _session_connections.drop_connections ();
5693
5694         super_rapid_screen_update_connection.disconnect ();
5695
5696         selection->clear ();
5697         cut_buffer->clear ();
5698
5699         clicked_regionview = 0;
5700         clicked_axisview = 0;
5701         clicked_routeview = 0;
5702         entered_regionview = 0;
5703         entered_track = 0;
5704         last_update_frame = 0;
5705         _drags->abort ();
5706
5707         playhead_cursor->hide ();
5708
5709         /* rip everything out of the list displays */
5710
5711         _regions->clear ();
5712         _routes->clear ();
5713         _route_groups->clear ();
5714
5715         /* do this first so that deleting a track doesn't reset cms to null
5716            and thus cause a leak.
5717         */
5718
5719         if (current_mixer_strip) {
5720                 if (current_mixer_strip->get_parent() != 0) {
5721                         global_hpacker.remove (*current_mixer_strip);
5722                 }
5723                 delete current_mixer_strip;
5724                 current_mixer_strip = 0;
5725         }
5726
5727         /* delete all trackviews */
5728
5729         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5730                 delete *i;
5731         }
5732         track_views.clear ();
5733
5734         nudge_clock->set_session (0);
5735
5736         editor_list_button.set_active(false);
5737         editor_list_button.set_sensitive(false);
5738
5739         /* clear tempo/meter rulers */
5740         remove_metric_marks ();
5741         hide_measures ();
5742         clear_marker_display ();
5743
5744         stop_step_editing ();
5745
5746         if (own_window()) {
5747
5748                 /* get rid of any existing editor mixer strip */
5749
5750                 WindowTitle title(Glib::get_application_name());
5751                 title += _("Editor");
5752
5753                 own_window()->set_title (title.get_string());
5754         }
5755
5756         SessionHandlePtr::session_going_away ();
5757 }
5758
5759 void
5760 Editor::trigger_script (int i)
5761 {
5762         LuaInstance::instance()-> call_action (i);
5763 }
5764
5765 void
5766 Editor::set_script_action_name (int i, const std::string& n)
5767 {
5768         string const a = string_compose (X_("script-action-%1"), i + 1);
5769         Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5770         assert (act);
5771         if (n.empty ()) {
5772                 act->set_label (string_compose (_("Unset #%1"), i + 1));
5773                 act->set_tooltip (_("no action bound"));
5774                 act->set_sensitive (false);
5775         } else {
5776                 act->set_label (n);
5777                 act->set_tooltip (n);
5778                 act->set_sensitive (true);
5779         }
5780         KeyEditor::UpdateBindings ();
5781 }
5782
5783 void
5784 Editor::show_editor_list (bool yn)
5785 {
5786         if (yn) {
5787                 _the_notebook.show ();
5788         } else {
5789                 _the_notebook.hide ();
5790         }
5791 }
5792
5793 void
5794 Editor::change_region_layering_order (bool from_context_menu)
5795 {
5796         const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5797
5798         if (!clicked_routeview) {
5799                 if (layering_order_editor) {
5800                         layering_order_editor->hide ();
5801                 }
5802                 return;
5803         }
5804
5805         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5806
5807         if (!track) {
5808                 return;
5809         }
5810
5811         boost::shared_ptr<Playlist> pl = track->playlist();
5812
5813         if (!pl) {
5814                 return;
5815         }
5816
5817         if (layering_order_editor == 0) {
5818                 layering_order_editor = new RegionLayeringOrderEditor (*this);
5819         }
5820
5821         layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5822         layering_order_editor->maybe_present ();
5823 }
5824
5825 void
5826 Editor::update_region_layering_order_editor ()
5827 {
5828         if (layering_order_editor && layering_order_editor->is_visible ()) {
5829                 change_region_layering_order (true);
5830         }
5831 }
5832
5833 void
5834 Editor::setup_fade_images ()
5835 {
5836         _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5837         _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5838         _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5839         _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5840         _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5841
5842         _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5843         _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5844         _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5845         _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5846         _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5847
5848         _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5849         _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5850         _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5851         _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5852         _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5853
5854         _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5855         _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5856         _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5857         _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5858         _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5859
5860 }
5861
5862 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5863 Gtk::MenuItem&
5864 Editor::action_menu_item (std::string const & name)
5865 {
5866         Glib::RefPtr<Action> a = editor_actions->get_action (name);
5867         assert (a);
5868
5869         return *manage (a->create_menu_item ());
5870 }
5871
5872 void
5873 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5874 {
5875         EventBox* b = manage (new EventBox);
5876         b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5877         Label* l = manage (new Label (name));
5878         l->set_angle (-90);
5879         b->add (*l);
5880         b->show_all ();
5881         _the_notebook.append_page (widget, *b);
5882 }
5883
5884 bool
5885 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5886 {
5887         if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5888                 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5889         }
5890
5891         if (ev->type == GDK_2BUTTON_PRESS) {
5892
5893                 /* double-click on a notebook tab shrinks or expands the notebook */
5894
5895                 if (_notebook_shrunk) {
5896                         if (pre_notebook_shrink_pane_width) {
5897                                 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5898                         }
5899                         _notebook_shrunk = false;
5900                 } else {
5901                         pre_notebook_shrink_pane_width = edit_pane.get_position();
5902
5903                         /* this expands the LHS of the edit pane to cover the notebook
5904                            PAGE but leaves the tabs visible.
5905                          */
5906                         edit_pane.set_position (edit_pane.get_position() + page->get_width());
5907                         _notebook_shrunk = true;
5908                 }
5909         }
5910
5911         return true;
5912 }
5913
5914 void
5915 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5916 {
5917         using namespace Menu_Helpers;
5918
5919         MenuList& items = _control_point_context_menu.items ();
5920         items.clear ();
5921
5922         items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5923         items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5924         if (!can_remove_control_point (item)) {
5925                 items.back().set_sensitive (false);
5926         }
5927
5928         _control_point_context_menu.popup (event->button.button, event->button.time);
5929 }
5930
5931 void
5932 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5933 {
5934         using namespace Menu_Helpers;
5935
5936         NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5937         if (!note) {
5938                 return;
5939         }
5940
5941         /* We need to get the selection here and pass it to the operations, since
5942            popping up the menu will cause a region leave event which clears
5943            entered_regionview. */
5944
5945         MidiRegionView&       mrv = note->region_view();
5946         const RegionSelection rs  = get_regions_from_selection_and_entered ();
5947         const uint32_t sel_size = mrv.selection_size ();
5948
5949         MenuList& items = _note_context_menu.items();
5950         items.clear();
5951
5952         if (sel_size > 0) {
5953                 items.push_back(MenuElem(_("Delete"),
5954                                          sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5955         }
5956
5957         items.push_back(MenuElem(_("Edit..."),
5958                                  sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5959         if (sel_size != 1) {
5960                 items.back().set_sensitive (false);
5961         }
5962
5963         items.push_back(MenuElem(_("Transpose..."),
5964                                  sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
5965
5966
5967         items.push_back(MenuElem(_("Legatize"),
5968                                  sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5969         if (sel_size < 2) {
5970                 items.back().set_sensitive (false);
5971         }
5972
5973         items.push_back(MenuElem(_("Quantize..."),
5974                                  sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5975
5976         items.push_back(MenuElem(_("Remove Overlap"),
5977                                  sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5978         if (sel_size < 2) {
5979                 items.back().set_sensitive (false);
5980         }
5981
5982         items.push_back(MenuElem(_("Transform..."),
5983                                  sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5984
5985         _note_context_menu.popup (event->button.button, event->button.time);
5986 }
5987
5988 void
5989 Editor::zoom_vertical_modifier_released()
5990 {
5991         _stepping_axis_view = 0;
5992 }
5993
5994 void
5995 Editor::ui_parameter_changed (string parameter)
5996 {
5997         if (parameter == "icon-set") {
5998                 while (!_cursor_stack.empty()) {
5999                         _cursor_stack.pop_back();
6000                 }
6001                 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6002                 _cursor_stack.push_back(_cursors->grabber);
6003         } else if (parameter == "draggable-playhead") {
6004                 if (_verbose_cursor) {
6005                         playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6006                 }
6007         }
6008 }
6009
6010 Gtk::Window*
6011 Editor::use_own_window (bool and_fill_it)
6012 {
6013         bool new_window = !own_window();
6014
6015         Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6016
6017         if (win && new_window) {
6018                 win->set_name ("EditorWindow");
6019
6020                 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6021
6022                 // win->signal_realize().connect (*this, &Editor::on_realize);
6023                 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6024                 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6025                 win->set_data ("ardour-bindings", bindings);
6026
6027                 update_title ();
6028         }
6029
6030         DisplaySuspender ds;
6031         contents().show_all ();
6032
6033         /* XXX: this is a bit unfortunate; it would probably
6034            be nicer if we could just call show () above rather
6035            than needing the show_all ()
6036         */
6037
6038         /* re-hide stuff if necessary */
6039         editor_list_button_toggled ();
6040         parameter_changed ("show-summary");
6041         parameter_changed ("show-group-tabs");
6042         parameter_changed ("show-zoom-tools");
6043
6044         /* now reset all audio_time_axis heights, because widgets might need
6045            to be re-hidden
6046         */
6047
6048         TimeAxisView *tv;
6049
6050         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6051                 tv = (static_cast<TimeAxisView*>(*i));
6052                 tv->reset_height ();
6053         }
6054
6055         if (current_mixer_strip) {
6056                 current_mixer_strip->hide_things ();
6057                 current_mixer_strip->parameter_changed ("mixer-element-visibility");
6058         }
6059
6060         return win;
6061 }