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