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