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