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