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