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