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