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