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