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