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