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