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