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