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