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>
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.
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.
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.
32 /* Note: public Editor methods are documented in public_editor.h */
42 #include "ardour_ui.h"
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.
49 #include <boost/none.hpp>
51 #include <sigc++/bind.h>
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/stacktrace.h"
60 #include "pbd/timersub.h"
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>
68 #include <gtkmm/menu.h>
69 #include <gtkmm/menuitem.h>
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"
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"
93 #include "canvas/debug.h"
94 #include "canvas/note.h"
95 #include "canvas/text.h"
97 #include "widgets/ardour_spacer.h"
98 #include "widgets/eventboxext.h"
99 #include "widgets/tooltips.h"
101 #include "control_protocol/control_protocol.h"
104 #include "analysis_window.h"
105 #include "audio_clock.h"
106 #include "audio_region_view.h"
107 #include "audio_streamview.h"
108 #include "audio_time_axis.h"
109 #include "automation_time_axis.h"
110 #include "bundle_manager.h"
111 #include "crossfade_edit.h"
114 #include "editing_convert.h"
116 #include "editor_cursors.h"
117 #include "editor_drag.h"
118 #include "editor_group_tabs.h"
119 #include "editor_locations.h"
120 #include "editor_regions.h"
121 #include "editor_route_groups.h"
122 #include "editor_routes.h"
123 #include "editor_snapshots.h"
124 #include "editor_sources.h"
125 #include "editor_summary.h"
126 #include "enums_convert.h"
127 #include "export_report.h"
128 #include "global_port_matrix.h"
129 #include "gui_object.h"
130 #include "gui_thread.h"
131 #include "keyboard.h"
132 #include "luainstance.h"
134 #include "midi_region_view.h"
135 #include "midi_time_axis.h"
136 #include "mixer_strip.h"
137 #include "mixer_ui.h"
138 #include "mouse_cursors.h"
139 #include "note_base.h"
140 #include "playlist_selector.h"
141 #include "public_editor.h"
142 #include "quantize_dialog.h"
143 #include "region_layering_order_editor.h"
144 #include "rgb_macros.h"
145 #include "rhythm_ferret.h"
146 #include "route_sorter.h"
147 #include "selection.h"
148 #include "simple_progress_dialog.h"
150 #include "grid_lines.h"
151 #include "time_axis_view.h"
152 #include "time_info_box.h"
154 #include "ui_config.h"
156 #include "vca_time_axis.h"
157 #include "verbose_cursor.h"
159 #include "pbd/i18n.h"
162 using namespace ARDOUR;
163 using namespace ArdourWidgets;
164 using namespace ARDOUR_UI_UTILS;
167 using namespace Glib;
168 using namespace Gtkmm2ext;
169 using namespace Editing;
171 using PBD::internationalize;
173 using Gtkmm2ext::Keyboard;
175 double Editor::timebar_height = 15.0;
177 static const gchar *_grid_type_strings[] = {
186 N_("1/3 (8th triplet)"), // or "1/12" ?
187 N_("1/6 (16th triplet)"),
188 N_("1/12 (32nd triplet)"),
189 N_("1/24 (64th triplet)"),
190 N_("1/5 (8th quintuplet)"),
191 N_("1/10 (16th quintuplet)"),
192 N_("1/20 (32nd quintuplet)"),
193 N_("1/7 (8th septuplet)"),
194 N_("1/14 (16th septuplet)"),
195 N_("1/28 (32nd septuplet)"),
202 static const gchar *_edit_point_strings[] = {
209 static const gchar *_edit_mode_strings[] = {
217 static const gchar *_zoom_focus_strings[] = {
227 #ifdef USE_RUBBERBAND
228 static const gchar *_rb_opt_strings[] = {
231 N_("Balanced multitimbral mixture"),
232 N_("Unpitched percussion with stable notes"),
233 N_("Crisp monophonic instrumental"),
234 N_("Unpitched solo percussion"),
235 N_("Resample without preserving pitch"),
240 /* Robin says: this should be odd to accomodate cairo drawing offset (width/2 rounds up to pixel boundary) */
242 #define COMBO_TRIANGLE_WIDTH 19 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
244 #define COMBO_TRIANGLE_WIDTH 11 // as-measured for win/linux.
248 : PublicEditor (global_hpacker)
249 , editor_mixer_strip_width (Wide)
250 , constructed (false)
251 , _playlist_selector (0)
253 , no_save_visual (false)
254 , _leftmost_sample (0)
255 , samples_per_pixel (2048)
256 , zoom_focus (ZoomFocusPlayhead)
257 , mouse_mode (MouseObject)
258 , pre_internal_grid_type (GridTypeBeat)
259 , pre_internal_snap_mode (SnapOff)
260 , internal_grid_type (GridTypeBeat)
261 , internal_snap_mode (SnapOff)
262 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
263 , _notebook_shrunk (false)
264 , location_marker_color (0)
265 , location_range_color (0)
266 , location_loop_color (0)
267 , location_punch_color (0)
268 , location_cd_marker_color (0)
270 , _show_marker_lines (false)
271 , clicked_axisview (0)
272 , clicked_routeview (0)
273 , clicked_regionview (0)
274 , clicked_selection (0)
275 , clicked_control_point (0)
276 , button_release_can_deselect (true)
277 , _mouse_changed_selection (false)
278 , _popup_region_menu_item (0)
280 , _track_canvas_viewport (0)
281 , within_track_canvas (false)
282 , _verbose_cursor (0)
286 , range_marker_group (0)
287 , transport_marker_group (0)
288 , cd_marker_group (0)
289 , _time_markers_group (0)
290 , hv_scroll_group (0)
292 , cursor_scroll_group (0)
293 , no_scroll_group (0)
294 , _trackview_group (0)
295 , _drag_motion_group (0)
296 , _canvas_drop_zone (0)
297 , no_ruler_shown_update (false)
298 , ruler_grabbed_widget (0)
300 , minsec_mark_interval (0)
301 , minsec_mark_modulo (0)
303 , timecode_ruler_scale (timecode_show_many_hours)
304 , timecode_mark_modulo (0)
305 , timecode_nmarks (0)
306 , _samples_ruler_interval (0)
307 , bbt_ruler_scale (bbt_show_many)
310 , bbt_bar_helper_on (0)
311 , bbt_accent_modulo (0)
316 , visible_timebars (0)
317 , editor_ruler_menu (0)
321 , range_marker_bar (0)
322 , transport_marker_bar (0)
324 , minsec_label (_("Mins:Secs"))
325 , bbt_label (_("Bars:Beats"))
326 , timecode_label (_("Timecode"))
327 , samples_label (_("Samples"))
328 , tempo_label (_("Tempo"))
329 , meter_label (_("Meter"))
330 , mark_label (_("Location Markers"))
331 , range_mark_label (_("Range Markers"))
332 , transport_mark_label (_("Loop/Punch Ranges"))
333 , cd_mark_label (_("CD Markers"))
334 , videotl_label (_("Video Timeline"))
337 , playhead_cursor (0)
338 , _region_boundary_cache_dirty (true)
339 , edit_packer (4, 4, true)
340 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
341 , horizontal_adjustment (0.0, 0.0, 1e16)
342 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
343 , controls_layout (unused_adjustment, vertical_adjustment)
344 , _scroll_callbacks (0)
345 , _visible_canvas_width (0)
346 , _visible_canvas_height (0)
347 , _full_canvas_height (0)
348 , edit_controls_left_menu (0)
349 , edit_controls_right_menu (0)
350 , visual_change_queued(false)
351 , _last_update_time (0)
352 , _err_screen_engine (0)
353 , cut_buffer_start (0)
354 , cut_buffer_length (0)
355 , button_bindings (0)
356 , last_paste_pos (-1)
359 , current_interthread_info (0)
360 , analysis_window (0)
361 , select_new_marker (false)
363 , scrubbing_direction (0)
364 , scrub_reversals (0)
365 , scrub_reverse_distance (0)
366 , have_pending_keyboard_selection (false)
367 , pending_keyboard_selection_start (0)
368 , _grid_type (GridTypeBeat)
369 , _snap_mode (SnapOff)
370 , ignore_gui_changes (false)
371 , _drags (new DragManager (this))
373 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
374 , _dragging_playhead (false)
375 , _dragging_edit_point (false)
376 , _follow_playhead (true)
377 , _stationary_playhead (false)
380 , global_rect_group (0)
381 , time_line_group (0)
382 , tempo_marker_menu (0)
383 , meter_marker_menu (0)
385 , range_marker_menu (0)
386 , new_transport_marker_menu (0)
387 , marker_menu_item (0)
388 , bbt_beat_subdivision (4)
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 , cd_marker_bar_drag_rect (0)
401 , range_bar_drag_rect (0)
402 , transport_bar_drag_rect (0)
403 , transport_bar_range_rect (0)
404 , transport_bar_preroll_rect (0)
405 , transport_bar_postroll_rect (0)
406 , transport_loop_range_rect (0)
407 , transport_punch_range_rect (0)
408 , transport_punchin_line (0)
409 , transport_punchout_line (0)
410 , transport_preroll_rect (0)
411 , transport_postroll_rect (0)
413 , rubberband_rect (0)
419 , autoscroll_horizontal_allowed (false)
420 , autoscroll_vertical_allowed (false)
422 , autoscroll_widget (0)
423 , show_gain_after_trim (false)
424 , selection_op_cmd_depth (0)
425 , selection_op_history_it (0)
426 , no_save_instant (false)
428 , current_mixer_strip (0)
429 , show_editor_mixer_when_tracks_arrive (false)
430 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
431 , current_stepping_trackview (0)
432 , last_track_height_step_timestamp (0)
434 , entered_regionview (0)
435 , clear_entered_track (false)
436 , _edit_point (EditAtMouse)
437 , meters_running (false)
439 , _have_idled (false)
440 , resize_idle_id (-1)
441 , _pending_resize_amount (0)
442 , _pending_resize_view (0)
443 , _pending_locate_request (false)
444 , _pending_initial_locate (false)
448 , layering_order_editor (0)
449 , _last_cut_copy_source_track (0)
450 , _region_selection_change_updates_region_list (true)
452 , _following_mixer_selection (false)
453 , _control_point_toggled_on_press (false)
454 , _stepping_axis_view (0)
455 , quantize_dialog (0)
456 , _main_menu_disabler (0)
458 /* we are a singleton */
460 PublicEditor::_instance = this;
464 last_event_time.tv_sec = 0;
465 last_event_time.tv_usec = 0;
467 selection_op_history.clear();
470 grid_type_strings = I18N (_grid_type_strings);
471 zoom_focus_strings = I18N (_zoom_focus_strings);
472 edit_mode_strings = I18N (_edit_mode_strings);
473 edit_point_strings = I18N (_edit_point_strings);
474 #ifdef USE_RUBBERBAND
475 rb_opt_strings = I18N (_rb_opt_strings);
479 build_edit_mode_menu();
480 build_zoom_focus_menu();
481 build_track_count_menu();
482 build_grid_type_menu();
483 build_edit_point_menu();
485 location_marker_color = UIConfiguration::instance().color ("location marker");
486 location_range_color = UIConfiguration::instance().color ("location range");
487 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
488 location_loop_color = UIConfiguration::instance().color ("location loop");
489 location_punch_color = UIConfiguration::instance().color ("location punch");
491 timebar_height = std::max (12., ceil (15. * UIConfiguration::instance().get_ui_scale()));
493 TimeAxisView::setup_sizes ();
494 ArdourMarker::setup_sizes (timebar_height);
495 TempoCurve::setup_sizes (timebar_height);
497 bbt_label.set_name ("EditorRulerLabel");
498 bbt_label.set_size_request (-1, (int)timebar_height);
499 bbt_label.set_alignment (1.0, 0.5);
500 bbt_label.set_padding (5,0);
502 bbt_label.set_no_show_all();
503 minsec_label.set_name ("EditorRulerLabel");
504 minsec_label.set_size_request (-1, (int)timebar_height);
505 minsec_label.set_alignment (1.0, 0.5);
506 minsec_label.set_padding (5,0);
507 minsec_label.hide ();
508 minsec_label.set_no_show_all();
509 timecode_label.set_name ("EditorRulerLabel");
510 timecode_label.set_size_request (-1, (int)timebar_height);
511 timecode_label.set_alignment (1.0, 0.5);
512 timecode_label.set_padding (5,0);
513 timecode_label.hide ();
514 timecode_label.set_no_show_all();
515 samples_label.set_name ("EditorRulerLabel");
516 samples_label.set_size_request (-1, (int)timebar_height);
517 samples_label.set_alignment (1.0, 0.5);
518 samples_label.set_padding (5,0);
519 samples_label.hide ();
520 samples_label.set_no_show_all();
522 tempo_label.set_name ("EditorRulerLabel");
523 tempo_label.set_size_request (-1, (int)timebar_height);
524 tempo_label.set_alignment (1.0, 0.5);
525 tempo_label.set_padding (5,0);
527 tempo_label.set_no_show_all();
529 meter_label.set_name ("EditorRulerLabel");
530 meter_label.set_size_request (-1, (int)timebar_height);
531 meter_label.set_alignment (1.0, 0.5);
532 meter_label.set_padding (5,0);
534 meter_label.set_no_show_all();
536 if (Profile->get_trx()) {
537 mark_label.set_text (_("Markers"));
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);
544 mark_label.set_no_show_all();
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();
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();
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();
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();
575 initialize_canvas ();
577 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
579 _summary = new EditorSummary (this);
581 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
582 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
584 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
586 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
587 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
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));
593 HBox* h = manage (new HBox);
594 _group_tabs = new EditorGroupTabs (this);
595 if (!ARDOUR::Profile->get_trx()) {
596 h->pack_start (*_group_tabs, PACK_SHRINK);
598 h->pack_start (edit_controls_vbox);
599 controls_layout.add (*h);
601 controls_layout.set_name ("EditControlsBase");
602 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
603 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
604 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
606 _cursors = new MouseCursors;
607 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
608 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
610 /* Push default cursor to ever-present bottom of cursor stack. */
611 push_canvas_cursor(_cursors->grabber);
613 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
615 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
616 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
617 pad_line_1->set_outline_color (0xFF0000FF);
623 edit_packer.set_col_spacings (0);
624 edit_packer.set_row_spacings (0);
625 edit_packer.set_homogeneous (false);
626 edit_packer.set_border_width (0);
627 edit_packer.set_name ("EditorWindow");
629 time_bars_event_box.add (time_bars_vbox);
630 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
631 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
633 ArdourWidgets::ArdourDropShadow *axis_view_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
634 axis_view_shadow->set_size_request (4, -1);
635 axis_view_shadow->set_name("EditorWindow");
636 axis_view_shadow->show();
638 edit_packer.attach (*axis_view_shadow, 0, 1, 0, 2, FILL, FILL|EXPAND, 0, 0);
640 /* labels for the time bars */
641 edit_packer.attach (time_bars_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
643 edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0);
645 edit_packer.attach (*_track_canvas_viewport, 2, 3, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
647 bottom_hbox.set_border_width (2);
648 bottom_hbox.set_spacing (3);
650 PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&Editor::presentation_info_changed, this, _1), gui_context());
652 _route_groups = new EditorRouteGroups (this);
653 _routes = new EditorRoutes (this);
654 _regions = new EditorRegions (this);
655 _sources = new EditorSources (this);
656 _snapshots = new EditorSnapshots (this);
657 _locations = new EditorLocations (this);
658 _time_info_box = new TimeInfoBox ("EditorTimeInfo", true);
660 /* these are static location signals */
662 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
663 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
664 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
666 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
667 add_notebook_page (_("Sources"), _sources->widget ());
668 add_notebook_page (_("Regions"), _regions->widget ());
669 add_notebook_page (_("Snapshots"), _snapshots->widget ());
670 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
671 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
673 _the_notebook.set_show_tabs (true);
674 _the_notebook.set_scrollable (true);
675 _the_notebook.popup_disable ();
676 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
677 _the_notebook.show_all ();
679 _notebook_shrunk = false;
682 /* Pick up some settings we need to cache, early */
684 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
687 settings->get_property ("notebook-shrunk", _notebook_shrunk);
690 editor_summary_pane.set_check_divider_position (true);
691 editor_summary_pane.add (edit_packer);
693 Button* summary_arrow_left = manage (new Button);
694 summary_arrow_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
695 summary_arrow_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
696 summary_arrow_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
698 Button* summary_arrow_right = manage (new Button);
699 summary_arrow_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
700 summary_arrow_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
701 summary_arrow_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
703 VBox* summary_arrows_left = manage (new VBox);
704 summary_arrows_left->pack_start (*summary_arrow_left);
706 VBox* summary_arrows_right = manage (new VBox);
707 summary_arrows_right->pack_start (*summary_arrow_right);
709 Frame* summary_frame = manage (new Frame);
710 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
712 summary_frame->add (*_summary);
713 summary_frame->show ();
715 _summary_hbox.pack_start (*summary_arrows_left, false, false);
716 _summary_hbox.pack_start (*summary_frame, true, true);
717 _summary_hbox.pack_start (*summary_arrows_right, false, false);
719 if (!ARDOUR::Profile->get_trx()) {
720 editor_summary_pane.add (_summary_hbox);
723 edit_pane.set_check_divider_position (true);
724 edit_pane.add (editor_summary_pane);
725 if (!ARDOUR::Profile->get_trx()) {
726 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
727 _editor_list_vbox.pack_start (_the_notebook);
728 edit_pane.add (_editor_list_vbox);
729 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
732 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
733 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
736 if (!settings || !settings->get_property ("edit-horizontal-pane-pos", fract) || fract > 1.0) {
737 /* initial allocation is 90% to canvas, 10% to notebook */
740 edit_pane.set_divider (0, fract);
742 if (!settings || !settings->get_property ("edit-vertical-pane-pos", fract) || fract > 1.0) {
743 /* initial allocation is 90% to canvas, 10% to summary */
746 editor_summary_pane.set_divider (0, fract);
748 global_vpacker.set_spacing (0);
749 global_vpacker.set_border_width (0);
751 /* the next three EventBoxes provide the ability for their child widgets to have a background color. That is all. */
753 Gtk::EventBox* ebox = manage (new Gtk::EventBox); // a themeable box
754 ebox->set_name("EditorWindow");
755 ebox->add (ebox_hpacker);
757 Gtk::EventBox* epane_box = manage (new EventBoxExt); // a themeable box
758 epane_box->set_name("EditorWindow");
759 epane_box->add (edit_pane);
761 Gtk::EventBox* epane_box2 = manage (new EventBoxExt); // a themeable box
762 epane_box2->set_name("EditorWindow");
763 epane_box2->add (global_vpacker);
765 ArdourWidgets::ArdourDropShadow *toolbar_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
766 toolbar_shadow->set_size_request (-1, 4);
767 toolbar_shadow->set_mode(ArdourWidgets::ArdourDropShadow::DropShadowBoth);
768 toolbar_shadow->set_name("EditorWindow");
769 toolbar_shadow->show();
771 global_vpacker.pack_start (*toolbar_shadow, false, false);
772 global_vpacker.pack_start (*ebox, false, false);
773 global_vpacker.pack_start (*epane_box, true, true);
774 global_hpacker.pack_start (*epane_box2, true, true);
776 /* need to show the "contents" widget so that notebook will show if tab is switched to
779 global_hpacker.show ();
783 /* register actions now so that set_state() can find them and set toggles/checks etc */
790 _playlist_selector = new PlaylistSelector();
791 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
793 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
797 nudge_forward_button.set_name ("nudge button");
798 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
800 nudge_backward_button.set_name ("nudge button");
801 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
803 fade_context_menu.set_name ("ArdourContextMenu");
805 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
807 /* allow external control surfaces/protocols to do various things */
809 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
810 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
811 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
812 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
813 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
814 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
815 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
816 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
817 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
818 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
819 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
820 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
821 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
822 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
824 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
825 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
826 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
827 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
828 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
830 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
834 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
836 /* problematic: has to return a value and thus cannot be x-thread */
838 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
840 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
841 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
843 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
845 _ignore_region_action = false;
846 _last_region_menu_was_main = false;
848 _show_marker_lines = false;
850 /* Button bindings */
852 button_bindings = new Bindings ("editor-mouse");
854 XMLNode* node = button_settings();
856 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
857 button_bindings->load_operation (**i);
863 /* grab current parameter state */
864 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
865 UIConfiguration::instance().map_parameters (pc);
867 setup_fade_images ();
869 set_grid_to (GridTypeNone);
874 delete tempo_marker_menu;
875 delete meter_marker_menu;
877 delete range_marker_menu;
878 delete new_transport_marker_menu;
879 delete editor_ruler_menu;
880 delete _popup_region_menu_item;
882 delete button_bindings;
884 delete _route_groups;
885 delete _track_canvas_viewport;
888 delete _verbose_cursor;
889 delete quantize_dialog;
895 delete _playlist_selector;
896 delete _time_info_box;
901 LuaInstance::destroy_instance ();
903 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
906 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
909 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
915 Editor::button_settings () const
917 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
918 XMLNode* node = find_named_node (*settings, X_("Buttons"));
921 node = new XMLNode (X_("Buttons"));
928 Editor::get_smart_mode () const
930 return ((current_mouse_mode() == MouseObject) && smart_mode_action->get_active());
934 Editor::catch_vanishing_regionview (RegionView *rv)
936 /* note: the selection will take care of the vanishing
937 audioregionview by itself.
940 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
944 if (clicked_regionview == rv) {
945 clicked_regionview = 0;
948 if (entered_regionview == rv) {
949 set_entered_regionview (0);
952 if (!_all_region_actions_sensitized) {
953 sensitize_all_region_actions (true);
958 Editor::set_entered_regionview (RegionView* rv)
960 if (rv == entered_regionview) {
964 if (entered_regionview) {
965 entered_regionview->exited ();
968 entered_regionview = rv;
970 if (entered_regionview != 0) {
971 entered_regionview->entered ();
974 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
975 /* This RegionView entry might have changed what region actions
976 are allowed, so sensitize them all in case a key is pressed.
978 sensitize_all_region_actions (true);
983 Editor::set_entered_track (TimeAxisView* tav)
986 entered_track->exited ();
992 entered_track->entered ();
997 Editor::instant_save ()
999 if (!constructed || !_session || no_save_instant) {
1003 _session->add_instant_xml(get_state());
1007 Editor::control_vertical_zoom_in_all ()
1009 tav_zoom_smooth (false, true);
1013 Editor::control_vertical_zoom_out_all ()
1015 tav_zoom_smooth (true, true);
1019 Editor::control_vertical_zoom_in_selected ()
1021 tav_zoom_smooth (false, false);
1025 Editor::control_vertical_zoom_out_selected ()
1027 tav_zoom_smooth (true, false);
1031 Editor::control_view (uint32_t view)
1033 goto_visual_state (view);
1037 Editor::control_unselect ()
1039 selection->clear_tracks ();
1043 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1045 TimeAxisView* tav = time_axis_view_from_stripable (s);
1049 case Selection::Add:
1050 selection->add (tav);
1052 case Selection::Toggle:
1053 selection->toggle (tav);
1055 case Selection::Extend:
1057 case Selection::Set:
1058 selection->set (tav);
1062 selection->clear_tracks ();
1067 Editor::control_step_tracks_up ()
1069 scroll_tracks_up_line ();
1073 Editor::control_step_tracks_down ()
1075 scroll_tracks_down_line ();
1079 Editor::control_scroll (float fraction)
1081 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1087 double step = fraction * current_page_samples();
1090 _control_scroll_target is an optional<T>
1092 it acts like a pointer to an samplepos_t, with
1093 a operator conversion to boolean to check
1094 that it has a value could possibly use
1095 playhead_cursor->current_sample to store the
1096 value and a boolean in the class to know
1097 when it's out of date
1100 if (!_control_scroll_target) {
1101 _control_scroll_target = _session->transport_sample();
1102 _dragging_playhead = true;
1105 if ((fraction < 0.0f) && (*_control_scroll_target <= (samplepos_t) fabs(step))) {
1106 *_control_scroll_target = 0;
1107 } else if ((fraction > 0.0f) && (max_samplepos - *_control_scroll_target < step)) {
1108 *_control_scroll_target = max_samplepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1110 *_control_scroll_target += (samplepos_t) trunc (step);
1113 /* move visuals, we'll catch up with it later */
1115 playhead_cursor->set_position (*_control_scroll_target);
1116 UpdateAllTransportClocks (*_control_scroll_target);
1118 if (*_control_scroll_target > (current_page_samples() / 2)) {
1119 /* try to center PH in window */
1120 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1126 Now we do a timeout to actually bring the session to the right place
1127 according to the playhead. This is to avoid reading disk buffers on every
1128 call to control_scroll, which is driven by ScrollTimeline and therefore
1129 probably by a control surface wheel which can generate lots of events.
1131 /* cancel the existing timeout */
1133 control_scroll_connection.disconnect ();
1135 /* add the next timeout */
1137 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1141 Editor::deferred_control_scroll (samplepos_t /*target*/)
1143 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1144 /* reset for next stream */
1145 _control_scroll_target = boost::none;
1146 _dragging_playhead = false;
1151 Editor::access_action (const std::string& action_group, const std::string& action_item)
1157 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1161 act = ActionManager::get_action (action_group.c_str(), action_item.c_str());
1165 } catch ( ActionManager::MissingActionException const& e) {
1166 cerr << "MissingActionException:" << e.what () << endl;
1171 Editor::set_toggleaction (const std::string& action_group, const std::string& action_item, bool s)
1173 ActionManager::set_toggleaction_state (action_group.c_str(), action_item.c_str(), s);
1177 Editor::on_realize ()
1181 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1182 start_lock_event_timing ();
1187 Editor::start_lock_event_timing ()
1189 /* check if we should lock the GUI every 30 seconds */
1191 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1195 Editor::generic_event_handler (GdkEvent* ev)
1198 case GDK_BUTTON_PRESS:
1199 case GDK_BUTTON_RELEASE:
1200 case GDK_MOTION_NOTIFY:
1202 case GDK_KEY_RELEASE:
1203 if (contents().is_mapped()) {
1204 gettimeofday (&last_event_time, 0);
1208 case GDK_LEAVE_NOTIFY:
1209 switch (ev->crossing.detail) {
1210 case GDK_NOTIFY_UNKNOWN:
1211 case GDK_NOTIFY_INFERIOR:
1212 case GDK_NOTIFY_ANCESTOR:
1214 case GDK_NOTIFY_VIRTUAL:
1215 case GDK_NOTIFY_NONLINEAR:
1216 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1217 /* leaving window, so reset focus, thus ending any and
1218 all text entry operations.
1220 ARDOUR_UI::instance()->reset_focus (&contents());
1233 Editor::lock_timeout_callback ()
1235 struct timeval now, delta;
1237 gettimeofday (&now, 0);
1239 timersub (&now, &last_event_time, &delta);
1241 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1243 /* don't call again. Returning false will effectively
1244 disconnect us from the timer callback.
1246 unlock() will call start_lock_event_timing() to get things
1256 Editor::map_position_change (samplepos_t sample)
1258 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, sample)
1260 if (_session == 0) {
1264 if (_follow_playhead) {
1265 center_screen (sample);
1268 playhead_cursor->set_position (sample);
1272 Editor::center_screen (samplepos_t sample)
1274 samplecnt_t const page = _visible_canvas_width * samples_per_pixel;
1276 /* if we're off the page, then scroll.
1279 if (sample < _leftmost_sample || sample >= _leftmost_sample + page) {
1280 center_screen_internal (sample, page);
1285 Editor::center_screen_internal (samplepos_t sample, float page)
1289 if (sample > page) {
1290 sample -= (samplepos_t) page;
1295 reset_x_origin (sample);
1300 Editor::update_title ()
1302 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1304 if (!own_window()) {
1309 bool dirty = _session->dirty();
1311 string session_name;
1313 if (_session->snap_name() != _session->name()) {
1314 session_name = _session->snap_name();
1316 session_name = _session->name();
1320 session_name = "*" + session_name;
1323 WindowTitle title(session_name);
1324 title += S_("Window|Editor");
1325 title += Glib::get_application_name();
1326 own_window()->set_title (title.get_string());
1328 /* ::session_going_away() will have taken care of it */
1333 Editor::set_session (Session *t)
1335 SessionHandlePtr::set_session (t);
1341 /* initialize _leftmost_sample to the extents of the session
1342 * this prevents a bogus setting of leftmost = "0" if the summary view asks for the leftmost sample
1343 * before the visible state has been loaded from instant.xml */
1344 _leftmost_sample = session_gui_extents().first;
1346 _playlist_selector->set_session (_session);
1347 nudge_clock->set_session (_session);
1348 _summary->set_session (_session);
1349 _group_tabs->set_session (_session);
1350 _route_groups->set_session (_session);
1351 _regions->set_session (_session);
1352 _sources->set_session (_session);
1353 _snapshots->set_session (_session);
1354 _routes->set_session (_session);
1355 _locations->set_session (_session);
1356 _time_info_box->set_session (_session);
1358 if (rhythm_ferret) {
1359 rhythm_ferret->set_session (_session);
1362 if (analysis_window) {
1363 analysis_window->set_session (_session);
1367 sfbrowser->set_session (_session);
1370 compute_fixed_ruler_scale ();
1372 /* Make sure we have auto loop and auto punch ranges */
1374 Location* loc = _session->locations()->auto_loop_location();
1376 loc->set_name (_("Loop"));
1379 loc = _session->locations()->auto_punch_location();
1382 loc->set_name (_("Punch"));
1385 refresh_location_display ();
1387 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1388 * the selected Marker; this needs the LocationMarker list to be available.
1390 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1391 set_state (*node, Stateful::loading_state_version);
1393 /* catch up on selection state, etc. */
1396 sc.add (Properties::selected);
1397 presentation_info_changed (sc);
1399 /* catch up with the playhead */
1401 _session->request_locate (playhead_cursor->current_sample ());
1402 _pending_initial_locate = true;
1406 /* These signals can all be emitted by a non-GUI thread. Therefore the
1407 handlers for them must not attempt to directly interact with the GUI,
1408 but use PBD::Signal<T>::connect() which accepts an event loop
1409 ("context") where the handler will be asked to run.
1412 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1413 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1414 _session->TransportLooped.connect (_session_connections, invalidator (*this), boost::bind (&Editor::transport_looped, this), gui_context());
1415 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1416 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1417 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1418 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1419 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1420 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1421 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1422 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1423 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1424 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1425 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1426 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1427 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1429 playhead_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1430 playhead_cursor->show ();
1432 snapped_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1433 snapped_cursor->set_color (UIConfiguration::instance().color ("edit point"));
1434 snapped_cursor->show ();
1436 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1437 Config->map_parameters (pc);
1438 _session->config.map_parameters (pc);
1440 restore_ruler_visibility ();
1441 //tempo_map_changed (PropertyChange (0));
1442 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1444 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1445 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1448 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1449 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1452 /* register for undo history */
1453 _session->register_with_memento_command_factory(id(), this);
1454 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1456 LuaInstance::instance()->set_session(_session);
1458 start_updating_meters ();
1462 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1464 using namespace Menu_Helpers;
1466 void (Editor::*emf)(FadeShape);
1467 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1470 images = &_xfade_in_images;
1471 emf = &Editor::set_fade_in_shape;
1473 images = &_xfade_out_images;
1474 emf = &Editor::set_fade_out_shape;
1479 _("Linear (for highly correlated material)"),
1480 *(*images)[FadeLinear],
1481 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1485 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1489 _("Constant power"),
1490 *(*images)[FadeConstantPower],
1491 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1494 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1499 *(*images)[FadeSymmetric],
1500 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1504 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1509 *(*images)[FadeSlow],
1510 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1513 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1518 *(*images)[FadeFast],
1519 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1522 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1525 /** Pop up a context menu for when the user clicks on a start crossfade */
1527 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1529 using namespace Menu_Helpers;
1530 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1535 MenuList& items (xfade_in_context_menu.items());
1538 if (arv->audio_region()->fade_in_active()) {
1539 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1541 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1544 items.push_back (SeparatorElem());
1545 fill_xfade_menu (items, true);
1547 xfade_in_context_menu.popup (button, time);
1550 /** Pop up a context menu for when the user clicks on an end crossfade */
1552 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1554 using namespace Menu_Helpers;
1555 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1560 MenuList& items (xfade_out_context_menu.items());
1563 if (arv->audio_region()->fade_out_active()) {
1564 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1566 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1569 items.push_back (SeparatorElem());
1570 fill_xfade_menu (items, false);
1572 xfade_out_context_menu.popup (button, time);
1576 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1578 using namespace Menu_Helpers;
1579 Menu* (Editor::*build_menu_function)();
1582 switch (item_type) {
1584 case RegionViewName:
1585 case RegionViewNameHighlight:
1586 case LeftFrameHandle:
1587 case RightFrameHandle:
1588 if (with_selection) {
1589 build_menu_function = &Editor::build_track_selection_context_menu;
1591 build_menu_function = &Editor::build_track_region_context_menu;
1596 if (with_selection) {
1597 build_menu_function = &Editor::build_track_selection_context_menu;
1599 build_menu_function = &Editor::build_track_context_menu;
1604 if (clicked_routeview->track()) {
1605 build_menu_function = &Editor::build_track_context_menu;
1607 build_menu_function = &Editor::build_track_bus_context_menu;
1612 /* probably shouldn't happen but if it does, we don't care */
1616 menu = (this->*build_menu_function)();
1617 menu->set_name ("ArdourContextMenu");
1619 /* now handle specific situations */
1621 switch (item_type) {
1623 case RegionViewName:
1624 case RegionViewNameHighlight:
1625 case LeftFrameHandle:
1626 case RightFrameHandle:
1636 /* probably shouldn't happen but if it does, we don't care */
1640 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1642 /* Bounce to disk */
1644 using namespace Menu_Helpers;
1645 MenuList& edit_items = menu->items();
1647 edit_items.push_back (SeparatorElem());
1649 switch (clicked_routeview->audio_track()->freeze_state()) {
1650 case AudioTrack::NoFreeze:
1651 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1654 case AudioTrack::Frozen:
1655 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1658 case AudioTrack::UnFrozen:
1659 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1665 if (item_type == StreamItem && clicked_routeview) {
1666 clicked_routeview->build_underlay_menu(menu);
1669 /* When the region menu is opened, we setup the actions so that they look right
1672 sensitize_the_right_region_actions (false);
1673 _last_region_menu_was_main = false;
1675 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1676 menu->popup (button, time);
1680 Editor::build_track_context_menu ()
1682 using namespace Menu_Helpers;
1684 MenuList& edit_items = track_context_menu.items();
1687 add_dstream_context_items (edit_items);
1688 return &track_context_menu;
1692 Editor::build_track_bus_context_menu ()
1694 using namespace Menu_Helpers;
1696 MenuList& edit_items = track_context_menu.items();
1699 add_bus_context_items (edit_items);
1700 return &track_context_menu;
1704 Editor::build_track_region_context_menu ()
1706 using namespace Menu_Helpers;
1707 MenuList& edit_items = track_region_context_menu.items();
1710 /* we've just cleared the track region context menu, so the menu that these
1711 two items were on will have disappeared; stop them dangling.
1713 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1716 boost::shared_ptr<Track> tr;
1717 boost::shared_ptr<Playlist> pl;
1719 if ((tr = rtv->track())) {
1720 add_region_context_items (edit_items, tr);
1724 add_dstream_context_items (edit_items);
1726 return &track_region_context_menu;
1730 Editor::loudness_analyze_region_selection ()
1735 Selection& s (PublicEditor::instance ().get_selection ());
1736 RegionSelection ars = s.regions;
1737 ARDOUR::AnalysisGraph ag (_session);
1738 samplecnt_t total_work = 0;
1740 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1741 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1745 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1748 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1749 total_work += arv->region ()->length ();
1752 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1754 ag.set_total_samples (total_work);
1755 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1758 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1759 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1763 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1767 ag.analyze_region (ar);
1770 if (!ag.canceled ()) {
1771 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1777 Editor::loudness_analyze_range_selection ()
1782 Selection& s (PublicEditor::instance ().get_selection ());
1783 TimeSelection ts = s.time;
1784 ARDOUR::AnalysisGraph ag (_session);
1785 samplecnt_t total_work = 0;
1787 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1788 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1792 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1796 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1797 total_work += j->length ();
1801 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1803 ag.set_total_samples (total_work);
1804 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1807 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1808 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1812 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1816 ag.analyze_range (rui->route (), pl, ts);
1819 if (!ag.canceled ()) {
1820 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1826 Editor::spectral_analyze_region_selection ()
1828 if (analysis_window == 0) {
1829 analysis_window = new AnalysisWindow();
1832 analysis_window->set_session(_session);
1834 analysis_window->show_all();
1837 analysis_window->set_regionmode();
1838 analysis_window->analyze();
1840 analysis_window->present();
1844 Editor::spectral_analyze_range_selection()
1846 if (analysis_window == 0) {
1847 analysis_window = new AnalysisWindow();
1850 analysis_window->set_session(_session);
1852 analysis_window->show_all();
1855 analysis_window->set_rangemode();
1856 analysis_window->analyze();
1858 analysis_window->present();
1862 Editor::build_track_selection_context_menu ()
1864 using namespace Menu_Helpers;
1865 MenuList& edit_items = track_selection_context_menu.items();
1866 edit_items.clear ();
1868 add_selection_context_items (edit_items);
1869 // edit_items.push_back (SeparatorElem());
1870 // add_dstream_context_items (edit_items);
1872 return &track_selection_context_menu;
1876 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1878 using namespace Menu_Helpers;
1880 /* OK, stick the region submenu at the top of the list, and then add
1884 RegionSelection rs = get_regions_from_selection_and_entered ();
1886 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1888 if (_popup_region_menu_item == 0) {
1889 _popup_region_menu_item = new MenuItem (menu_item_name, false);
1890 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1891 _popup_region_menu_item->show ();
1893 _popup_region_menu_item->set_label (menu_item_name);
1896 /* No layering allowed in later is higher layering model */
1897 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1898 if (act && Config->get_layer_model() == LaterHigher) {
1899 act->set_sensitive (false);
1901 act->set_sensitive (true);
1904 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1906 edit_items.push_back (*_popup_region_menu_item);
1907 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1908 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1910 edit_items.push_back (SeparatorElem());
1913 /** Add context menu items relevant to selection ranges.
1914 * @param edit_items List to add the items to.
1917 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1919 using namespace Menu_Helpers;
1921 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1922 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1924 edit_items.push_back (SeparatorElem());
1925 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1927 edit_items.push_back (SeparatorElem());
1928 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1929 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1931 edit_items.push_back (SeparatorElem());
1933 edit_items.push_back (
1935 _("Move Range Start to Previous Region Boundary"),
1936 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1940 edit_items.push_back (
1942 _("Move Range Start to Next Region Boundary"),
1943 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1947 edit_items.push_back (
1949 _("Move Range End to Previous Region Boundary"),
1950 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1954 edit_items.push_back (
1956 _("Move Range End to Next Region Boundary"),
1957 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1961 edit_items.push_back (SeparatorElem());
1962 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1963 // edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1965 edit_items.push_back (SeparatorElem());
1966 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1968 edit_items.push_back (SeparatorElem());
1969 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1970 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1971 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1973 edit_items.push_back (SeparatorElem());
1974 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1976 edit_items.push_back (SeparatorElem());
1977 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1978 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1980 edit_items.push_back (SeparatorElem());
1981 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1982 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1983 edit_items.push_back (MenuElem (_("Bounce Range to Source List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1984 edit_items.push_back (MenuElem (_("Bounce Range to Source List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1985 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1986 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1987 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1993 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1995 using namespace Menu_Helpers;
1999 Menu *play_menu = manage (new Menu);
2000 MenuList& play_items = play_menu->items();
2001 play_menu->set_name ("ArdourContextMenu");
2003 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2004 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2005 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2006 play_items.push_back (SeparatorElem());
2007 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2009 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2013 Menu *select_menu = manage (new Menu);
2014 MenuList& select_items = select_menu->items();
2015 select_menu->set_name ("ArdourContextMenu");
2017 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2018 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2019 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2020 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2021 select_items.push_back (SeparatorElem());
2022 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2023 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2024 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2025 select_items.push_back (SeparatorElem());
2026 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2027 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2028 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2029 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2030 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2031 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2032 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2034 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2038 Menu *cutnpaste_menu = manage (new Menu);
2039 MenuList& cutnpaste_items = cutnpaste_menu->items();
2040 cutnpaste_menu->set_name ("ArdourContextMenu");
2042 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2043 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2044 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2046 cutnpaste_items.push_back (SeparatorElem());
2048 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2049 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2051 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2053 /* Adding new material */
2055 edit_items.push_back (SeparatorElem());
2056 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_source_list_selection), 1.0f)));
2057 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2061 Menu *nudge_menu = manage (new Menu());
2062 MenuList& nudge_items = nudge_menu->items();
2063 nudge_menu->set_name ("ArdourContextMenu");
2065 edit_items.push_back (SeparatorElem());
2066 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2067 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2068 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2069 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2071 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2075 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2077 using namespace Menu_Helpers;
2081 Menu *play_menu = manage (new Menu);
2082 MenuList& play_items = play_menu->items();
2083 play_menu->set_name ("ArdourContextMenu");
2085 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2086 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2087 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2091 Menu *select_menu = manage (new Menu);
2092 MenuList& select_items = select_menu->items();
2093 select_menu->set_name ("ArdourContextMenu");
2095 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2096 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2097 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2098 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2099 select_items.push_back (SeparatorElem());
2100 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2101 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2102 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2103 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2105 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2108 #if 0 // unused, why?
2109 Menu *cutnpaste_menu = manage (new Menu);
2110 MenuList& cutnpaste_items = cutnpaste_menu->items();
2111 cutnpaste_menu->set_name ("ArdourContextMenu");
2113 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2114 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2115 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2118 Menu *nudge_menu = manage (new Menu());
2119 MenuList& nudge_items = nudge_menu->items();
2120 nudge_menu->set_name ("ArdourContextMenu");
2122 edit_items.push_back (SeparatorElem());
2123 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2124 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2125 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2126 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2128 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2132 Editor::grid_type() const
2138 Editor::grid_musical() const
2140 switch (_grid_type) {
2141 case GridTypeBeatDiv32:
2142 case GridTypeBeatDiv28:
2143 case GridTypeBeatDiv24:
2144 case GridTypeBeatDiv20:
2145 case GridTypeBeatDiv16:
2146 case GridTypeBeatDiv14:
2147 case GridTypeBeatDiv12:
2148 case GridTypeBeatDiv10:
2149 case GridTypeBeatDiv8:
2150 case GridTypeBeatDiv7:
2151 case GridTypeBeatDiv6:
2152 case GridTypeBeatDiv5:
2153 case GridTypeBeatDiv4:
2154 case GridTypeBeatDiv3:
2155 case GridTypeBeatDiv2:
2160 case GridTypeTimecode:
2161 case GridTypeMinSec:
2162 case GridTypeCDFrame:
2169 Editor::grid_nonmusical() const
2171 switch (_grid_type) {
2172 case GridTypeTimecode:
2173 case GridTypeMinSec:
2174 case GridTypeCDFrame:
2176 case GridTypeBeatDiv32:
2177 case GridTypeBeatDiv28:
2178 case GridTypeBeatDiv24:
2179 case GridTypeBeatDiv20:
2180 case GridTypeBeatDiv16:
2181 case GridTypeBeatDiv14:
2182 case GridTypeBeatDiv12:
2183 case GridTypeBeatDiv10:
2184 case GridTypeBeatDiv8:
2185 case GridTypeBeatDiv7:
2186 case GridTypeBeatDiv6:
2187 case GridTypeBeatDiv5:
2188 case GridTypeBeatDiv4:
2189 case GridTypeBeatDiv3:
2190 case GridTypeBeatDiv2:
2199 Editor::snap_mode() const
2205 Editor::show_rulers_for_grid ()
2207 /* show appropriate rulers for this grid setting. */
2208 if (grid_musical()) {
2209 ruler_tempo_action->set_active(true);
2210 ruler_meter_action->set_active(true);
2211 ruler_bbt_action->set_active(true);
2213 if (UIConfiguration::instance().get_rulers_follow_grid()) {
2214 ruler_timecode_action->set_active(false);
2215 ruler_minsec_action->set_active(false);
2216 ruler_samples_action->set_active(false);
2218 } else if (_grid_type == GridTypeTimecode) {
2219 ruler_timecode_action->set_active(true);
2221 if (UIConfiguration::instance().get_rulers_follow_grid()) {
2222 ruler_tempo_action->set_active(false);
2223 ruler_meter_action->set_active(false);
2224 ruler_bbt_action->set_active(false);
2225 ruler_minsec_action->set_active(false);
2226 ruler_samples_action->set_active(false);
2228 } else if (_grid_type == GridTypeMinSec) {
2229 ruler_minsec_action->set_active(true);
2231 if (UIConfiguration::instance().get_rulers_follow_grid()) {
2232 ruler_tempo_action->set_active(false);
2233 ruler_meter_action->set_active(false);
2234 ruler_bbt_action->set_active(false);
2235 ruler_timecode_action->set_active(false);
2236 ruler_samples_action->set_active(false);
2238 } else if (_grid_type == GridTypeCDFrame) {
2239 ruler_cd_marker_action->set_active(true);
2240 ruler_minsec_action->set_active(true);
2242 if (UIConfiguration::instance().get_rulers_follow_grid()) {
2243 ruler_tempo_action->set_active(false);
2244 ruler_meter_action->set_active(false);
2245 ruler_bbt_action->set_active(false);
2246 ruler_timecode_action->set_active(false);
2247 ruler_samples_action->set_active(false);
2253 Editor::set_grid_to (GridType gt)
2255 if (_grid_type == gt) { // already set
2259 unsigned int grid_ind = (unsigned int)gt;
2261 if (internal_editing() && UIConfiguration::instance().get_grid_follows_internal()) {
2262 internal_grid_type = gt;
2264 pre_internal_grid_type = gt;
2269 if (grid_ind > grid_type_strings.size() - 1) {
2271 _grid_type = (GridType)grid_ind;
2274 string str = grid_type_strings[grid_ind];
2276 if (str != grid_type_selector.get_text()) {
2277 grid_type_selector.set_text (str);
2280 if (UIConfiguration::instance().get_show_grids_ruler()) {
2281 show_rulers_for_grid ();
2286 if (grid_musical()) {
2287 compute_bbt_ruler_scale (_leftmost_sample, _leftmost_sample + current_page_samples());
2288 update_tempo_based_rulers ();
2291 mark_region_boundary_cache_dirty ();
2293 redisplay_grid (false);
2295 SnapChanged (); /* EMIT SIGNAL */
2299 Editor::set_snap_mode (SnapMode mode)
2301 if (internal_editing()) {
2302 internal_snap_mode = mode;
2304 pre_internal_snap_mode = mode;
2309 if (_snap_mode == SnapOff) {
2310 snap_mode_button.set_active_state (Gtkmm2ext::Off);
2312 snap_mode_button.set_active_state (Gtkmm2ext::ExplicitActive);
2319 Editor::set_edit_point_preference (EditPoint ep, bool force)
2321 if (Profile->get_mixbus()) {
2322 if (ep == EditAtSelectedMarker) {
2323 ep = EditAtPlayhead;
2327 bool changed = (_edit_point != ep);
2331 string str = edit_point_strings[(int)ep];
2332 if (str != edit_point_selector.get_text ()) {
2333 edit_point_selector.set_text (str);
2336 update_all_enter_cursors();
2338 if (!force && !changed) {
2342 const char* action=NULL;
2344 switch (_edit_point) {
2345 case EditAtPlayhead:
2346 action = "edit-at-playhead";
2348 case EditAtSelectedMarker:
2349 action = "edit-at-selected-marker";
2352 action = "edit-at-mouse";
2356 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action ("Editor", action);
2357 tact->set_active (true);
2360 bool in_track_canvas;
2362 if (!mouse_sample (foo, in_track_canvas)) {
2363 in_track_canvas = false;
2366 reset_canvas_action_sensitivity (in_track_canvas);
2367 sensitize_the_right_region_actions (false);
2373 Editor::set_state (const XMLNode& node, int version)
2376 PBD::Unwinder<bool> nsi (no_save_instant, true);
2379 Tabbable::set_state (node, version);
2382 if (_session && node.get_property ("playhead", ph_pos)) {
2384 playhead_cursor->set_position (ph_pos);
2386 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2387 playhead_cursor->set_position (0);
2390 playhead_cursor->set_position (0);
2393 node.get_property ("mixer-width", editor_mixer_strip_width);
2395 node.get_property ("zoom-focus", zoom_focus);
2396 zoom_focus_selection_done (zoom_focus);
2399 if (node.get_property ("zoom", z)) {
2400 /* older versions of ardour used floating point samples_per_pixel */
2401 reset_zoom (llrintf (z));
2403 reset_zoom (samples_per_pixel);
2407 if (node.get_property ("visible-track-count", cnt)) {
2408 set_visible_track_count (cnt);
2412 if (!node.get_property ("grid-type", grid_type)) {
2413 grid_type = _grid_type;
2415 set_grid_to (grid_type);
2418 if (node.get_property ("snap-mode", sm)) {
2419 snap_mode_selection_done(sm);
2420 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2421 * snap_mode_selection_done() will only mark an already active item as active
2422 * which does not trigger set_text().
2426 set_snap_mode (_snap_mode);
2429 node.get_property ("internal-grid-type", internal_grid_type);
2430 node.get_property ("internal-snap-mode", internal_snap_mode);
2431 node.get_property ("pre-internal-grid-type", pre_internal_grid_type);
2432 node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2435 if (node.get_property ("mouse-mode", mm_str)) {
2436 MouseMode m = str2mousemode(mm_str);
2437 set_mouse_mode (m, true);
2439 set_mouse_mode (MouseObject, true);
2443 if (node.get_property ("left-frame", lf_pos)) {
2447 reset_x_origin (lf_pos);
2451 if (node.get_property ("y-origin", y_origin)) {
2452 reset_y_origin (y_origin);
2456 node.get_property ("join-object-range", yn);
2458 RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2459 /* do it twice to force the change */
2460 tact->set_active (!yn);
2461 tact->set_active (yn);
2462 set_mouse_mode(mouse_mode, true);
2466 if (node.get_property ("edit-point", ep)) {
2467 set_edit_point_preference (ep, true);
2469 set_edit_point_preference (_edit_point);
2472 if (node.get_property ("follow-playhead", yn)) {
2473 set_follow_playhead (yn);
2476 if (node.get_property ("stationary-playhead", yn)) {
2477 set_stationary_playhead (yn);
2480 if (node.get_property ("show-editor-mixer", yn)) {
2482 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-mixer"));
2483 /* do it twice to force the change */
2484 tact->set_active (!yn);
2485 tact->set_active (yn);
2489 node.get_property ("show-editor-list", yn);
2491 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-list"));
2492 /* do it twice to force the change */
2493 tact->set_active (!yn);
2494 tact->set_active (yn);
2498 if (node.get_property (X_("editor-list-page"), el_page)) {
2499 _the_notebook.set_current_page (el_page);
2503 node.get_property (X_("show-marker-lines"), yn);
2505 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-marker-lines"));
2506 /* do it twice to force the change */
2507 tact->set_active (!yn);
2508 tact->set_active (yn);
2511 XMLNodeList children = node.children ();
2512 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2513 selection->set_state (**i, Stateful::current_state_version);
2514 _regions->set_state (**i);
2515 _locations->set_state (**i);
2518 if (node.get_property ("maximised", yn)) {
2519 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Common"), X_("ToggleMaximalEditor"));
2520 bool fs = tact->get_active();
2522 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2526 samplepos_t nudge_clock_value;
2527 if (node.get_property ("nudge-clock-value", nudge_clock_value)) {
2528 nudge_clock->set (nudge_clock_value);
2530 nudge_clock->set_mode (AudioClock::Timecode);
2531 nudge_clock->set (_session->sample_rate() * 5, true);
2536 * Not all properties may have been in XML, but
2537 * those that are linked to a private variable may need changing
2539 RefPtr<ToggleAction> tact;
2541 tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-follow-playhead"));
2542 yn = _follow_playhead;
2543 if (tact->get_active() != yn) {
2544 tact->set_active (yn);
2547 tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-stationary-playhead"));
2548 yn = _stationary_playhead;
2549 if (tact->get_active() != yn) {
2550 tact->set_active (yn);
2558 Editor::get_state ()
2560 XMLNode* node = new XMLNode (X_("Editor"));
2562 node->set_property ("id", id().to_s ());
2564 node->add_child_nocopy (Tabbable::get_state());
2566 node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ());
2567 node->set_property("notebook-shrunk", _notebook_shrunk);
2568 node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider());
2570 maybe_add_mixer_strip_width (*node);
2572 node->set_property ("zoom-focus", zoom_focus);
2574 node->set_property ("zoom", samples_per_pixel);
2575 node->set_property ("grid-type", _grid_type);
2576 node->set_property ("snap-mode", _snap_mode);
2577 node->set_property ("internal-grid-type", internal_grid_type);
2578 node->set_property ("internal-snap-mode", internal_snap_mode);
2579 node->set_property ("pre-internal-grid-type", pre_internal_grid_type);
2580 node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2581 node->set_property ("edit-point", _edit_point);
2582 node->set_property ("visible-track-count", _visible_track_count);
2584 node->set_property ("playhead", playhead_cursor->current_sample ());
2585 node->set_property ("left-frame", _leftmost_sample);
2586 node->set_property ("y-origin", vertical_adjustment.get_value ());
2588 node->set_property ("maximised", _maximised);
2589 node->set_property ("follow-playhead", _follow_playhead);
2590 node->set_property ("stationary-playhead", _stationary_playhead);
2591 node->set_property ("mouse-mode", mouse_mode);
2592 node->set_property ("join-object-range", smart_mode_action->get_active ());
2594 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-mixer"));
2595 node->set_property (X_("show-editor-mixer"), tact->get_active());
2597 tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-list"));
2598 node->set_property (X_("show-editor-list"), tact->get_active());
2600 node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
2602 if (button_bindings) {
2603 XMLNode* bb = new XMLNode (X_("Buttons"));
2604 button_bindings->save (*bb);
2605 node->add_child_nocopy (*bb);
2608 node->set_property (X_("show-marker-lines"), _show_marker_lines);
2610 node->add_child_nocopy (selection->get_state ());
2611 node->add_child_nocopy (_regions->get_state ());
2613 node->set_property ("nudge-clock-value", nudge_clock->current_duration());
2615 node->add_child_nocopy (_locations->get_state ());
2620 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2621 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2623 * @return pair: TimeAxisView that y is over, layer index.
2625 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2626 * in stacked or expanded region display mode, otherwise 0.
2628 std::pair<TimeAxisView *, double>
2629 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2631 if (!trackview_relative_offset) {
2632 y -= _trackview_group->canvas_origin().y;
2636 return std::make_pair ((TimeAxisView *) 0, 0);
2639 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2641 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2648 return std::make_pair ((TimeAxisView *) 0, 0);
2652 Editor::set_snapped_cursor_position (samplepos_t pos)
2654 if (_edit_point == EditAtMouse) {
2655 snapped_cursor->set_position(pos);
2660 /** Snap a position to the grid, if appropriate, taking into account current
2661 * grid settings and also the state of any snap modifier keys that may be pressed.
2662 * @param start Position to snap.
2663 * @param event Event to get current key modifier information from, or 0.
2666 Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, RoundMode direction, SnapPref pref)
2668 if (!_session || !event) {
2672 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2673 if (_snap_mode == SnapOff) {
2674 snap_to_internal (start, direction, pref);
2676 start.set (start.sample, 0);
2679 if (_snap_mode != SnapOff) {
2680 snap_to_internal (start, direction, pref);
2681 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2682 /* SnapOff, but we pressed the snap_delta modifier */
2683 snap_to_internal (start, direction, pref);
2685 start.set (start.sample, 0);
2691 Editor::snap_to (MusicSample& start, RoundMode direction, SnapPref pref, bool ensure_snap)
2693 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2694 start.set (start.sample, 0);
2698 snap_to_internal (start, direction, pref, ensure_snap);
2702 check_best_snap (samplepos_t presnap, samplepos_t &test, samplepos_t &dist, samplepos_t &best)
2704 samplepos_t diff = abs (test - presnap);
2710 test = max_samplepos; // reset this so it doesn't get accidentally reused
2714 Editor::snap_to_timecode (MusicSample presnap, RoundMode direction, SnapPref gpref)
2716 samplepos_t start = presnap.sample;
2717 const samplepos_t one_timecode_second = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2718 samplepos_t one_timecode_minute = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2720 TimecodeRulerScale scale = (gpref != SnapToGrid_Unscaled) ? timecode_ruler_scale : timecode_show_samples;
2723 case timecode_show_bits:
2724 case timecode_show_samples:
2725 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2726 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2727 /* start is already on a whole timecode frame, do nothing */
2728 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2729 start = (samplepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2731 start = (samplepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2735 case timecode_show_seconds:
2736 if (_session->config.get_timecode_offset_negative()) {
2737 start += _session->config.get_timecode_offset ();
2739 start -= _session->config.get_timecode_offset ();
2741 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2742 (start % one_timecode_second == 0)) {
2743 /* start is already on a whole second, do nothing */
2744 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2745 start = (samplepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2747 start = (samplepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2750 if (_session->config.get_timecode_offset_negative()) {
2751 start -= _session->config.get_timecode_offset ();
2753 start += _session->config.get_timecode_offset ();
2757 case timecode_show_minutes:
2758 case timecode_show_hours:
2759 case timecode_show_many_hours:
2760 if (_session->config.get_timecode_offset_negative()) {
2761 start += _session->config.get_timecode_offset ();
2763 start -= _session->config.get_timecode_offset ();
2765 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2766 (start % one_timecode_minute == 0)) {
2767 /* start is already on a whole minute, do nothing */
2768 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2769 start = (samplepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2771 start = (samplepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2773 if (_session->config.get_timecode_offset_negative()) {
2774 start -= _session->config.get_timecode_offset ();
2776 start += _session->config.get_timecode_offset ();
2780 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2783 MusicSample ret(start,0);
2788 Editor::snap_to_minsec (MusicSample presnap, RoundMode direction, SnapPref gpref)
2790 MusicSample ret(presnap);
2792 const samplepos_t one_second = _session->sample_rate();
2793 const samplepos_t one_minute = one_second * 60;
2794 const samplepos_t one_hour = one_minute * 60;
2796 MinsecRulerScale scale = (gpref != SnapToGrid_Unscaled) ? minsec_ruler_scale : minsec_show_seconds;
2799 case minsec_show_msecs:
2800 case minsec_show_seconds: {
2801 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2802 presnap.sample % one_second == 0) {
2803 /* start is already on a whole second, do nothing */
2804 } else if (((direction == 0) && (presnap.sample % one_second > one_second / 2)) || (direction > 0)) {
2805 ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_second) * one_second;
2807 ret.sample = (samplepos_t) floor ((double) presnap.sample / one_second) * one_second;
2811 case minsec_show_minutes: {
2812 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2813 presnap.sample % one_minute == 0) {
2814 /* start is already on a whole minute, do nothing */
2815 } else if (((direction == 0) && (presnap.sample % one_minute > one_minute / 2)) || (direction > 0)) {
2816 ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_minute) * one_minute;
2818 ret.sample = (samplepos_t) floor ((double) presnap.sample / one_minute) * one_minute;
2823 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2824 presnap.sample % one_hour == 0) {
2825 /* start is already on a whole hour, do nothing */
2826 } else if (((direction == 0) && (presnap.sample % one_hour > one_hour / 2)) || (direction > 0)) {
2827 ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_hour) * one_hour;
2829 ret.sample = (samplepos_t) floor ((double) presnap.sample / one_hour) * one_hour;
2838 Editor::snap_to_cd_frames (MusicSample presnap, RoundMode direction, SnapPref gpref)
2840 if ((gpref != SnapToGrid_Unscaled) && (minsec_ruler_scale != minsec_show_msecs)) {
2841 return snap_to_minsec (presnap, direction, gpref);
2844 const samplepos_t one_second = _session->sample_rate();
2846 MusicSample ret(presnap);
2848 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2849 presnap.sample % (one_second/75) == 0) {
2850 /* start is already on a whole CD sample, do nothing */
2851 } else if (((direction == 0) && (presnap.sample % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2852 ret.sample = (samplepos_t) ceil ((double) presnap.sample / (one_second / 75)) * (one_second / 75);
2854 ret.sample = (samplepos_t) floor ((double) presnap.sample / (one_second / 75)) * (one_second / 75);
2861 Editor::snap_to_bbt (MusicSample presnap, RoundMode direction, SnapPref gpref)
2863 MusicSample ret(presnap);
2865 if (gpref != SnapToGrid_Unscaled) { // use the visual grid lines which are limited by the zoom scale that the user selected
2868 switch (_grid_type) {
2869 case GridTypeBeatDiv3:
2870 case GridTypeBeatDiv6:
2871 case GridTypeBeatDiv12:
2872 case GridTypeBeatDiv24:
2875 case GridTypeBeatDiv5:
2876 case GridTypeBeatDiv10:
2877 case GridTypeBeatDiv20:
2880 case GridTypeBeatDiv7:
2881 case GridTypeBeatDiv14:
2882 case GridTypeBeatDiv28:
2889 BBTRulerScale scale = bbt_ruler_scale;
2896 ret = _session->tempo_map().round_to_bar (presnap.sample, direction);
2898 case bbt_show_quarters:
2899 ret = _session->tempo_map().round_to_beat (presnap.sample, direction);
2901 case bbt_show_eighths:
2902 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 1 * divisor, direction);
2904 case bbt_show_sixteenths:
2905 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 2 * divisor, direction);
2907 case bbt_show_thirtyseconds:
2908 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 4 * divisor, direction);
2912 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, get_grid_beat_divisions(_grid_type), direction);
2919 Editor::snap_to_grid (MusicSample presnap, RoundMode direction, SnapPref gpref)
2921 MusicSample ret(presnap);
2923 if (grid_musical()) {
2924 ret = snap_to_bbt (presnap, direction, gpref);
2927 switch (_grid_type) {
2928 case GridTypeTimecode:
2929 ret = snap_to_timecode(presnap, direction, gpref);
2931 case GridTypeMinSec:
2932 ret = snap_to_minsec(presnap, direction, gpref);
2934 case GridTypeCDFrame:
2935 ret = snap_to_cd_frames(presnap, direction, gpref);
2945 Editor::snap_to_marker (samplepos_t presnap, RoundMode direction)
2951 _session->locations()->marks_either_side (presnap, before, after);
2953 if (before == max_samplepos && after == max_samplepos) {
2954 /* No marks to snap to, so just don't snap */
2956 } else if (before == max_samplepos) {
2958 } else if (after == max_samplepos) {
2961 if ((direction == RoundUpMaybe || direction == RoundUpAlways)) {
2963 } else if ((direction == RoundDownMaybe || direction == RoundDownAlways)) {
2965 } else if (direction == 0) {
2966 if ((presnap - before) < (after - presnap)) {
2978 Editor::snap_to_internal (MusicSample& start, RoundMode direction, SnapPref pref, bool ensure_snap)
2980 const samplepos_t presnap = start.sample;
2982 samplepos_t test = max_samplepos; // for each snap, we'll use this value
2983 samplepos_t dist = max_samplepos; // this records the distance of the best snap result we've found so far
2984 samplepos_t best = max_samplepos; // this records the best snap-result we've found so far
2986 /* check snap-to-marker */
2987 if ((pref == SnapToAny_Visual) && UIConfiguration::instance().get_snap_to_marks()) {
2988 test = snap_to_marker (presnap, direction);
2989 check_best_snap(presnap, test, dist, best);
2992 /* check snap-to-region-{start/end/sync} */
2994 (pref == SnapToAny_Visual) &&
2995 (UIConfiguration::instance().get_snap_to_region_start() || UIConfiguration::instance().get_snap_to_region_end() || UIConfiguration::instance().get_snap_to_region_sync())
2997 if (!region_boundary_cache.empty()) {
2999 vector<samplepos_t>::iterator prev = region_boundary_cache.begin();
3000 vector<samplepos_t>::iterator next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
3001 if (next != region_boundary_cache.begin ()) {
3006 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
3008 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
3010 else if (direction == 0) {
3011 if ((presnap - *prev) < (*next - presnap)) {
3020 check_best_snap(presnap, test, dist, best);
3024 if (UIConfiguration::instance().get_snap_to_grid() && (_grid_type != GridTypeNone)) {
3025 MusicSample pre(presnap, 0);
3026 MusicSample post = snap_to_grid (pre, direction, pref);
3027 check_best_snap(presnap, post.sample, dist, best);
3030 /* now check "magnetic" state: is the grid within reasonable on-screen distance to trigger a snap?
3031 * this also helps to avoid snapping to somewhere the user can't see. (i.e.: I clicked on a region and it disappeared!!)
3032 * ToDo: Perhaps this should only occur if EditPointMouse?
3034 int snap_threshold_s = pixel_to_sample(UIConfiguration::instance().get_snap_threshold());
3036 start.set (best, 0);
3038 } else if (presnap > best) {
3039 if (presnap > (best+ snap_threshold_s)) {
3042 } else if (presnap < best) {
3043 if (presnap < (best - snap_threshold_s)) {
3048 start.set (best, 0);
3053 Editor::setup_toolbar ()
3055 HBox* mode_box = manage(new HBox);
3056 mode_box->set_border_width (2);
3057 mode_box->set_spacing(2);
3059 HBox* mouse_mode_box = manage (new HBox);
3060 HBox* mouse_mode_hbox = manage (new HBox);
3061 VBox* mouse_mode_vbox = manage (new VBox);
3062 Alignment* mouse_mode_align = manage (new Alignment);
3064 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3065 mouse_mode_size_group->add_widget (smart_mode_button);
3066 mouse_mode_size_group->add_widget (mouse_move_button);
3067 if (!Profile->get_mixbus()) {
3068 mouse_mode_size_group->add_widget (mouse_cut_button);
3070 mouse_mode_size_group->add_widget (mouse_select_button);
3071 mouse_mode_size_group->add_widget (mouse_timefx_button);
3072 if (!Profile->get_mixbus()) {
3073 mouse_mode_size_group->add_widget (mouse_audition_button);
3075 mouse_mode_size_group->add_widget (mouse_draw_button);
3076 mouse_mode_size_group->add_widget (mouse_content_button);
3078 if (!Profile->get_mixbus()) {
3079 mouse_mode_size_group->add_widget (zoom_in_button);
3080 mouse_mode_size_group->add_widget (zoom_out_button);
3081 mouse_mode_size_group->add_widget (zoom_out_full_button);
3082 mouse_mode_size_group->add_widget (zoom_focus_selector);
3083 mouse_mode_size_group->add_widget (tav_shrink_button);
3084 mouse_mode_size_group->add_widget (tav_expand_button);
3086 mouse_mode_size_group->add_widget (zoom_preset_selector);
3087 mouse_mode_size_group->add_widget (visible_tracks_selector);
3090 mouse_mode_size_group->add_widget (grid_type_selector);
3091 mouse_mode_size_group->add_widget (snap_mode_button);
3093 mouse_mode_size_group->add_widget (edit_point_selector);
3094 mouse_mode_size_group->add_widget (edit_mode_selector);
3096 mouse_mode_size_group->add_widget (*nudge_clock);
3097 mouse_mode_size_group->add_widget (nudge_forward_button);
3098 mouse_mode_size_group->add_widget (nudge_backward_button);
3100 mouse_mode_hbox->set_spacing (2);
3102 if (!ARDOUR::Profile->get_trx()) {
3103 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3106 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3107 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3109 if (!ARDOUR::Profile->get_mixbus()) {
3110 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3111 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3114 if (!ARDOUR::Profile->get_trx()) {
3115 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3116 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3117 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3120 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3122 mouse_mode_align->add (*mouse_mode_vbox);
3123 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3125 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3127 edit_mode_selector.set_name ("mouse mode button");
3129 if (!ARDOUR::Profile->get_trx()) {
3130 mode_box->pack_start (edit_mode_selector, false, false);
3131 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3132 mode_box->pack_start (edit_point_selector, false, false);
3133 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3136 mode_box->pack_start (*mouse_mode_box, false, false);
3140 _zoom_box.set_spacing (2);
3141 _zoom_box.set_border_width (2);
3145 zoom_preset_selector.set_name ("zoom button");
3146 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3148 zoom_in_button.set_name ("zoom button");
3149 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3150 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3151 zoom_in_button.set_related_action (act);
3153 zoom_out_button.set_name ("zoom button");
3154 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3155 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3156 zoom_out_button.set_related_action (act);
3158 zoom_out_full_button.set_name ("zoom button");
3159 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3160 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3161 zoom_out_full_button.set_related_action (act);
3163 zoom_focus_selector.set_name ("zoom button");
3165 if (ARDOUR::Profile->get_mixbus()) {
3166 _zoom_box.pack_start (zoom_preset_selector, false, false);
3167 } else if (ARDOUR::Profile->get_trx()) {
3168 mode_box->pack_start (zoom_out_button, false, false);
3169 mode_box->pack_start (zoom_in_button, false, false);
3171 _zoom_box.pack_start (zoom_out_button, false, false);
3172 _zoom_box.pack_start (zoom_in_button, false, false);
3173 _zoom_box.pack_start (zoom_out_full_button, false, false);
3174 _zoom_box.pack_start (zoom_focus_selector, false, false);
3177 /* Track zoom buttons */
3178 _track_box.set_spacing (2);
3179 _track_box.set_border_width (2);
3181 visible_tracks_selector.set_name ("zoom button");
3182 if (Profile->get_mixbus()) {
3183 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3185 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3188 tav_expand_button.set_name ("zoom button");
3189 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3190 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3191 tav_expand_button.set_related_action (act);
3193 tav_shrink_button.set_name ("zoom button");
3194 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3195 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3196 tav_shrink_button.set_related_action (act);
3198 if (ARDOUR::Profile->get_mixbus()) {
3199 _track_box.pack_start (visible_tracks_selector);
3200 } else if (ARDOUR::Profile->get_trx()) {
3201 _track_box.pack_start (tav_shrink_button);
3202 _track_box.pack_start (tav_expand_button);
3204 _track_box.pack_start (visible_tracks_selector);
3205 _track_box.pack_start (tav_shrink_button);
3206 _track_box.pack_start (tav_expand_button);
3209 snap_box.set_spacing (2);
3210 snap_box.set_border_width (2);
3212 grid_type_selector.set_name ("mouse mode button");
3214 snap_mode_button.set_name ("mouse mode button");
3216 edit_point_selector.set_name ("mouse mode button");
3218 snap_box.pack_start (snap_mode_button, false, false);
3219 snap_box.pack_start (grid_type_selector, false, false);
3223 HBox *nudge_box = manage (new HBox);
3224 nudge_box->set_spacing (2);
3225 nudge_box->set_border_width (2);
3227 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3228 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3230 nudge_box->pack_start (nudge_backward_button, false, false);
3231 nudge_box->pack_start (nudge_forward_button, false, false);
3232 nudge_box->pack_start (*nudge_clock, false, false);
3235 /* Pack everything in... */
3237 toolbar_hbox.set_spacing (2);
3238 toolbar_hbox.set_border_width (2);
3240 ArdourWidgets::ArdourDropShadow *tool_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
3241 tool_shadow->set_size_request (4, -1);
3242 tool_shadow->show();
3244 ebox_hpacker.pack_start (*tool_shadow, false, false);
3245 ebox_hpacker.pack_start(ebox_vpacker, true, true);
3247 Gtk::EventBox* spacer = manage (new Gtk::EventBox); // extra space under the mouse toolbar, for aesthetics
3248 spacer->set_name("EditorWindow");
3249 spacer->set_size_request(-1,4);
3252 ebox_vpacker.pack_start(toolbar_hbox, false, false);
3253 ebox_vpacker.pack_start(*spacer, false, false);
3254 ebox_vpacker.show();
3256 toolbar_hbox.pack_start (*mode_box, false, false);
3258 if (!ARDOUR::Profile->get_trx()) {
3260 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3262 toolbar_hbox.pack_start (snap_box, false, false);
3264 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3266 toolbar_hbox.pack_start (*nudge_box, false, false);
3268 toolbar_hbox.pack_end (_zoom_box, false, false, 2);
3270 toolbar_hbox.pack_end (*(manage (new ArdourVSpacer ())), false, false, 3);
3272 toolbar_hbox.pack_end (_track_box, false, false);
3276 toolbar_hbox.show_all ();
3280 Editor::build_edit_point_menu ()
3282 using namespace Menu_Helpers;
3284 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3285 if(!Profile->get_mixbus())
3286 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3287 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3289 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3293 Editor::build_edit_mode_menu ()
3295 using namespace Menu_Helpers;
3297 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3298 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3299 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3300 /* Note: Splice was removed */
3302 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3306 Editor::build_grid_type_menu ()
3308 using namespace Menu_Helpers;
3310 /* main grid: bars, quarter-notes, etc */
3311 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeNone], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeNone)));
3312 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBar], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBar)));
3313 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeat], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeat)));
3314 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv2)));
3315 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv4)));
3316 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv8)));
3317 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv16)));
3318 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv32)));
3321 grid_type_selector.AddMenuElem(SeparatorElem());
3322 Gtk::Menu *_triplet_menu = manage (new Menu);
3323 MenuList& triplet_items (_triplet_menu->items());
3325 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv3)));
3326 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv6)));
3327 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv12)));
3328 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv24)));
3330 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Triplets"), *_triplet_menu));
3332 /* quintuplet grid */
3333 Gtk::Menu *_quintuplet_menu = manage (new Menu);
3334 MenuList& quintuplet_items (_quintuplet_menu->items());
3336 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv5)));
3337 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv10)));
3338 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv20)));
3340 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Quintuplets"), *_quintuplet_menu));
3342 /* septuplet grid */
3343 Gtk::Menu *_septuplet_menu = manage (new Menu);
3344 MenuList& septuplet_items (_septuplet_menu->items());
3346 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv7)));
3347 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv14)));
3348 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv28)));
3350 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Septuplets"), *_septuplet_menu));
3352 grid_type_selector.AddMenuElem(SeparatorElem());
3353 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeTimecode], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeTimecode)));
3354 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeMinSec], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeMinSec)));
3355 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeCDFrame)));
3359 Editor::setup_tooltips ()
3361 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3362 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3363 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3364 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3365 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3366 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3367 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3368 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3369 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3370 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3371 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3372 set_tooltip (zoom_in_button, _("Zoom In"));
3373 set_tooltip (zoom_out_button, _("Zoom Out"));
3374 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3375 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3376 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3377 set_tooltip (tav_expand_button, _("Expand Tracks"));
3378 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3379 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3380 set_tooltip (grid_type_selector, _("Grid Mode"));
3381 set_tooltip (snap_mode_button, _("Snap Mode\n\nRight-click to visit Snap preferences."));
3382 set_tooltip (edit_point_selector, _("Edit Point"));
3383 set_tooltip (edit_mode_selector, _("Edit Mode"));
3384 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3388 Editor::convert_drop_to_paths (
3389 vector<string>& paths,
3390 const RefPtr<Gdk::DragContext>& /*context*/,
3393 const SelectionData& data,
3397 if (_session == 0) {
3401 vector<string> uris = data.get_uris();
3405 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3406 are actually URI lists. So do it by hand.
3409 if (data.get_target() != "text/plain") {
3413 /* Parse the "uri-list" format that Nautilus provides,
3414 where each pathname is delimited by \r\n.
3416 THERE MAY BE NO NULL TERMINATING CHAR!!!
3419 string txt = data.get_text();
3423 p = (char *) malloc (txt.length() + 1);
3424 txt.copy (p, txt.length(), 0);
3425 p[txt.length()] = '\0';
3431 while (g_ascii_isspace (*p))
3435 while (*q && (*q != '\n') && (*q != '\r')) {
3442 while (q > p && g_ascii_isspace (*q))
3447 uris.push_back (string (p, q - p + 1));
3451 p = strchr (p, '\n');
3463 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3464 if ((*i).substr (0,7) == "file://") {
3465 paths.push_back (Glib::filename_from_uri (*i));
3473 Editor::new_tempo_section ()
3478 Editor::map_transport_state ()
3480 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3482 if (_session && _session->transport_stopped()) {
3483 have_pending_keyboard_selection = false;
3486 update_loop_range_view ();
3490 Editor::transport_looped ()
3492 /* reset Playhead position interpolation.
3493 * see Editor::super_rapid_screen_update
3495 _last_update_time = 0;
3501 Editor::begin_selection_op_history ()
3503 selection_op_cmd_depth = 0;
3504 selection_op_history_it = 0;
3506 while(!selection_op_history.empty()) {
3507 delete selection_op_history.front();
3508 selection_op_history.pop_front();
3511 selection_undo_action->set_sensitive (false);
3512 selection_redo_action->set_sensitive (false);
3513 selection_op_history.push_front (&_selection_memento->get_state ());
3517 Editor::begin_reversible_selection_op (string name)
3520 //cerr << name << endl;
3521 /* begin/commit pairs can be nested */
3522 selection_op_cmd_depth++;
3527 Editor::commit_reversible_selection_op ()
3530 if (selection_op_cmd_depth == 1) {
3532 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3533 /* The user has undone some selection ops and then made a new one,
3534 * making anything earlier in the list invalid.
3537 list<XMLNode *>::iterator it = selection_op_history.begin();
3538 list<XMLNode *>::iterator e_it = it;
3539 advance (e_it, selection_op_history_it);
3541 for (; it != e_it; ++it) {
3544 selection_op_history.erase (selection_op_history.begin(), e_it);
3547 selection_op_history.push_front (&_selection_memento->get_state ());
3548 selection_op_history_it = 0;
3550 selection_undo_action->set_sensitive (true);
3551 selection_redo_action->set_sensitive (false);
3554 if (selection_op_cmd_depth > 0) {
3555 selection_op_cmd_depth--;
3561 Editor::undo_selection_op ()
3564 selection_op_history_it++;
3566 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3567 if (n == selection_op_history_it) {
3568 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3569 selection_redo_action->set_sensitive (true);
3573 /* is there an earlier entry? */
3574 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3575 selection_undo_action->set_sensitive (false);
3581 Editor::redo_selection_op ()
3584 if (selection_op_history_it > 0) {
3585 selection_op_history_it--;
3588 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3589 if (n == selection_op_history_it) {
3590 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3591 selection_undo_action->set_sensitive (true);
3596 if (selection_op_history_it == 0) {
3597 selection_redo_action->set_sensitive (false);
3603 Editor::begin_reversible_command (string name)
3606 before.push_back (&_selection_memento->get_state ());
3607 _session->begin_reversible_command (name);
3612 Editor::begin_reversible_command (GQuark q)
3615 before.push_back (&_selection_memento->get_state ());
3616 _session->begin_reversible_command (q);
3621 Editor::abort_reversible_command ()
3624 while(!before.empty()) {
3625 delete before.front();
3628 _session->abort_reversible_command ();
3633 Editor::commit_reversible_command ()
3636 if (before.size() == 1) {
3637 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3638 redo_action->set_sensitive(false);
3639 undo_action->set_sensitive(true);
3640 begin_selection_op_history ();
3643 if (before.empty()) {
3644 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3649 _session->commit_reversible_command ();
3654 Editor::history_changed ()
3658 if (undo_action && _session) {
3659 if (_session->undo_depth() == 0) {
3660 label = S_("Command|Undo");
3662 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3664 undo_action->property_label() = label;
3667 if (redo_action && _session) {
3668 if (_session->redo_depth() == 0) {
3670 redo_action->set_sensitive (false);
3672 label = string_compose(_("Redo (%1)"), _session->next_redo());
3673 redo_action->set_sensitive (true);
3675 redo_action->property_label() = label;
3680 Editor::duplicate_range (bool with_dialog)
3684 RegionSelection rs = get_regions_from_selection_and_entered ();
3686 if (selection->time.length() == 0 && rs.empty()) {
3692 ArdourDialog win (_("Duplicate"));
3693 Label label (_("Number of duplications:"));
3694 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3695 SpinButton spinner (adjustment, 0.0, 1);
3698 win.get_vbox()->set_spacing (12);
3699 win.get_vbox()->pack_start (hbox);
3700 hbox.set_border_width (6);
3701 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3703 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3704 place, visually. so do this by hand.
3707 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3708 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3709 spinner.grab_focus();
3715 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3716 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3717 win.set_default_response (RESPONSE_ACCEPT);
3719 spinner.grab_focus ();
3721 switch (win.run ()) {
3722 case RESPONSE_ACCEPT:
3728 times = adjustment.get_value();
3731 if ((current_mouse_mode() == MouseRange)) {
3732 if (selection->time.length()) {
3733 duplicate_selection (times);
3735 } else if (get_smart_mode()) {
3736 if (selection->time.length()) {
3737 duplicate_selection (times);
3739 duplicate_some_regions (rs, times);
3741 duplicate_some_regions (rs, times);
3746 Editor::set_edit_mode (EditMode m)
3748 Config->set_edit_mode (m);
3752 Editor::cycle_edit_mode ()
3754 switch (Config->get_edit_mode()) {
3756 Config->set_edit_mode (Ripple);
3760 Config->set_edit_mode (Lock);
3763 Config->set_edit_mode (Slide);
3769 Editor::edit_mode_selection_done (EditMode m)
3771 Config->set_edit_mode (m);
3775 Editor::grid_type_selection_done (GridType gridtype)
3777 RefPtr<RadioAction> ract = grid_type_action (gridtype);
3779 ract->set_active ();
3784 Editor::snap_mode_selection_done (SnapMode mode)
3786 RefPtr<RadioAction> ract = snap_mode_action (mode);
3789 ract->set_active (true);
3794 Editor::cycle_edit_point (bool with_marker)
3796 if(Profile->get_mixbus())
3797 with_marker = false;
3799 switch (_edit_point) {
3801 set_edit_point_preference (EditAtPlayhead);
3803 case EditAtPlayhead:
3805 set_edit_point_preference (EditAtSelectedMarker);
3807 set_edit_point_preference (EditAtMouse);
3810 case EditAtSelectedMarker:
3811 set_edit_point_preference (EditAtMouse);
3817 Editor::edit_point_selection_done (EditPoint ep)
3819 set_edit_point_preference (ep);
3823 Editor::build_zoom_focus_menu ()
3825 using namespace Menu_Helpers;
3827 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3828 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3829 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3830 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3831 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3832 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3834 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3838 Editor::zoom_focus_selection_done (ZoomFocus f)
3840 RefPtr<RadioAction> ract = zoom_focus_action (f);
3842 ract->set_active ();
3847 Editor::build_track_count_menu ()
3849 using namespace Menu_Helpers;
3851 if (!Profile->get_mixbus()) {
3852 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3853 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3854 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3855 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3856 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3857 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3858 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3859 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3860 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3861 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3862 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3863 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3864 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3866 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3867 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3868 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3869 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3870 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3871 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3872 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3873 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3874 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3875 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3877 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3878 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3879 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3880 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3881 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3882 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3883 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3884 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3885 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3886 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3887 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Extents"), sigc::mem_fun(*this, &Editor::temporal_zoom_extents)));
3888 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3893 Editor::set_zoom_preset (int64_t ms)
3896 temporal_zoom_session();
3900 ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3901 temporal_zoom ((sample_rate * ms / 1000) / _visible_canvas_width);
3905 Editor::set_visible_track_count (int32_t n)
3907 _visible_track_count = n;
3909 /* if the canvas hasn't really been allocated any size yet, just
3910 record the desired number of visible tracks and return. when canvas
3911 allocation happens, we will get called again and then we can do the
3915 if (_visible_canvas_height <= 1) {
3921 DisplaySuspender ds;
3923 if (_visible_track_count > 0) {
3924 h = trackviews_height() / _visible_track_count;
3925 std::ostringstream s;
3926 s << _visible_track_count;
3928 } else if (_visible_track_count == 0) {
3930 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
3931 if ((*i)->marked_for_display()) {
3933 TimeAxisView::Children cl ((*i)->get_child_list ());
3934 for (TimeAxisView::Children::const_iterator j = cl.begin(); j != cl.end(); ++j) {
3935 if ((*j)->marked_for_display()) {
3942 visible_tracks_selector.set_text (X_("*"));
3945 h = trackviews_height() / n;
3948 /* negative value means that the visible track count has
3949 been overridden by explicit track height changes.
3951 visible_tracks_selector.set_text (X_("*"));
3955 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3956 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3959 if (str != visible_tracks_selector.get_text()) {
3960 visible_tracks_selector.set_text (str);
3965 Editor::override_visible_track_count ()
3967 _visible_track_count = -1;
3968 visible_tracks_selector.set_text (_("*"));
3972 Editor::edit_controls_button_release (GdkEventButton* ev)
3974 if (Keyboard::is_context_menu_event (ev)) {
3975 ARDOUR_UI::instance()->add_route ();
3976 } else if (ev->button == 1) {
3977 selection->clear_tracks ();
3984 Editor::mouse_select_button_release (GdkEventButton* ev)
3986 /* this handles just right-clicks */
3988 if (ev->button != 3) {
3996 Editor::set_zoom_focus (ZoomFocus f)
3998 string str = zoom_focus_strings[(int)f];
4000 if (str != zoom_focus_selector.get_text()) {
4001 zoom_focus_selector.set_text (str);
4004 if (zoom_focus != f) {
4011 Editor::cycle_zoom_focus ()
4013 switch (zoom_focus) {
4015 set_zoom_focus (ZoomFocusRight);
4017 case ZoomFocusRight:
4018 set_zoom_focus (ZoomFocusCenter);
4020 case ZoomFocusCenter:
4021 set_zoom_focus (ZoomFocusPlayhead);
4023 case ZoomFocusPlayhead:
4024 set_zoom_focus (ZoomFocusMouse);
4026 case ZoomFocusMouse:
4027 set_zoom_focus (ZoomFocusEdit);
4030 set_zoom_focus (ZoomFocusLeft);
4036 Editor::update_grid ()
4038 if (grid_musical()) {
4039 std::vector<TempoMap::BBTPoint> grid;
4040 if (bbt_ruler_scale != bbt_show_many) {
4041 compute_current_bbt_points (grid, _leftmost_sample, _leftmost_sample + current_page_samples());
4043 maybe_draw_grid_lines ();
4044 } else if (grid_nonmusical()) {
4045 maybe_draw_grid_lines ();
4052 Editor::toggle_follow_playhead ()
4054 RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-follow-playhead"));
4055 set_follow_playhead (tact->get_active());
4058 /** @param yn true to follow playhead, otherwise false.
4059 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4062 Editor::set_follow_playhead (bool yn, bool catch_up)
4064 if (_follow_playhead != yn) {
4065 if ((_follow_playhead = yn) == true && catch_up) {
4067 reset_x_origin_to_follow_playhead ();
4074 Editor::toggle_stationary_playhead ()
4076 RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-stationary-playhead"));
4077 set_stationary_playhead (tact->get_active());
4081 Editor::set_stationary_playhead (bool yn)
4083 if (_stationary_playhead != yn) {
4084 if ((_stationary_playhead = yn) == true) {
4085 /* catch up -- FIXME need a 3.0 equivalent of this 2.X call */
4086 // update_current_screen ();
4093 Editor::playlist_selector () const
4095 return *_playlist_selector;
4099 Editor::get_paste_offset (samplepos_t pos, unsigned paste_count, samplecnt_t duration)
4101 if (paste_count == 0) {
4102 /* don't bother calculating an offset that will be zero anyway */
4106 /* calculate basic unsnapped multi-paste offset */
4107 samplecnt_t offset = paste_count * duration;
4109 /* snap offset so pos + offset is aligned to the grid */
4110 MusicSample offset_pos (pos + offset, 0);
4111 snap_to(offset_pos, RoundUpMaybe);
4112 offset = offset_pos.sample - pos;
4118 Editor::get_grid_beat_divisions(samplepos_t position)
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;
4139 case GridTypeNone: return 0;
4140 case GridTypeTimecode: return 0;
4141 case GridTypeMinSec: return 0;
4142 case GridTypeCDFrame: return 0;
4148 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4149 if the grid is non-musical, returns 0.
4150 if the grid is snapped to bars, returns -1.
4151 @param event_state the current keyboard modifier mask.
4154 Editor::get_grid_music_divisions (uint32_t event_state)
4156 if (snap_mode() == SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4160 if (snap_mode() != SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4164 switch (_grid_type) {
4165 case GridTypeBeatDiv32: return 32;
4166 case GridTypeBeatDiv28: return 28;
4167 case GridTypeBeatDiv24: return 24;
4168 case GridTypeBeatDiv20: return 20;
4169 case GridTypeBeatDiv16: return 16;
4170 case GridTypeBeatDiv14: return 14;
4171 case GridTypeBeatDiv12: return 12;
4172 case GridTypeBeatDiv10: return 10;
4173 case GridTypeBeatDiv8: return 8;
4174 case GridTypeBeatDiv7: return 7;
4175 case GridTypeBeatDiv6: return 6;
4176 case GridTypeBeatDiv5: return 5;
4177 case GridTypeBeatDiv4: return 4;
4178 case GridTypeBeatDiv3: return 3;
4179 case GridTypeBeatDiv2: return 2;
4180 case GridTypeBeat: return 1;
4181 case GridTypeBar : return -1;
4183 case GridTypeNone: return 0;
4184 case GridTypeTimecode: return 0;
4185 case GridTypeMinSec: return 0;
4186 case GridTypeCDFrame: return 0;
4192 Editor::get_grid_type_as_beats (bool& success, samplepos_t position)
4196 const unsigned divisions = get_grid_beat_divisions(position);
4198 return Temporal::Beats(1.0 / (double)get_grid_beat_divisions(position));
4201 switch (_grid_type) {
4203 return Temporal::Beats(4.0 / _session->tempo_map().meter_at_sample (position).note_divisor());
4206 const Meter& m = _session->tempo_map().meter_at_sample (position);
4207 return Temporal::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4215 return Temporal::Beats();
4219 Editor::get_nudge_distance (samplepos_t pos, samplecnt_t& next)
4223 ret = nudge_clock->current_duration (pos);
4224 next = ret + 1; /* XXXX fix me */
4230 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4232 ArdourDialog dialog (_("Playlist Deletion"));
4233 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4234 "If it is kept, its audio files will not be cleaned.\n"
4235 "If it is deleted, audio files used by it alone will be cleaned."),
4238 dialog.set_position (WIN_POS_CENTER);
4239 dialog.get_vbox()->pack_start (label);
4243 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4244 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4245 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4246 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4247 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4249 /* by default gtk uses the left most button */
4250 keep->grab_focus ();
4252 switch (dialog.run ()) {
4254 /* keep this and all remaining ones */
4259 /* delete this and all others */
4263 case RESPONSE_ACCEPT:
4264 /* delete the playlist */
4268 case RESPONSE_REJECT:
4269 /* keep the playlist */
4281 Editor::audio_region_selection_covers (samplepos_t where)
4283 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4284 if ((*a)->region()->covers (where)) {
4293 Editor::cleanup_regions ()
4295 _regions->remove_unused_regions();
4300 Editor::prepare_for_cleanup ()
4302 cut_buffer->clear_regions ();
4303 cut_buffer->clear_playlists ();
4305 selection->clear_regions ();
4306 selection->clear_playlists ();
4308 _regions->suspend_redisplay ();
4312 Editor::finish_cleanup ()
4314 _regions->resume_redisplay ();
4318 Editor::transport_loop_location()
4321 return _session->locations()->auto_loop_location();
4328 Editor::transport_punch_location()
4331 return _session->locations()->auto_punch_location();
4338 Editor::control_layout_scroll (GdkEventScroll* ev)
4340 /* Just forward to the normal canvas scroll method. The coordinate
4341 systems are different but since the canvas is always larger than the
4342 track headers, and aligned with the trackview area, this will work.
4344 In the not too distant future this layout is going away anyway and
4345 headers will be on the canvas.
4347 return canvas_scroll_event (ev, false);
4351 Editor::session_state_saved (string)
4354 _snapshots->redisplay ();
4358 Editor::maximise_editing_space ()
4364 Gtk::Window* toplevel = current_toplevel();
4367 toplevel->fullscreen ();
4373 Editor::restore_editing_space ()
4379 Gtk::Window* toplevel = current_toplevel();
4382 toplevel->unfullscreen();
4388 * Make new playlists for a given track and also any others that belong
4389 * to the same active route group with the `select' property.
4394 Editor::new_playlists (TimeAxisView* v)
4396 begin_reversible_command (_("new playlists"));
4397 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4398 _session->playlists()->get (playlists);
4399 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4400 commit_reversible_command ();
4404 * Use a copy of the current playlist for a given track and also any others that belong
4405 * to the same active route group with the `select' property.
4410 Editor::copy_playlists (TimeAxisView* v)
4412 begin_reversible_command (_("copy playlists"));
4413 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4414 _session->playlists()->get (playlists);
4415 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4416 commit_reversible_command ();
4419 /** Clear the current playlist for a given track and also any others that belong
4420 * to the same active route group with the `select' property.
4425 Editor::clear_playlists (TimeAxisView* v)
4427 begin_reversible_command (_("clear playlists"));
4428 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4429 _session->playlists()->get (playlists);
4430 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4431 commit_reversible_command ();
4435 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4437 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4441 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4443 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4447 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4449 atv.clear_playlist ();
4453 Editor::get_y_origin () const
4455 return vertical_adjustment.get_value ();
4458 /** Queue up a change to the viewport x origin.
4459 * @param sample New x origin.
4462 Editor::reset_x_origin (samplepos_t sample)
4464 pending_visual_change.add (VisualChange::TimeOrigin);
4465 pending_visual_change.time_origin = sample;
4466 ensure_visual_change_idle_handler ();
4470 Editor::reset_y_origin (double y)
4472 pending_visual_change.add (VisualChange::YOrigin);
4473 pending_visual_change.y_origin = y;
4474 ensure_visual_change_idle_handler ();
4478 Editor::reset_zoom (samplecnt_t spp)
4480 if (spp == samples_per_pixel) {
4484 pending_visual_change.add (VisualChange::ZoomLevel);
4485 pending_visual_change.samples_per_pixel = spp;
4486 ensure_visual_change_idle_handler ();
4490 Editor::reposition_and_zoom (samplepos_t sample, double fpu)
4492 reset_x_origin (sample);
4495 if (!no_save_visual) {
4496 undo_visual_stack.push_back (current_visual_state(false));
4500 Editor::VisualState::VisualState (bool with_tracks)
4501 : gui_state (with_tracks ? new GUIObjectState : 0)
4505 Editor::VisualState::~VisualState ()
4510 Editor::VisualState*
4511 Editor::current_visual_state (bool with_tracks)
4513 VisualState* vs = new VisualState (with_tracks);
4514 vs->y_position = vertical_adjustment.get_value();
4515 vs->samples_per_pixel = samples_per_pixel;
4516 vs->_leftmost_sample = _leftmost_sample;
4517 vs->zoom_focus = zoom_focus;
4520 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4527 Editor::undo_visual_state ()
4529 if (undo_visual_stack.empty()) {
4533 VisualState* vs = undo_visual_stack.back();
4534 undo_visual_stack.pop_back();
4537 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4540 use_visual_state (*vs);
4545 Editor::redo_visual_state ()
4547 if (redo_visual_stack.empty()) {
4551 VisualState* vs = redo_visual_stack.back();
4552 redo_visual_stack.pop_back();
4554 /* XXX: can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack? */
4555 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4558 use_visual_state (*vs);
4563 Editor::swap_visual_state ()
4565 if (undo_visual_stack.empty()) {
4566 redo_visual_state ();
4568 undo_visual_state ();
4573 Editor::use_visual_state (VisualState& vs)
4575 PBD::Unwinder<bool> nsv (no_save_visual, true);
4576 DisplaySuspender ds;
4578 vertical_adjustment.set_value (vs.y_position);
4580 set_zoom_focus (vs.zoom_focus);
4581 reposition_and_zoom (vs._leftmost_sample, vs.samples_per_pixel);
4584 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4586 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4587 (*i)->clear_property_cache();
4588 (*i)->reset_visual_state ();
4592 _routes->update_visibility ();
4595 /** This is the core function that controls the zoom level of the canvas. It is called
4596 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4597 * @param spp new number of samples per pixel
4600 Editor::set_samples_per_pixel (samplecnt_t spp)
4606 const samplecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->sample_rate() : 48000);
4607 const samplecnt_t lots_of_pixels = 4000;
4609 /* if the zoom level is greater than what you'd get trying to display 3
4610 * days of audio on a really big screen, then it's too big.
4613 if (spp * lots_of_pixels > three_days) {
4617 samples_per_pixel = spp;
4621 Editor::on_samples_per_pixel_changed ()
4623 bool const showing_time_selection = selection->time.length() > 0;
4625 if (showing_time_selection && selection->time.start () != selection->time.end_sample ()) {
4626 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4627 (*i)->reshow_selection (selection->time);
4631 ZoomChanged (); /* EMIT_SIGNAL */
4633 ArdourCanvas::GtkCanvasViewport* c;
4635 c = get_track_canvas();
4637 c->canvas()->zoomed ();
4640 if (playhead_cursor) {
4641 playhead_cursor->set_position (playhead_cursor->current_sample ());
4644 refresh_location_display();
4645 _summary->set_overlays_dirty ();
4647 update_marker_labels ();
4653 Editor::playhead_cursor_sample () const
4655 return playhead_cursor->current_sample();
4659 Editor::queue_visual_videotimeline_update ()
4661 pending_visual_change.add (VisualChange::VideoTimeline);
4662 ensure_visual_change_idle_handler ();
4666 Editor::ensure_visual_change_idle_handler ()
4668 if (pending_visual_change.idle_handler_id < 0) {
4669 /* see comment in add_to_idle_resize above. */
4670 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4671 pending_visual_change.being_handled = false;
4676 Editor::_idle_visual_changer (void* arg)
4678 return static_cast<Editor*>(arg)->idle_visual_changer ();
4682 Editor::pre_render ()
4684 visual_change_queued = false;
4686 if (pending_visual_change.pending != 0) {
4687 ensure_visual_change_idle_handler();
4692 Editor::idle_visual_changer ()
4694 pending_visual_change.idle_handler_id = -1;
4696 if (pending_visual_change.pending == 0) {
4700 /* set_horizontal_position() below (and maybe other calls) call
4701 gtk_main_iteration(), so it's possible that a signal will be handled
4702 half-way through this method. If this signal wants an
4703 idle_visual_changer we must schedule another one after this one, so
4704 mark the idle_handler_id as -1 here to allow that. Also make a note
4705 that we are doing the visual change, so that changes in response to
4706 super-rapid-screen-update can be dropped if we are still processing
4710 if (visual_change_queued) {
4714 pending_visual_change.being_handled = true;
4716 VisualChange vc = pending_visual_change;
4718 pending_visual_change.pending = (VisualChange::Type) 0;
4720 visual_changer (vc);
4722 pending_visual_change.being_handled = false;
4724 visual_change_queued = true;
4726 return 0; /* this is always a one-shot call */
4730 Editor::visual_changer (const VisualChange& vc)
4733 * Changed first so the correct horizontal canvas position is calculated in
4734 * Editor::set_horizontal_position
4736 if (vc.pending & VisualChange::ZoomLevel) {
4737 set_samples_per_pixel (vc.samples_per_pixel);
4740 if (vc.pending & VisualChange::TimeOrigin) {
4741 double new_time_origin = sample_to_pixel_unrounded (vc.time_origin);
4742 set_horizontal_position (new_time_origin);
4745 if (vc.pending & VisualChange::YOrigin) {
4746 vertical_adjustment.set_value (vc.y_origin);
4750 * Now the canvas is in the final state before render the canvas items that
4751 * support the Item::prepare_for_render interface can calculate the correct
4752 * item to visible canvas intersection.
4754 if (vc.pending & VisualChange::ZoomLevel) {
4755 on_samples_per_pixel_changed ();
4757 compute_fixed_ruler_scale ();
4759 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4760 update_tempo_based_rulers ();
4763 if (!(vc.pending & VisualChange::ZoomLevel)) {
4764 /* If the canvas is not being zoomed then the canvas items will not change
4765 * and cause Item::prepare_for_render to be called so do it here manually.
4766 * Not ideal, but I can't think of a better solution atm.
4768 _track_canvas->prepare_for_render();
4771 /* If we are only scrolling vertically there is no need to update these */
4772 if (vc.pending != VisualChange::YOrigin) {
4773 update_fixed_rulers ();
4774 redisplay_grid (true);
4776 /* video frames & position need to be updated for zoom, horiz-scroll
4777 * and (explicitly) VisualChange::VideoTimeline.
4779 update_video_timeline();
4782 _summary->set_overlays_dirty ();
4785 struct EditorOrderTimeAxisSorter {
4786 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4787 return a->order () < b->order ();
4792 Editor::sort_track_selection (TrackViewList& sel)
4794 EditorOrderTimeAxisSorter cmp;
4799 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4802 samplepos_t where = 0;
4803 EditPoint ep = _edit_point;
4805 if (Profile->get_mixbus()) {
4806 if (ep == EditAtSelectedMarker) {
4807 ep = EditAtPlayhead;
4811 if (from_outside_canvas && (ep == EditAtMouse)) {
4812 ep = EditAtPlayhead;
4813 } else if (from_context_menu && (ep == EditAtMouse)) {
4814 return canvas_event_sample (&context_click_event, 0, 0);
4817 if (entered_marker) {
4818 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4819 return entered_marker->position();
4822 if ((ignore == EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4823 ep = EditAtSelectedMarker;
4826 if ((ignore == EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4827 ep = EditAtPlayhead;
4830 MusicSample snap_mf (0, 0);
4833 case EditAtPlayhead:
4834 if (_dragging_playhead) {
4835 /* NOTE: since the user is dragging with the mouse, this operation will implicitly be Snapped */
4836 where = playhead_cursor->current_sample();
4838 where = _session->audible_sample();
4840 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4843 case EditAtSelectedMarker:
4844 if (!selection->markers.empty()) {
4846 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4849 where = loc->start();
4853 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4861 if (!mouse_sample (where, ignored)) {
4862 /* XXX not right but what can we do ? */
4865 snap_mf.sample = where;
4867 where = snap_mf.sample;
4868 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4876 Editor::set_loop_range (samplepos_t start, samplepos_t end, string cmd)
4878 if (!_session) return;
4880 begin_reversible_command (cmd);
4884 if ((tll = transport_loop_location()) == 0) {
4885 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4886 XMLNode &before = _session->locations()->get_state();
4887 _session->locations()->add (loc, true);
4888 _session->set_auto_loop_location (loc);
4889 XMLNode &after = _session->locations()->get_state();
4890 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4892 XMLNode &before = tll->get_state();
4893 tll->set_hidden (false, this);
4894 tll->set (start, end);
4895 XMLNode &after = tll->get_state();
4896 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4899 commit_reversible_command ();
4903 Editor::set_punch_range (samplepos_t start, samplepos_t end, string cmd)
4905 if (!_session) return;
4907 begin_reversible_command (cmd);
4911 if ((tpl = transport_punch_location()) == 0) {
4912 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4913 XMLNode &before = _session->locations()->get_state();
4914 _session->locations()->add (loc, true);
4915 _session->set_auto_punch_location (loc);
4916 XMLNode &after = _session->locations()->get_state();
4917 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4919 XMLNode &before = tpl->get_state();
4920 tpl->set_hidden (false, this);
4921 tpl->set (start, end);
4922 XMLNode &after = tpl->get_state();
4923 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4926 commit_reversible_command ();
4929 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4930 * @param rs List to which found regions are added.
4931 * @param where Time to look at.
4932 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4935 Editor::get_regions_at (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4937 const TrackViewList* tracks;
4940 tracks = &track_views;
4945 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4947 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4950 boost::shared_ptr<Track> tr;
4951 boost::shared_ptr<Playlist> pl;
4953 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4955 boost::shared_ptr<RegionList> regions = pl->regions_at (where);
4957 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4958 RegionView* rv = rtv->view()->find_view (*i);
4969 Editor::get_regions_after (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4971 const TrackViewList* tracks;
4974 tracks = &track_views;
4979 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4980 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4982 boost::shared_ptr<Track> tr;
4983 boost::shared_ptr<Playlist> pl;
4985 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4987 boost::shared_ptr<RegionList> regions = pl->regions_touched (where, max_samplepos);
4989 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4991 RegionView* rv = rtv->view()->find_view (*i);
5002 /** Get regions using the following method:
5004 * Make a region list using:
5005 * (a) any selected regions
5006 * (b) the intersection of any selected tracks and the edit point(*)
5007 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
5009 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
5011 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
5015 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
5017 RegionSelection regions;
5019 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
5020 regions.add (entered_regionview);
5022 regions = selection->regions;
5025 if (regions.empty()) {
5026 TrackViewList tracks = selection->tracks;
5028 if (!tracks.empty()) {
5029 /* no region selected or entered, but some selected tracks:
5030 * act on all regions on the selected tracks at the edit point
5032 samplepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
5033 get_regions_at(regions, where, tracks);
5040 /** Get regions using the following method:
5042 * Make a region list using:
5043 * (a) any selected regions
5044 * (b) the intersection of any selected tracks and the edit point(*)
5045 * (c) if neither exists, then whatever region is under the mouse
5047 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
5049 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
5052 Editor::get_regions_from_selection_and_mouse (samplepos_t pos)
5054 RegionSelection regions;
5056 if (entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
5057 regions.add (entered_regionview);
5059 regions = selection->regions;
5062 if (regions.empty()) {
5063 TrackViewList tracks = selection->tracks;
5065 if (!tracks.empty()) {
5066 /* no region selected or entered, but some selected tracks:
5067 * act on all regions on the selected tracks at the edit point
5069 get_regions_at(regions, pos, tracks);
5076 /** Start with regions that are selected, or the entered regionview if none are selected.
5077 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
5078 * of the regions that we started with.
5082 Editor::get_regions_from_selection_and_entered () const
5084 RegionSelection regions = selection->regions;
5086 if (regions.empty() && entered_regionview) {
5087 regions.add (entered_regionview);
5094 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
5096 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5097 RouteTimeAxisView* rtav;
5099 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5100 boost::shared_ptr<Playlist> pl;
5101 std::vector<boost::shared_ptr<Region> > results;
5102 boost::shared_ptr<Track> tr;
5104 if ((tr = rtav->track()) == 0) {
5109 if ((pl = (tr->playlist())) != 0) {
5110 boost::shared_ptr<Region> r = pl->region_by_id (id);
5112 RegionView* rv = rtav->view()->find_view (r);
5114 regions.push_back (rv);
5123 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > > &selection) const
5126 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5127 MidiTimeAxisView* mtav;
5129 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5131 mtav->get_per_region_note_selection (selection);
5138 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5140 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5142 RouteTimeAxisView* tatv;
5144 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5146 boost::shared_ptr<Playlist> pl;
5147 vector<boost::shared_ptr<Region> > results;
5149 boost::shared_ptr<Track> tr;
5151 if ((tr = tatv->track()) == 0) {
5156 if ((pl = (tr->playlist())) != 0) {
5157 if (src_comparison) {
5158 pl->get_source_equivalent_regions (region, results);
5160 pl->get_region_list_equivalent_regions (region, results);
5164 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5165 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5166 regions.push_back (marv);
5175 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5177 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5178 RouteTimeAxisView* tatv;
5179 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5180 if (!tatv->track()) {
5183 RegionView* marv = tatv->view()->find_view (region);
5193 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5195 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5196 RouteTimeAxisView* rtav;
5197 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5198 if (rtav->route() == route) {
5207 Editor::show_rhythm_ferret ()
5209 if (rhythm_ferret == 0) {
5210 rhythm_ferret = new RhythmFerret(*this);
5213 rhythm_ferret->set_session (_session);
5214 rhythm_ferret->show ();
5215 rhythm_ferret->present ();
5219 Editor::first_idle ()
5221 MessageDialog* dialog = 0;
5223 if (track_views.size() > 1) {
5224 Timers::TimerSuspender t;
5225 dialog = new MessageDialog (
5226 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5230 ARDOUR_UI::instance()->flush_pending (60);
5233 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5237 /* now that all regionviews should exist, setup region selection */
5241 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5242 /* this is cumulative: rs is NOT cleared each time */
5243 get_regionviews_by_id (*pr, rs);
5246 selection->set (rs);
5248 /* first idle adds route children (automation tracks), so we need to redisplay here */
5249 _routes->redisplay ();
5253 if (_session->undo_depth() == 0) {
5254 undo_action->set_sensitive(false);
5256 redo_action->set_sensitive(false);
5257 begin_selection_op_history ();
5263 Editor::_idle_resize (gpointer arg)
5265 return ((Editor*)arg)->idle_resize ();
5269 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5271 if (resize_idle_id < 0) {
5272 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5273 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5274 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5276 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5277 _pending_resize_amount = 0;
5280 /* make a note of the smallest resulting height, so that we can clamp the
5281 lower limit at TimeAxisView::hSmall */
5283 int32_t min_resulting = INT32_MAX;
5285 _pending_resize_amount += h;
5286 _pending_resize_view = view;
5288 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5290 if (selection->tracks.contains (_pending_resize_view)) {
5291 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5292 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5296 if (min_resulting < 0) {
5301 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5302 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5306 /** Handle pending resizing of tracks */
5308 Editor::idle_resize ()
5310 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5312 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5313 selection->tracks.contains (_pending_resize_view)) {
5315 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5316 if (*i != _pending_resize_view) {
5317 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5322 _pending_resize_amount = 0;
5323 _group_tabs->set_dirty ();
5324 resize_idle_id = -1;
5332 ENSURE_GUI_THREAD (*this, &Editor::located);
5335 playhead_cursor->set_position (_session->audible_sample ());
5336 if (_follow_playhead && !_pending_initial_locate) {
5337 reset_x_origin_to_follow_playhead ();
5341 _pending_locate_request = false;
5342 _pending_initial_locate = false;
5343 _last_update_time = 0;
5347 Editor::region_view_added (RegionView * rv)
5349 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5351 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5352 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5353 if (rv->region()->id () == (*rnote).first) {
5354 mrv->select_notes ((*rnote).second);
5355 selection->pending_midi_note_selection.erase(rnote);
5361 _summary->set_background_dirty ();
5363 mark_region_boundary_cache_dirty ();
5367 Editor::region_view_removed ()
5369 _summary->set_background_dirty ();
5371 mark_region_boundary_cache_dirty ();
5375 Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
5377 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5378 if ((*j)->stripable() == s) {
5387 Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
5389 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5390 if ((*j)->control() == c) {
5394 TimeAxisView::Children kids = (*j)->get_child_list ();
5396 for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) {
5397 if ((*k)->control() == c) {
5407 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5411 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5412 TimeAxisView* tv = time_axis_view_from_stripable (*i);
5422 Editor::suspend_route_redisplay ()
5425 _routes->suspend_redisplay();
5430 Editor::resume_route_redisplay ()
5433 _routes->redisplay(); // queue redisplay
5434 _routes->resume_redisplay();
5439 Editor::add_vcas (VCAList& vlist)
5443 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5444 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5447 add_stripables (sl);
5451 Editor::add_routes (RouteList& rlist)
5455 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5459 add_stripables (sl);
5463 Editor::add_stripables (StripableList& sl)
5465 list<TimeAxisView*> new_views;
5466 boost::shared_ptr<VCA> v;
5467 boost::shared_ptr<Route> r;
5468 TrackViewList new_selection;
5469 bool from_scratch = (track_views.size() == 0);
5471 sl.sort (Stripable::Sorter());
5473 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5475 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5477 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5479 new_views.push_back (vtv);
5481 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5483 if (r->is_auditioner() || r->is_monitor()) {
5487 RouteTimeAxisView* rtv;
5488 DataType dt = r->input()->default_type();
5490 if (dt == ARDOUR::DataType::AUDIO) {
5491 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5493 } else if (dt == ARDOUR::DataType::MIDI) {
5494 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5497 throw unknown_type();
5500 new_views.push_back (rtv);
5501 track_views.push_back (rtv);
5502 new_selection.push_back (rtv);
5504 rtv->effective_gain_display ();
5506 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5507 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5511 if (new_views.size() > 0) {
5512 _routes->time_axis_views_added (new_views);
5513 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5516 /* note: !new_selection.empty() means that we got some routes rather
5520 if (!from_scratch && !new_selection.empty()) {
5521 selection->set (new_selection);
5522 begin_selection_op_history();
5525 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5526 show_editor_mixer (true);
5529 editor_list_button.set_sensitive (true);
5533 Editor::timeaxisview_deleted (TimeAxisView *tv)
5535 if (tv == entered_track) {
5539 if (_session && _session->deletion_in_progress()) {
5540 /* the situation is under control */
5544 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5546 if (dynamic_cast<AutomationTimeAxisView*> (tv)) {
5547 selection->remove (tv);
5551 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5553 _routes->route_removed (tv);
5555 TimeAxisView::Children c = tv->get_child_list ();
5556 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5557 if (entered_track == i->get()) {
5562 /* remove it from the list of track views */
5564 TrackViewList::iterator i;
5566 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5567 i = track_views.erase (i);
5570 /* Update the route that is shown in the editor-mixer. */
5575 boost::shared_ptr<Route> route = rtav->route ();
5576 if (current_mixer_strip && current_mixer_strip->route() == route) {
5578 TimeAxisView* next_tv;
5580 if (track_views.empty()) {
5582 } else if (i == track_views.end()) {
5583 next_tv = track_views.front();
5588 // skip VCAs (cannot be selected, n/a in editor-mixer)
5589 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5590 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5591 next_tv = track_views.front();
5593 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5594 /* just in case: no master, only a VCA remains */
5600 set_selected_mixer_strip (*next_tv);
5602 /* make the editor mixer strip go away setting the
5603 * button to inactive (which also unticks the menu option)
5606 ActionManager::uncheck_toggleaction ("Editor/show-editor-mixer");
5612 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5618 DisplaySuspender ds;
5619 PresentationInfo::ChangeSuspender cs;
5621 if (apply_to_selection) {
5622 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end();) {
5624 TrackSelection::iterator j = i;
5627 hide_track_in_display (*i, false);
5632 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5634 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5635 /* this will hide the mixer strip */
5636 set_selected_mixer_strip (*tv);
5639 _routes->hide_track_in_display (*tv);
5644 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5649 _routes->show_track_in_display (*tv);
5650 if (move_into_view) {
5651 ensure_time_axis_view_is_visible (*tv, false);
5656 Editor::sync_track_view_list_and_routes ()
5658 track_views = TrackViewList (_routes->views ());
5660 _summary->set_background_dirty();
5661 _group_tabs->set_dirty ();
5663 return false; // do not call again (until needed)
5667 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5669 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5674 /** Find a StripableTimeAxisView by the ID of its stripable */
5675 StripableTimeAxisView*
5676 Editor::get_stripable_time_axis_by_id (const PBD::ID& id) const
5678 StripableTimeAxisView* v;
5680 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5681 if((v = dynamic_cast<StripableTimeAxisView*>(*i)) != 0) {
5682 if(v->stripable()->id() == id) {
5692 Editor::fit_route_group (RouteGroup *g)
5694 TrackViewList ts = axis_views_from_routes (g->route_list ());
5699 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5701 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5704 _session->cancel_audition ();
5708 if (_session->is_auditioning()) {
5709 _session->cancel_audition ();
5710 if (r == last_audition_region) {
5715 _session->audition_region (r);
5716 last_audition_region = r;
5721 Editor::hide_a_region (boost::shared_ptr<Region> r)
5723 r->set_hidden (true);
5727 Editor::show_a_region (boost::shared_ptr<Region> r)
5729 r->set_hidden (false);
5733 Editor::audition_region_from_region_list ()
5735 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5739 Editor::step_edit_status_change (bool yn)
5742 start_step_editing ();
5744 stop_step_editing ();
5749 Editor::start_step_editing ()
5751 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5755 Editor::stop_step_editing ()
5757 step_edit_connection.disconnect ();
5761 Editor::check_step_edit ()
5763 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5764 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5766 mtv->check_step_edit ();
5770 return true; // do it again, till we stop
5774 Editor::scroll_press (Direction dir)
5776 ++_scroll_callbacks;
5778 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5779 /* delay the first auto-repeat */
5785 scroll_backward (1);
5793 scroll_up_one_track ();
5797 scroll_down_one_track ();
5801 /* do hacky auto-repeat */
5802 if (!_scroll_connection.connected ()) {
5804 _scroll_connection = Glib::signal_timeout().connect (
5805 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5808 _scroll_callbacks = 0;
5815 Editor::scroll_release ()
5817 _scroll_connection.disconnect ();
5820 /** Queue a change for the Editor viewport x origin to follow the playhead */
5822 Editor::reset_x_origin_to_follow_playhead ()
5824 samplepos_t const sample = playhead_cursor->current_sample ();
5826 if (sample < _leftmost_sample || sample > _leftmost_sample + current_page_samples()) {
5828 if (_session->transport_speed() < 0) {
5830 if (sample > (current_page_samples() / 2)) {
5831 center_screen (sample-(current_page_samples()/2));
5833 center_screen (current_page_samples()/2);
5840 if (sample < _leftmost_sample) {
5842 if (_session->transport_rolling()) {
5843 /* rolling; end up with the playhead at the right of the page */
5844 l = sample - current_page_samples ();
5846 /* not rolling: end up with the playhead 1/4 of the way along the page */
5847 l = sample - current_page_samples() / 4;
5851 if (_session->transport_rolling()) {
5852 /* rolling: end up with the playhead on the left of the page */
5855 /* not rolling: end up with the playhead 3/4 of the way along the page */
5856 l = sample - 3 * current_page_samples() / 4;
5864 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5870 Editor::super_rapid_screen_update ()
5872 if (!_session || !_session->engine().running()) {
5876 /* METERING / MIXER STRIPS */
5878 /* update track meters, if required */
5879 if (contents().is_mapped() && meters_running) {
5880 RouteTimeAxisView* rtv;
5881 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5882 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5883 rtv->fast_update ();
5888 /* and any current mixer strip */
5889 if (current_mixer_strip) {
5890 current_mixer_strip->fast_update ();
5893 bool latent_locate = false;
5894 samplepos_t sample = _session->audible_sample (&latent_locate);
5895 const int64_t now = g_get_monotonic_time ();
5898 if (_session->exporting ()) {
5899 /* freewheel/export may be faster or slower than transport_speed() / SR.
5900 * Also exporting multiple ranges locates/jumps without a _pending_locate_request.
5902 _last_update_time = 0;
5905 if (!_session->transport_rolling () || _session->is_auditioning ()) {
5906 /* Do not interpolate the playhead position; just set it */
5907 _last_update_time = 0;
5910 if (_last_update_time > 0) {
5911 /* interpolate and smoothen playhead position */
5912 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_sample_rate () * 1e-6;
5913 samplepos_t guess = playhead_cursor->current_sample () + rint (ds);
5914 err = sample - guess;
5916 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5917 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5920 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5922 err, _err_screen_engine);
5927 _err_screen_engine = 0;
5930 if (err > 8192 || latent_locate) {
5931 // in case of x-runs or freewheeling
5932 _last_update_time = 0;
5933 sample = _session->audible_sample ();
5935 _last_update_time = now;
5938 /* snapped cursor stuff (the snapped_cursor shows where an operation is going to occur) */
5940 MusicSample where (sample, 0);
5941 if (!UIConfiguration::instance().get_show_snapped_cursor()) {
5942 snapped_cursor->hide ();
5943 } else if (_edit_point == EditAtPlayhead && !_dragging_playhead) {
5944 /* EditAtPlayhead does not snap */
5945 } else if (_edit_point == EditAtSelectedMarker) {
5946 /* NOTE: I don't think EditAtSelectedMarker should snap. They are what they are.
5947 * however, the current editing code -does- snap so I'll draw it that way for now.
5949 if (!selection->markers.empty()) {
5950 MusicSample ms (selection->markers.front()->position(), 0);
5951 snap_to (ms); // should use snap_to_with_modifier?
5952 snapped_cursor->set_position (ms.sample);
5953 snapped_cursor->show ();
5955 } else if (mouse_sample (where.sample, ignored)) { // cursor is in the editing canvas. show it.
5956 snapped_cursor->show ();
5957 } else { // mouse is out of the editing canvas. hide the snapped_cursor
5958 snapped_cursor->hide ();
5961 /* There are a few reasons why we might not update the playhead / viewport stuff:
5963 * 1. we don't update things when there's a pending locate request, otherwise
5964 * when the editor requests a locate there is a chance that this method
5965 * will move the playhead before the locate request is processed, causing
5967 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5968 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5970 if (_pending_locate_request) {
5971 _last_update_time = 0;
5975 if (_dragging_playhead) {
5976 _last_update_time = 0;
5980 if (playhead_cursor->current_sample () == sample) {
5984 playhead_cursor->set_position (sample);
5986 if (_session->requested_return_sample() >= 0) {
5987 _last_update_time = 0;
5991 if (!_follow_playhead || pending_visual_change.being_handled) {
5992 /* We only do this if we aren't already
5993 * handling a visual change (ie if
5994 * pending_visual_change.being_handled is
5995 * false) so that these requests don't stack
5996 * up there are too many of them to handle in
6002 if (!_stationary_playhead) {
6003 reset_x_origin_to_follow_playhead ();
6005 samplepos_t const sample = playhead_cursor->current_sample ();
6006 double target = ((double)sample - (double)current_page_samples() / 2.0);
6007 if (target <= 0.0) {
6010 /* compare to EditorCursor::set_position() */
6011 double const old_pos = sample_to_pixel_unrounded (_leftmost_sample);
6012 double const new_pos = sample_to_pixel_unrounded (target);
6013 if (rint (new_pos) != rint (old_pos)) {
6014 reset_x_origin (pixel_to_sample (new_pos));
6021 Editor::session_going_away ()
6023 _have_idled = false;
6025 _session_connections.drop_connections ();
6027 super_rapid_screen_update_connection.disconnect ();
6029 selection->clear ();
6030 cut_buffer->clear ();
6032 clicked_regionview = 0;
6033 clicked_axisview = 0;
6034 clicked_routeview = 0;
6035 entered_regionview = 0;
6037 _last_update_time = 0;
6040 playhead_cursor->hide ();
6042 /* rip everything out of the list displays */
6047 _route_groups->clear ();
6049 /* do this first so that deleting a track doesn't reset cms to null
6050 and thus cause a leak.
6053 if (current_mixer_strip) {
6054 if (current_mixer_strip->get_parent() != 0) {
6055 global_hpacker.remove (*current_mixer_strip);
6057 delete current_mixer_strip;
6058 current_mixer_strip = 0;
6061 /* delete all trackviews */
6063 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6066 track_views.clear ();
6068 nudge_clock->set_session (0);
6070 editor_list_button.set_active(false);
6071 editor_list_button.set_sensitive(false);
6073 /* clear tempo/meter rulers */
6074 remove_metric_marks ();
6075 clear_marker_display ();
6081 stop_step_editing ();
6085 /* get rid of any existing editor mixer strip */
6087 WindowTitle title(Glib::get_application_name());
6088 title += _("Editor");
6090 own_window()->set_title (title.get_string());
6093 SessionHandlePtr::session_going_away ();
6097 Editor::trigger_script (int i)
6099 LuaInstance::instance()-> call_action (i);
6103 Editor::show_editor_list (bool yn)
6106 _editor_list_vbox.show ();
6108 _editor_list_vbox.hide ();
6113 Editor::change_region_layering_order (bool from_context_menu)
6115 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
6117 if (!clicked_routeview) {
6118 if (layering_order_editor) {
6119 layering_order_editor->hide ();
6124 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
6130 boost::shared_ptr<Playlist> pl = track->playlist();
6136 if (layering_order_editor == 0) {
6137 layering_order_editor = new RegionLayeringOrderEditor (*this);
6140 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
6141 layering_order_editor->maybe_present ();
6145 Editor::update_region_layering_order_editor ()
6147 if (layering_order_editor && layering_order_editor->is_visible ()) {
6148 change_region_layering_order (true);
6153 Editor::setup_fade_images ()
6155 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
6156 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
6157 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
6158 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
6159 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
6161 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
6162 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
6163 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
6164 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
6165 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
6169 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
6171 Editor::action_menu_item (std::string const & name)
6173 Glib::RefPtr<Action> a = editor_actions->get_action (name);
6176 return *manage (a->create_menu_item ());
6180 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6182 EventBox* b = manage (new EventBox);
6183 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6184 Label* l = manage (new Label (name));
6188 _the_notebook.append_page (widget, *b);
6192 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6194 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6195 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6198 if (ev->type == GDK_2BUTTON_PRESS) {
6200 /* double-click on a notebook tab shrinks or expands the notebook */
6202 if (_notebook_shrunk) {
6203 if (pre_notebook_shrink_pane_width) {
6204 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6206 _notebook_shrunk = false;
6208 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6210 /* this expands the LHS of the edit pane to cover the notebook
6211 PAGE but leaves the tabs visible.
6213 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6214 _notebook_shrunk = true;
6222 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6224 using namespace Menu_Helpers;
6226 MenuList& items = _control_point_context_menu.items ();
6229 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6230 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6231 if (!can_remove_control_point (item)) {
6232 items.back().set_sensitive (false);
6235 _control_point_context_menu.popup (event->button.button, event->button.time);
6239 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6241 using namespace Menu_Helpers;
6243 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6248 /* We need to get the selection here and pass it to the operations, since
6249 popping up the menu will cause a region leave event which clears
6250 entered_regionview. */
6252 MidiRegionView& mrv = note->region_view();
6253 const RegionSelection rs = get_regions_from_selection_and_entered ();
6254 const uint32_t sel_size = mrv.selection_size ();
6256 MenuList& items = _note_context_menu.items();
6260 items.push_back(MenuElem(_("Delete"),
6261 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6264 items.push_back(MenuElem(_("Edit..."),
6265 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6266 if (sel_size != 1) {
6267 items.back().set_sensitive (false);
6270 items.push_back(MenuElem(_("Transpose..."),
6271 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6274 items.push_back(MenuElem(_("Legatize"),
6275 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6277 items.back().set_sensitive (false);
6280 items.push_back(MenuElem(_("Quantize..."),
6281 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6283 items.push_back(MenuElem(_("Remove Overlap"),
6284 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6286 items.back().set_sensitive (false);
6289 items.push_back(MenuElem(_("Transform..."),
6290 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6292 _note_context_menu.popup (event->button.button, event->button.time);
6296 Editor::zoom_vertical_modifier_released()
6298 _stepping_axis_view = 0;
6302 Editor::ui_parameter_changed (string parameter)
6304 if (parameter == "icon-set") {
6305 while (!_cursor_stack.empty()) {
6306 _cursor_stack.pop_back();
6308 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6309 _cursor_stack.push_back(_cursors->grabber);
6310 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6311 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6313 } else if (parameter == "draggable-playhead") {
6314 if (_verbose_cursor) {
6315 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6317 } else if (parameter == "use-note-bars-for-velocity") {
6318 ArdourCanvas::Note::set_show_velocity_bars (UIConfiguration::instance().get_use_note_bars_for_velocity());
6319 _track_canvas->request_redraw (_track_canvas->visible_area());
6320 } else if (parameter == "use-note-color-for-velocity") {
6321 /* handled individually by each MidiRegionView */
6326 Editor::use_own_window (bool and_fill_it)
6328 bool new_window = !own_window();
6330 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6332 if (win && new_window) {
6333 win->set_name ("EditorWindow");
6335 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6337 // win->signal_realize().connect (*this, &Editor::on_realize);
6338 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6339 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6340 win->set_data ("ardour-bindings", bindings);
6345 DisplaySuspender ds;
6346 contents().show_all ();
6348 /* XXX: this is a bit unfortunate; it would probably
6349 be nicer if we could just call show () above rather
6350 than needing the show_all ()
6353 /* re-hide stuff if necessary */
6354 editor_list_button_toggled ();
6355 parameter_changed ("show-summary");
6356 parameter_changed ("show-group-tabs");
6357 parameter_changed ("show-zoom-tools");
6359 /* now reset all audio_time_axis heights, because widgets might need
6365 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6366 tv = (static_cast<TimeAxisView*>(*i));
6367 tv->reset_height ();
6370 if (current_mixer_strip) {
6371 current_mixer_strip->hide_things ();
6372 current_mixer_strip->parameter_changed ("mixer-element-visibility");