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