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