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