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