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