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