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