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