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