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