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