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