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