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