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