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