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