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