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