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