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