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