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