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