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