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