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