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