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