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