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