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