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