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