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