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