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