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