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