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