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