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