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