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