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