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