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