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