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