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