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