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