tell the editor to try to load editor.bindings
[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         current_toplevel()->fullscreen ();
4207
4208         _maximised = true;
4209 }
4210
4211 void
4212 Editor::restore_editing_space ()
4213 {
4214         if (!_maximised) {
4215                 return;
4216         }
4217
4218         current_toplevel()->unfullscreen();
4219
4220         _maximised = false;
4221 }
4222
4223 /**
4224  *  Make new playlists for a given track and also any others that belong
4225  *  to the same active route group with the `select' property.
4226  *  @param v Track.
4227  */
4228
4229 void
4230 Editor::new_playlists (TimeAxisView* v)
4231 {
4232         begin_reversible_command (_("new playlists"));
4233         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4234         _session->playlists->get (playlists);
4235         mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4236         commit_reversible_command ();
4237 }
4238
4239 /**
4240  *  Use a copy of the current playlist for a given track and also any others that belong
4241  *  to the same active route group with the `select' property.
4242  *  @param v Track.
4243  */
4244
4245 void
4246 Editor::copy_playlists (TimeAxisView* v)
4247 {
4248         begin_reversible_command (_("copy playlists"));
4249         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4250         _session->playlists->get (playlists);
4251         mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4252         commit_reversible_command ();
4253 }
4254
4255 /** Clear the current playlist for a given track and also any others that belong
4256  *  to the same active route group with the `select' property.
4257  *  @param v Track.
4258  */
4259
4260 void
4261 Editor::clear_playlists (TimeAxisView* v)
4262 {
4263         begin_reversible_command (_("clear playlists"));
4264         vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4265         _session->playlists->get (playlists);
4266         mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4267         commit_reversible_command ();
4268 }
4269
4270 void
4271 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4272 {
4273         atv.use_new_playlist (sz > 1 ? false : true, playlists);
4274 }
4275
4276 void
4277 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4278 {
4279         atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4280 }
4281
4282 void
4283 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4284 {
4285         atv.clear_playlist ();
4286 }
4287
4288 double
4289 Editor::get_y_origin () const
4290 {
4291         return vertical_adjustment.get_value ();
4292 }
4293
4294 /** Queue up a change to the viewport x origin.
4295  *  @param frame New x origin.
4296  */
4297 void
4298 Editor::reset_x_origin (framepos_t frame)
4299 {
4300         pending_visual_change.add (VisualChange::TimeOrigin);
4301         pending_visual_change.time_origin = frame;
4302         ensure_visual_change_idle_handler ();
4303 }
4304
4305 void
4306 Editor::reset_y_origin (double y)
4307 {
4308         pending_visual_change.add (VisualChange::YOrigin);
4309         pending_visual_change.y_origin = y;
4310         ensure_visual_change_idle_handler ();
4311 }
4312
4313 void
4314 Editor::reset_zoom (framecnt_t spp)
4315 {
4316         if (spp == samples_per_pixel) {
4317                 return;
4318         }
4319
4320         pending_visual_change.add (VisualChange::ZoomLevel);
4321         pending_visual_change.samples_per_pixel = spp;
4322         ensure_visual_change_idle_handler ();
4323 }
4324
4325 void
4326 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4327 {
4328         reset_x_origin (frame);
4329         reset_zoom (fpu);
4330
4331         if (!no_save_visual) {
4332                 undo_visual_stack.push_back (current_visual_state(false));
4333         }
4334 }
4335
4336 Editor::VisualState::VisualState (bool with_tracks)
4337         : gui_state (with_tracks ? new GUIObjectState : 0)
4338 {
4339 }
4340
4341 Editor::VisualState::~VisualState ()
4342 {
4343         delete gui_state;
4344 }
4345
4346 Editor::VisualState*
4347 Editor::current_visual_state (bool with_tracks)
4348 {
4349         VisualState* vs = new VisualState (with_tracks);
4350         vs->y_position = vertical_adjustment.get_value();
4351         vs->samples_per_pixel = samples_per_pixel;
4352         vs->leftmost_frame = leftmost_frame;
4353         vs->zoom_focus = zoom_focus;
4354
4355         if (with_tracks) {
4356                 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4357         }
4358
4359         return vs;
4360 }
4361
4362 void
4363 Editor::undo_visual_state ()
4364 {
4365         if (undo_visual_stack.empty()) {
4366                 return;
4367         }
4368
4369         VisualState* vs = undo_visual_stack.back();
4370         undo_visual_stack.pop_back();
4371
4372
4373         redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4374
4375         if (vs) {
4376                 use_visual_state (*vs);
4377         }
4378 }
4379
4380 void
4381 Editor::redo_visual_state ()
4382 {
4383         if (redo_visual_stack.empty()) {
4384                 return;
4385         }
4386
4387         VisualState* vs = redo_visual_stack.back();
4388         redo_visual_stack.pop_back();
4389
4390         // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4391         // why do we check here?
4392         undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4393
4394         if (vs) {
4395                 use_visual_state (*vs);
4396         }
4397 }
4398
4399 void
4400 Editor::swap_visual_state ()
4401 {
4402         if (undo_visual_stack.empty()) {
4403                 redo_visual_state ();
4404         } else {
4405                 undo_visual_state ();
4406         }
4407 }
4408
4409 void
4410 Editor::use_visual_state (VisualState& vs)
4411 {
4412         PBD::Unwinder<bool> nsv (no_save_visual, true);
4413         DisplaySuspender ds;
4414
4415         vertical_adjustment.set_value (vs.y_position);
4416
4417         set_zoom_focus (vs.zoom_focus);
4418         reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4419
4420         if (vs.gui_state) {
4421                 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4422
4423                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4424                         (*i)->clear_property_cache();
4425                         (*i)->reset_visual_state ();
4426                 }
4427         }
4428
4429         _routes->update_visibility ();
4430 }
4431
4432 /** This is the core function that controls the zoom level of the canvas. It is called
4433  *  whenever one or more calls are made to reset_zoom().  It executes in an idle handler.
4434  *  @param spp new number of samples per pixel
4435  */
4436 void
4437 Editor::set_samples_per_pixel (framecnt_t spp)
4438 {
4439         if (spp < 1) {
4440                 return;
4441         }
4442
4443         const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4444         const framecnt_t lots_of_pixels = 4000;
4445
4446         /* if the zoom level is greater than what you'd get trying to display 3
4447          * days of audio on a really big screen, then it's too big.
4448          */
4449
4450         if (spp * lots_of_pixels > three_days) {
4451                 return;
4452         }
4453
4454         samples_per_pixel = spp;
4455
4456         if (tempo_lines) {
4457                 tempo_lines->tempo_map_changed();
4458         }
4459
4460         bool const showing_time_selection = selection->time.length() > 0;
4461
4462         if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4463                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4464                         (*i)->reshow_selection (selection->time);
4465                 }
4466         }
4467
4468         ZoomChanged (); /* EMIT_SIGNAL */
4469
4470         ArdourCanvas::GtkCanvasViewport* c;
4471
4472         c = get_track_canvas();
4473         if (c) {
4474                 c->canvas()->zoomed ();
4475         }
4476
4477         if (playhead_cursor) {
4478                 playhead_cursor->set_position (playhead_cursor->current_frame ());
4479         }
4480
4481         refresh_location_display();
4482         _summary->set_overlays_dirty ();
4483
4484         update_marker_labels ();
4485
4486         instant_save ();
4487 }
4488
4489 void
4490 Editor::queue_visual_videotimeline_update ()
4491 {
4492         /* TODO:
4493          * pending_visual_change.add (VisualChange::VideoTimeline);
4494          * or maybe even more specific: which videotimeline-image
4495          * currently it calls update_video_timeline() to update
4496          * _all outdated_ images on the video-timeline.
4497          * see 'exposeimg()' in video_image_frame.cc
4498          */
4499         ensure_visual_change_idle_handler ();
4500 }
4501
4502 void
4503 Editor::ensure_visual_change_idle_handler ()
4504 {
4505         if (pending_visual_change.idle_handler_id < 0) {
4506                 // see comment in add_to_idle_resize above.
4507                 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4508                 pending_visual_change.being_handled = false;
4509         }
4510 }
4511
4512 int
4513 Editor::_idle_visual_changer (void* arg)
4514 {
4515         return static_cast<Editor*>(arg)->idle_visual_changer ();
4516 }
4517
4518 int
4519 Editor::idle_visual_changer ()
4520 {
4521         /* set_horizontal_position() below (and maybe other calls) call
4522            gtk_main_iteration(), so it's possible that a signal will be handled
4523            half-way through this method.  If this signal wants an
4524            idle_visual_changer we must schedule another one after this one, so
4525            mark the idle_handler_id as -1 here to allow that.  Also make a note
4526            that we are doing the visual change, so that changes in response to
4527            super-rapid-screen-update can be dropped if we are still processing
4528            the last one.
4529         */
4530
4531         pending_visual_change.idle_handler_id = -1;
4532         pending_visual_change.being_handled = true;
4533
4534         VisualChange vc = pending_visual_change;
4535
4536         pending_visual_change.pending = (VisualChange::Type) 0;
4537
4538         visual_changer (vc);
4539
4540         pending_visual_change.being_handled = false;
4541
4542         return 0; /* this is always a one-shot call */
4543 }
4544
4545 void
4546 Editor::visual_changer (const VisualChange& vc)
4547 {
4548         double const last_time_origin = horizontal_position ();
4549
4550         if (vc.pending & VisualChange::ZoomLevel) {
4551                 set_samples_per_pixel (vc.samples_per_pixel);
4552
4553                 compute_fixed_ruler_scale ();
4554
4555                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4556                 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4557
4558                 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4559                                             current_bbt_points_begin, current_bbt_points_end);
4560                 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4561                                          current_bbt_points_begin, current_bbt_points_end);
4562                 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4563
4564                 update_video_timeline();
4565         }
4566
4567         if (vc.pending & VisualChange::TimeOrigin) {
4568                 set_horizontal_position (vc.time_origin / samples_per_pixel);
4569         }
4570
4571         if (vc.pending & VisualChange::YOrigin) {
4572                 vertical_adjustment.set_value (vc.y_origin);
4573         }
4574
4575         if (last_time_origin == horizontal_position ()) {
4576                 /* changed signal not emitted */
4577                 update_fixed_rulers ();
4578                 redisplay_tempo (true);
4579         }
4580
4581         if (!(vc.pending & VisualChange::ZoomLevel)) {
4582                 update_video_timeline();
4583         }
4584
4585         _summary->set_overlays_dirty ();
4586 }
4587
4588 struct EditorOrderTimeAxisSorter {
4589     bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4590             return a->order () < b->order ();
4591     }
4592 };
4593
4594 void
4595 Editor::sort_track_selection (TrackViewList& sel)
4596 {
4597         EditorOrderTimeAxisSorter cmp;
4598         sel.sort (cmp);
4599 }
4600
4601 framepos_t
4602 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4603 {
4604         bool ignored;
4605         framepos_t where = 0;
4606         EditPoint ep = _edit_point;
4607
4608         if (Profile->get_mixbus())
4609                 if (ep == EditAtSelectedMarker)
4610                         ep = EditAtPlayhead;
4611
4612         if (from_outside_canvas && (ep == EditAtMouse)) {
4613                 ep = EditAtPlayhead;
4614         } else if (from_context_menu && (ep == EditAtMouse)) {
4615                 return  canvas_event_sample (&context_click_event, 0, 0);
4616         }
4617
4618         if (entered_marker) {
4619                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4620                 return entered_marker->position();
4621         }
4622
4623         if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4624                 ep = EditAtSelectedMarker;
4625         }
4626
4627         if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4628                 ep = EditAtPlayhead;
4629         }
4630
4631         switch (ep) {
4632         case EditAtPlayhead:
4633                 if (_dragging_playhead) {
4634                         where = *_control_scroll_target;
4635                 } else {
4636                         where = _session->audible_frame();
4637                 }
4638                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4639                 break;
4640
4641         case EditAtSelectedMarker:
4642                 if (!selection->markers.empty()) {
4643                         bool is_start;
4644                         Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4645                         if (loc) {
4646                                 if (is_start) {
4647                                         where =  loc->start();
4648                                 } else {
4649                                         where = loc->end();
4650                                 }
4651                                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4652                                 break;
4653                         }
4654                 }
4655                 /* fallthru */
4656
4657         default:
4658         case EditAtMouse:
4659                 if (!mouse_frame (where, ignored)) {
4660                         /* XXX not right but what can we do ? */
4661                         return 0;
4662                 }
4663                 snap_to (where);
4664                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4665                 break;
4666         }
4667
4668         return where;
4669 }
4670
4671 void
4672 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4673 {
4674         if (!_session) return;
4675
4676         begin_reversible_command (cmd);
4677
4678         Location* tll;
4679
4680         if ((tll = transport_loop_location()) == 0) {
4681                 Location* loc = new Location (*_session, start, end, _("Loop"),  Location::IsAutoLoop);
4682                 XMLNode &before = _session->locations()->get_state();
4683                 _session->locations()->add (loc, true);
4684                 _session->set_auto_loop_location (loc);
4685                 XMLNode &after = _session->locations()->get_state();
4686                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4687         } else {
4688                 XMLNode &before = tll->get_state();
4689                 tll->set_hidden (false, this);
4690                 tll->set (start, end);
4691                 XMLNode &after = tll->get_state();
4692                 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4693         }
4694
4695         commit_reversible_command ();
4696 }
4697
4698 void
4699 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4700 {
4701         if (!_session) return;
4702
4703         begin_reversible_command (cmd);
4704
4705         Location* tpl;
4706
4707         if ((tpl = transport_punch_location()) == 0) {
4708                 Location* loc = new Location (*_session, start, end, _("Punch"),  Location::IsAutoPunch);
4709                 XMLNode &before = _session->locations()->get_state();
4710                 _session->locations()->add (loc, true);
4711                 _session->set_auto_punch_location (loc);
4712                 XMLNode &after = _session->locations()->get_state();
4713                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4714         } else {
4715                 XMLNode &before = tpl->get_state();
4716                 tpl->set_hidden (false, this);
4717                 tpl->set (start, end);
4718                 XMLNode &after = tpl->get_state();
4719                 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4720         }
4721
4722         commit_reversible_command ();
4723 }
4724
4725 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4726  *  @param rs List to which found regions are added.
4727  *  @param where Time to look at.
4728  *  @param ts Tracks to look on; if this is empty, all tracks are examined.
4729  */
4730 void
4731 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4732 {
4733         const TrackViewList* tracks;
4734
4735         if (ts.empty()) {
4736                 tracks = &track_views;
4737         } else {
4738                 tracks = &ts;
4739         }
4740
4741         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4742
4743                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4744
4745                 if (rtv) {
4746                         boost::shared_ptr<Track> tr;
4747                         boost::shared_ptr<Playlist> pl;
4748
4749                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4750
4751                                 boost::shared_ptr<RegionList> regions = pl->regions_at (
4752                                                 (framepos_t) floor ( (double) where * tr->speed()));
4753
4754                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4755                                         RegionView* rv = rtv->view()->find_view (*i);
4756                                         if (rv) {
4757                                                 rs.add (rv);
4758                                         }
4759                                 }
4760                         }
4761                 }
4762         }
4763 }
4764
4765 void
4766 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4767 {
4768         const TrackViewList* tracks;
4769
4770         if (ts.empty()) {
4771                 tracks = &track_views;
4772         } else {
4773                 tracks = &ts;
4774         }
4775
4776         for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4777                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4778                 if (rtv) {
4779                         boost::shared_ptr<Track> tr;
4780                         boost::shared_ptr<Playlist> pl;
4781
4782                         if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4783
4784                                 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4785                                         (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4786
4787                                 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4788
4789                                         RegionView* rv = rtv->view()->find_view (*i);
4790
4791                                         if (rv) {
4792                                                 rs.add (rv);
4793                                         }
4794                                 }
4795                         }
4796                 }
4797         }
4798 }
4799
4800 /** Get regions using the following method:
4801  *
4802  *  Make a region list using:
4803  *   (a) any selected regions
4804  *   (b) the intersection of any selected tracks and the edit point(*)
4805  *   (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4806  *
4807  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4808  *
4809  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4810  */
4811
4812 RegionSelection
4813 Editor::get_regions_from_selection_and_edit_point ()
4814 {
4815         RegionSelection regions;
4816
4817         if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4818                 regions.add (entered_regionview);
4819         } else {
4820                 regions = selection->regions;
4821         }
4822
4823         if ( regions.empty() ) {
4824                 TrackViewList tracks = selection->tracks;
4825
4826                 if (!tracks.empty()) {
4827                         /* no region selected or entered, but some selected tracks:
4828                          * act on all regions on the selected tracks at the edit point
4829                          */
4830                         framepos_t const where = get_preferred_edit_position ();
4831                         get_regions_at(regions, where, tracks);
4832                 }
4833         }
4834
4835         return regions;
4836 }
4837
4838 /** Get regions using the following method:
4839  *
4840  *  Make a region list using:
4841  *   (a) any selected regions
4842  *   (b) the intersection of any selected tracks and the edit point(*)
4843  *   (c) if neither exists, then whatever region is under the mouse
4844  *
4845  *  (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4846  *
4847  *  Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4848  */
4849 RegionSelection
4850 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4851 {
4852         RegionSelection regions;
4853
4854         if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4855                 regions.add (entered_regionview);
4856         } else {
4857                 regions = selection->regions;
4858         }
4859
4860         if ( regions.empty() ) {
4861                 TrackViewList tracks = selection->tracks;
4862
4863                 if (!tracks.empty()) {
4864                         /* no region selected or entered, but some selected tracks:
4865                          * act on all regions on the selected tracks at the edit point
4866                          */
4867                         get_regions_at(regions, pos, tracks);
4868                 }
4869         }
4870
4871         return regions;
4872 }
4873
4874 /** Start with regions that are selected, or the entered regionview if none are selected.
4875  *  Then add equivalent regions on tracks in the same active edit-enabled route group as any
4876  *  of the regions that we started with.
4877  */
4878
4879 RegionSelection
4880 Editor::get_regions_from_selection_and_entered ()
4881 {
4882         RegionSelection regions = selection->regions;
4883
4884         if (regions.empty() && entered_regionview) {
4885                 regions.add (entered_regionview);
4886         }
4887
4888         return regions;
4889 }
4890
4891 void
4892 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4893 {
4894         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4895                 RouteTimeAxisView* rtav;
4896
4897                 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4898                         boost::shared_ptr<Playlist> pl;
4899                         std::vector<boost::shared_ptr<Region> > results;
4900                         boost::shared_ptr<Track> tr;
4901
4902                         if ((tr = rtav->track()) == 0) {
4903                                 /* bus */
4904                                 continue;
4905                         }
4906
4907                         if ((pl = (tr->playlist())) != 0) {
4908                                 boost::shared_ptr<Region> r = pl->region_by_id (id);
4909                                 if (r) {
4910                                         RegionView* rv = rtav->view()->find_view (r);
4911                                         if (rv) {
4912                                                 regions.push_back (rv);
4913                                         }
4914                                 }
4915                         }
4916                 }
4917         }
4918 }
4919
4920 void
4921 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4922 {
4923
4924         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4925                 MidiTimeAxisView* mtav;
4926
4927                 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4928
4929                         mtav->get_per_region_note_selection (selection);
4930                 }
4931         }
4932
4933 }
4934
4935 void
4936 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4937 {
4938         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4939
4940                 RouteTimeAxisView* tatv;
4941
4942                 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4943
4944                         boost::shared_ptr<Playlist> pl;
4945                         vector<boost::shared_ptr<Region> > results;
4946                         RegionView* marv;
4947                         boost::shared_ptr<Track> tr;
4948
4949                         if ((tr = tatv->track()) == 0) {
4950                                 /* bus */
4951                                 continue;
4952                         }
4953
4954                         if ((pl = (tr->playlist())) != 0) {
4955                                 if (src_comparison) {
4956                                         pl->get_source_equivalent_regions (region, results);
4957                                 } else {
4958                                         pl->get_region_list_equivalent_regions (region, results);
4959                                 }
4960                         }
4961
4962                         for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4963                                 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4964                                         regions.push_back (marv);
4965                                 }
4966                         }
4967
4968                 }
4969         }
4970 }
4971
4972 void
4973 Editor::show_rhythm_ferret ()
4974 {
4975         if (rhythm_ferret == 0) {
4976                 rhythm_ferret = new RhythmFerret(*this);
4977         }
4978
4979         rhythm_ferret->set_session (_session);
4980         rhythm_ferret->show ();
4981         rhythm_ferret->present ();
4982 }
4983
4984 void
4985 Editor::first_idle ()
4986 {
4987         MessageDialog* dialog = 0;
4988
4989         if (track_views.size() > 1) {
4990                 Timers::TimerSuspender t;
4991                 dialog = new MessageDialog (
4992                         *current_toplevel(),
4993                         string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4994                         true
4995                         );
4996                 dialog->present ();
4997                 ARDOUR_UI::instance()->flush_pending ();
4998         }
4999
5000         for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5001                 (*t)->first_idle();
5002         }
5003
5004         // first idle adds route children (automation tracks), so we need to redisplay here
5005         _routes->redisplay ();
5006
5007         delete dialog;
5008
5009         if (_session->undo_depth() == 0) {
5010                 undo_action->set_sensitive(false);
5011         }
5012         redo_action->set_sensitive(false);
5013         begin_selection_op_history ();
5014
5015         _have_idled = true;
5016 }
5017
5018 gboolean
5019 Editor::_idle_resize (gpointer arg)
5020 {
5021         return ((Editor*)arg)->idle_resize ();
5022 }
5023
5024 void
5025 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5026 {
5027         if (resize_idle_id < 0) {
5028                 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5029                  * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5030                  * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5031                  */
5032                 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5033                 _pending_resize_amount = 0;
5034         }
5035
5036         /* make a note of the smallest resulting height, so that we can clamp the
5037            lower limit at TimeAxisView::hSmall */
5038
5039         int32_t min_resulting = INT32_MAX;
5040
5041         _pending_resize_amount += h;
5042         _pending_resize_view = view;
5043
5044         min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5045
5046         if (selection->tracks.contains (_pending_resize_view)) {
5047                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5048                         min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5049                 }
5050         }
5051
5052         if (min_resulting < 0) {
5053                 min_resulting = 0;
5054         }
5055
5056         /* clamp */
5057         if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5058                 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5059         }
5060 }
5061
5062 /** Handle pending resizing of tracks */
5063 bool
5064 Editor::idle_resize ()
5065 {
5066         _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5067
5068         if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5069             selection->tracks.contains (_pending_resize_view)) {
5070
5071                 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5072                         if (*i != _pending_resize_view) {
5073                                 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5074                         }
5075                 }
5076         }
5077
5078         _pending_resize_amount = 0;
5079         _group_tabs->set_dirty ();
5080         resize_idle_id = -1;
5081
5082         return false;
5083 }
5084
5085 void
5086 Editor::located ()
5087 {
5088         ENSURE_GUI_THREAD (*this, &Editor::located);
5089
5090         if (_session) {
5091                 playhead_cursor->set_position (_session->audible_frame ());
5092                 if (_follow_playhead && !_pending_initial_locate) {
5093                         reset_x_origin_to_follow_playhead ();
5094                 }
5095         }
5096
5097         _pending_locate_request = false;
5098         _pending_initial_locate = false;
5099 }
5100
5101 void
5102 Editor::region_view_added (RegionView * rv)
5103 {
5104         for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5105                 if (rv->region ()->id () == (*pr)) {
5106                         selection->add (rv);
5107                         selection->regions.pending.erase (pr);
5108                         break;
5109                 }
5110         }
5111
5112         MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5113         if (mrv) {
5114                 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5115                 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5116                         if (rv->region()->id () == (*rnote).first) {
5117                                 mrv->select_notes ((*rnote).second);
5118                                 selection->pending_midi_note_selection.erase(rnote);
5119                                 break;
5120                         }
5121                 }
5122         }
5123
5124         _summary->set_background_dirty ();
5125 }
5126
5127 void
5128 Editor::region_view_removed ()
5129 {
5130         _summary->set_background_dirty ();
5131 }
5132
5133 RouteTimeAxisView*
5134 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5135 {
5136         TrackViewList::const_iterator j = track_views.begin ();
5137         while (j != track_views.end()) {
5138                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5139                 if (rtv && rtv->route() == r) {
5140                         return rtv;
5141                 }
5142                 ++j;
5143         }
5144
5145         return 0;
5146 }
5147
5148
5149 TrackViewList
5150 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5151 {
5152         TrackViewList t;
5153
5154         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5155                 TimeAxisView* tv = axis_view_from_route (*i);
5156                 if (tv) {
5157                         t.push_back (tv);
5158                 }
5159         }
5160
5161         return t;
5162 }
5163
5164 void
5165 Editor::suspend_route_redisplay ()
5166 {
5167         if (_routes) {
5168                 _routes->suspend_redisplay();
5169         }
5170 }
5171
5172 void
5173 Editor::resume_route_redisplay ()
5174 {
5175         if (_routes) {
5176                 _routes->redisplay(); // queue redisplay
5177                 _routes->resume_redisplay();
5178         }
5179 }
5180
5181 void
5182 Editor::add_routes (RouteList& routes)
5183 {
5184         ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5185
5186         RouteTimeAxisView *rtv;
5187         list<RouteTimeAxisView*> new_views;
5188         TrackViewList new_selection;
5189         bool from_scratch = (track_views.size() == 0);
5190
5191         for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5192                 boost::shared_ptr<Route> route = (*x);
5193
5194                 if (route->is_auditioner() || route->is_monitor()) {
5195                         continue;
5196                 }
5197
5198                 DataType dt = route->input()->default_type();
5199
5200                 if (dt == ARDOUR::DataType::AUDIO) {
5201                         rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5202                         rtv->set_route (route);
5203                 } else if (dt == ARDOUR::DataType::MIDI) {
5204                         rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5205                         rtv->set_route (route);
5206                 } else {
5207                         throw unknown_type();
5208                 }
5209
5210                 new_views.push_back (rtv);
5211                 track_views.push_back (rtv);
5212                 new_selection.push_back (rtv);
5213
5214                 rtv->effective_gain_display ();
5215
5216                 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5217                 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5218         }
5219
5220         if (new_views.size() > 0) {
5221                 _routes->routes_added (new_views);
5222                 _summary->routes_added (new_views);
5223         }
5224
5225         if (!from_scratch) {
5226                 selection->tracks.clear();
5227                 selection->add (new_selection);
5228                 begin_selection_op_history();
5229         }
5230
5231         if (show_editor_mixer_when_tracks_arrive) {
5232                 show_editor_mixer (true);
5233         }
5234
5235         editor_list_button.set_sensitive (true);
5236 }
5237
5238 void
5239 Editor::timeaxisview_deleted (TimeAxisView *tv)
5240 {
5241         if (tv == entered_track) {
5242                 entered_track = 0;
5243         }
5244
5245         if (_session && _session->deletion_in_progress()) {
5246                 /* the situation is under control */
5247                 return;
5248         }
5249
5250         ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5251
5252         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5253
5254         _routes->route_removed (tv);
5255
5256         TimeAxisView::Children c = tv->get_child_list ();
5257         for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5258                 if (entered_track == i->get()) {
5259                         entered_track = 0;
5260                 }
5261         }
5262
5263         /* remove it from the list of track views */
5264
5265         TrackViewList::iterator i;
5266
5267         if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5268                 i = track_views.erase (i);
5269         }
5270
5271         /* update whatever the current mixer strip is displaying, if revelant */
5272
5273         boost::shared_ptr<Route> route;
5274
5275         if (rtav) {
5276                 route = rtav->route ();
5277         }
5278
5279         if (current_mixer_strip && current_mixer_strip->route() == route) {
5280
5281                 TimeAxisView* next_tv;
5282
5283                 if (track_views.empty()) {
5284                         next_tv = 0;
5285                 } else if (i == track_views.end()) {
5286                         next_tv = track_views.front();
5287                 } else {
5288                         next_tv = (*i);
5289                 }
5290
5291
5292                 if (next_tv) {
5293                         set_selected_mixer_strip (*next_tv);
5294                 } else {
5295                         /* make the editor mixer strip go away setting the
5296                          * button to inactive (which also unticks the menu option)
5297                          */
5298
5299                         ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5300                 }
5301         }
5302 }
5303
5304 void
5305 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5306 {
5307         if (apply_to_selection) {
5308                 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5309
5310                         TrackSelection::iterator j = i;
5311                         ++j;
5312
5313                         hide_track_in_display (*i, false);
5314
5315                         i = j;
5316                 }
5317         } else {
5318                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5319
5320                 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5321                         // this will hide the mixer strip
5322                         set_selected_mixer_strip (*tv);
5323                 }
5324
5325                 _routes->hide_track_in_display (*tv);
5326         }
5327 }
5328
5329 bool
5330 Editor::sync_track_view_list_and_routes ()
5331 {
5332         track_views = TrackViewList (_routes->views ());
5333
5334         _summary->set_background_dirty();
5335         _group_tabs->set_dirty ();
5336
5337         return false; // do not call again (until needed)
5338 }
5339
5340 void
5341 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5342 {
5343         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5344                 theslot (**i);
5345         }
5346 }
5347
5348 /** Find a RouteTimeAxisView by the ID of its route */
5349 RouteTimeAxisView*
5350 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5351 {
5352         RouteTimeAxisView* v;
5353
5354         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5355                 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5356                         if(v->route()->id() == id) {
5357                                 return v;
5358                         }
5359                 }
5360         }
5361
5362         return 0;
5363 }
5364
5365 void
5366 Editor::fit_route_group (RouteGroup *g)
5367 {
5368         TrackViewList ts = axis_views_from_routes (g->route_list ());
5369         fit_tracks (ts);
5370 }
5371
5372 void
5373 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5374 {
5375         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5376
5377         if (r == 0) {
5378                 _session->cancel_audition ();
5379                 return;
5380         }
5381
5382         if (_session->is_auditioning()) {
5383                 _session->cancel_audition ();
5384                 if (r == last_audition_region) {
5385                         return;
5386                 }
5387         }
5388
5389         _session->audition_region (r);
5390         last_audition_region = r;
5391 }
5392
5393
5394 void
5395 Editor::hide_a_region (boost::shared_ptr<Region> r)
5396 {
5397         r->set_hidden (true);
5398 }
5399
5400 void
5401 Editor::show_a_region (boost::shared_ptr<Region> r)
5402 {
5403         r->set_hidden (false);
5404 }
5405
5406 void
5407 Editor::audition_region_from_region_list ()
5408 {
5409         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5410 }
5411
5412 void
5413 Editor::hide_region_from_region_list ()
5414 {
5415         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5416 }
5417
5418 void
5419 Editor::show_region_in_region_list ()
5420 {
5421         _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5422 }
5423
5424 void
5425 Editor::step_edit_status_change (bool yn)
5426 {
5427         if (yn) {
5428                 start_step_editing ();
5429         } else {
5430                 stop_step_editing ();
5431         }
5432 }
5433
5434 void
5435 Editor::start_step_editing ()
5436 {
5437         step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5438 }
5439
5440 void
5441 Editor::stop_step_editing ()
5442 {
5443         step_edit_connection.disconnect ();
5444 }
5445
5446 bool
5447 Editor::check_step_edit ()
5448 {
5449         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5450                 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5451                 if (mtv) {
5452                         mtv->check_step_edit ();
5453                 }
5454         }
5455
5456         return true; // do it again, till we stop
5457 }
5458
5459 bool
5460 Editor::scroll_press (Direction dir)
5461 {
5462         ++_scroll_callbacks;
5463
5464         if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5465                 /* delay the first auto-repeat */
5466                 return true;
5467         }
5468
5469         switch (dir) {
5470         case LEFT:
5471                 scroll_backward (1);
5472                 break;
5473
5474         case RIGHT:
5475                 scroll_forward (1);
5476                 break;
5477
5478         case UP:
5479                 scroll_up_one_track ();
5480                 break;
5481
5482         case DOWN:
5483                 scroll_down_one_track ();
5484                 break;
5485         }
5486
5487         /* do hacky auto-repeat */
5488         if (!_scroll_connection.connected ()) {
5489
5490                 _scroll_connection = Glib::signal_timeout().connect (
5491                         sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5492                         );
5493
5494                 _scroll_callbacks = 0;
5495         }
5496
5497         return true;
5498 }
5499
5500 void
5501 Editor::scroll_release ()
5502 {
5503         _scroll_connection.disconnect ();
5504 }
5505
5506 /** Queue a change for the Editor viewport x origin to follow the playhead */
5507 void
5508 Editor::reset_x_origin_to_follow_playhead ()
5509 {
5510         framepos_t const frame = playhead_cursor->current_frame ();
5511
5512         if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5513
5514                 if (_session->transport_speed() < 0) {
5515
5516                         if (frame > (current_page_samples() / 2)) {
5517                                 center_screen (frame-(current_page_samples()/2));
5518                         } else {
5519                                 center_screen (current_page_samples()/2);
5520                         }
5521
5522                 } else {
5523
5524                         framepos_t l = 0;
5525
5526                         if (frame < leftmost_frame) {
5527                                 /* moving left */
5528                                 if (_session->transport_rolling()) {
5529                                         /* rolling; end up with the playhead at the right of the page */
5530                                         l = frame - current_page_samples ();
5531                                 } else {
5532                                         /* not rolling: end up with the playhead 1/4 of the way along the page */
5533                                         l = frame - current_page_samples() / 4;
5534                                 }
5535                         } else {
5536                                 /* moving right */
5537                                 if (_session->transport_rolling()) {
5538                                         /* rolling: end up with the playhead on the left of the page */
5539                                         l = frame;
5540                                 } else {
5541                                         /* not rolling: end up with the playhead 3/4 of the way along the page */
5542                                         l = frame - 3 * current_page_samples() / 4;
5543                                 }
5544                         }
5545
5546                         if (l < 0) {
5547                                 l = 0;
5548                         }
5549
5550                         center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5551                 }
5552         }
5553 }
5554
5555 void
5556 Editor::super_rapid_screen_update ()
5557 {
5558         if (!_session || !_session->engine().running()) {
5559                 return;
5560         }
5561
5562         /* METERING / MIXER STRIPS */
5563
5564         /* update track meters, if required */
5565         if (contents().is_mapped() && meters_running) {
5566                 RouteTimeAxisView* rtv;
5567                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5568                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5569                                 rtv->fast_update ();
5570                         }
5571                 }
5572         }
5573
5574         /* and any current mixer strip */
5575         if (current_mixer_strip) {
5576                 current_mixer_strip->fast_update ();
5577         }
5578
5579         /* PLAYHEAD AND VIEWPORT */
5580
5581         framepos_t const frame = _session->audible_frame();
5582
5583         /* There are a few reasons why we might not update the playhead / viewport stuff:
5584          *
5585          * 1.  we don't update things when there's a pending locate request, otherwise
5586          *     when the editor requests a locate there is a chance that this method
5587          *     will move the playhead before the locate request is processed, causing
5588          *     a visual glitch.
5589          * 2.  if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5590          * 3.  if we're still at the same frame that we were last time, there's nothing to do.
5591          */
5592
5593         if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5594
5595                 last_update_frame = frame;
5596
5597                 if (!_dragging_playhead) {
5598                         playhead_cursor->set_position (frame);
5599                 }
5600
5601                 if (!_stationary_playhead) {
5602
5603                         if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5604                                 /* We only do this if we aren't already
5605                                    handling a visual change (ie if
5606                                    pending_visual_change.being_handled is
5607                                    false) so that these requests don't stack
5608                                    up there are too many of them to handle in
5609                                    time.
5610                                 */
5611                                 reset_x_origin_to_follow_playhead ();
5612                         }
5613
5614                 } else {
5615
5616                         if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5617                                 framepos_t const frame = playhead_cursor->current_frame ();
5618                                 double target = ((double)frame - (double)current_page_samples()/2.0);
5619                                 if (target <= 0.0) {
5620                                         target = 0.0;
5621                                 }
5622                                 // compare to EditorCursor::set_position()
5623                                 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5624                                 double const new_pos = sample_to_pixel_unrounded (target);
5625                                 if (rint (new_pos) != rint (old_pos)) {
5626                                         reset_x_origin (pixel_to_sample (floor (new_pos)));
5627                                 }
5628                         }
5629
5630                 }
5631
5632         }
5633 }
5634
5635
5636 void
5637 Editor::session_going_away ()
5638 {
5639         _have_idled = false;
5640
5641         _session_connections.drop_connections ();
5642
5643         super_rapid_screen_update_connection.disconnect ();
5644
5645         selection->clear ();
5646         cut_buffer->clear ();
5647
5648         clicked_regionview = 0;
5649         clicked_axisview = 0;
5650         clicked_routeview = 0;
5651         entered_regionview = 0;
5652         entered_track = 0;
5653         last_update_frame = 0;
5654         _drags->abort ();
5655
5656         playhead_cursor->hide ();
5657
5658         /* rip everything out of the list displays */
5659
5660         _regions->clear ();
5661         _routes->clear ();
5662         _route_groups->clear ();
5663
5664         /* do this first so that deleting a track doesn't reset cms to null
5665            and thus cause a leak.
5666         */
5667
5668         if (current_mixer_strip) {
5669                 if (current_mixer_strip->get_parent() != 0) {
5670                         global_hpacker.remove (*current_mixer_strip);
5671                 }
5672                 delete current_mixer_strip;
5673                 current_mixer_strip = 0;
5674         }
5675
5676         /* delete all trackviews */
5677
5678         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5679                 delete *i;
5680         }
5681         track_views.clear ();
5682
5683         nudge_clock->set_session (0);
5684
5685         editor_list_button.set_active(false);
5686         editor_list_button.set_sensitive(false);
5687
5688         /* clear tempo/meter rulers */
5689         remove_metric_marks ();
5690         hide_measures ();
5691         clear_marker_display ();
5692
5693         stop_step_editing ();
5694
5695         if (own_window()) {
5696         
5697                 /* get rid of any existing editor mixer strip */
5698                 
5699                 WindowTitle title(Glib::get_application_name());
5700                 title += _("Editor");
5701                 
5702                 own_window()->set_title (title.get_string());
5703         }
5704
5705         SessionHandlePtr::session_going_away ();
5706 }
5707
5708
5709 void
5710 Editor::show_editor_list (bool yn)
5711 {
5712         if (yn) {
5713                 _the_notebook.show ();
5714         } else {
5715                 _the_notebook.hide ();
5716         }
5717 }
5718
5719 void
5720 Editor::change_region_layering_order (bool from_context_menu)
5721 {
5722         const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5723
5724         if (!clicked_routeview) {
5725                 if (layering_order_editor) {
5726                         layering_order_editor->hide ();
5727                 }
5728                 return;
5729         }
5730
5731         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5732
5733         if (!track) {
5734                 return;
5735         }
5736
5737         boost::shared_ptr<Playlist> pl = track->playlist();
5738
5739         if (!pl) {
5740                 return;
5741         }
5742
5743         if (layering_order_editor == 0) {
5744                 layering_order_editor = new RegionLayeringOrderEditor (*this);
5745         }
5746
5747         layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5748         layering_order_editor->maybe_present ();
5749 }
5750
5751 void
5752 Editor::update_region_layering_order_editor ()
5753 {
5754         if (layering_order_editor && layering_order_editor->is_visible ()) {
5755                 change_region_layering_order (true);
5756         }
5757 }
5758
5759 void
5760 Editor::setup_fade_images ()
5761 {
5762         _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5763         _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5764         _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5765         _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5766         _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5767
5768         _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5769         _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5770         _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5771         _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5772         _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5773
5774         _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5775         _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5776         _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5777         _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5778         _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5779
5780         _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5781         _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5782         _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5783         _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5784         _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5785
5786 }
5787
5788 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5789 Gtk::MenuItem&
5790 Editor::action_menu_item (std::string const & name)
5791 {
5792         Glib::RefPtr<Action> a = editor_actions->get_action (name);
5793         assert (a);
5794
5795         return *manage (a->create_menu_item ());
5796 }
5797
5798 void
5799 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5800 {
5801         EventBox* b = manage (new EventBox);
5802         b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5803         Label* l = manage (new Label (name));
5804         l->set_angle (-90);
5805         b->add (*l);
5806         b->show_all ();
5807         _the_notebook.append_page (widget, *b);
5808 }
5809
5810 bool
5811 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5812 {
5813         if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5814                 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5815         }
5816
5817         if (ev->type == GDK_2BUTTON_PRESS) {
5818
5819                 /* double-click on a notebook tab shrinks or expands the notebook */
5820
5821                 if (_notebook_shrunk) {
5822                         if (pre_notebook_shrink_pane_width) {
5823                                 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5824                         }
5825                         _notebook_shrunk = false;
5826                 } else {
5827                         pre_notebook_shrink_pane_width = edit_pane.get_position();
5828
5829                         /* this expands the LHS of the edit pane to cover the notebook
5830                            PAGE but leaves the tabs visible.
5831                          */
5832                         edit_pane.set_position (edit_pane.get_position() + page->get_width());
5833                         _notebook_shrunk = true;
5834                 }
5835         }
5836
5837         return true;
5838 }
5839
5840 void
5841 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5842 {
5843         using namespace Menu_Helpers;
5844
5845         MenuList& items = _control_point_context_menu.items ();
5846         items.clear ();
5847
5848         items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5849         items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5850         if (!can_remove_control_point (item)) {
5851                 items.back().set_sensitive (false);
5852         }
5853
5854         _control_point_context_menu.popup (event->button.button, event->button.time);
5855 }
5856
5857 void
5858 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5859 {
5860         using namespace Menu_Helpers;
5861
5862         NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5863         if (!note) {
5864                 return;
5865         }
5866
5867         /* We need to get the selection here and pass it to the operations, since
5868            popping up the menu will cause a region leave event which clears
5869            entered_regionview. */
5870
5871         MidiRegionView&       mrv = note->region_view();
5872         const RegionSelection rs  = get_regions_from_selection_and_entered ();
5873         const uint32_t sel_size = mrv.selection_size ();
5874
5875         MenuList& items = _note_context_menu.items();
5876         items.clear();
5877
5878         if (sel_size > 0) {
5879                 items.push_back(MenuElem(_("Delete"),
5880                                          sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5881         }
5882
5883         items.push_back(MenuElem(_("Edit..."),
5884                                  sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5885         if (sel_size != 1) {
5886                 items.back().set_sensitive (false);
5887         }
5888
5889         items.push_back(MenuElem(_("Transpose..."),
5890                                  sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
5891
5892
5893         items.push_back(MenuElem(_("Legatize"),
5894                                  sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5895         if (sel_size < 2) {
5896                 items.back().set_sensitive (false);
5897         }
5898
5899         items.push_back(MenuElem(_("Quantize..."),
5900                                  sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5901
5902         items.push_back(MenuElem(_("Remove Overlap"),
5903                                  sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5904         if (sel_size < 2) {
5905                 items.back().set_sensitive (false);
5906         }
5907
5908         items.push_back(MenuElem(_("Transform..."),
5909                                  sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5910
5911         _note_context_menu.popup (event->button.button, event->button.time);
5912 }
5913
5914 void
5915 Editor::zoom_vertical_modifier_released()
5916 {
5917         _stepping_axis_view = 0;
5918 }
5919
5920 void
5921 Editor::ui_parameter_changed (string parameter)
5922 {
5923         if (parameter == "icon-set") {
5924                 while (!_cursor_stack.empty()) {
5925                         _cursor_stack.pop_back();
5926                 }
5927                 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
5928                 _cursor_stack.push_back(_cursors->grabber);
5929         } else if (parameter == "draggable-playhead") {
5930                 if (_verbose_cursor) {
5931                         playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
5932                 }
5933         }
5934 }
5935
5936 Gtk::Window*
5937 Editor::use_own_window (bool and_fill_it)
5938 {
5939         bool new_window = !own_window();
5940         
5941         Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
5942
5943         if (win && new_window) {
5944                 win->set_name ("EditorWindow");
5945
5946                 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
5947
5948                 // win->signal_realize().connect (*this, &Editor::on_realize);
5949                 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
5950                 win->set_data ("ardour-bindings", &key_bindings);
5951                 
5952                 update_title ();
5953         }
5954
5955         DisplaySuspender ds;
5956         contents().show_all ();
5957         
5958         /* XXX: this is a bit unfortunate; it would probably
5959            be nicer if we could just call show () above rather
5960            than needing the show_all ()
5961         */
5962         
5963         /* re-hide stuff if necessary */
5964         editor_list_button_toggled ();
5965         parameter_changed ("show-summary");
5966         parameter_changed ("show-group-tabs");
5967         parameter_changed ("show-zoom-tools");
5968         
5969         /* now reset all audio_time_axis heights, because widgets might need
5970            to be re-hidden
5971         */
5972         
5973         TimeAxisView *tv;
5974         
5975         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5976                 tv = (static_cast<TimeAxisView*>(*i));
5977                 tv->reset_height ();
5978         }
5979         
5980         if (current_mixer_strip) {
5981                 current_mixer_strip->hide_things ();
5982                 current_mixer_strip->parameter_changed ("mixer-element-visibility");
5983         }
5984         
5985         return win;
5986 }