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