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