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