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