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