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