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