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