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