Fix up fade in/out cursors.
[ardour.git] / gtk2_ardour / editor.cc
1 /*
2     Copyright (C) 2000-2009 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 /* Note: public Editor methods are documented in public_editor.h */
21
22 #include <stdint.h>
23 #include <unistd.h>
24 #include <cstdlib>
25 #include <cmath>
26 #include <string>
27 #include <algorithm>
28 #include <map>
29
30 #include "ardour_ui.h"
31 /*
32  * ardour_ui.h include was moved to the top of the list
33  * due to a conflicting definition of 'Style' between
34  * Apple's MacTypes.h and BarController.
35  */
36
37 #include <boost/none.hpp>
38
39 #include <sigc++/bind.h>
40
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46
47 #include <glibmm/miscutils.h>
48 #include <gtkmm/image.h>
49 #include <gdkmm/color.h>
50 #include <gdkmm/bitmap.h>
51
52 #include <gtkmm2ext/grouped_buttons.h>
53 #include <gtkmm2ext/gtk_ui.h>
54 #include <gtkmm2ext/tearoff.h>
55 #include <gtkmm2ext/utils.h>
56 #include <gtkmm2ext/window_title.h>
57 #include <gtkmm2ext/choice.h>
58 #include <gtkmm2ext/cell_renderer_pixbuf_toggle.h>
59
60 #include "ardour/audio_diskstream.h"
61 #include "ardour/audio_track.h"
62 #include "ardour/audioplaylist.h"
63 #include "ardour/audioregion.h"
64 #include "ardour/location.h"
65 #include "ardour/midi_region.h"
66 #include "ardour/plugin_manager.h"
67 #include "ardour/profile.h"
68 #include "ardour/route_group.h"
69 #include "ardour/session_directory.h"
70 #include "ardour/session_route.h"
71 #include "ardour/session_state_utils.h"
72 #include "ardour/tempo.h"
73 #include "ardour/utils.h"
74 #include "ardour/session_playlists.h"
75 #include "ardour/audioengine.h"
76
77 #include "control_protocol/control_protocol.h"
78
79 #include "editor.h"
80 #include "keyboard.h"
81 #include "marker.h"
82 #include "playlist_selector.h"
83 #include "audio_region_view.h"
84 #include "rgb_macros.h"
85 #include "selection.h"
86 #include "audio_streamview.h"
87 #include "time_axis_view.h"
88 #include "audio_time_axis.h"
89 #include "utils.h"
90 #include "crossfade_view.h"
91 #include "canvas-noevent-text.h"
92 #include "editing.h"
93 #include "public_editor.h"
94 #include "crossfade_edit.h"
95 #include "canvas_impl.h"
96 #include "actions.h"
97 #include "sfdb_ui.h"
98 #include "gui_thread.h"
99 #include "simpleline.h"
100 #include "rhythm_ferret.h"
101 #include "actions.h"
102 #include "tempo_lines.h"
103 #include "analysis_window.h"
104 #include "bundle_manager.h"
105 #include "global_port_matrix.h"
106 #include "editor_drag.h"
107 #include "editor_group_tabs.h"
108 #include "automation_time_axis.h"
109 #include "editor_routes.h"
110 #include "midi_time_axis.h"
111 #include "mixer_strip.h"
112 #include "editor_route_groups.h"
113 #include "editor_regions.h"
114 #include "editor_locations.h"
115 #include "editor_snapshots.h"
116 #include "editor_summary.h"
117 #include "region_layering_order_editor.h"
118
119 #include "i18n.h"
120
121 #ifdef WITH_CMT
122 #include "imageframe_socket_handler.h"
123 #endif
124
125 using namespace std;
126 using namespace ARDOUR;
127 using namespace PBD;
128 using namespace Gtk;
129 using namespace Glib;
130 using namespace Gtkmm2ext;
131 using namespace Editing;
132
133 using PBD::internationalize;
134 using PBD::atoi;
135 using Gtkmm2ext::Keyboard;
136
137 const double Editor::timebar_height = 15.0;
138
139 #include "editor_xpms"
140
141 static const gchar *_snap_type_strings[] = {
142         N_("CD Frames"),
143         N_("Timecode Frames"),
144         N_("Timecode Seconds"),
145         N_("Timecode Minutes"),
146         N_("Seconds"),
147         N_("Minutes"),
148         N_("Beats/32"),
149         N_("Beats/28"),
150         N_("Beats/24"),
151         N_("Beats/20"),
152         N_("Beats/16"),
153         N_("Beats/14"),
154         N_("Beats/12"),
155         N_("Beats/10"),
156         N_("Beats/8"),
157         N_("Beats/7"),
158         N_("Beats/6"),
159         N_("Beats/5"),
160         N_("Beats/4"),
161         N_("Beats/3"),
162         N_("Beats/2"),
163         N_("Beats"),
164         N_("Bars"),
165         N_("Marks"),
166         N_("Region starts"),
167         N_("Region ends"),
168         N_("Region syncs"),
169         N_("Region bounds"),
170         0
171 };
172
173 static const gchar *_snap_mode_strings[] = {
174         N_("No Grid"),
175         N_("Grid"),
176         N_("Magnetic"),
177         0
178 };
179
180 static const gchar *_edit_point_strings[] = {
181         N_("Playhead"),
182         N_("Marker"),
183         N_("Mouse"),
184         0
185 };
186
187 static const gchar *_zoom_focus_strings[] = {
188         N_("Left"),
189         N_("Right"),
190         N_("Center"),
191         N_("Playhead"),
192         N_("Mouse"),
193         N_("Edit point"),
194         0
195 };
196
197 #ifdef USE_RUBBERBAND
198 static const gchar *_rb_opt_strings[] = {
199         N_("Mushy"),
200         N_("Smooth"),
201         N_("Balanced multitimbral mixture"),
202         N_("Unpitched percussion with stable notes"),
203         N_("Crisp monophonic instrumental"),
204         N_("Unpitched solo percussion"),
205         N_("Resample without preserving pitch"),
206         0
207 };
208 #endif
209
210 /* Soundfile  drag-n-drop */
211
212 Gdk::Cursor* Editor::cross_hair_cursor = 0;
213 Gdk::Cursor* Editor::selector_cursor = 0;
214 Gdk::Cursor* Editor::trimmer_cursor = 0;
215 Gdk::Cursor* Editor::left_side_trim_cursor = 0;
216 Gdk::Cursor* Editor::right_side_trim_cursor = 0;
217 Gdk::Cursor* Editor::fade_in_cursor = 0;
218 Gdk::Cursor* Editor::fade_out_cursor = 0;
219 Gdk::Cursor* Editor::grabber_cursor = 0;
220 Gdk::Cursor* Editor::grabber_note_cursor = 0;
221 Gdk::Cursor* Editor::grabber_edit_point_cursor = 0;
222 Gdk::Cursor* Editor::zoom_in_cursor = 0;
223 Gdk::Cursor* Editor::zoom_out_cursor = 0;
224 Gdk::Cursor* Editor::time_fx_cursor = 0;
225 Gdk::Cursor* Editor::fader_cursor = 0;
226 Gdk::Cursor* Editor::speaker_cursor = 0;
227 Gdk::Cursor* Editor::midi_pencil_cursor = 0;
228 Gdk::Cursor* Editor::midi_select_cursor = 0;
229 Gdk::Cursor* Editor::midi_resize_cursor = 0;
230 Gdk::Cursor* Editor::midi_erase_cursor = 0;
231 Gdk::Cursor* Editor::wait_cursor = 0;
232 Gdk::Cursor* Editor::timebar_cursor = 0;
233 Gdk::Cursor* Editor::transparent_cursor = 0;
234 Gdk::Cursor* Editor::up_down_cursor = 0;
235
236 void
237 show_me_the_size (Requisition* r, const char* what)
238 {
239         cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
240 }
241
242 #ifdef GTKOSX
243 static void
244 pane_size_watcher (Paned* pane)
245 {
246        /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
247           it is no longer accessible. so stop that. this doesn't happen on X11,
248           just the quartz backend.
249
250           ugh.
251        */
252
253        int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 25;
254
255        gint pos = pane->get_position ();
256
257        if (pos > max_width_of_lhs) {
258                pane->set_position (max_width_of_lhs);
259        }
260 }
261 #endif
262
263 Editor::Editor ()
264         : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
265
266           /* time display buttons */
267         , minsec_label (_("Mins:Secs"))
268         , bbt_label (_("Bars:Beats"))
269         , timecode_label (_("Timecode"))
270         , frame_label (_("Samples"))
271         , tempo_label (_("Tempo"))
272         , meter_label (_("Meter"))
273         , mark_label (_("Location Markers"))
274         , range_mark_label (_("Range Markers"))
275         , transport_mark_label (_("Loop/Punch Ranges"))
276         , cd_mark_label (_("CD Markers"))
277         , edit_packer (4, 4, true)
278
279           /* the values here don't matter: layout widgets
280              reset them as needed.
281           */
282
283         , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
284
285           /* tool bar related */
286
287         , zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, false, true)
288
289         , toolbar_selection_clock_table (2,3)
290
291         , automation_mode_button (_("mode"))
292         , global_automation_button (_("automation"))
293
294         , midi_panic_button (_("Panic"))
295
296 #ifdef WITH_CMT
297         , image_socket_listener(0)
298 #endif
299
300           /* nudge */
301
302         , nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, false, true)
303         , meters_running(false)
304         , _pending_locate_request (false)
305         , _pending_initial_locate (false)
306         , _last_cut_copy_source_track (0)
307
308         , _region_selection_change_updates_region_list (true)
309 {
310         constructed = false;
311
312         /* we are a singleton */
313
314         PublicEditor::_instance = this;
315
316         _have_idled = false;
317
318         selection = new Selection (this);
319         cut_buffer = new Selection (this);
320
321         clicked_regionview = 0;
322         clicked_axisview = 0;
323         clicked_routeview = 0;
324         clicked_crossfadeview = 0;
325         clicked_control_point = 0;
326         last_update_frame = 0;
327         pre_press_cursor = 0;
328         _drags = new DragManager (this);
329         current_mixer_strip = 0;
330         current_bbt_points = 0;
331         tempo_lines = 0;
332
333         snap_type_strings =  I18N (_snap_type_strings);
334         snap_mode_strings =  I18N (_snap_mode_strings);
335         zoom_focus_strings = I18N (_zoom_focus_strings);
336         edit_point_strings = I18N (_edit_point_strings);
337 #ifdef USE_RUBBERBAND
338         rb_opt_strings = I18N (_rb_opt_strings);
339         rb_current_opt = 4;
340 #endif
341
342         snap_threshold = 5.0;
343         bbt_beat_subdivision = 4;
344         _canvas_width = 0;
345         _canvas_height = 0;
346         last_autoscroll_x = 0;
347         last_autoscroll_y = 0;
348         autoscroll_active = false;
349         autoscroll_timeout_tag = -1;
350         logo_item = 0;
351
352         analysis_window = 0;
353
354         current_interthread_info = 0;
355         _show_measures = true;
356         show_gain_after_trim = false;
357         verbose_cursor_on = true;
358         last_item_entered = 0;
359
360         have_pending_keyboard_selection = false;
361         _follow_playhead = true;
362         _stationary_playhead = false;
363         _xfade_visibility = true;
364         editor_ruler_menu = 0;
365         no_ruler_shown_update = false;
366         marker_menu = 0;
367         session_range_marker_menu = 0;
368         range_marker_menu = 0;
369         marker_menu_item = 0;
370         tempo_or_meter_marker_menu = 0;
371         transport_marker_menu = 0;
372         new_transport_marker_menu = 0;
373         editor_mixer_strip_width = Wide;
374         show_editor_mixer_when_tracks_arrive = false;
375         region_edit_menu_split_multichannel_item = 0;
376         region_edit_menu_split_item = 0;
377         temp_location = 0;
378         leftmost_frame = 0;
379         current_stepping_trackview = 0;
380         entered_track = 0;
381         entered_regionview = 0;
382         entered_marker = 0;
383         clear_entered_track = false;
384         current_timefx = 0;
385         playhead_cursor = 0;
386         button_release_can_deselect = true;
387         _dragging_playhead = false;
388         _dragging_edit_point = false;
389         select_new_marker = false;
390         rhythm_ferret = 0;
391         layering_order_editor = 0;
392         _bundle_manager = 0;
393         no_save_visual = false;
394         resize_idle_id = -1;
395
396         scrubbing_direction = 0;
397
398         sfbrowser = 0;
399
400         location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
401         location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
402         location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
403         location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
404         location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
405
406         _edit_point = EditAtMouse;
407         _internal_editing = false;
408         current_canvas_cursor = 0;
409
410         frames_per_unit = 2048; /* too early to use reset_zoom () */
411
412         _scroll_callbacks = 0;
413
414         zoom_focus = ZoomFocusLeft;
415         set_zoom_focus (ZoomFocusLeft);
416         zoom_range_clock.ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
417
418         bbt_label.set_name ("EditorTimeButton");
419         bbt_label.set_size_request (-1, (int)timebar_height);
420         bbt_label.set_alignment (1.0, 0.5);
421         bbt_label.set_padding (5,0);
422         bbt_label.hide ();
423         bbt_label.set_no_show_all();
424         minsec_label.set_name ("EditorTimeButton");
425         minsec_label.set_size_request (-1, (int)timebar_height);
426         minsec_label.set_alignment (1.0, 0.5);
427         minsec_label.set_padding (5,0);
428         minsec_label.hide ();
429         minsec_label.set_no_show_all();
430         timecode_label.set_name ("EditorTimeButton");
431         timecode_label.set_size_request (-1, (int)timebar_height);
432         timecode_label.set_alignment (1.0, 0.5);
433         timecode_label.set_padding (5,0);
434         timecode_label.hide ();
435         timecode_label.set_no_show_all();
436         frame_label.set_name ("EditorTimeButton");
437         frame_label.set_size_request (-1, (int)timebar_height);
438         frame_label.set_alignment (1.0, 0.5);
439         frame_label.set_padding (5,0);
440         frame_label.hide ();
441         frame_label.set_no_show_all();
442
443         tempo_label.set_name ("EditorTimeButton");
444         tempo_label.set_size_request (-1, (int)timebar_height);
445         tempo_label.set_alignment (1.0, 0.5);
446         tempo_label.set_padding (5,0);
447         tempo_label.hide();
448         tempo_label.set_no_show_all();
449         meter_label.set_name ("EditorTimeButton");
450         meter_label.set_size_request (-1, (int)timebar_height);
451         meter_label.set_alignment (1.0, 0.5);
452         meter_label.set_padding (5,0);
453         meter_label.hide();
454         meter_label.set_no_show_all();
455         mark_label.set_name ("EditorTimeButton");
456         mark_label.set_size_request (-1, (int)timebar_height);
457         mark_label.set_alignment (1.0, 0.5);
458         mark_label.set_padding (5,0);
459         mark_label.hide();
460         mark_label.set_no_show_all();
461         cd_mark_label.set_name ("EditorTimeButton");
462         cd_mark_label.set_size_request (-1, (int)timebar_height);
463         cd_mark_label.set_alignment (1.0, 0.5);
464         cd_mark_label.set_padding (5,0);
465         cd_mark_label.hide();
466         cd_mark_label.set_no_show_all();
467         range_mark_label.set_name ("EditorTimeButton");
468         range_mark_label.set_size_request (-1, (int)timebar_height);
469         range_mark_label.set_alignment (1.0, 0.5);
470         range_mark_label.set_padding (5,0);
471         range_mark_label.hide();
472         range_mark_label.set_no_show_all();
473         transport_mark_label.set_name ("EditorTimeButton");
474         transport_mark_label.set_size_request (-1, (int)timebar_height);
475         transport_mark_label.set_alignment (1.0, 0.5);
476         transport_mark_label.set_padding (5,0);
477         transport_mark_label.hide();
478         transport_mark_label.set_no_show_all();
479
480         initialize_rulers ();
481         initialize_canvas ();
482         _summary = new EditorSummary (this);
483
484         selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
485         selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
486         editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
487         selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
488         selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
489
490         edit_controls_vbox.set_spacing (0);
491         vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
492         track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
493
494         HBox* h = manage (new HBox);
495         _group_tabs = new EditorGroupTabs (this);
496         h->pack_start (*_group_tabs, PACK_SHRINK);
497         h->pack_start (edit_controls_vbox);
498         controls_layout.add (*h);
499
500         controls_layout.set_name ("EditControlsBase");
501         controls_layout.add_events (Gdk::SCROLL_MASK);
502         controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
503
504         controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
505         controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
506         controls_layout_size_request_connection = controls_layout.signal_size_request().connect (sigc::mem_fun (*this, &Editor::controls_layout_size_request));
507
508         build_cursors ();
509
510         ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
511         ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
512                         0.0, 1.0, 100.0, 1.0));
513         pad_line_1->property_color_rgba() = 0xFF0000FF;
514         pad_line_1->show();
515         time_pad->show();
516
517         time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
518         time_canvas_vbox.set_size_request (-1, -1);
519
520         ruler_label_event_box.add (ruler_label_vbox);
521         ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
522         ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
523
524         time_button_event_box.add (time_button_vbox);
525         time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
526         time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
527
528         /* these enable us to have a dedicated window (for cursor setting, etc.)
529            for the canvas areas.
530         */
531
532         track_canvas_event_box.add (*track_canvas);
533
534         time_canvas_event_box.add (time_canvas_vbox);
535         time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
536
537         edit_packer.set_col_spacings (0);
538         edit_packer.set_row_spacings (0);
539         edit_packer.set_homogeneous (false);
540         edit_packer.set_border_width (0);
541         edit_packer.set_name ("EditorWindow");
542
543         /* labels for the rulers */
544         edit_packer.attach (ruler_label_event_box,   1, 2, 0, 1,    FILL,        SHRINK, 0, 0);
545         /* labels for the marker "tracks" */
546         edit_packer.attach (time_button_event_box,   1, 2, 1, 2,    FILL,        SHRINK, 0, 0);
547         /* the rulers */
548         edit_packer.attach (time_canvas_event_box,   2, 3, 0, 1,    FILL|EXPAND, FILL, 0, 0);
549         /* track controls */
550         edit_packer.attach (controls_layout,         0, 2, 2, 3,    FILL,        FILL|EXPAND, 0, 0);
551         /* main canvas */
552         edit_packer.attach (track_canvas_event_box,  2, 3, 1, 3,    FILL|EXPAND, FILL|EXPAND, 0, 0);
553
554         bottom_hbox.set_border_width (2);
555         bottom_hbox.set_spacing (3);
556
557         _route_groups = new EditorRouteGroups (this);
558         _routes = new EditorRoutes (this);
559         _regions = new EditorRegions (this);
560         _snapshots = new EditorSnapshots (this);
561         _locations = new EditorLocations (this);
562
563         Gtk::Label* nlabel;
564
565         nlabel = manage (new Label (_("Regions")));
566         nlabel->set_angle (-90);
567         the_notebook.append_page (_regions->widget (), *nlabel);
568         nlabel = manage (new Label (_("Tracks & Busses")));
569         nlabel->set_angle (-90);
570         the_notebook.append_page (_routes->widget (), *nlabel);
571         nlabel = manage (new Label (_("Snapshots")));
572         nlabel->set_angle (-90);
573         the_notebook.append_page (_snapshots->widget (), *nlabel);
574         nlabel = manage (new Label (_("Route Groups")));
575         nlabel->set_angle (-90);
576         the_notebook.append_page (_route_groups->widget (), *nlabel);
577         nlabel = manage (new Label (_("Ranges & Marks")));
578         nlabel->set_angle (-90);
579         the_notebook.append_page (_locations->widget (), *nlabel);
580
581         the_notebook.set_show_tabs (true);
582         the_notebook.set_scrollable (true);
583         the_notebook.popup_disable ();
584         the_notebook.set_tab_pos (Gtk::POS_RIGHT);
585         the_notebook.show_all ();
586         
587         post_maximal_editor_width = 0;
588         post_maximal_horizontal_pane_position = 0;
589         post_maximal_editor_height = 0;
590         post_maximal_vertical_pane_position = 0;
591
592         editor_summary_pane.pack1(edit_packer);
593
594         Button* summary_arrows_left_left = manage (new Button);
595         summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
596         summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_press)));
597         summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_release));
598         Button* summary_arrows_left_right = manage (new Button);
599         summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
600         summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_press)));
601         summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_release));
602         VBox* summary_arrows_left = manage (new VBox);
603         summary_arrows_left->pack_start (*summary_arrows_left_left);
604         summary_arrows_left->pack_start (*summary_arrows_left_right);
605
606         Button* summary_arrows_right_left = manage (new Button);
607         summary_arrows_right_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
608         summary_arrows_right_left->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_press)));
609         summary_arrows_right_left->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_release));
610         Button* summary_arrows_right_right = manage (new Button);
611         summary_arrows_right_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
612         summary_arrows_right_right->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_press)));
613         summary_arrows_right_right->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_release));
614         VBox* summary_arrows_right = manage (new VBox);
615         summary_arrows_right->pack_start (*summary_arrows_right_left);
616         summary_arrows_right->pack_start (*summary_arrows_right_right);
617
618         Frame* summary_frame = manage (new Frame);
619         summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
620         summary_frame->add (*_summary);
621         summary_frame->show ();
622
623         _summary_hbox.pack_start (*summary_arrows_left, false, false);
624         _summary_hbox.pack_start (*summary_frame, true, true);
625         _summary_hbox.pack_start (*summary_arrows_right, false, false);
626         
627         editor_summary_pane.pack2 (_summary_hbox);
628
629         edit_pane.pack1 (editor_summary_pane, true, true);
630         edit_pane.pack2 (the_notebook, false, true);
631
632         editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
633
634         /* XXX: editor_summary_pane might need similar special OS X treatment to the edit_pane */
635
636         edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
637 #ifdef GTKOSX
638         Glib::PropertyProxy<int> proxy = edit_pane.property_position();
639         proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
640 #endif
641         top_hbox.pack_start (toolbar_frame, false, true);
642
643         HBox *hbox = manage (new HBox);
644         hbox->pack_start (edit_pane, true, true);
645
646         global_vpacker.pack_start (top_hbox, false, false);
647         global_vpacker.pack_start (*hbox, true, true);
648
649         global_hpacker.pack_start (global_vpacker, true, true);
650
651         set_name ("EditorWindow");
652         add_accel_group (ActionManager::ui_manager->get_accel_group());
653
654         status_bar_hpacker.show ();
655
656         vpacker.pack_end (status_bar_hpacker, false, false);
657         vpacker.pack_end (global_hpacker, true, true);
658
659         /* register actions now so that set_state() can find them and set toggles/checks etc */
660
661         register_actions ();
662
663         setup_toolbar ();
664         setup_midi_toolbar ();
665
666         _snap_type = SnapToBeat;
667         set_snap_to (_snap_type);
668         _snap_mode = SnapOff;
669         set_snap_mode (_snap_mode);
670         set_mouse_mode (MouseObject, true);
671         set_edit_point_preference (EditAtMouse, true);
672
673         _playlist_selector = new PlaylistSelector();
674         _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
675
676         RegionView::RegionViewGoingAway.connect (*this, invalidator (*this),  ui_bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
677
678         /* nudge stuff */
679
680         nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
681         nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
682
683         nudge_forward_button.set_name ("TransportButton");
684         nudge_backward_button.set_name ("TransportButton");
685
686         fade_context_menu.set_name ("ArdourContextMenu");
687
688         /* icons, titles, WM stuff */
689
690         list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
691         Glib::RefPtr<Gdk::Pixbuf> icon;
692
693         if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
694                 window_icons.push_back (icon);
695         }
696         if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
697                 window_icons.push_back (icon);
698         }
699         if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
700                 window_icons.push_back (icon);
701         }
702         if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
703                 window_icons.push_back (icon);
704         }
705         if (!window_icons.empty()) {
706                 set_icon_list (window_icons);
707                 set_default_icon_list (window_icons);
708         }
709
710         WindowTitle title(Glib::get_application_name());
711         title += _("Editor");
712         set_title (title.get_string());
713         set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
714
715         add (vpacker);
716         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
717
718         signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
719         signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
720
721         /* allow external control surfaces/protocols to do various things */
722
723         ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
724         ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
725         ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
726         ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), ui_bind (&Editor::control_scroll, this, _1), gui_context());
727         BasicUI::AccessAction.connect (*this, invalidator (*this), ui_bind (&Editor::access_action, this, _1, _2), gui_context());
728         
729         /* problematic: has to return a value and thus cannot be x-thread */
730
731         Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
732
733         Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
734
735         TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), ui_bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
736
737         _ignore_region_action = false;
738         _last_region_menu_was_main = false;
739         _popup_region_menu_item = 0;
740
741         _show_marker_lines = false;
742
743         constructed = true;
744         instant_save ();
745
746         setup_fade_images ();
747 }
748
749 Editor::~Editor()
750 {
751 #ifdef WITH_CMT
752         if(image_socket_listener) {
753                 if(image_socket_listener->is_connected())
754                 {
755                         image_socket_listener->close_connection() ;
756                 }
757
758                 delete image_socket_listener ;
759                 image_socket_listener = 0 ;
760         }
761 #endif
762         
763         delete _routes;
764         delete _route_groups;
765         delete track_canvas;
766         delete _drags;
767 }
768
769 void
770 Editor::add_toplevel_controls (Container& cont)
771 {
772         vpacker.pack_start (cont, false, false);
773         cont.show_all ();
774 }
775
776 void
777 Editor::catch_vanishing_regionview (RegionView *rv)
778 {
779         /* note: the selection will take care of the vanishing
780            audioregionview by itself.
781         */
782
783         if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
784                 _drags->abort ();
785         }
786
787         if (clicked_regionview == rv) {
788                 clicked_regionview = 0;
789         }
790
791         if (entered_regionview == rv) {
792                 set_entered_regionview (0);
793         }
794
795         if (!_all_region_actions_sensitized) {
796                 sensitize_all_region_actions (true);
797         }
798 }
799
800 void
801 Editor::set_entered_regionview (RegionView* rv)
802 {
803         if (rv == entered_regionview) {
804                 return;
805         }
806
807         if (entered_regionview) {
808                 entered_regionview->exited ();
809         }
810
811         if ((entered_regionview = rv) != 0) {
812                 entered_regionview->entered (internal_editing ());
813         }
814
815         if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
816                 /* This RegionView entry might have changed what region actions
817                    are allowed, so sensitize them all in case a key is pressed.
818                 */
819                 sensitize_all_region_actions (true);
820         }
821 }
822
823 void
824 Editor::set_entered_track (TimeAxisView* tav)
825 {
826         if (entered_track) {
827                 entered_track->exited ();
828         }
829
830         if ((entered_track = tav) != 0) {
831                 entered_track->entered ();
832         }
833 }
834
835 void
836 Editor::show_window ()
837 {
838         if (! is_visible ()) {
839                 show_all ();
840
841                 /* re-hide editor list if necessary */
842                 editor_list_button_toggled ();
843
844                 /* re-hide summary widget if necessary */
845                 parameter_changed ("show-summary");
846
847                 parameter_changed ("show-edit-group-tabs");
848
849                 /* now reset all audio_time_axis heights, because widgets might need
850                    to be re-hidden
851                 */
852
853                 TimeAxisView *tv;
854
855                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
856                         tv = (static_cast<TimeAxisView*>(*i));
857                         tv->reset_height ();
858                 }
859         }
860
861         present ();
862 }
863
864 void
865 Editor::instant_save ()
866 {
867         if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
868                 return;
869         }
870
871         if (_session) {
872                 _session->add_instant_xml(get_state());
873         } else {
874                 Config->add_instant_xml(get_state());
875         }
876 }
877
878 void
879 Editor::zoom_adjustment_changed ()
880 {
881         if (_session == 0) {
882                 return;
883         }
884
885         double fpu = zoom_range_clock.current_duration() / _canvas_width;
886
887         if (fpu < 1.0) {
888                 fpu = 1.0;
889                 zoom_range_clock.set ((framepos_t) floor (fpu * _canvas_width));
890         } else if (fpu > _session->current_end_frame() / _canvas_width) {
891                 fpu = _session->current_end_frame() / _canvas_width;
892                 zoom_range_clock.set ((framepos_t) floor (fpu * _canvas_width));
893         }
894
895         temporal_zoom (fpu);
896 }
897
898 void
899 Editor::control_scroll (float fraction)
900 {
901         ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
902
903         if (!_session) {
904                 return;
905         }
906
907         double step = fraction * current_page_frames();
908
909         /*
910                 _control_scroll_target is an optional<T>
911
912                 it acts like a pointer to an framepos_t, with
913                 a operator conversion to boolean to check
914                 that it has a value could possibly use
915                 playhead_cursor->current_frame to store the
916                 value and a boolean in the class to know
917                 when it's out of date
918         */
919
920         if (!_control_scroll_target) {
921                 _control_scroll_target = _session->transport_frame();
922                 _dragging_playhead = true;
923         }
924
925         if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
926                 *_control_scroll_target = 0;
927         } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
928                 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
929         } else {
930                 *_control_scroll_target += (framepos_t) floor (step);
931         }
932
933         /* move visuals, we'll catch up with it later */
934
935         playhead_cursor->set_position (*_control_scroll_target);
936         UpdateAllTransportClocks (*_control_scroll_target);
937
938         if (*_control_scroll_target > (current_page_frames() / 2)) {
939                 /* try to center PH in window */
940                 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
941         } else {
942                 reset_x_origin (0);
943         }
944
945         /*
946                 Now we do a timeout to actually bring the session to the right place
947                 according to the playhead. This is to avoid reading disk buffers on every
948                 call to control_scroll, which is driven by ScrollTimeline and therefore
949                 probably by a control surface wheel which can generate lots of events.
950         */
951         /* cancel the existing timeout */
952
953         control_scroll_connection.disconnect ();
954
955         /* add the next timeout */
956
957         control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
958 }
959
960 bool
961 Editor::deferred_control_scroll (framepos_t /*target*/)
962 {
963         _session->request_locate (*_control_scroll_target, _session->transport_rolling());
964         // reset for next stream
965         _control_scroll_target = boost::none;
966         _dragging_playhead = false;
967         return false;
968 }
969
970 void
971 Editor::access_action (std::string action_group, std::string action_item)
972 {
973         if (!_session) {
974                 return;
975         }
976
977         ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
978
979         RefPtr<Action> act;
980         act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
981
982         if (act) {
983                 act->activate();
984         }
985 }
986
987 void
988 Editor::on_realize ()
989 {
990         Window::on_realize ();
991         Realized ();
992 }
993
994 void
995 Editor::map_position_change (framepos_t frame)
996 {
997         ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
998
999         if (_session == 0) {
1000                 return;
1001         }
1002
1003         if (_follow_playhead) {
1004                 center_screen (frame);
1005         }
1006
1007         playhead_cursor->set_position (frame);
1008 }
1009
1010 void
1011 Editor::center_screen (framepos_t frame)
1012 {
1013         double page = _canvas_width * frames_per_unit;
1014
1015         /* if we're off the page, then scroll.
1016          */
1017
1018         if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1019                 center_screen_internal (frame, page);
1020         }
1021 }
1022
1023 void
1024 Editor::center_screen_internal (framepos_t frame, float page)
1025 {
1026         page /= 2;
1027
1028         if (frame > page) {
1029                 frame -= (framepos_t) page;
1030         } else {
1031                 frame = 0;
1032         }
1033
1034         reset_x_origin (frame);
1035 }
1036
1037
1038 void
1039 Editor::update_title ()
1040 {
1041         ENSURE_GUI_THREAD (*this, &Editor::update_title)
1042
1043         if (_session) {
1044                 bool dirty = _session->dirty();
1045
1046                 string session_name;
1047
1048                 if (_session->snap_name() != _session->name()) {
1049                         session_name = _session->snap_name();
1050                 } else {
1051                         session_name = _session->name();
1052                 }
1053
1054                 if (dirty) {
1055                         session_name = "*" + session_name;
1056                 }
1057
1058                 WindowTitle title(session_name);
1059                 title += Glib::get_application_name();
1060                 set_title (title.get_string());
1061         }
1062 }
1063
1064 void
1065 Editor::set_session (Session *t)
1066 {
1067         SessionHandlePtr::set_session (t);
1068
1069         if (!_session) {
1070                 return;
1071         }
1072
1073         zoom_range_clock.set_session (_session);
1074         _playlist_selector->set_session (_session);
1075         nudge_clock.set_session (_session);
1076         _summary->set_session (_session);
1077         _group_tabs->set_session (_session);
1078         _route_groups->set_session (_session);
1079         _regions->set_session (_session);
1080         _snapshots->set_session (_session);
1081         _routes->set_session (_session);
1082         _locations->set_session (_session);
1083
1084         if (rhythm_ferret) {
1085                 rhythm_ferret->set_session (_session);
1086         }
1087
1088         if (analysis_window) {
1089                 analysis_window->set_session (_session);
1090         }
1091
1092         if (sfbrowser) {
1093                 sfbrowser->set_session (_session);
1094         }
1095
1096         compute_fixed_ruler_scale ();
1097
1098         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1099         set_state (*node, Stateful::loading_state_version);
1100
1101         /* catch up with the playhead */
1102
1103         _session->request_locate (playhead_cursor->current_frame);
1104         _pending_initial_locate = true;
1105
1106         update_title ();
1107
1108         /* These signals can all be emitted by a non-GUI thread. Therefore the
1109            handlers for them must not attempt to directly interact with the GUI,
1110            but use Gtkmm2ext::UI::instance()->call_slot();
1111         */
1112
1113         _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), ui_bind(&Editor::step_edit_status_change, this, _1), gui_context());
1114         _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1115         _session->PositionChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::map_position_change, this, _1), gui_context());
1116         _session->RouteAdded.connect (_session_connections, invalidator (*this), ui_bind (&Editor::handle_new_route, this, _1), gui_context());
1117         _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1118         _session->TimecodeOffsetChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_just_timecode, this), gui_context());
1119         _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::tempo_map_changed, this, _1), gui_context());
1120         _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1121         _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
1122         _session->StateSaved.connect (_session_connections, invalidator (*this), ui_bind (&Editor::session_state_saved, this, _1), gui_context());
1123         _session->locations()->added.connect (_session_connections, invalidator (*this), ui_bind (&Editor::add_new_location, this, _1), gui_context());
1124         _session->locations()->removed.connect (_session_connections, invalidator (*this), ui_bind (&Editor::location_gone, this, _1), gui_context());
1125         _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1126         _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::refresh_location_display_s, this, _1), gui_context());
1127         _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1128
1129         if (Profile->get_sae()) {
1130                 BBT_Time bbt;
1131                 bbt.bars = 0;
1132                 bbt.beats = 0;
1133                 bbt.ticks = 120;
1134                 nframes_t pos = _session->tempo_map().bbt_duration_at (0, bbt, 1);
1135                 nudge_clock.set_mode(AudioClock::BBT);
1136                 nudge_clock.set (pos, true, 0, AudioClock::BBT);
1137
1138         } else {
1139                 nudge_clock.set (_session->frame_rate() * 5, true, 0, AudioClock::Timecode); // default of 5 seconds
1140         }
1141
1142         playhead_cursor->canvas_item.show ();
1143
1144         Location* loc = _session->locations()->auto_loop_location();
1145         if (loc == 0) {
1146                 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1147                 if (loc->start() == loc->end()) {
1148                         loc->set_end (loc->start() + 1);
1149                 }
1150                 _session->locations()->add (loc, false);
1151                 _session->set_auto_loop_location (loc);
1152         } else {
1153                 // force name
1154                 loc->set_name (_("Loop"));
1155         }
1156
1157         loc = _session->locations()->auto_punch_location();
1158         if (loc == 0) {
1159                 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1160                 if (loc->start() == loc->end()) {
1161                         loc->set_end (loc->start() + 1);
1162                 }
1163                 _session->locations()->add (loc, false);
1164                 _session->set_auto_punch_location (loc);
1165         } else {
1166                 // force name
1167                 loc->set_name (_("Punch"));
1168         }
1169
1170         boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1171         Config->map_parameters (pc);
1172         _session->config.map_parameters (pc);
1173
1174         refresh_location_display ();
1175
1176         restore_ruler_visibility ();
1177         //tempo_map_changed (PropertyChange (0));
1178         _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1179
1180         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1181                 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1182         }
1183
1184         super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1185                 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1186                 );
1187         
1188         switch (_snap_type) {
1189         case SnapToRegionStart:
1190         case SnapToRegionEnd:
1191         case SnapToRegionSync:
1192         case SnapToRegionBoundary:
1193                 build_region_boundary_cache ();
1194                 break;
1195
1196         default:
1197                 break;
1198         }
1199
1200         /* register for undo history */
1201         _session->register_with_memento_command_factory(_id, this);
1202
1203         ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1204
1205         start_updating_meters ();
1206 }
1207
1208 void
1209 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1210 {
1211         if (a->get_name() == "RegionMenu") {
1212                 /* When the main menu's region menu is opened, we setup the actions so that they look right
1213                    in the menu.  I can't find a way of getting a signal when this menu is subsequently closed,
1214                    so we resensitize all region actions when the entered regionview or the region selection
1215                    changes.  HOWEVER we can't always resensitize on entered_regionview change because that
1216                    happens after the region context menu is opened.  So we set a flag here, too.
1217
1218                    What a carry on :(
1219                 */
1220                 sensitize_the_right_region_actions ();
1221                 _last_region_menu_was_main = true;
1222         }
1223 }
1224
1225 void
1226 Editor::build_cursors ()
1227 {
1228         using namespace Gdk;
1229
1230         {
1231                 Glib::RefPtr<Gdk::Pixbuf> zoom_in_cursor_pixbuf (::get_icon ("zoom_in_cursor"));
1232                 zoom_in_cursor = new Gdk::Cursor (Gdk::Display::get_default(), zoom_in_cursor_pixbuf, 5, 5);
1233         }
1234
1235         {
1236                 Glib::RefPtr<Gdk::Pixbuf> zoom_out_cursor_pixbuf (::get_icon ("zoom_out_cursor"));
1237                 zoom_out_cursor = new Gdk::Cursor (Gdk::Display::get_default(), zoom_out_cursor_pixbuf, 5, 5);
1238         }
1239         
1240         Gdk::Color fbg ("#ffffff" );
1241         Gdk::Color ffg  ("#000000" );
1242
1243         {
1244                 RefPtr<Bitmap> source, mask;
1245
1246                 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1247                 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1248                 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1249         }
1250
1251         {
1252                 RefPtr<Bitmap> source, mask;
1253                 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1254                 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1255                 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1256         }
1257
1258         {
1259                 RefPtr<Bitmap> bits;
1260                 char pix[4] = { 0, 0, 0, 0 };
1261                 bits = Bitmap::create (pix, 2, 2);
1262                 Gdk::Color c;
1263                 transparent_cursor = new Gdk::Cursor (bits, bits, c, c, 0, 0);
1264         }
1265
1266         {
1267                 RefPtr<Bitmap> bits;
1268                 char pix[4] = { 0, 0, 0, 0 };
1269                 bits = Bitmap::create (pix, 2, 2);
1270                 Gdk::Color c;
1271                 transparent_cursor = new Gdk::Cursor (bits, bits, c, c, 0, 0);
1272         }
1273
1274         {
1275                 Glib::RefPtr<Gdk::Pixbuf> grabber_pixbuf (::get_icon ("grabber"));
1276                 grabber_cursor = new Gdk::Cursor (Gdk::Display::get_default(), grabber_pixbuf, 5, 0);
1277         }
1278
1279         {
1280                 Glib::RefPtr<Gdk::Pixbuf> grabber_note_pixbuf (::get_icon ("grabber_note"));
1281                 grabber_note_cursor = new Gdk::Cursor (Gdk::Display::get_default(), grabber_note_pixbuf, 5, 10);
1282         }
1283
1284         {
1285                 Glib::RefPtr<Gdk::Pixbuf> grabber_edit_point_pixbuf (::get_icon ("grabber_edit_point"));
1286                 grabber_edit_point_cursor = new Gdk::Cursor (Gdk::Display::get_default(), grabber_edit_point_pixbuf, 5, 17);
1287         }
1288
1289         cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1290         trimmer_cursor =  new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1291
1292         {
1293                 Glib::RefPtr<Gdk::Pixbuf> apixbuf (::get_icon ("trim_left_cursor"));
1294                 left_side_trim_cursor = new Gdk::Cursor (Gdk::Display::get_default(), apixbuf, 5, 11);
1295         }
1296
1297         {
1298                 Glib::RefPtr<Gdk::Pixbuf> apixbuf (::get_icon ("trim_right_cursor"));
1299                 right_side_trim_cursor = new Gdk::Cursor (Gdk::Display::get_default(), apixbuf, 23, 11);
1300         }
1301
1302         {
1303                 Glib::RefPtr<Gdk::Pixbuf> apixbuf (::get_icon ("fade_in_cursor"));
1304                 fade_in_cursor = new Gdk::Cursor (Gdk::Display::get_default(), apixbuf, 0, 0);
1305         }
1306
1307         {
1308                 Glib::RefPtr<Gdk::Pixbuf> apixbuf (::get_icon ("fade_out_cursor"));
1309                 fade_out_cursor = new Gdk::Cursor (Gdk::Display::get_default(), apixbuf, 29, 0);
1310         }
1311
1312         selector_cursor = new Gdk::Cursor (XTERM);
1313         time_fx_cursor = new Gdk::Cursor (SIZING);
1314         wait_cursor = new Gdk::Cursor  (WATCH);
1315         timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1316         midi_pencil_cursor = new Gdk::Cursor (PENCIL);
1317         midi_select_cursor = new Gdk::Cursor (CENTER_PTR);
1318         midi_resize_cursor = new Gdk::Cursor (SIZING);
1319         midi_erase_cursor = new Gdk::Cursor (DRAPED_BOX);
1320         up_down_cursor = new Gdk::Cursor (Gdk::SB_V_DOUBLE_ARROW);
1321 }
1322
1323 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1324 void
1325 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1326 {
1327         using namespace Menu_Helpers;
1328         AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1329
1330         if (arv == 0) {
1331                 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1332                 /*NOTREACHED*/
1333         }
1334
1335         MenuList& items (fade_context_menu.items());
1336
1337         items.clear ();
1338
1339         switch (item_type) {
1340         case FadeInItem:
1341         case FadeInHandleItem:
1342                 if (arv->audio_region()->fade_in_active()) {
1343                         items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1344                 } else {
1345                         items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1346                 }
1347
1348                 items.push_back (SeparatorElem());
1349
1350                 if (Profile->get_sae()) {
1351                         
1352                         items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1353                         items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1354                         
1355                 } else {
1356
1357                         items.push_back (
1358                                 ImageMenuElem (
1359                                         _("Linear"),
1360                                         *_fade_in_images[FadeLinear],
1361                                         sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1362                                         )
1363                                 );
1364
1365                         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1366
1367                         items.push_back (
1368                                 ImageMenuElem (
1369                                         _("Slowest"),
1370                                         *_fade_in_images[FadeFast],
1371                                         sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1372                                         ));
1373                         
1374                         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1375                         
1376                         items.push_back (
1377                                 ImageMenuElem (
1378                                         _("Slow"),
1379                                         *_fade_in_images[FadeLogB],
1380                                         sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogB)
1381                                         ));
1382                         
1383                         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1384                         
1385                         items.push_back (
1386                                 ImageMenuElem (
1387                                         _("Fast"),
1388                                         *_fade_in_images[FadeLogA],
1389                                         sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogA)
1390                                         ));
1391                         
1392                         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1393                         
1394                         items.push_back (
1395                                 ImageMenuElem (
1396                                         _("Fastest"),
1397                                         *_fade_in_images[FadeSlow],
1398                                         sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1399                                         ));
1400                         
1401                         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1402                 }
1403
1404                 break;
1405
1406         case FadeOutItem:
1407         case FadeOutHandleItem:
1408                 if (arv->audio_region()->fade_out_active()) {
1409                         items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1410                 } else {
1411                         items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1412                 }
1413
1414                 items.push_back (SeparatorElem());
1415
1416                 if (Profile->get_sae()) {
1417                         items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1418                         items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1419                 } else {
1420
1421                         items.push_back (
1422                                 ImageMenuElem (
1423                                         _("Linear"),
1424                                         *_fade_out_images[FadeLinear],
1425                                         sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1426                                         )
1427                                 );
1428
1429                         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1430
1431                         items.push_back (
1432                                 ImageMenuElem (
1433                                         _("Slowest"),
1434                                         *_fade_out_images[FadeFast],
1435                                         sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1436                                         ));
1437                         
1438                         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1439                         
1440                         items.push_back (
1441                                 ImageMenuElem (
1442                                         _("Slow"),
1443                                         *_fade_out_images[FadeLogB],
1444                                         sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogA)
1445                                         ));
1446                         
1447                         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1448                         
1449                         items.push_back (
1450                                 ImageMenuElem (
1451                                         _("Fast"),
1452                                         *_fade_out_images[FadeLogA],
1453                                         sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogB)
1454                                         ));
1455                         
1456                         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1457                         
1458                         items.push_back (
1459                                 ImageMenuElem (
1460                                         _("Fastest"),
1461                                         *_fade_out_images[FadeSlow],
1462                                         sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1463                                         ));
1464                         
1465                         dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1466                 }
1467
1468                 break;
1469
1470         default:
1471                 fatal << _("programming error: ")
1472                       << X_("non-fade canvas item passed to popup_fade_context_menu()")
1473                       << endmsg;
1474                 /*NOTREACHED*/
1475         }
1476
1477         fade_context_menu.popup (button, time);
1478 }
1479
1480 void
1481 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1482 {
1483         using namespace Menu_Helpers;
1484         Menu* (Editor::*build_menu_function)();
1485         Menu *menu;
1486
1487         switch (item_type) {
1488         case RegionItem:
1489         case RegionViewName:
1490         case RegionViewNameHighlight:
1491         case LeftFrameHandle:
1492         case RightFrameHandle:
1493                 if (with_selection) {
1494                         build_menu_function = &Editor::build_track_selection_context_menu;
1495                 } else {
1496                         build_menu_function = &Editor::build_track_region_context_menu;
1497                 }
1498                 break;
1499
1500         case SelectionItem:
1501                 if (with_selection) {
1502                         build_menu_function = &Editor::build_track_selection_context_menu;
1503                 } else {
1504                         build_menu_function = &Editor::build_track_context_menu;
1505                 }
1506                 break;
1507
1508         case CrossfadeViewItem:
1509                 build_menu_function = &Editor::build_track_crossfade_context_menu;
1510                 break;
1511
1512         case StreamItem:
1513                 if (clicked_routeview->track()) {
1514                         build_menu_function = &Editor::build_track_context_menu;
1515                 } else {
1516                         build_menu_function = &Editor::build_track_bus_context_menu;
1517                 }
1518                 break;
1519
1520         default:
1521                 /* probably shouldn't happen but if it does, we don't care */
1522                 return;
1523         }
1524
1525         menu = (this->*build_menu_function)();
1526         menu->set_name ("ArdourContextMenu");
1527
1528         /* now handle specific situations */
1529
1530         switch (item_type) {
1531         case RegionItem:
1532         case RegionViewName:
1533         case RegionViewNameHighlight:
1534         case LeftFrameHandle:
1535         case RightFrameHandle:
1536                 if (!with_selection) {
1537                         if (region_edit_menu_split_item) {
1538                                 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1539                                         ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1540                                 } else {
1541                                         ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1542                                 }
1543                         }
1544                         if (region_edit_menu_split_multichannel_item) {
1545                                 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1546                                         region_edit_menu_split_multichannel_item->set_sensitive (true);
1547                                 } else {
1548                                         region_edit_menu_split_multichannel_item->set_sensitive (false);
1549                                 }
1550                         }
1551                 }
1552                 break;
1553
1554         case SelectionItem:
1555                 break;
1556
1557         case CrossfadeViewItem:
1558                 break;
1559
1560         case StreamItem:
1561                 break;
1562
1563         default:
1564                 /* probably shouldn't happen but if it does, we don't care */
1565                 return;
1566         }
1567
1568         if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1569
1570                 /* Bounce to disk */
1571
1572                 using namespace Menu_Helpers;
1573                 MenuList& edit_items  = menu->items();
1574
1575                 edit_items.push_back (SeparatorElem());
1576
1577                 switch (clicked_routeview->audio_track()->freeze_state()) {
1578                 case AudioTrack::NoFreeze:
1579                         edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1580                         break;
1581
1582                 case AudioTrack::Frozen:
1583                         edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1584                         break;
1585
1586                 case AudioTrack::UnFrozen:
1587                         edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1588                         break;
1589                 }
1590
1591         }
1592
1593         if (item_type == StreamItem && clicked_routeview) {
1594                 clicked_routeview->build_underlay_menu(menu);
1595         }
1596
1597         /* When the region menu is opened, we setup the actions so that they look right
1598            in the menu.
1599         */
1600         sensitize_the_right_region_actions ();
1601         _last_region_menu_was_main = false;
1602
1603         menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1604         menu->popup (button, time);
1605 }
1606
1607 Menu*
1608 Editor::build_track_context_menu ()
1609 {
1610         using namespace Menu_Helpers;
1611
1612         MenuList& edit_items = track_context_menu.items();
1613         edit_items.clear();
1614
1615         add_dstream_context_items (edit_items);
1616         return &track_context_menu;
1617 }
1618
1619 Menu*
1620 Editor::build_track_bus_context_menu ()
1621 {
1622         using namespace Menu_Helpers;
1623
1624         MenuList& edit_items = track_context_menu.items();
1625         edit_items.clear();
1626
1627         add_bus_context_items (edit_items);
1628         return &track_context_menu;
1629 }
1630
1631 Menu*
1632 Editor::build_track_region_context_menu ()
1633 {
1634         using namespace Menu_Helpers;
1635         MenuList& edit_items  = track_region_context_menu.items();
1636         edit_items.clear();
1637
1638         /* we've just cleared the track region context menu, so the menu that these
1639            two items were on will have disappeared; stop them dangling.
1640         */
1641         region_edit_menu_split_item = 0;
1642         region_edit_menu_split_multichannel_item = 0;
1643
1644         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1645
1646         if (rtv) {
1647                 boost::shared_ptr<Track> tr;
1648                 boost::shared_ptr<Playlist> pl;
1649
1650                 /* Don't offer a region submenu if we are in internal edit mode, as we don't select regions in this
1651                    mode and so offering region context is somewhat confusing.
1652                 */
1653                 if ((tr = rtv->track()) && ((pl = tr->playlist())) && !internal_editing()) {
1654                         framepos_t const framepos = (framepos_t) floor ((double) get_preferred_edit_position() * tr->speed());
1655                         uint32_t regions_at = pl->count_regions_at (framepos);
1656                         add_region_context_items (edit_items, regions_at > 1);
1657                 }
1658         }
1659
1660         add_dstream_context_items (edit_items);
1661
1662         return &track_region_context_menu;
1663 }
1664
1665 Menu*
1666 Editor::build_track_crossfade_context_menu ()
1667 {
1668         using namespace Menu_Helpers;
1669         MenuList& edit_items  = track_crossfade_context_menu.items();
1670         edit_items.clear ();
1671
1672         AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1673
1674         if (atv) {
1675                 boost::shared_ptr<Track> tr;
1676                 boost::shared_ptr<Playlist> pl;
1677                 boost::shared_ptr<AudioPlaylist> apl;
1678
1679                 if ((tr = atv->track()) && ((pl = tr->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1680
1681                         AudioPlaylist::Crossfades xfades;
1682
1683                         apl->crossfades_at (get_preferred_edit_position (), xfades);
1684
1685                         bool many = xfades.size() > 1;
1686
1687                         for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1688                                 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1689                         }
1690
1691                         framepos_t framepos = (framepos_t) floor ((double) get_preferred_edit_position() * tr->speed());
1692                         uint32_t regions_at = pl->count_regions_at (framepos);
1693                         add_region_context_items (edit_items, regions_at > 1);
1694                 }
1695         }
1696
1697         add_dstream_context_items (edit_items);
1698
1699         return &track_crossfade_context_menu;
1700 }
1701
1702 void
1703 Editor::analyze_region_selection ()
1704 {
1705         if (analysis_window == 0) {
1706                 analysis_window = new AnalysisWindow();
1707
1708                 if (_session != 0)
1709                         analysis_window->set_session(_session);
1710
1711                 analysis_window->show_all();
1712         }
1713
1714         analysis_window->set_regionmode();
1715         analysis_window->analyze();
1716
1717         analysis_window->present();
1718 }
1719
1720 void
1721 Editor::analyze_range_selection()
1722 {
1723         if (analysis_window == 0) {
1724                 analysis_window = new AnalysisWindow();
1725
1726                 if (_session != 0)
1727                         analysis_window->set_session(_session);
1728
1729                 analysis_window->show_all();
1730         }
1731
1732         analysis_window->set_rangemode();
1733         analysis_window->analyze();
1734
1735         analysis_window->present();
1736 }
1737
1738 Menu*
1739 Editor::build_track_selection_context_menu ()
1740 {
1741         using namespace Menu_Helpers;
1742         MenuList& edit_items  = track_selection_context_menu.items();
1743         edit_items.clear ();
1744
1745         add_selection_context_items (edit_items);
1746         // edit_items.push_back (SeparatorElem());
1747         // add_dstream_context_items (edit_items);
1748
1749         return &track_selection_context_menu;
1750 }
1751
1752 /** Add context menu items relevant to crossfades.
1753  * @param edit_items List to add the items to.
1754  */
1755 void
1756 Editor::add_crossfade_context_items (AudioStreamView* /*view*/, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1757 {
1758         using namespace Menu_Helpers;
1759         Menu     *xfade_menu = manage (new Menu);
1760         MenuList& items       = xfade_menu->items();
1761         xfade_menu->set_name ("ArdourContextMenu");
1762         string str;
1763
1764         if (xfade->active()) {
1765                 str = _("Mute");
1766         } else {
1767                 str = _("Unmute");
1768         }
1769
1770         items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1771         items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1772
1773         if (xfade->can_follow_overlap()) {
1774
1775                 if (xfade->following_overlap()) {
1776                         str = _("Convert to Short");
1777                 } else {
1778                         str = _("Convert to Full");
1779                 }
1780
1781                 items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1782         }
1783
1784         if (many) {
1785                 str = xfade->out()->name();
1786                 str += "->";
1787                 str += xfade->in()->name();
1788         } else {
1789                 str = _("Crossfade");
1790         }
1791
1792         edit_items.push_back (MenuElem (str, *xfade_menu));
1793         edit_items.push_back (SeparatorElem());
1794 }
1795
1796 void
1797 Editor::xfade_edit_left_region ()
1798 {
1799         if (clicked_crossfadeview) {
1800                 clicked_crossfadeview->left_view.show_region_editor ();
1801         }
1802 }
1803
1804 void
1805 Editor::xfade_edit_right_region ()
1806 {
1807         if (clicked_crossfadeview) {
1808                 clicked_crossfadeview->right_view.show_region_editor ();
1809         }
1810 }
1811
1812 void
1813 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, bool multiple_regions_at_position)
1814 {
1815         using namespace Menu_Helpers;
1816         
1817         /* OK, stick the region submenu at the top of the list, and then add
1818            the standard items.
1819         */
1820
1821         /* we have to hack up the region name because "_" has a special
1822            meaning for menu titles.
1823         */
1824
1825         RegionSelection rs = get_regions_from_selection_and_entered ();
1826         
1827         string::size_type pos = 0;
1828         string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1829
1830         while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1831                 menu_item_name.replace (pos, 1, "__");
1832                 pos += 2;
1833         }
1834
1835         if (_popup_region_menu_item == 0) {
1836                 _popup_region_menu_item = new MenuItem (menu_item_name);
1837                 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1838                 _popup_region_menu_item->show ();
1839         } else {
1840                 _popup_region_menu_item->set_label (menu_item_name);
1841         }
1842
1843         edit_items.push_back (*_popup_region_menu_item);
1844         if (multiple_regions_at_position && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1845                 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region")->create_menu_item ()));
1846         }
1847         edit_items.push_back (SeparatorElem());
1848 }
1849
1850 /** Add context menu items relevant to selection ranges.
1851  * @param edit_items List to add the items to.
1852  */
1853 void
1854 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1855 {
1856         using namespace Menu_Helpers;
1857
1858         edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1859         edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1860
1861         edit_items.push_back (SeparatorElem());
1862         edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1863
1864         if (!selection->regions.empty()) {
1865                 edit_items.push_back (SeparatorElem());
1866                 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)));
1867                 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)));
1868         }
1869
1870         edit_items.push_back (SeparatorElem());
1871         edit_items.push_back (MenuElem (_("Convert to region in-place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1872         edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1873
1874         edit_items.push_back (SeparatorElem());
1875         edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1876
1877         edit_items.push_back (SeparatorElem());
1878         edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1879         edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1880
1881         edit_items.push_back (SeparatorElem());
1882         edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1883
1884         edit_items.push_back (SeparatorElem());
1885         edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1886         edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1887         edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false)));
1888
1889         edit_items.push_back (SeparatorElem());
1890         edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1891         edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1892         edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1893         edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1894         edit_items.push_back (MenuElem (_("Export Range"), sigc::mem_fun(*this, &Editor::export_selection)));
1895 }
1896
1897
1898 void
1899 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1900 {
1901         using namespace Menu_Helpers;
1902
1903         /* Playback */
1904
1905         Menu *play_menu = manage (new Menu);
1906         MenuList& play_items = play_menu->items();
1907         play_menu->set_name ("ArdourContextMenu");
1908
1909         play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1910         play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1911         play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1912         play_items.push_back (SeparatorElem());
1913         play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1914
1915         edit_items.push_back (MenuElem (_("Play"), *play_menu));
1916
1917         /* Selection */
1918
1919         Menu *select_menu = manage (new Menu);
1920         MenuList& select_items = select_menu->items();
1921         select_menu->set_name ("ArdourContextMenu");
1922
1923         select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1924         select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1925         select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1926         select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1927         select_items.push_back (SeparatorElem());
1928         select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1929         select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1930         select_items.push_back (SeparatorElem());
1931         select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1932         select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1933         select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1934         select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1935         select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1936         select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1937         select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1938
1939         edit_items.push_back (MenuElem (_("Select"), *select_menu));
1940
1941         /* Cut-n-Paste */
1942
1943         Menu *cutnpaste_menu = manage (new Menu);
1944         MenuList& cutnpaste_items = cutnpaste_menu->items();
1945         cutnpaste_menu->set_name ("ArdourContextMenu");
1946
1947         cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1948         cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1949         cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f)));
1950
1951         cutnpaste_items.push_back (SeparatorElem());
1952
1953         cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1954         cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1955
1956         edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1957
1958         /* Adding new material */
1959
1960         edit_items.push_back (SeparatorElem());
1961         edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1962         edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1963
1964         /* Nudge track */
1965
1966         Menu *nudge_menu = manage (new Menu());
1967         MenuList& nudge_items = nudge_menu->items();
1968         nudge_menu->set_name ("ArdourContextMenu");
1969
1970         edit_items.push_back (SeparatorElem());
1971         nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1972         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1973         nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1974         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1975
1976         edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1977 }
1978
1979 void
1980 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1981 {
1982         using namespace Menu_Helpers;
1983
1984         /* Playback */
1985
1986         Menu *play_menu = manage (new Menu);
1987         MenuList& play_items = play_menu->items();
1988         play_menu->set_name ("ArdourContextMenu");
1989
1990         play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1991         play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1992         edit_items.push_back (MenuElem (_("Play"), *play_menu));
1993
1994         /* Selection */
1995
1996         Menu *select_menu = manage (new Menu);
1997         MenuList& select_items = select_menu->items();
1998         select_menu->set_name ("ArdourContextMenu");
1999
2000         select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2001         select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2002         select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2003         select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2004         select_items.push_back (SeparatorElem());
2005         select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2006         select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2007         select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2008         select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2009
2010         edit_items.push_back (MenuElem (_("Select"), *select_menu));
2011
2012         /* Cut-n-Paste */
2013
2014         Menu *cutnpaste_menu = manage (new Menu);
2015         MenuList& cutnpaste_items = cutnpaste_menu->items();
2016         cutnpaste_menu->set_name ("ArdourContextMenu");
2017
2018         cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2019         cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2020         cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f)));
2021
2022         Menu *nudge_menu = manage (new Menu());
2023         MenuList& nudge_items = nudge_menu->items();
2024         nudge_menu->set_name ("ArdourContextMenu");
2025
2026         edit_items.push_back (SeparatorElem());
2027         nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2028         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2029         nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2030         nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2031
2032         edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2033 }
2034
2035 SnapType
2036 Editor::snap_type() const
2037 {
2038         return _snap_type;
2039 }
2040
2041 SnapMode
2042 Editor::snap_mode() const
2043 {
2044         return _snap_mode;
2045 }
2046
2047 void
2048 Editor::set_snap_to (SnapType st)
2049 {
2050         unsigned int snap_ind = (unsigned int)st;
2051
2052         _snap_type = st;
2053
2054         if (snap_ind > snap_type_strings.size() - 1) {
2055                 snap_ind = 0;
2056                 _snap_type = (SnapType)snap_ind;
2057         }
2058
2059         string str = snap_type_strings[snap_ind];
2060
2061         if (str != snap_type_selector.get_active_text()) {
2062                 snap_type_selector.set_active_text (str);
2063         }
2064
2065         instant_save ();
2066
2067         switch (_snap_type) {
2068         case SnapToBeatDiv32:
2069         case SnapToBeatDiv28:
2070         case SnapToBeatDiv24:
2071         case SnapToBeatDiv20:
2072         case SnapToBeatDiv16:
2073         case SnapToBeatDiv14:
2074         case SnapToBeatDiv12:
2075         case SnapToBeatDiv10:
2076         case SnapToBeatDiv8:
2077         case SnapToBeatDiv7:
2078         case SnapToBeatDiv6:
2079         case SnapToBeatDiv5:
2080         case SnapToBeatDiv4:
2081         case SnapToBeatDiv3:
2082         case SnapToBeatDiv2:
2083                 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
2084                 update_tempo_based_rulers ();
2085                 break;
2086
2087         case SnapToRegionStart:
2088         case SnapToRegionEnd:
2089         case SnapToRegionSync:
2090         case SnapToRegionBoundary:
2091                 build_region_boundary_cache ();
2092                 break;
2093
2094         default:
2095                 /* relax */
2096                 break;
2097         }
2098
2099         SnapChanged (); /* EMIT SIGNAL */
2100 }
2101
2102 void
2103 Editor::set_snap_mode (SnapMode mode)
2104 {
2105         _snap_mode = mode;
2106         string str = snap_mode_strings[(int)mode];
2107
2108         if (str != snap_mode_selector.get_active_text ()) {
2109                 snap_mode_selector.set_active_text (str);
2110         }
2111
2112         instant_save ();
2113 }
2114 void
2115 Editor::set_edit_point_preference (EditPoint ep, bool force)
2116 {
2117         bool changed = (_edit_point != ep);
2118
2119         _edit_point = ep;
2120         string str = edit_point_strings[(int)ep];
2121
2122         if (str != edit_point_selector.get_active_text ()) {
2123                 edit_point_selector.set_active_text (str);
2124         }
2125
2126         set_canvas_cursor ();
2127
2128         if (!force && !changed) {
2129                 return;
2130         }
2131
2132         const char* action=NULL;
2133
2134         switch (_edit_point) {
2135         case EditAtPlayhead:
2136                 action = "edit-at-playhead";
2137                 break;
2138         case EditAtSelectedMarker:
2139                 action = "edit-at-marker";
2140                 break;
2141         case EditAtMouse:
2142                 action = "edit-at-mouse";
2143                 break;
2144         }
2145
2146         Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2147         if (act) {
2148                 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2149         }
2150
2151         framepos_t foo;
2152         bool in_track_canvas;
2153
2154         if (!mouse_frame (foo, in_track_canvas)) {
2155                 in_track_canvas = false;
2156         }
2157
2158         reset_canvas_action_sensitivity (in_track_canvas);
2159
2160         instant_save ();
2161 }
2162
2163 int
2164 Editor::set_state (const XMLNode& node, int /*version*/)
2165 {
2166         const XMLProperty* prop;
2167         XMLNode* geometry;
2168         int x, y, xoff, yoff;
2169         Gdk::Geometry g;
2170
2171         if ((prop = node.property ("id")) != 0) {
2172                 _id = prop->value ();
2173         }
2174
2175         g.base_width = default_width;
2176         g.base_height = default_height;
2177         x = 1;
2178         y = 1;
2179         xoff = 0;
2180         yoff = 21;
2181
2182         if ((geometry = find_named_node (node, "geometry")) != 0) {
2183
2184                 XMLProperty* prop;
2185
2186                 if ((prop = geometry->property("x_size")) == 0) {
2187                         prop = geometry->property ("x-size");
2188                 }
2189                 if (prop) {
2190                         g.base_width = atoi(prop->value());
2191                 }
2192                 if ((prop = geometry->property("y_size")) == 0) {
2193                         prop = geometry->property ("y-size");
2194                 }
2195                 if (prop) {
2196                         g.base_height = atoi(prop->value());
2197                 }
2198
2199                 if ((prop = geometry->property ("x_pos")) == 0) {
2200                         prop = geometry->property ("x-pos");
2201                 }
2202                 if (prop) {
2203                         x = atoi (prop->value());
2204
2205                 }
2206                 if ((prop = geometry->property ("y_pos")) == 0) {
2207                         prop = geometry->property ("y-pos");
2208                 }
2209                 if (prop) {
2210                         y = atoi (prop->value());
2211                 }
2212
2213                 if ((prop = geometry->property ("x_off")) == 0) {
2214                         prop = geometry->property ("x-off");
2215                 }
2216                 if (prop) {
2217                         xoff = atoi (prop->value());
2218                 }
2219                 if ((prop = geometry->property ("y_off")) == 0) {
2220                         prop = geometry->property ("y-off");
2221                 }
2222                 if (prop) {
2223                         yoff = atoi (prop->value());
2224                 }
2225         }
2226
2227         set_default_size (g.base_width, g.base_height);
2228         move (x, y);
2229
2230         if (_session && (prop = node.property ("playhead"))) {
2231                 framepos_t pos;
2232                 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2233                 playhead_cursor->set_position (pos);
2234         } else {
2235                 playhead_cursor->set_position (0);
2236         }
2237         
2238         if ((prop = node.property ("mixer-width"))) {
2239                 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2240         }
2241
2242         if ((prop = node.property ("zoom-focus"))) {
2243                 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2244         }
2245
2246         if ((prop = node.property ("zoom"))) {
2247                 reset_zoom (PBD::atof (prop->value()));
2248         } else {
2249                 reset_zoom (frames_per_unit);
2250         }
2251
2252         if ((prop = node.property ("snap-to"))) {
2253                 set_snap_to ((SnapType) atoi (prop->value()));
2254         }
2255
2256         if ((prop = node.property ("snap-mode"))) {
2257                 set_snap_mode ((SnapMode) atoi (prop->value()));
2258         }
2259
2260         if ((prop = node.property ("mouse-mode"))) {
2261                 MouseMode m = str2mousemode(prop->value());
2262                 set_mouse_mode (m, true);
2263         } else {
2264                 set_mouse_mode (MouseObject, true);
2265         }
2266
2267         if ((prop = node.property ("left-frame")) != 0){
2268                 framepos_t pos;
2269                 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2270                         reset_x_origin (pos);
2271                 }
2272         }
2273
2274         if ((prop = node.property ("y-origin")) != 0) {
2275                 reset_y_origin (atof (prop->value ()));
2276         }
2277
2278         if ((prop = node.property ("internal-edit"))) {
2279                 bool yn = string_is_affirmative (prop->value());
2280                 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2281                 if (act) {
2282                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2283                         tact->set_active (!yn);
2284                         tact->set_active (yn);
2285                 }
2286         }
2287
2288         if ((prop = node.property ("join-object-range"))) {
2289                 join_object_range_button.set_active (string_is_affirmative (prop->value ()));
2290         }
2291
2292         if ((prop = node.property ("edit-point"))) {
2293                 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2294         }
2295
2296         if ((prop = node.property ("show-measures"))) {
2297                 bool yn = string_is_affirmative (prop->value());
2298                 _show_measures = yn;
2299                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2300                 if (act) {
2301                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2302                         /* do it twice to force the change */
2303                         tact->set_active (!yn);
2304                         tact->set_active (yn);
2305                 }
2306         }
2307
2308         if ((prop = node.property ("follow-playhead"))) {
2309                 bool yn = string_is_affirmative (prop->value());
2310                 set_follow_playhead (yn);
2311                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2312                 if (act) {
2313                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2314                         if (tact->get_active() != yn) {
2315                                 tact->set_active (yn);
2316                         }
2317                 }
2318         }
2319
2320         if ((prop = node.property ("stationary-playhead"))) {
2321                 bool yn = (prop->value() == "yes");
2322                 set_stationary_playhead (yn);
2323                 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2324                 if (act) {
2325                         RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2326                         if (tact->get_active() != yn) {
2327                                 tact->set_active (yn);
2328                         }
2329                 }
2330         }
2331         
2332         if ((prop = node.property ("region-list-sort-type"))) {
2333                 RegionListSortType st;
2334                 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2335         }
2336
2337         if ((prop = node.property ("xfades-visible"))) {
2338                 bool yn = string_is_affirmative (prop->value());
2339                 _xfade_visibility = !yn;
2340                 // set_xfade_visibility (yn);
2341         }
2342
2343         if ((prop = node.property ("show-editor-mixer"))) {
2344
2345                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2346                 assert (act);
2347
2348                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2349                 bool yn = string_is_affirmative (prop->value());
2350                 
2351                 /* do it twice to force the change */
2352                 
2353                 tact->set_active (!yn);
2354                 tact->set_active (yn);
2355         }
2356
2357         if ((prop = node.property ("show-editor-list"))) {
2358
2359                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2360                 assert (act);
2361
2362                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2363                 bool yn = string_is_affirmative (prop->value());
2364                 
2365                 /* do it twice to force the change */
2366                 
2367                 tact->set_active (!yn);
2368                 tact->set_active (yn);
2369         }
2370
2371         if ((prop = node.property (X_("editor-list-page")))) {
2372                 the_notebook.set_current_page (atoi (prop->value ()));
2373         }
2374
2375         if ((prop = node.property (X_("show-marker-lines")))) {
2376                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2377                 assert (act);
2378                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2379                 bool yn = string_is_affirmative (prop->value ());
2380
2381                 tact->set_active (!yn);
2382                 tact->set_active (yn);
2383         }
2384
2385         XMLNodeList children = node.children ();
2386         for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2387                 selection->set_state (**i, Stateful::current_state_version);
2388                 _regions->set_state (**i);
2389         }
2390
2391         return 0;
2392 }
2393
2394 XMLNode&
2395 Editor::get_state ()
2396 {
2397         XMLNode* node = new XMLNode ("Editor");
2398         char buf[32];
2399
2400         _id.print (buf, sizeof (buf));
2401         node->add_property ("id", buf);
2402
2403         if (is_realized()) {
2404                 Glib::RefPtr<Gdk::Window> win = get_window();
2405
2406                 int x, y, xoff, yoff, width, height;
2407                 win->get_root_origin(x, y);
2408                 win->get_position(xoff, yoff);
2409                 win->get_size(width, height);
2410
2411                 XMLNode* geometry = new XMLNode ("geometry");
2412
2413                 snprintf(buf, sizeof(buf), "%d", width);
2414                 geometry->add_property("x-size", string(buf));
2415                 snprintf(buf, sizeof(buf), "%d", height);
2416                 geometry->add_property("y-size", string(buf));
2417                 snprintf(buf, sizeof(buf), "%d", x);
2418                 geometry->add_property("x-pos", string(buf));
2419                 snprintf(buf, sizeof(buf), "%d", y);
2420                 geometry->add_property("y-pos", string(buf));
2421                 snprintf(buf, sizeof(buf), "%d", xoff);
2422                 geometry->add_property("x-off", string(buf));
2423                 snprintf(buf, sizeof(buf), "%d", yoff);
2424                 geometry->add_property("y-off", string(buf));
2425                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2426                 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2427                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2428                 geometry->add_property("edit-vertical-pane-pos", string(buf));
2429
2430                 node->add_child_nocopy (*geometry);
2431         }
2432
2433         maybe_add_mixer_strip_width (*node);
2434
2435         snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2436         node->add_property ("zoom-focus", buf);
2437         snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2438         node->add_property ("zoom", buf);
2439         snprintf (buf, sizeof(buf), "%d", (int) _snap_type);
2440         node->add_property ("snap-to", buf);
2441         snprintf (buf, sizeof(buf), "%d", (int) _snap_mode);
2442         node->add_property ("snap-mode", buf);
2443
2444         node->add_property ("edit-point", enum_2_string (_edit_point));
2445
2446         snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2447         node->add_property ("playhead", buf);
2448         snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2449         node->add_property ("left-frame", buf);
2450         snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2451         node->add_property ("y-origin", buf);
2452
2453         node->add_property ("show-measures", _show_measures ? "yes" : "no");
2454         node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2455         node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2456         node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2457         node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2458         node->add_property ("mouse-mode", enum2str(mouse_mode));
2459         node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2460         node->add_property ("join-object-range", join_object_range_button.get_active () ? "yes" : "no");
2461
2462         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2463         if (act) {
2464                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2465                 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2466         }
2467
2468         act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2469         if (act) {
2470                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2471                 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2472         }
2473
2474         snprintf (buf, sizeof (buf), "%d", the_notebook.get_current_page ());
2475         node->add_property (X_("editor-list-page"), buf);
2476
2477         node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2478
2479         node->add_child_nocopy (selection->get_state ());
2480         node->add_child_nocopy (_regions->get_state ());
2481         
2482         return *node;
2483 }
2484
2485
2486
2487 /** @param y y offset from the top of all trackviews.
2488  *  @return pair: TimeAxisView that y is over, layer index.
2489  *  TimeAxisView may be 0.  Layer index is the layer number if the TimeAxisView is valid and is
2490  *  in stacked region display mode, otherwise 0.
2491  */
2492 std::pair<TimeAxisView *, layer_t>
2493 Editor::trackview_by_y_position (double y)
2494 {
2495         for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2496
2497                 std::pair<TimeAxisView*, int> const r = (*iter)->covers_y_position (y);
2498                 if (r.first) {
2499                         return r;
2500                 }
2501         }
2502
2503         return std::make_pair ( (TimeAxisView *) 0, 0);
2504 }
2505
2506 /** Snap a position to the grid, if appropriate, taking into account current
2507  *  grid settings and also the state of any snap modifier keys that may be pressed.
2508  *  @param start Position to snap.
2509  *  @param event Event to get current key modifier information from, or 0.
2510  */
2511 void
2512 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2513 {
2514         if (!_session || !event) {
2515                 return;
2516         }
2517
2518         if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2519                 if (_snap_mode == SnapOff) {
2520                         snap_to_internal (start, direction, for_mark);
2521                 }
2522         } else {
2523                 if (_snap_mode != SnapOff) {
2524                         snap_to_internal (start, direction, for_mark);
2525                 }
2526         }
2527 }
2528
2529 void
2530 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2531 {
2532         if (!_session || _snap_mode == SnapOff) {
2533                 return;
2534         }
2535
2536         snap_to_internal (start, direction, for_mark);
2537 }
2538
2539 void
2540 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2541 {
2542         const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2543         framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2544
2545         switch (_snap_type) {
2546         case SnapToTimecodeFrame:
2547                 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2548                         start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2549                 } else {
2550                         start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) *  _session->frames_per_timecode_frame());
2551                 }
2552                 break;
2553
2554         case SnapToTimecodeSeconds:
2555                 if (_session->timecode_offset_negative())
2556                 {
2557                         start += _session->timecode_offset ();
2558                 } else {
2559                         start -= _session->timecode_offset ();
2560                 }
2561                 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2562                         start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2563                 } else {
2564                         start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2565                 }
2566
2567                 if (_session->timecode_offset_negative())
2568                 {
2569                         start -= _session->timecode_offset ();
2570                 } else {
2571                         start += _session->timecode_offset ();
2572                 }
2573                 break;
2574
2575         case SnapToTimecodeMinutes:
2576                 if (_session->timecode_offset_negative())
2577                 {
2578                         start += _session->timecode_offset ();
2579                 } else {
2580                         start -= _session->timecode_offset ();
2581                 }
2582                 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2583                         start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2584                 } else {
2585                         start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2586                 }
2587                 if (_session->timecode_offset_negative())
2588                 {
2589                         start -= _session->timecode_offset ();
2590                 } else {
2591                         start += _session->timecode_offset ();
2592                 }
2593                 break;
2594         default:
2595                 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2596                 /*NOTREACHED*/
2597         }
2598 }
2599
2600 void
2601 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2602 {
2603         const framepos_t one_second = _session->frame_rate();
2604         const framepos_t one_minute = _session->frame_rate() * 60;
2605         framepos_t presnap = start;
2606         framepos_t before;
2607         framepos_t after;
2608
2609         switch (_snap_type) {
2610         case SnapToTimecodeFrame:
2611         case SnapToTimecodeSeconds:
2612         case SnapToTimecodeMinutes:
2613                 return timecode_snap_to_internal (start, direction, for_mark);
2614
2615         case SnapToCDFrame:
2616                 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2617                         start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2618                 } else {
2619                         start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2620                 }
2621                 break;
2622
2623         case SnapToSeconds:
2624                 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2625                         start = (framepos_t) ceil ((double) start / one_second) * one_second;
2626                 } else {
2627                         start = (framepos_t) floor ((double) start / one_second) * one_second;
2628                 }
2629                 break;
2630
2631         case SnapToMinutes:
2632                 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2633                         start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2634                 } else {
2635                         start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2636                 }
2637                 break;
2638
2639         case SnapToBar:
2640                 start = _session->tempo_map().round_to_bar (start, direction);
2641                 break;
2642
2643         case SnapToBeat:
2644                 start = _session->tempo_map().round_to_beat (start, direction);
2645                 break;
2646
2647         case SnapToBeatDiv32:
2648                 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2649                 break;
2650         case SnapToBeatDiv28:
2651                 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2652                 break;
2653         case SnapToBeatDiv24:
2654                 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2655                 break;
2656         case SnapToBeatDiv20:
2657                 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2658                 break;
2659         case SnapToBeatDiv16:
2660                 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2661                 break;
2662         case SnapToBeatDiv14:
2663                 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2664                 break;
2665         case SnapToBeatDiv12:
2666                 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2667                 break;
2668         case SnapToBeatDiv10:
2669                 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2670                 break;
2671         case SnapToBeatDiv8:
2672                 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2673                 break;
2674         case SnapToBeatDiv7:
2675                 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2676                 break;
2677         case SnapToBeatDiv6:
2678                 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2679                 break;
2680         case SnapToBeatDiv5:
2681                 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2682                 break;
2683         case SnapToBeatDiv4:
2684                 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2685                 break;
2686         case SnapToBeatDiv3:
2687                 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2688                 break;
2689         case SnapToBeatDiv2:
2690                 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2691                 break;
2692
2693         case SnapToMark:
2694                 if (for_mark) {
2695                         return;
2696                 }
2697
2698                 _session->locations()->marks_either_side (start, before, after);
2699
2700                 if (before == max_framepos) {
2701                         start = after;
2702                 } else if (after == max_framepos) {
2703                         start = before;
2704                 } else if (before != max_framepos && after != max_framepos) {
2705                         /* have before and after */
2706                         if ((start - before) < (after - start)) {
2707                                 start = before;
2708                         } else {
2709                                 start = after;
2710                         }
2711                 }
2712
2713                 break;
2714
2715         case SnapToRegionStart:
2716         case SnapToRegionEnd:
2717         case SnapToRegionSync:
2718         case SnapToRegionBoundary:
2719                 if (!region_boundary_cache.empty()) {
2720
2721                         vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2722                         vector<framepos_t>::iterator next = region_boundary_cache.end ();
2723
2724                         if (direction > 0) {
2725                                 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2726                         } else {
2727                                 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2728                         }
2729
2730                         if (next != region_boundary_cache.begin ()) {
2731                                 prev = next;
2732                                 prev--;
2733                         }
2734
2735                         framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2736                         framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2737
2738                         if (start > (p + n) / 2) {
2739                                 start = n;
2740                         } else {
2741                                 start = p;
2742                         }
2743                 }
2744                 break;
2745         }
2746
2747         switch (_snap_mode) {
2748         case SnapNormal:
2749                 return;
2750
2751         case SnapMagnetic:
2752
2753                 if (presnap > start) {
2754                         if (presnap > (start + unit_to_frame(snap_threshold))) {
2755                                 start = presnap;
2756                         }
2757
2758                 } else if (presnap < start) {
2759                         if (presnap < (start - unit_to_frame(snap_threshold))) {
2760                                 start = presnap;
2761                         }
2762                 }
2763
2764         default:
2765                 /* handled at entry */
2766                 return;
2767
2768         }
2769 }
2770
2771
2772 void
2773 Editor::setup_toolbar ()
2774 {
2775         string pixmap_path;
2776
2777         /* Mode Buttons (tool selection) */
2778
2779         mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2780         mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2781         mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2782         mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2783         mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2784         mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2785         // internal_edit_button.set_relief(Gtk::RELIEF_NONE);
2786         join_object_range_button.set_relief(Gtk::RELIEF_NONE);
2787
2788         HBox* mode_box = manage(new HBox);
2789         mode_box->set_border_width (2);
2790         mode_box->set_spacing(4);
2791
2792         /* table containing mode buttons */
2793
2794         HBox* mouse_mode_button_box = manage (new HBox ());
2795
2796         if (Profile->get_sae()) {
2797                 mouse_mode_button_box->pack_start (mouse_move_button);
2798         } else {
2799                 mouse_mode_button_box->pack_start (mouse_move_button);
2800                 mouse_mode_button_box->pack_start (join_object_range_button);
2801                 mouse_mode_button_box->pack_start (mouse_select_button);
2802         }
2803
2804         mouse_mode_button_box->pack_start (mouse_zoom_button);
2805
2806         if (!Profile->get_sae()) {
2807                 mouse_mode_button_box->pack_start (mouse_gain_button);
2808         }
2809
2810         mouse_mode_button_box->pack_start (mouse_timefx_button);
2811         mouse_mode_button_box->pack_start (mouse_audition_button);
2812         mouse_mode_button_box->pack_start (internal_edit_button);
2813
2814         vector<string> edit_mode_strings;
2815         edit_mode_strings.push_back (edit_mode_to_string (Slide));
2816         if (!Profile->get_sae()) {
2817                 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2818         }
2819         edit_mode_strings.push_back (edit_mode_to_string (Lock));
2820
2821         edit_mode_selector.set_name ("EditModeSelector");
2822         set_popdown_strings (edit_mode_selector, edit_mode_strings, true);
2823         edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2824
2825         mode_box->pack_start (edit_mode_selector);
2826         mode_box->pack_start (*mouse_mode_button_box);
2827
2828         _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2829         _mouse_mode_tearoff->set_name ("MouseModeBase");
2830         _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2831
2832         if (Profile->get_sae()) {
2833                 _mouse_mode_tearoff->set_can_be_torn_off (false);
2834         }
2835
2836         _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2837                                                          &_mouse_mode_tearoff->tearoff_window()));
2838         _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2839                                                          &_mouse_mode_tearoff->tearoff_window(), 1));
2840         _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2841                                                          &_mouse_mode_tearoff->tearoff_window()));
2842         _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2843                                                           &_mouse_mode_tearoff->tearoff_window(), 1));
2844
2845         mouse_move_button.set_mode (false);
2846         mouse_select_button.set_mode (false);
2847         mouse_gain_button.set_mode (false);
2848         mouse_zoom_button.set_mode (false);
2849         mouse_timefx_button.set_mode (false);
2850         mouse_audition_button.set_mode (false);
2851         join_object_range_button.set_mode (false);
2852
2853         mouse_move_button.set_name ("MouseModeButton");
2854         mouse_select_button.set_name ("MouseModeButton");
2855         mouse_gain_button.set_name ("MouseModeButton");
2856         mouse_zoom_button.set_name ("MouseModeButton");
2857         mouse_timefx_button.set_name ("MouseModeButton");
2858         mouse_audition_button.set_name ("MouseModeButton");
2859         internal_edit_button.set_name ("MouseModeButton");
2860         join_object_range_button.set_name ("MouseModeButton");
2861
2862         mouse_move_button.unset_flags (CAN_FOCUS);
2863         mouse_select_button.unset_flags (CAN_FOCUS);
2864         mouse_gain_button.unset_flags (CAN_FOCUS);
2865         mouse_zoom_button.unset_flags (CAN_FOCUS);
2866         mouse_timefx_button.unset_flags (CAN_FOCUS);
2867         mouse_audition_button.unset_flags (CAN_FOCUS);
2868         internal_edit_button.unset_flags (CAN_FOCUS);
2869         join_object_range_button.unset_flags (CAN_FOCUS);
2870
2871         /* Zoom */
2872
2873         _zoom_box.set_spacing (1);
2874         _zoom_box.set_border_width (0);
2875
2876         zoom_in_button.set_name ("EditorTimeButton");
2877         zoom_in_button.set_image (*(manage (new Image (Stock::ZOOM_IN, Gtk::ICON_SIZE_MENU))));
2878         zoom_in_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step), false));
2879
2880         zoom_out_button.set_name ("EditorTimeButton");
2881         zoom_out_button.set_image (*(manage (new Image (Stock::ZOOM_OUT, Gtk::ICON_SIZE_MENU))));
2882         zoom_out_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step), true));
2883
2884         zoom_out_full_button.set_name ("EditorTimeButton");
2885         zoom_out_full_button.set_image (*(manage (new Image (Stock::ZOOM_100, Gtk::ICON_SIZE_MENU))));
2886         zoom_out_full_button.signal_clicked().connect (sigc::mem_fun(*this, &Editor::temporal_zoom_session));
2887
2888         zoom_focus_selector.set_name ("ZoomFocusSelector");
2889         set_popdown_strings (zoom_focus_selector, zoom_focus_strings, true);
2890         zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2891
2892         _zoom_box.pack_start (zoom_out_button, false, false);
2893         _zoom_box.pack_start (zoom_in_button, false, false);
2894         _zoom_box.pack_start (zoom_out_full_button, false, false);
2895
2896         _zoom_box.pack_start (zoom_focus_selector);
2897         
2898         /* Track zoom buttons */
2899         tav_expand_button.set_name ("TrackHeightButton");
2900         tav_expand_button.set_size_request(-1,20);
2901         tav_expand_button.add (*(manage (new Image (::get_icon("tav_exp")))));
2902         tav_expand_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::tav_zoom_step), true));
2903
2904         tav_shrink_button.set_name ("TrackHeightButton");
2905         tav_shrink_button.set_size_request(-1,20);
2906         tav_shrink_button.add (*(manage (new Image (::get_icon("tav_shrink")))));
2907         tav_shrink_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::tav_zoom_step), false));
2908
2909         _zoom_box.pack_start (tav_shrink_button);
2910         _zoom_box.pack_start (tav_expand_button);
2911         
2912         _zoom_tearoff = manage (new TearOff (_zoom_box));
2913
2914         _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2915                                                    &_zoom_tearoff->tearoff_window()));
2916         _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2917                                                    &_zoom_tearoff->tearoff_window(), 0));
2918         _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2919                                                    &_zoom_tearoff->tearoff_window()));
2920         _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2921                                                     &_zoom_tearoff->tearoff_window(), 0));
2922         
2923         snap_box.set_spacing (1);
2924         snap_box.set_border_width (2);
2925
2926         snap_type_selector.set_name ("SnapTypeSelector");
2927         set_popdown_strings (snap_type_selector, snap_type_strings, true);
2928         snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2929
2930         snap_mode_selector.set_name ("SnapModeSelector");
2931         set_popdown_strings (snap_mode_selector, snap_mode_strings, true);
2932         snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2933
2934         edit_point_selector.set_name ("EditPointSelector");
2935         set_popdown_strings (edit_point_selector, edit_point_strings, true);
2936         edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2937
2938         snap_box.pack_start (snap_mode_selector, false, false);
2939         snap_box.pack_start (snap_type_selector, false, false);
2940         snap_box.pack_start (edit_point_selector, false, false);
2941
2942         /* Nudge */
2943
2944         HBox *nudge_box = manage (new HBox);
2945         nudge_box->set_spacing(1);
2946         nudge_box->set_border_width (2);
2947
2948         nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2949         nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2950
2951         nudge_box->pack_start (nudge_backward_button, false, false);
2952         nudge_box->pack_start (nudge_forward_button, false, false);
2953         nudge_box->pack_start (nudge_clock, false, false);
2954
2955
2956         /* Pack everything in... */
2957
2958         HBox* hbox = manage (new HBox);
2959         hbox->set_spacing(10);
2960
2961         _tools_tearoff = manage (new TearOff (*hbox));
2962         _tools_tearoff->set_name ("MouseModeBase");
2963         _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2964         
2965         if (Profile->get_sae()) {
2966                 _tools_tearoff->set_can_be_torn_off (false);
2967         }
2968
2969         _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2970                                                     &_tools_tearoff->tearoff_window()));
2971         _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2972                                                     &_tools_tearoff->tearoff_window(), 0));
2973         _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2974                                                     &_tools_tearoff->tearoff_window()));
2975         _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2976                                                      &_tools_tearoff->tearoff_window(), 0));
2977
2978         toolbar_hbox.set_spacing (10);
2979         toolbar_hbox.set_border_width (1);
2980
2981         toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2982         toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
2983         toolbar_hbox.pack_start (*_tools_tearoff, false, false);
2984
2985         hbox->pack_start (snap_box, false, false);
2986         hbox->pack_start (*nudge_box, false, false);
2987         hbox->pack_start (panic_box, false, false);
2988
2989         hbox->show_all ();
2990
2991         toolbar_base.set_name ("ToolBarBase");
2992         toolbar_base.add (toolbar_hbox);
2993
2994         toolbar_frame.set_shadow_type (SHADOW_OUT);
2995         toolbar_frame.set_name ("BaseFrame");
2996         toolbar_frame.add (toolbar_base);
2997 }
2998
2999 void
3000 Editor::setup_tooltips ()
3001 {
3002         ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
3003         ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3004         ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3005         ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3006         ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3007         ARDOUR_UI::instance()->set_tip (join_object_range_button, _("Select/Move Objects or Ranges"));
3008         ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)"));
3009         ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3010         ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
3011         ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
3012         ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3013         ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3014         ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3015         ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3016         ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3017         ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3018         ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3019         ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3020         ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3021         ARDOUR_UI::instance()->set_tip (midi_sound_notes, _("Sound Notes"));
3022         ARDOUR_UI::instance()->set_tip (midi_panic_button, _("Send note off and reset controller messages on all MIDI channels"));
3023         ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3024 }
3025
3026 void
3027 Editor::midi_panic ()
3028 {
3029         cerr << "MIDI panic\n";
3030
3031         if (_session) {
3032                 _session->midi_panic();
3033         }
3034 }
3035
3036 void
3037 Editor::setup_midi_toolbar ()
3038 {
3039         RefPtr<Action> act;
3040
3041         /* Midi sound notes */
3042         midi_sound_notes.add (*(manage (new Image (::get_icon("midi_sound_notes")))));
3043         midi_sound_notes.set_relief(Gtk::RELIEF_NONE);
3044         midi_sound_notes.unset_flags (CAN_FOCUS);
3045
3046         /* Panic */
3047
3048         act = ActionManager::get_action (X_("MIDI"), X_("panic"));
3049         midi_panic_button.set_name("MidiPanicButton");
3050         act->connect_proxy (midi_panic_button);
3051
3052         panic_box.pack_start (midi_sound_notes , true, true);
3053         panic_box.pack_start (midi_panic_button, true, true);
3054 }
3055
3056 int
3057 Editor::convert_drop_to_paths (
3058                 vector<string>&                paths,
3059                 const RefPtr<Gdk::DragContext>& /*context*/,
3060                 gint                            /*x*/,
3061                 gint                            /*y*/,
3062                 const SelectionData&            data,
3063                 guint                           /*info*/,
3064                 guint                           /*time*/)
3065 {
3066         if (_session == 0) {
3067                 return -1;
3068         }
3069         
3070         vector<string> uris = data.get_uris();
3071
3072         if (uris.empty()) {
3073
3074                 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3075                    are actually URI lists. So do it by hand.
3076                 */
3077
3078                 if (data.get_target() != "text/plain") {
3079                         return -1;
3080                 }
3081
3082                 /* Parse the "uri-list" format that Nautilus provides,
3083                    where each pathname is delimited by \r\n.
3084
3085                    THERE MAY BE NO NULL TERMINATING CHAR!!!
3086                 */
3087
3088                 string txt = data.get_text();
3089                 const char* p;
3090                 const char* q;
3091
3092                 p = (const char *) malloc (txt.length() + 1);
3093                 txt.copy ((char *) p, txt.length(), 0);
3094                 ((char*)p)[txt.length()] = '\0';
3095
3096                 while (p)
3097                 {
3098                         if (*p != '#')
3099                         {
3100                                 while (g_ascii_isspace (*p))
3101                                         p++;
3102
3103                                 q = p;
3104                                 while (*q && (*q != '\n') && (*q != '\r')) {
3105                                         q++;
3106                                 }
3107
3108                                 if (q > p)
3109                                 {
3110                                         q--;
3111                                         while (q > p && g_ascii_isspace (*q))
3112                                                 q--;
3113
3114                                         if (q > p)
3115                                         {
3116                                                 uris.push_back (string (p, q - p + 1));
3117                                         }
3118                                 }
3119                         }
3120                         p = strchr (p, '\n');
3121                         if (p)
3122                                 p++;
3123                 }
3124
3125                 free ((void*)p);
3126
3127                 if (uris.empty()) {
3128                         return -1;
3129                 }
3130         }
3131
3132         for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3133
3134                 if ((*i).substr (0,7) == "file://") {
3135
3136                         string p = *i;
3137                         PBD::url_decode (p);
3138
3139                         // scan forward past three slashes
3140
3141                         string::size_type slashcnt = 0;
3142                         string::size_type n = 0;
3143                         string::iterator x = p.begin();
3144
3145                         while (slashcnt < 3 && x != p.end()) {
3146                                 if ((*x) == '/') {
3147                                         slashcnt++;
3148                                 } else if (slashcnt == 3) {
3149                                         break;
3150                                 }
3151                                 ++n;
3152                                 ++x;
3153                         }
3154
3155                         if (slashcnt != 3 || x == p.end()) {
3156                                 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3157                                 continue;
3158                         }
3159
3160                         paths.push_back (p.substr (n - 1));
3161                 }
3162         }
3163
3164         return 0;
3165 }
3166
3167 void
3168 Editor::new_tempo_section ()
3169
3170 {
3171 }
3172
3173 void
3174 Editor::map_transport_state ()
3175 {
3176         ENSURE_GUI_THREAD (*this, &Editor::map_transport_state)
3177
3178         if (_session && _session->transport_stopped()) {
3179                 have_pending_keyboard_selection = false;
3180         }
3181
3182         update_loop_range_view (true);
3183 }
3184
3185 /* UNDO/REDO */
3186
3187 Editor::State::State (PublicEditor const * e)
3188 {
3189         selection = new Selection (e);
3190 }
3191
3192 Editor::State::~State ()
3193 {
3194         delete selection;
3195 }
3196
3197 void
3198 Editor::begin_reversible_command (string name)
3199 {
3200         if (_session) {
3201                 _session->begin_reversible_command (name);
3202         }
3203 }
3204
3205 void
3206 Editor::commit_reversible_command ()
3207 {
3208         if (_session) {
3209                 _session->commit_reversible_command ();
3210         }
3211 }
3212
3213 void
3214 Editor::set_route_group_solo (Route& route, bool yn)
3215 {
3216         RouteGroup *route_group;
3217
3218         if ((route_group = route.route_group()) != 0) {
3219                 route_group->apply (&Route::set_solo, yn, this);
3220         } else {
3221                 route.set_solo (yn, this);
3222         }
3223 }
3224
3225 void
3226 Editor::set_route_group_mute (Route& route, bool yn)
3227 {
3228         RouteGroup *route_group = 0;
3229
3230         if ((route_group = route.route_group()) != 0) {
3231                 route_group->apply (&Route::set_mute, yn, this);
3232         } else {
3233                 route.set_mute (yn, this);
3234         }
3235 }
3236
3237 void
3238 Editor::history_changed ()
3239 {
3240         string label;
3241
3242         if (undo_action && _session) {
3243                 if (_session->undo_depth() == 0) {
3244                         label = _("Undo");
3245                 } else {
3246                         label = string_compose(_("Undo (%1)"), _session->next_undo());
3247                 }
3248                 undo_action->property_label() = label;
3249         }
3250
3251         if (redo_action && _session) {
3252                 if (_session->redo_depth() == 0) {
3253                         label = _("Redo");
3254                 } else {
3255                         label = string_compose(_("Redo (%1)"), _session->next_redo());
3256                 }
3257                 redo_action->property_label() = label;
3258         }
3259 }
3260
3261 void
3262 Editor::duplicate_dialog (bool with_dialog)
3263 {
3264         float times = 1.0f;
3265
3266         if (mouse_mode == MouseRange) {
3267                 if (selection->time.length() == 0) {
3268                         return;
3269                 }
3270         }
3271
3272         RegionSelection rs = get_regions_from_selection_and_entered ();
3273
3274         if (mouse_mode != MouseRange && rs.empty()) {
3275                 return;
3276         }
3277
3278         if (with_dialog) {
3279
3280                 ArdourDialog win (_("Duplicate"));
3281                 Label label (_("Number of duplications:"));
3282                 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3283                 SpinButton spinner (adjustment, 0.0, 1);
3284                 HBox hbox;
3285
3286                 win.get_vbox()->set_spacing (12);
3287                 win.get_vbox()->pack_start (hbox);
3288                 hbox.set_border_width (6);
3289                 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3290
3291                 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3292                    place, visually. so do this by hand.
3293                 */
3294
3295                 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3296                 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3297                 spinner.grab_focus();
3298
3299                 hbox.show ();
3300                 label.show ();
3301                 spinner.show ();
3302
3303                 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3304                 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3305                 win.set_default_response (RESPONSE_ACCEPT);
3306
3307                 win.set_position (WIN_POS_MOUSE);
3308
3309                 spinner.grab_focus ();
3310
3311                 switch (win.run ()) {
3312                 case RESPONSE_ACCEPT:
3313                         break;
3314                 default:
3315                         return;
3316                 }
3317
3318                 times = adjustment.get_value();
3319         }
3320
3321         if (mouse_mode == MouseRange) {
3322                 duplicate_selection (times);
3323         } else {
3324                 duplicate_some_regions (rs, times);
3325         }
3326 }
3327
3328 void
3329 Editor::show_verbose_canvas_cursor ()
3330 {
3331         verbose_canvas_cursor->raise_to_top();
3332         verbose_canvas_cursor->show();
3333         verbose_cursor_visible = true;
3334 }
3335
3336 void
3337 Editor::hide_verbose_canvas_cursor ()
3338 {
3339         verbose_canvas_cursor->hide();
3340         verbose_cursor_visible = false;
3341 }
3342
3343 double
3344 Editor::clamp_verbose_cursor_x (double x)
3345 {
3346         if (x < 0) {
3347                 x = 0;
3348         } else {
3349                 x = min (_canvas_width - 200.0, x);
3350         }
3351         return x;
3352 }
3353
3354 double
3355 Editor::clamp_verbose_cursor_y (double y)
3356 {
3357         if (y < canvas_timebars_vsize) {
3358                 y = canvas_timebars_vsize;
3359         } else {
3360                 y = min (_canvas_height - 50, y);
3361         }
3362         return y;
3363 }
3364
3365 void
3366 Editor::show_verbose_canvas_cursor_with (const string & txt, int32_t xoffset, int32_t yoffset)
3367 {
3368         verbose_canvas_cursor->property_text() = txt.c_str();
3369
3370         int x, y;
3371         double wx, wy;
3372
3373         track_canvas->get_pointer (x, y);
3374         track_canvas->window_to_world (x, y, wx, wy);
3375
3376         wx += xoffset;
3377         wy += yoffset;
3378
3379         /* don't get too close to the edge */
3380         verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (wx);
3381         verbose_canvas_cursor->property_y() = clamp_verbose_cursor_y (wy);
3382
3383         show_verbose_canvas_cursor ();
3384 }
3385
3386 void
3387 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3388 {
3389         verbose_canvas_cursor->property_text() = txt.c_str();
3390         /* don't get too close to the edge */
3391         verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (x);
3392         verbose_canvas_cursor->property_y() = clamp_verbose_cursor_y (y);
3393 }
3394
3395 void
3396 Editor::set_verbose_canvas_cursor_text (const string & txt)
3397 {
3398         verbose_canvas_cursor->property_text() = txt.c_str();
3399 }
3400
3401 void
3402 Editor::set_edit_mode (EditMode m)
3403 {
3404         Config->set_edit_mode (m);
3405 }
3406
3407 void
3408 Editor::cycle_edit_mode ()
3409 {
3410         switch (Config->get_edit_mode()) {
3411         case Slide:
3412                 if (Profile->get_sae()) {
3413                         Config->set_edit_mode (Lock);
3414                 } else {
3415                         Config->set_edit_mode (Splice);
3416                 }
3417                 break;
3418         case Splice:
3419                 Config->set_edit_mode (Lock);
3420                 break;
3421         case Lock:
3422                 Config->set_edit_mode (Slide);
3423                 break;
3424         }
3425 }
3426
3427 void
3428 Editor::edit_mode_selection_done ()
3429 {
3430         Config->set_edit_mode (string_to_edit_mode (edit_mode_selector.get_active_text ()));
3431 }
3432
3433 void
3434 Editor::snap_type_selection_done ()
3435 {
3436         string choice = snap_type_selector.get_active_text();
3437         SnapType snaptype = SnapToBeat;
3438
3439         if (choice == _("Beats/2")) {
3440                 snaptype = SnapToBeatDiv2;
3441         } else if (choice == _("Beats/3")) {
3442                 snaptype = SnapToBeatDiv3;
3443         } else if (choice == _("Beats/4")) {
3444                 snaptype = SnapToBeatDiv4;
3445         } else if (choice == _("Beats/5")) {
3446                 snaptype = SnapToBeatDiv5;
3447         } else if (choice == _("Beats/6")) {
3448                 snaptype = SnapToBeatDiv6;
3449         } else if (choice == _("Beats/7")) {
3450                 snaptype = SnapToBeatDiv7;
3451         } else if (choice == _("Beats/8")) {
3452                 snaptype = SnapToBeatDiv8;
3453         } else if (choice == _("Beats/10")) {
3454                 snaptype = SnapToBeatDiv10;
3455         } else if (choice == _("Beats/12")) {
3456                 snaptype = SnapToBeatDiv12;
3457         } else if (choice == _("Beats/14")) {
3458                 snaptype = SnapToBeatDiv14;
3459         } else if (choice == _("Beats/16")) {
3460                 snaptype = SnapToBeatDiv16;
3461         } else if (choice == _("Beats/20")) {
3462                 snaptype = SnapToBeatDiv20;
3463         } else if (choice == _("Beats/24")) {
3464                 snaptype = SnapToBeatDiv24;
3465         } else if (choice == _("Beats/28")) {
3466                 snaptype = SnapToBeatDiv28;
3467         } else if (choice == _("Beats/32")) {
3468                 snaptype = SnapToBeatDiv32;
3469         } else if (choice == _("Beats")) {
3470                 snaptype = SnapToBeat;
3471         } else if (choice == _("Bars")) {
3472                 snaptype = SnapToBar;
3473         } else if (choice == _("Marks")) {
3474                 snaptype = SnapToMark;
3475         } else if (choice == _("Region starts")) {
3476                 snaptype = SnapToRegionStart;
3477         } else if (choice == _("Region ends")) {
3478                 snaptype = SnapToRegionEnd;
3479         } else if (choice == _("Region bounds")) {
3480                 snaptype = SnapToRegionBoundary;
3481         } else if (choice == _("Region syncs")) {
3482                 snaptype = SnapToRegionSync;
3483         } else if (choice == _("CD Frames")) {
3484                 snaptype = SnapToCDFrame;
3485         } else if (choice == _("Timecode Frames")) {
3486                 snaptype = SnapToTimecodeFrame;
3487         } else if (choice == _("Timecode Seconds")) {
3488                 snaptype = SnapToTimecodeSeconds;
3489         } else if (choice == _("Timecode Minutes")) {
3490                 snaptype = SnapToTimecodeMinutes;
3491         } else if (choice == _("Seconds")) {
3492                 snaptype = SnapToSeconds;
3493         } else if (choice == _("Minutes")) {
3494                 snaptype = SnapToMinutes;
3495         }
3496
3497         RefPtr<RadioAction> ract = snap_type_action (snaptype);
3498         if (ract) {
3499                 ract->set_active ();
3500         }
3501 }
3502
3503 void
3504 Editor::snap_mode_selection_done ()
3505 {
3506         string choice = snap_mode_selector.get_active_text();
3507         SnapMode mode = SnapNormal;
3508
3509         if (choice == _("No Grid")) {
3510                 mode = SnapOff;
3511         } else if (choice == _("Grid")) {
3512                 mode = SnapNormal;
3513         } else if (choice == _("Magnetic")) {
3514                 mode = SnapMagnetic;
3515         }
3516
3517         RefPtr<RadioAction> ract = snap_mode_action (mode);
3518
3519         if (ract) {
3520                 ract->set_active (true);
3521         }
3522 }
3523
3524 void
3525 Editor::cycle_edit_point (bool with_marker)
3526 {
3527         switch (_edit_point) {
3528         case EditAtMouse:
3529                 set_edit_point_preference (EditAtPlayhead);
3530                 break;
3531         case EditAtPlayhead:
3532                 if (with_marker) {
3533                         set_edit_point_preference (EditAtSelectedMarker);
3534                 } else {
3535                         set_edit_point_preference (EditAtMouse);
3536                 }
3537                 break;
3538         case EditAtSelectedMarker:
3539                 set_edit_point_preference (EditAtMouse);
3540                 break;
3541         }
3542 }
3543
3544 void
3545 Editor::edit_point_selection_done ()
3546 {
3547         string choice = edit_point_selector.get_active_text();
3548         EditPoint ep = EditAtSelectedMarker;
3549
3550         if (choice == _("Marker")) {
3551                 set_edit_point_preference (EditAtSelectedMarker);
3552         } else if (choice == _("Playhead")) {
3553                 set_edit_point_preference (EditAtPlayhead);
3554         } else {
3555                 set_edit_point_preference (EditAtMouse);
3556         }
3557
3558         RefPtr<RadioAction> ract = edit_point_action (ep);
3559
3560         if (ract) {
3561                 ract->set_active (true);
3562         }
3563 }
3564
3565 void
3566 Editor::zoom_focus_selection_done ()
3567 {
3568         string choice = zoom_focus_selector.get_active_text();
3569         ZoomFocus focus_type = ZoomFocusLeft;
3570
3571         if (choice == _("Left")) {
3572                 focus_type = ZoomFocusLeft;
3573         } else if (choice == _("Right")) {
3574                 focus_type = ZoomFocusRight;
3575         } else if (choice == _("Center")) {
3576                 focus_type = ZoomFocusCenter;
3577         } else if (choice == _("Playhead")) {
3578                 focus_type = ZoomFocusPlayhead;
3579         } else if (choice == _("Mouse")) {
3580                 focus_type = ZoomFocusMouse;
3581         } else if (choice == _("Edit point")) {
3582                 focus_type = ZoomFocusEdit;
3583         }
3584
3585         RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3586
3587         if (ract) {
3588                 ract->set_active ();
3589         }
3590 }
3591
3592 gint
3593 Editor::edit_controls_button_release (GdkEventButton* ev)
3594 {
3595         if (Keyboard::is_context_menu_event (ev)) {
3596                 ARDOUR_UI::instance()->add_route (this);
3597         }
3598         return TRUE;
3599 }
3600
3601 gint
3602 Editor::mouse_select_button_release (GdkEventButton* ev)
3603 {
3604         /* this handles just right-clicks */
3605
3606         if (ev->button != 3) {
3607                 return false;
3608         }
3609
3610         return true;
3611 }
3612
3613 void
3614 Editor::set_zoom_focus (ZoomFocus f)
3615 {
3616         string str = zoom_focus_strings[(int)f];
3617
3618         if (str != zoom_focus_selector.get_active_text()) {
3619                 zoom_focus_selector.set_active_text (str);
3620         }
3621
3622         if (zoom_focus != f) {
3623                 zoom_focus = f;
3624
3625                 ZoomFocusChanged (); /* EMIT_SIGNAL */
3626
3627                 instant_save ();
3628         }
3629 }
3630
3631 void
3632 Editor::ensure_float (Window& win)
3633 {
3634         win.set_transient_for (*this);
3635 }
3636
3637 void
3638 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3639 {
3640         /* recover or initialize pane positions. do this here rather than earlier because
3641            we don't want the positions to change the child allocations, which they seem to do.
3642          */
3643
3644         int pos;
3645         XMLProperty* prop;
3646         char buf[32];
3647         XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3648         int width, height;
3649
3650         enum Pane {
3651                 Horizontal = 0x1,
3652                 Vertical = 0x2
3653         };
3654
3655         static Pane done;
3656         
3657         XMLNode* geometry;
3658
3659         width = default_width;
3660         height = default_height;
3661
3662         if ((geometry = find_named_node (*node, "geometry")) != 0) {
3663
3664                 prop = geometry->property ("x-size");
3665                 if (prop) {
3666                         width = atoi (prop->value());
3667                 }
3668                 prop = geometry->property ("y-size");
3669                 if (prop) {
3670                         height = atoi (prop->value());
3671                 }
3672         }
3673
3674         if (which == static_cast<Paned*> (&edit_pane)) {
3675
3676                 if (done & Horizontal) {
3677                         return;
3678                 }
3679
3680                 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3681                         /* initial allocation is 90% to canvas, 10% to notebook */
3682                         pos = (int) floor (alloc.get_width() * 0.90f);
3683                         snprintf (buf, sizeof(buf), "%d", pos);
3684                 } else {
3685                         pos = atoi (prop->value());
3686                 }
3687
3688                 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3689                         edit_pane.set_position (pos);
3690                         pre_maximal_horizontal_pane_position = pos;
3691                 }
3692
3693                 done = (Pane) (done | Horizontal);
3694                 
3695         } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3696
3697                 if (done & Vertical) {
3698                         return;
3699                 }
3700
3701                 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3702                         /* initial allocation is 90% to canvas, 10% to summary */
3703                         pos = (int) floor (alloc.get_height() * 0.90f);
3704                         snprintf (buf, sizeof(buf), "%d", pos);
3705                 } else {
3706                         pos = atoi (prop->value());
3707                 }
3708
3709                 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3710                         editor_summary_pane.set_position (pos);
3711                         pre_maximal_vertical_pane_position = pos;
3712                 }
3713
3714                 done = (Pane) (done | Vertical);
3715         }
3716 }
3717
3718 void
3719 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3720 {
3721         if (_tools_tearoff->torn_off() && _mouse_mode_tearoff->torn_off()) {
3722                 top_hbox.remove (toolbar_frame);
3723         }
3724 }
3725
3726 void
3727 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3728 {
3729         if (toolbar_frame.get_parent() == 0) {
3730                 top_hbox.pack_end (toolbar_frame);
3731         }
3732 }
3733
3734 void
3735 Editor::set_show_measures (bool yn)
3736 {
3737         if (_show_measures != yn) {
3738                 hide_measures ();
3739
3740                 if ((_show_measures = yn) == true) {
3741                         if (tempo_lines)
3742                                 tempo_lines->show();
3743                         draw_measures ();
3744                 }
3745                 instant_save ();
3746         }
3747 }
3748
3749 void
3750 Editor::toggle_follow_playhead ()
3751 {
3752         RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3753         if (act) {
3754                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3755                 set_follow_playhead (tact->get_active());
3756         }
3757 }
3758
3759 void
3760 Editor::set_follow_playhead (bool yn)
3761 {
3762         if (_follow_playhead != yn) {
3763                 if ((_follow_playhead = yn) == true) {
3764                         /* catch up */
3765                         reset_x_origin_to_follow_playhead ();
3766                 }
3767                 instant_save ();
3768         }
3769 }
3770
3771 void
3772 Editor::toggle_stationary_playhead ()
3773 {
3774        RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3775        if (act) {
3776                RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3777                set_stationary_playhead (tact->get_active());
3778        }
3779 }
3780
3781 void
3782 Editor::set_stationary_playhead (bool yn)
3783 {
3784        if (_stationary_playhead != yn) {
3785                if ((_stationary_playhead = yn) == true) {
3786                        /* catch up */
3787                        // FIXME need a 3.0 equivalent of this 2.X call
3788                        // update_current_screen ();
3789                }
3790                instant_save ();
3791        }
3792 }
3793
3794 void
3795 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3796 {
3797         boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3798         if (xfade) {
3799                 xfade->set_active (!xfade->active());
3800         }
3801 }
3802
3803 void
3804 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3805 {
3806         boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3807         if (xfade) {
3808                 xfade->set_follow_overlap (!xfade->following_overlap());
3809         }
3810 }
3811
3812 void
3813 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3814 {
3815         boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3816
3817         if (!xfade) {
3818                 return;
3819         }
3820
3821         CrossfadeEditor cew (_session, xfade, xfade->fade_in().get_min_y(), 1.0);
3822
3823         ensure_float (cew);
3824
3825         switch (cew.run ()) {
3826         case RESPONSE_ACCEPT:
3827                 break;
3828         default:
3829                 return;
3830         }
3831
3832         cew.apply ();
3833         PropertyChange all_crossfade_properties;
3834         all_crossfade_properties.add (ARDOUR::Properties::active);
3835         all_crossfade_properties.add (ARDOUR::Properties::follow_overlap);
3836         xfade->PropertyChanged (all_crossfade_properties);
3837 }
3838
3839 PlaylistSelector&
3840 Editor::playlist_selector () const
3841 {
3842         return *_playlist_selector;
3843 }
3844
3845 Evoral::MusicalTime
3846 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3847 {
3848         success = true;
3849
3850         switch (_snap_type) {
3851         case SnapToBeat:
3852                 return 1.0;
3853                 break;
3854
3855         case SnapToBeatDiv32:
3856                 return 1.0/32.0;
3857                 break;
3858         case SnapToBeatDiv28:
3859                 return 1.0/28.0;
3860                 break;
3861         case SnapToBeatDiv24:
3862                 return 1.0/24.0;
3863                 break;
3864         case SnapToBeatDiv20:
3865                 return 1.0/20.0;
3866                 break;
3867         case SnapToBeatDiv16:
3868                 return 1.0/16.0;
3869                 break;
3870         case SnapToBeatDiv14:
3871                 return 1.0/14.0;
3872                 break;
3873         case SnapToBeatDiv12:
3874                 return 1.0/12.0;
3875                 break;
3876         case SnapToBeatDiv10:
3877                 return 1.0/10.0;
3878                 break;
3879         case SnapToBeatDiv8:
3880                 return 1.0/8.0;
3881                 break;
3882         case SnapToBeatDiv7:
3883                 return 1.0/7.0;
3884                 break;
3885         case SnapToBeatDiv6:
3886                 return 1.0/6.0;
3887                 break;
3888         case SnapToBeatDiv5:
3889                 return 1.0/5.0;
3890                 break;
3891         case SnapToBeatDiv4:
3892                 return 1.0/4.0;
3893                 break;
3894         case SnapToBeatDiv3:
3895                 return 1.0/3.0;
3896                 break;
3897         case SnapToBeatDiv2:
3898                 return 1.0/2.0;
3899                 break;
3900
3901         case SnapToBar:
3902                 if (_session) {
3903                         return _session->tempo_map().meter_at (position).beats_per_bar();
3904                 }
3905                 break;
3906
3907         case SnapToCDFrame:
3908         case SnapToTimecodeFrame:
3909         case SnapToTimecodeSeconds:
3910         case SnapToTimecodeMinutes:
3911         case SnapToSeconds:
3912         case SnapToMinutes:
3913         case SnapToRegionStart:
3914         case SnapToRegionEnd:
3915         case SnapToRegionSync:
3916         case SnapToRegionBoundary:
3917         default:
3918                 success = false;
3919                 break;
3920         }
3921
3922         return 0.0;
3923 }
3924
3925 framecnt_t
3926 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3927 {
3928         framecnt_t ret;
3929
3930         ret = nudge_clock.current_duration (pos);
3931         next = ret + 1; /* XXXX fix me */
3932
3933         return ret;
3934 }
3935
3936 int
3937 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3938 {
3939         ArdourDialog dialog (_("Playlist Deletion"));
3940         Label  label (string_compose (_("Playlist %1 is currently unused.\n"
3941                                         "If left alone, no audio files used by it will be cleaned.\n"
3942                                         "If deleted, audio files used by it alone by will cleaned."),
3943                                       pl->name()));
3944
3945         dialog.set_position (WIN_POS_CENTER);
3946         dialog.get_vbox()->pack_start (label);
3947
3948         label.show ();
3949
3950         dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3951         dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3952         dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3953
3954         switch (dialog.run ()) {
3955         case RESPONSE_ACCEPT:
3956                 /* delete the playlist */
3957                 return 0;
3958                 break;
3959
3960         case RESPONSE_REJECT:
3961                 /* keep the playlist */
3962                 return 1;
3963                 break;
3964
3965         default:
3966                 break;
3967         }
3968
3969         return -1;
3970 }
3971
3972 bool
3973 Editor::audio_region_selection_covers (framepos_t where)
3974 {
3975         for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3976                 if ((*a)->region()->covers (where)) {
3977                         return true;
3978                 }
3979         }
3980
3981         return false;
3982 }
3983
3984 void
3985 Editor::prepare_for_cleanup ()
3986 {
3987         cut_buffer->clear_regions ();
3988         cut_buffer->clear_playlists ();
3989
3990         selection->clear_regions ();
3991         selection->clear_playlists ();
3992
3993         _regions->suspend_redisplay ();
3994 }
3995
3996 void
3997 Editor::finish_cleanup ()
3998 {
3999         _regions->resume_redisplay ();
4000 }
4001
4002 Location*
4003 Editor::transport_loop_location()
4004 {
4005         if (_session) {
4006                 return _session->locations()->auto_loop_location();
4007         } else {
4008                 return 0;
4009         }
4010 }
4011
4012 Location*
4013 Editor::transport_punch_location()
4014 {
4015         if (_session) {
4016                 return _session->locations()->auto_punch_location();
4017         } else {
4018                 return 0;
4019         }
4020 }
4021
4022 bool
4023 Editor::control_layout_scroll (GdkEventScroll* ev)
4024 {
4025         if (Keyboard::some_magic_widget_has_focus()) {
4026                 return false;
4027         }
4028
4029         switch (ev->direction) {
4030         case GDK_SCROLL_UP:
4031                 scroll_tracks_up_line ();
4032                 return true;
4033                 break;
4034
4035         case GDK_SCROLL_DOWN:
4036                 scroll_tracks_down_line ();
4037                 return true;
4038
4039         default:
4040                 /* no left/right handling yet */
4041                 break;
4042         }
4043
4044         return false;
4045 }
4046
4047 void
4048 Editor::session_state_saved (string)
4049 {
4050         update_title ();        
4051         _snapshots->redisplay ();
4052 }
4053
4054 void
4055 Editor::maximise_editing_space ()
4056 {
4057         _mouse_mode_tearoff->set_visible (false);
4058         _tools_tearoff->set_visible (false);
4059         _zoom_tearoff->set_visible (false);
4060
4061         pre_maximal_horizontal_pane_position = edit_pane.get_position ();
4062         pre_maximal_vertical_pane_position = editor_summary_pane.get_position ();
4063         pre_maximal_editor_width = this->get_width ();
4064         pre_maximal_editor_height = this->get_height ();
4065
4066         if (post_maximal_horizontal_pane_position == 0) {
4067                 post_maximal_horizontal_pane_position = edit_pane.get_width();
4068         }
4069
4070         if (post_maximal_vertical_pane_position == 0) {
4071                 post_maximal_vertical_pane_position = editor_summary_pane.get_height();
4072         }
4073         
4074         fullscreen ();
4075
4076         if (post_maximal_editor_width) {
4077                 edit_pane.set_position (post_maximal_horizontal_pane_position -
4078                         abs(post_maximal_editor_width - pre_maximal_editor_width));
4079         } else {
4080                 edit_pane.set_position (post_maximal_horizontal_pane_position);
4081         }
4082
4083         if (post_maximal_editor_height) {
4084                 editor_summary_pane.set_position (post_maximal_vertical_pane_position -
4085                         abs(post_maximal_editor_height - pre_maximal_editor_height));
4086         } else {
4087                 editor_summary_pane.set_position (post_maximal_vertical_pane_position);
4088         }
4089
4090         if (Config->get_keep_tearoffs()) {
4091                 _mouse_mode_tearoff->set_visible (true);
4092                 _tools_tearoff->set_visible (true);
4093                 _zoom_tearoff->set_visible (true);
4094         }
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         Glib::RefPtr<Action> a = editor_actions->get_action (name);
5511         assert (a);
5512         
5513         return *manage (a->create_menu_item ());
5514 }
5515