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