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