2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/gtk_ui.h"
61 #include "gtkmm2ext/keyboard.h"
62 #include "gtkmm2ext/utils.h"
63 #include "gtkmm2ext/window_title.h"
64 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
66 #include "ardour/analysis_graph.h"
67 #include "ardour/audio_track.h"
68 #include "ardour/audioengine.h"
69 #include "ardour/audioregion.h"
70 #include "ardour/lmath.h"
71 #include "ardour/location.h"
72 #include "ardour/profile.h"
73 #include "ardour/route.h"
74 #include "ardour/route_group.h"
75 #include "ardour/session_playlists.h"
76 #include "ardour/tempo.h"
77 #include "ardour/utils.h"
78 #include "ardour/vca_manager.h"
79 #include "ardour/vca.h"
81 #include "canvas/debug.h"
82 #include "canvas/note.h"
83 #include "canvas/text.h"
85 #include "widgets/ardour_spacer.h"
86 #include "widgets/eventboxext.h"
87 #include "widgets/tooltips.h"
89 #include "control_protocol/control_protocol.h"
92 #include "analysis_window.h"
93 #include "audio_clock.h"
94 #include "audio_region_view.h"
95 #include "audio_streamview.h"
96 #include "audio_time_axis.h"
97 #include "automation_time_axis.h"
98 #include "bundle_manager.h"
99 #include "crossfade_edit.h"
102 #include "editing_convert.h"
104 #include "editor_cursors.h"
105 #include "editor_drag.h"
106 #include "editor_group_tabs.h"
107 #include "editor_locations.h"
108 #include "editor_regions.h"
109 #include "editor_route_groups.h"
110 #include "editor_routes.h"
111 #include "editor_snapshots.h"
112 #include "editor_summary.h"
113 #include "enums_convert.h"
114 #include "export_report.h"
115 #include "global_port_matrix.h"
116 #include "gui_object.h"
117 #include "gui_thread.h"
118 #include "keyboard.h"
119 #include "luainstance.h"
121 #include "midi_region_view.h"
122 #include "midi_time_axis.h"
123 #include "mixer_strip.h"
124 #include "mixer_ui.h"
125 #include "mouse_cursors.h"
126 #include "note_base.h"
127 #include "playlist_selector.h"
128 #include "public_editor.h"
129 #include "quantize_dialog.h"
130 #include "region_layering_order_editor.h"
131 #include "rgb_macros.h"
132 #include "rhythm_ferret.h"
133 #include "route_sorter.h"
134 #include "selection.h"
135 #include "simple_progress_dialog.h"
137 #include "grid_lines.h"
138 #include "time_axis_view.h"
139 #include "time_info_box.h"
141 #include "ui_config.h"
143 #include "vca_time_axis.h"
144 #include "verbose_cursor.h"
146 #include "pbd/i18n.h"
149 using namespace ARDOUR;
150 using namespace ArdourWidgets;
151 using namespace ARDOUR_UI_UTILS;
154 using namespace Glib;
155 using namespace Gtkmm2ext;
156 using namespace Editing;
158 using PBD::internationalize;
160 using Gtkmm2ext::Keyboard;
162 double Editor::timebar_height = 15.0;
164 static const gchar *_grid_type_strings[] = {
173 N_("1/3 (8th triplet)"), // or "1/12" ?
174 N_("1/6 (16th triplet)"),
175 N_("1/12 (32nd triplet)"),
176 N_("1/24 (64th triplet)"),
177 N_("1/5 (8th quintuplet)"),
178 N_("1/10 (16th quintuplet)"),
179 N_("1/20 (32nd quintuplet)"),
180 N_("1/7 (8th septuplet)"),
181 N_("1/14 (16th septuplet)"),
182 N_("1/28 (32nd septuplet)"),
189 static const gchar *_edit_point_strings[] = {
196 static const gchar *_edit_mode_strings[] = {
204 static const gchar *_zoom_focus_strings[] = {
214 #ifdef USE_RUBBERBAND
215 static const gchar *_rb_opt_strings[] = {
218 N_("Balanced multitimbral mixture"),
219 N_("Unpitched percussion with stable notes"),
220 N_("Crisp monophonic instrumental"),
221 N_("Unpitched solo percussion"),
222 N_("Resample without preserving pitch"),
227 /* Robin says: this should be odd to accomodate cairo drawing offset (width/2 rounds up to pixel boundary) */
229 #define COMBO_TRIANGLE_WIDTH 19 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
231 #define COMBO_TRIANGLE_WIDTH 11 // as-measured for win/linux.
235 : PublicEditor (global_hpacker)
236 , editor_mixer_strip_width (Wide)
237 , constructed (false)
238 , _playlist_selector (0)
240 , no_save_visual (false)
241 , _leftmost_sample (0)
242 , samples_per_pixel (2048)
243 , zoom_focus (ZoomFocusPlayhead)
244 , mouse_mode (MouseObject)
245 , pre_internal_grid_type (GridTypeBeat)
246 , pre_internal_snap_mode (SnapOff)
247 , internal_grid_type (GridTypeBeat)
248 , internal_snap_mode (SnapOff)
249 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
250 , _notebook_shrunk (false)
251 , location_marker_color (0)
252 , location_range_color (0)
253 , location_loop_color (0)
254 , location_punch_color (0)
255 , location_cd_marker_color (0)
257 , _show_marker_lines (false)
258 , clicked_axisview (0)
259 , clicked_routeview (0)
260 , clicked_regionview (0)
261 , clicked_selection (0)
262 , clicked_control_point (0)
263 , button_release_can_deselect (true)
264 , _mouse_changed_selection (false)
265 , region_edit_menu_split_item (0)
266 , region_edit_menu_split_multichannel_item (0)
267 , track_region_edit_playlist_menu (0)
268 , track_edit_playlist_submenu (0)
269 , track_selection_edit_playlist_submenu (0)
270 , _popup_region_menu_item (0)
272 , _track_canvas_viewport (0)
273 , within_track_canvas (false)
274 , _verbose_cursor (0)
278 , range_marker_group (0)
279 , transport_marker_group (0)
280 , cd_marker_group (0)
281 , _time_markers_group (0)
282 , hv_scroll_group (0)
284 , cursor_scroll_group (0)
285 , no_scroll_group (0)
286 , _trackview_group (0)
287 , _drag_motion_group (0)
288 , _canvas_drop_zone (0)
289 , no_ruler_shown_update (false)
290 , ruler_grabbed_widget (0)
292 , minsec_mark_interval (0)
293 , minsec_mark_modulo (0)
295 , timecode_ruler_scale (timecode_show_many_hours)
296 , timecode_mark_modulo (0)
297 , timecode_nmarks (0)
298 , _samples_ruler_interval (0)
299 , bbt_ruler_scale (bbt_show_many)
302 , bbt_bar_helper_on (0)
303 , bbt_accent_modulo (0)
308 , visible_timebars (0)
309 , editor_ruler_menu (0)
313 , range_marker_bar (0)
314 , transport_marker_bar (0)
316 , minsec_label (_("Mins:Secs"))
317 , bbt_label (_("Bars:Beats"))
318 , timecode_label (_("Timecode"))
319 , samples_label (_("Samples"))
320 , tempo_label (_("Tempo"))
321 , meter_label (_("Meter"))
322 , mark_label (_("Location Markers"))
323 , range_mark_label (_("Range Markers"))
324 , transport_mark_label (_("Loop/Punch Ranges"))
325 , cd_mark_label (_("CD Markers"))
326 , videotl_label (_("Video Timeline"))
329 , playhead_cursor (0)
330 , _region_boundary_cache_dirty (true)
331 , edit_packer (4, 4, true)
332 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
333 , horizontal_adjustment (0.0, 0.0, 1e16)
334 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
335 , controls_layout (unused_adjustment, vertical_adjustment)
336 , _scroll_callbacks (0)
337 , _visible_canvas_width (0)
338 , _visible_canvas_height (0)
339 , _full_canvas_height (0)
340 , edit_controls_left_menu (0)
341 , edit_controls_right_menu (0)
342 , visual_change_queued(false)
343 , _last_update_time (0)
344 , _err_screen_engine (0)
345 , cut_buffer_start (0)
346 , cut_buffer_length (0)
347 , button_bindings (0)
348 , last_paste_pos (-1)
351 , current_interthread_info (0)
352 , analysis_window (0)
353 , select_new_marker (false)
355 , scrubbing_direction (0)
356 , scrub_reversals (0)
357 , scrub_reverse_distance (0)
358 , have_pending_keyboard_selection (false)
359 , pending_keyboard_selection_start (0)
360 , _grid_type (GridTypeBeat)
361 , _snap_mode (SnapOff)
362 , ignore_gui_changes (false)
363 , _drags (new DragManager (this))
365 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
366 , _dragging_playhead (false)
367 , _dragging_edit_point (false)
368 , _follow_playhead (true)
369 , _stationary_playhead (false)
372 , global_rect_group (0)
373 , time_line_group (0)
374 , tempo_marker_menu (0)
375 , meter_marker_menu (0)
377 , range_marker_menu (0)
378 , transport_marker_menu (0)
379 , new_transport_marker_menu (0)
381 , marker_menu_item (0)
382 , bbt_beat_subdivision (4)
383 , _visible_track_count (-1)
384 , toolbar_selection_clock_table (2,3)
385 , automation_mode_button (_("mode"))
386 , selection (new Selection (this, true))
387 , cut_buffer (new Selection (this, false))
388 , _selection_memento (new SelectionMemento())
389 , _all_region_actions_sensitized (false)
390 , _ignore_region_action (false)
391 , _last_region_menu_was_main (false)
392 , _track_selection_change_without_scroll (false)
393 , _editor_track_selection_change_without_scroll (false)
394 , cd_marker_bar_drag_rect (0)
395 , range_bar_drag_rect (0)
396 , transport_bar_drag_rect (0)
397 , transport_bar_range_rect (0)
398 , transport_bar_preroll_rect (0)
399 , transport_bar_postroll_rect (0)
400 , transport_loop_range_rect (0)
401 , transport_punch_range_rect (0)
402 , transport_punchin_line (0)
403 , transport_punchout_line (0)
404 , transport_preroll_rect (0)
405 , transport_postroll_rect (0)
407 , rubberband_rect (0)
413 , autoscroll_horizontal_allowed (false)
414 , autoscroll_vertical_allowed (false)
416 , autoscroll_widget (0)
417 , show_gain_after_trim (false)
418 , selection_op_cmd_depth (0)
419 , selection_op_history_it (0)
420 , no_save_instant (false)
422 , current_mixer_strip (0)
423 , show_editor_mixer_when_tracks_arrive (false)
424 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
425 , current_stepping_trackview (0)
426 , last_track_height_step_timestamp (0)
428 , entered_regionview (0)
429 , clear_entered_track (false)
430 , _edit_point (EditAtMouse)
431 , meters_running (false)
433 , _have_idled (false)
434 , resize_idle_id (-1)
435 , _pending_resize_amount (0)
436 , _pending_resize_view (0)
437 , _pending_locate_request (false)
438 , _pending_initial_locate (false)
442 , layering_order_editor (0)
443 , _last_cut_copy_source_track (0)
444 , _region_selection_change_updates_region_list (true)
446 , _following_mixer_selection (false)
447 , _control_point_toggled_on_press (false)
448 , _stepping_axis_view (0)
449 , quantize_dialog (0)
450 , _main_menu_disabler (0)
451 , myactions (X_("editor"))
453 /* we are a singleton */
455 PublicEditor::_instance = this;
459 last_event_time.tv_sec = 0;
460 last_event_time.tv_usec = 0;
462 selection_op_history.clear();
465 grid_type_strings = I18N (_grid_type_strings);
466 zoom_focus_strings = I18N (_zoom_focus_strings);
467 edit_mode_strings = I18N (_edit_mode_strings);
468 edit_point_strings = I18N (_edit_point_strings);
469 #ifdef USE_RUBBERBAND
470 rb_opt_strings = I18N (_rb_opt_strings);
474 build_edit_mode_menu();
475 build_zoom_focus_menu();
476 build_track_count_menu();
477 build_grid_type_menu();
478 build_edit_point_menu();
480 location_marker_color = UIConfiguration::instance().color ("location marker");
481 location_range_color = UIConfiguration::instance().color ("location range");
482 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
483 location_loop_color = UIConfiguration::instance().color ("location loop");
484 location_punch_color = UIConfiguration::instance().color ("location punch");
486 timebar_height = std::max (12., ceil (15. * UIConfiguration::instance().get_ui_scale()));
488 TimeAxisView::setup_sizes ();
489 ArdourMarker::setup_sizes (timebar_height);
490 TempoCurve::setup_sizes (timebar_height);
492 bbt_label.set_name ("EditorRulerLabel");
493 bbt_label.set_size_request (-1, (int)timebar_height);
494 bbt_label.set_alignment (1.0, 0.5);
495 bbt_label.set_padding (5,0);
497 bbt_label.set_no_show_all();
498 minsec_label.set_name ("EditorRulerLabel");
499 minsec_label.set_size_request (-1, (int)timebar_height);
500 minsec_label.set_alignment (1.0, 0.5);
501 minsec_label.set_padding (5,0);
502 minsec_label.hide ();
503 minsec_label.set_no_show_all();
504 timecode_label.set_name ("EditorRulerLabel");
505 timecode_label.set_size_request (-1, (int)timebar_height);
506 timecode_label.set_alignment (1.0, 0.5);
507 timecode_label.set_padding (5,0);
508 timecode_label.hide ();
509 timecode_label.set_no_show_all();
510 samples_label.set_name ("EditorRulerLabel");
511 samples_label.set_size_request (-1, (int)timebar_height);
512 samples_label.set_alignment (1.0, 0.5);
513 samples_label.set_padding (5,0);
514 samples_label.hide ();
515 samples_label.set_no_show_all();
517 tempo_label.set_name ("EditorRulerLabel");
518 tempo_label.set_size_request (-1, (int)timebar_height);
519 tempo_label.set_alignment (1.0, 0.5);
520 tempo_label.set_padding (5,0);
522 tempo_label.set_no_show_all();
524 meter_label.set_name ("EditorRulerLabel");
525 meter_label.set_size_request (-1, (int)timebar_height);
526 meter_label.set_alignment (1.0, 0.5);
527 meter_label.set_padding (5,0);
529 meter_label.set_no_show_all();
531 if (Profile->get_trx()) {
532 mark_label.set_text (_("Markers"));
534 mark_label.set_name ("EditorRulerLabel");
535 mark_label.set_size_request (-1, (int)timebar_height);
536 mark_label.set_alignment (1.0, 0.5);
537 mark_label.set_padding (5,0);
539 mark_label.set_no_show_all();
541 cd_mark_label.set_name ("EditorRulerLabel");
542 cd_mark_label.set_size_request (-1, (int)timebar_height);
543 cd_mark_label.set_alignment (1.0, 0.5);
544 cd_mark_label.set_padding (5,0);
545 cd_mark_label.hide();
546 cd_mark_label.set_no_show_all();
548 videotl_bar_height = 4;
549 videotl_label.set_name ("EditorRulerLabel");
550 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
551 videotl_label.set_alignment (1.0, 0.5);
552 videotl_label.set_padding (5,0);
553 videotl_label.hide();
554 videotl_label.set_no_show_all();
556 range_mark_label.set_name ("EditorRulerLabel");
557 range_mark_label.set_size_request (-1, (int)timebar_height);
558 range_mark_label.set_alignment (1.0, 0.5);
559 range_mark_label.set_padding (5,0);
560 range_mark_label.hide();
561 range_mark_label.set_no_show_all();
563 transport_mark_label.set_name ("EditorRulerLabel");
564 transport_mark_label.set_size_request (-1, (int)timebar_height);
565 transport_mark_label.set_alignment (1.0, 0.5);
566 transport_mark_label.set_padding (5,0);
567 transport_mark_label.hide();
568 transport_mark_label.set_no_show_all();
570 initialize_canvas ();
572 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
574 _summary = new EditorSummary (this);
576 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
577 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
579 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
581 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
582 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
584 edit_controls_vbox.set_spacing (0);
585 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
586 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
588 HBox* h = manage (new HBox);
589 _group_tabs = new EditorGroupTabs (this);
590 if (!ARDOUR::Profile->get_trx()) {
591 h->pack_start (*_group_tabs, PACK_SHRINK);
593 h->pack_start (edit_controls_vbox);
594 controls_layout.add (*h);
596 controls_layout.set_name ("EditControlsBase");
597 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
598 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
599 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
601 _cursors = new MouseCursors;
602 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
603 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
605 /* Push default cursor to ever-present bottom of cursor stack. */
606 push_canvas_cursor(_cursors->grabber);
608 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
610 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
611 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
612 pad_line_1->set_outline_color (0xFF0000FF);
618 edit_packer.set_col_spacings (0);
619 edit_packer.set_row_spacings (0);
620 edit_packer.set_homogeneous (false);
621 edit_packer.set_border_width (0);
622 edit_packer.set_name ("EditorWindow");
624 time_bars_event_box.add (time_bars_vbox);
625 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
626 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
628 ArdourWidgets::ArdourDropShadow *axis_view_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
629 axis_view_shadow->set_size_request (4, -1);
630 axis_view_shadow->set_name("EditorWindow");
631 axis_view_shadow->show();
633 edit_packer.attach (*axis_view_shadow, 0, 1, 0, 2, FILL, FILL|EXPAND, 0, 0);
635 /* labels for the time bars */
636 edit_packer.attach (time_bars_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
638 edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0);
640 edit_packer.attach (*_track_canvas_viewport, 2, 3, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
642 bottom_hbox.set_border_width (2);
643 bottom_hbox.set_spacing (3);
645 PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&Editor::presentation_info_changed, this, _1), gui_context());
647 _route_groups = new EditorRouteGroups (this);
648 _routes = new EditorRoutes (this);
649 _regions = new EditorRegions (this);
650 _snapshots = new EditorSnapshots (this);
651 _locations = new EditorLocations (this);
652 _time_info_box = new TimeInfoBox ("EditorTimeInfo", true);
654 /* these are static location signals */
656 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
657 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
658 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
660 add_notebook_page (_("Regions"), _regions->widget ());
661 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
662 add_notebook_page (_("Snapshots"), _snapshots->widget ());
663 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
664 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
666 _the_notebook.set_show_tabs (true);
667 _the_notebook.set_scrollable (true);
668 _the_notebook.popup_disable ();
669 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
670 _the_notebook.show_all ();
672 _notebook_shrunk = false;
675 /* Pick up some settings we need to cache, early */
677 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
680 settings->get_property ("notebook-shrunk", _notebook_shrunk);
683 editor_summary_pane.set_check_divider_position (true);
684 editor_summary_pane.add (edit_packer);
686 Button* summary_arrow_left = manage (new Button);
687 summary_arrow_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
688 summary_arrow_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
689 summary_arrow_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
691 Button* summary_arrow_right = manage (new Button);
692 summary_arrow_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
693 summary_arrow_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
694 summary_arrow_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
696 VBox* summary_arrows_left = manage (new VBox);
697 summary_arrows_left->pack_start (*summary_arrow_left);
699 VBox* summary_arrows_right = manage (new VBox);
700 summary_arrows_right->pack_start (*summary_arrow_right);
702 Frame* summary_frame = manage (new Frame);
703 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
705 summary_frame->add (*_summary);
706 summary_frame->show ();
708 _summary_hbox.pack_start (*summary_arrows_left, false, false);
709 _summary_hbox.pack_start (*summary_frame, true, true);
710 _summary_hbox.pack_start (*summary_arrows_right, false, false);
712 if (!ARDOUR::Profile->get_trx()) {
713 editor_summary_pane.add (_summary_hbox);
716 edit_pane.set_check_divider_position (true);
717 edit_pane.add (editor_summary_pane);
718 if (!ARDOUR::Profile->get_trx()) {
719 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
720 _editor_list_vbox.pack_start (_the_notebook);
721 edit_pane.add (_editor_list_vbox);
722 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
725 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
726 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
729 if (!settings || !settings->get_property ("edit-horizontal-pane-pos", fract) || fract > 1.0) {
730 /* initial allocation is 90% to canvas, 10% to notebook */
733 edit_pane.set_divider (0, fract);
735 if (!settings || !settings->get_property ("edit-vertical-pane-pos", fract) || fract > 1.0) {
736 /* initial allocation is 90% to canvas, 10% to summary */
739 editor_summary_pane.set_divider (0, fract);
741 global_vpacker.set_spacing (0);
742 global_vpacker.set_border_width (0);
744 /* the next three EventBoxes provide the ability for their child widgets to have a background color. That is all. */
746 Gtk::EventBox* ebox = manage (new Gtk::EventBox); // a themeable box
747 ebox->set_name("EditorWindow");
748 ebox->add (ebox_hpacker);
750 Gtk::EventBox* epane_box = manage (new EventBoxExt); // a themeable box
751 epane_box->set_name("EditorWindow");
752 epane_box->add (edit_pane);
754 Gtk::EventBox* epane_box2 = manage (new EventBoxExt); // a themeable box
755 epane_box2->set_name("EditorWindow");
756 epane_box2->add (global_vpacker);
758 ArdourWidgets::ArdourDropShadow *toolbar_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
759 toolbar_shadow->set_size_request (-1, 4);
760 toolbar_shadow->set_mode(ArdourWidgets::ArdourDropShadow::DropShadowBoth);
761 toolbar_shadow->set_name("EditorWindow");
762 toolbar_shadow->show();
764 global_vpacker.pack_start (*toolbar_shadow, false, false);
765 global_vpacker.pack_start (*ebox, false, false);
766 global_vpacker.pack_start (*epane_box, true, true);
767 global_hpacker.pack_start (*epane_box2, true, true);
769 /* need to show the "contents" widget so that notebook will show if tab is switched to
772 global_hpacker.show ();
776 /* register actions now so that set_state() can find them and set toggles/checks etc */
783 _playlist_selector = new PlaylistSelector();
784 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
786 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
790 nudge_forward_button.set_name ("nudge button");
791 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
793 nudge_backward_button.set_name ("nudge button");
794 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
796 fade_context_menu.set_name ("ArdourContextMenu");
798 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
800 /* allow external control surfaces/protocols to do various things */
802 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
803 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
804 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
805 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
806 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
807 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
808 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
809 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
810 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
811 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
812 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
813 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
814 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
815 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
817 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
818 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
819 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
820 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
821 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
823 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
827 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
829 /* problematic: has to return a value and thus cannot be x-thread */
831 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
833 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
834 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
836 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
838 _ignore_region_action = false;
839 _last_region_menu_was_main = false;
840 _popup_region_menu_item = 0;
842 _show_marker_lines = false;
844 /* Button bindings */
846 button_bindings = new Bindings ("editor-mouse");
848 XMLNode* node = button_settings();
850 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
851 button_bindings->load_operation (**i);
857 /* grab current parameter state */
858 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
859 UIConfiguration::instance().map_parameters (pc);
861 setup_fade_images ();
863 set_grid_to (GridTypeNone);
870 delete button_bindings;
872 delete _route_groups;
873 delete _track_canvas_viewport;
876 delete _verbose_cursor;
877 delete quantize_dialog;
883 delete _playlist_selector;
884 delete _time_info_box;
889 LuaInstance::destroy_instance ();
891 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
894 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
897 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
903 Editor::button_settings () const
905 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
906 XMLNode* node = find_named_node (*settings, X_("Buttons"));
909 node = new XMLNode (X_("Buttons"));
916 Editor::get_smart_mode () const
918 return ((current_mouse_mode() == MouseObject) && smart_mode_action->get_active());
922 Editor::catch_vanishing_regionview (RegionView *rv)
924 /* note: the selection will take care of the vanishing
925 audioregionview by itself.
928 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
932 if (clicked_regionview == rv) {
933 clicked_regionview = 0;
936 if (entered_regionview == rv) {
937 set_entered_regionview (0);
940 if (!_all_region_actions_sensitized) {
941 sensitize_all_region_actions (true);
946 Editor::set_entered_regionview (RegionView* rv)
948 if (rv == entered_regionview) {
952 if (entered_regionview) {
953 entered_regionview->exited ();
956 entered_regionview = rv;
958 if (entered_regionview != 0) {
959 entered_regionview->entered ();
962 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
963 /* This RegionView entry might have changed what region actions
964 are allowed, so sensitize them all in case a key is pressed.
966 sensitize_all_region_actions (true);
971 Editor::set_entered_track (TimeAxisView* tav)
974 entered_track->exited ();
980 entered_track->entered ();
985 Editor::instant_save ()
987 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
992 _session->add_instant_xml(get_state());
994 Config->add_instant_xml(get_state());
999 Editor::control_vertical_zoom_in_all ()
1001 tav_zoom_smooth (false, true);
1005 Editor::control_vertical_zoom_out_all ()
1007 tav_zoom_smooth (true, true);
1011 Editor::control_vertical_zoom_in_selected ()
1013 tav_zoom_smooth (false, false);
1017 Editor::control_vertical_zoom_out_selected ()
1019 tav_zoom_smooth (true, false);
1023 Editor::control_view (uint32_t view)
1025 goto_visual_state (view);
1029 Editor::control_unselect ()
1031 selection->clear_tracks ();
1035 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1037 TimeAxisView* tav = time_axis_view_from_stripable (s);
1041 case Selection::Add:
1042 selection->add (tav);
1044 case Selection::Toggle:
1045 selection->toggle (tav);
1047 case Selection::Extend:
1049 case Selection::Set:
1050 selection->set (tav);
1054 selection->clear_tracks ();
1059 Editor::control_step_tracks_up ()
1061 scroll_tracks_up_line ();
1065 Editor::control_step_tracks_down ()
1067 scroll_tracks_down_line ();
1071 Editor::control_scroll (float fraction)
1073 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1079 double step = fraction * current_page_samples();
1082 _control_scroll_target is an optional<T>
1084 it acts like a pointer to an samplepos_t, with
1085 a operator conversion to boolean to check
1086 that it has a value could possibly use
1087 playhead_cursor->current_sample to store the
1088 value and a boolean in the class to know
1089 when it's out of date
1092 if (!_control_scroll_target) {
1093 _control_scroll_target = _session->transport_sample();
1094 _dragging_playhead = true;
1097 if ((fraction < 0.0f) && (*_control_scroll_target <= (samplepos_t) fabs(step))) {
1098 *_control_scroll_target = 0;
1099 } else if ((fraction > 0.0f) && (max_samplepos - *_control_scroll_target < step)) {
1100 *_control_scroll_target = max_samplepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1102 *_control_scroll_target += (samplepos_t) trunc (step);
1105 /* move visuals, we'll catch up with it later */
1107 playhead_cursor->set_position (*_control_scroll_target);
1108 UpdateAllTransportClocks (*_control_scroll_target);
1110 if (*_control_scroll_target > (current_page_samples() / 2)) {
1111 /* try to center PH in window */
1112 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1118 Now we do a timeout to actually bring the session to the right place
1119 according to the playhead. This is to avoid reading disk buffers on every
1120 call to control_scroll, which is driven by ScrollTimeline and therefore
1121 probably by a control surface wheel which can generate lots of events.
1123 /* cancel the existing timeout */
1125 control_scroll_connection.disconnect ();
1127 /* add the next timeout */
1129 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1133 Editor::deferred_control_scroll (samplepos_t /*target*/)
1135 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1136 /* reset for next stream */
1137 _control_scroll_target = boost::none;
1138 _dragging_playhead = false;
1143 Editor::access_action (const std::string& action_group, const std::string& action_item)
1149 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1152 act = ActionManager::get_action (action_group.c_str(), action_item.c_str());
1160 Editor::set_toggleaction (const std::string& action_group, const std::string& action_item, bool s)
1162 ActionManager::set_toggleaction_state (action_group.c_str(), action_item.c_str(), s);
1166 Editor::on_realize ()
1170 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1171 start_lock_event_timing ();
1176 Editor::start_lock_event_timing ()
1178 /* check if we should lock the GUI every 30 seconds */
1180 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1184 Editor::generic_event_handler (GdkEvent* ev)
1187 case GDK_BUTTON_PRESS:
1188 case GDK_BUTTON_RELEASE:
1189 case GDK_MOTION_NOTIFY:
1191 case GDK_KEY_RELEASE:
1192 if (contents().is_mapped()) {
1193 gettimeofday (&last_event_time, 0);
1197 case GDK_LEAVE_NOTIFY:
1198 switch (ev->crossing.detail) {
1199 case GDK_NOTIFY_UNKNOWN:
1200 case GDK_NOTIFY_INFERIOR:
1201 case GDK_NOTIFY_ANCESTOR:
1203 case GDK_NOTIFY_VIRTUAL:
1204 case GDK_NOTIFY_NONLINEAR:
1205 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1206 /* leaving window, so reset focus, thus ending any and
1207 all text entry operations.
1209 ARDOUR_UI::instance()->reset_focus (&contents());
1222 Editor::lock_timeout_callback ()
1224 struct timeval now, delta;
1226 gettimeofday (&now, 0);
1228 timersub (&now, &last_event_time, &delta);
1230 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1232 /* don't call again. Returning false will effectively
1233 disconnect us from the timer callback.
1235 unlock() will call start_lock_event_timing() to get things
1245 Editor::map_position_change (samplepos_t sample)
1247 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, sample)
1249 if (_session == 0) {
1253 if (_follow_playhead) {
1254 center_screen (sample);
1257 playhead_cursor->set_position (sample);
1261 Editor::center_screen (samplepos_t sample)
1263 samplecnt_t const page = _visible_canvas_width * samples_per_pixel;
1265 /* if we're off the page, then scroll.
1268 if (sample < _leftmost_sample || sample >= _leftmost_sample + page) {
1269 center_screen_internal (sample, page);
1274 Editor::center_screen_internal (samplepos_t sample, float page)
1278 if (sample > page) {
1279 sample -= (samplepos_t) page;
1284 reset_x_origin (sample);
1289 Editor::update_title ()
1291 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1293 if (!own_window()) {
1298 bool dirty = _session->dirty();
1300 string session_name;
1302 if (_session->snap_name() != _session->name()) {
1303 session_name = _session->snap_name();
1305 session_name = _session->name();
1309 session_name = "*" + session_name;
1312 WindowTitle title(session_name);
1313 title += S_("Window|Editor");
1314 title += Glib::get_application_name();
1315 own_window()->set_title (title.get_string());
1317 /* ::session_going_away() will have taken care of it */
1322 Editor::set_session (Session *t)
1324 SessionHandlePtr::set_session (t);
1330 /* initialize _leftmost_sample to the extents of the session
1331 * this prevents a bogus setting of leftmost = "0" if the summary view asks for the leftmost sample
1332 * before the visible state has been loaded from instant.xml */
1333 _leftmost_sample = session_gui_extents().first;
1335 _playlist_selector->set_session (_session);
1336 nudge_clock->set_session (_session);
1337 _summary->set_session (_session);
1338 _group_tabs->set_session (_session);
1339 _route_groups->set_session (_session);
1340 _regions->set_session (_session);
1341 _snapshots->set_session (_session);
1342 _routes->set_session (_session);
1343 _locations->set_session (_session);
1344 _time_info_box->set_session (_session);
1346 if (rhythm_ferret) {
1347 rhythm_ferret->set_session (_session);
1350 if (analysis_window) {
1351 analysis_window->set_session (_session);
1355 sfbrowser->set_session (_session);
1358 compute_fixed_ruler_scale ();
1360 /* Make sure we have auto loop and auto punch ranges */
1362 Location* loc = _session->locations()->auto_loop_location();
1364 loc->set_name (_("Loop"));
1367 loc = _session->locations()->auto_punch_location();
1370 loc->set_name (_("Punch"));
1373 refresh_location_display ();
1375 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1376 * the selected Marker; this needs the LocationMarker list to be available.
1378 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1379 set_state (*node, Stateful::loading_state_version);
1381 /* catch up on selection state, etc. */
1384 sc.add (Properties::selected);
1385 presentation_info_changed (sc);
1387 /* catch up with the playhead */
1389 _session->request_locate (playhead_cursor->current_sample ());
1390 _pending_initial_locate = true;
1394 /* These signals can all be emitted by a non-GUI thread. Therefore the
1395 handlers for them must not attempt to directly interact with the GUI,
1396 but use PBD::Signal<T>::connect() which accepts an event loop
1397 ("context") where the handler will be asked to run.
1400 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1401 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1402 _session->TransportLooped.connect (_session_connections, invalidator (*this), boost::bind (&Editor::transport_looped, this), gui_context());
1403 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1404 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1405 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1406 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1407 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1408 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1409 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1410 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1411 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1412 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1413 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1414 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1415 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1417 playhead_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1418 playhead_cursor->show ();
1420 snapped_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1421 snapped_cursor->set_color (UIConfiguration::instance().color ("edit point"));
1422 snapped_cursor->show ();
1424 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1425 Config->map_parameters (pc);
1426 _session->config.map_parameters (pc);
1428 restore_ruler_visibility ();
1429 //tempo_map_changed (PropertyChange (0));
1430 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1432 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1433 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1436 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1437 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1440 /* register for undo history */
1441 _session->register_with_memento_command_factory(id(), this);
1442 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1444 LuaInstance::instance()->set_session(_session);
1446 start_updating_meters ();
1450 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1452 using namespace Menu_Helpers;
1454 void (Editor::*emf)(FadeShape);
1455 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1458 images = &_xfade_in_images;
1459 emf = &Editor::set_fade_in_shape;
1461 images = &_xfade_out_images;
1462 emf = &Editor::set_fade_out_shape;
1467 _("Linear (for highly correlated material)"),
1468 *(*images)[FadeLinear],
1469 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1473 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1477 _("Constant power"),
1478 *(*images)[FadeConstantPower],
1479 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1482 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1487 *(*images)[FadeSymmetric],
1488 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1492 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1497 *(*images)[FadeSlow],
1498 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1501 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1506 *(*images)[FadeFast],
1507 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1510 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1513 /** Pop up a context menu for when the user clicks on a start crossfade */
1515 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1517 using namespace Menu_Helpers;
1518 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1523 MenuList& items (xfade_in_context_menu.items());
1526 if (arv->audio_region()->fade_in_active()) {
1527 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1529 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1532 items.push_back (SeparatorElem());
1533 fill_xfade_menu (items, true);
1535 xfade_in_context_menu.popup (button, time);
1538 /** Pop up a context menu for when the user clicks on an end crossfade */
1540 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1542 using namespace Menu_Helpers;
1543 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1548 MenuList& items (xfade_out_context_menu.items());
1551 if (arv->audio_region()->fade_out_active()) {
1552 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1554 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1557 items.push_back (SeparatorElem());
1558 fill_xfade_menu (items, false);
1560 xfade_out_context_menu.popup (button, time);
1564 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1566 using namespace Menu_Helpers;
1567 Menu* (Editor::*build_menu_function)();
1570 switch (item_type) {
1572 case RegionViewName:
1573 case RegionViewNameHighlight:
1574 case LeftFrameHandle:
1575 case RightFrameHandle:
1576 if (with_selection) {
1577 build_menu_function = &Editor::build_track_selection_context_menu;
1579 build_menu_function = &Editor::build_track_region_context_menu;
1584 if (with_selection) {
1585 build_menu_function = &Editor::build_track_selection_context_menu;
1587 build_menu_function = &Editor::build_track_context_menu;
1592 if (clicked_routeview->track()) {
1593 build_menu_function = &Editor::build_track_context_menu;
1595 build_menu_function = &Editor::build_track_bus_context_menu;
1600 /* probably shouldn't happen but if it does, we don't care */
1604 menu = (this->*build_menu_function)();
1605 menu->set_name ("ArdourContextMenu");
1607 /* now handle specific situations */
1609 switch (item_type) {
1611 case RegionViewName:
1612 case RegionViewNameHighlight:
1613 case LeftFrameHandle:
1614 case RightFrameHandle:
1615 if (!with_selection) {
1616 if (region_edit_menu_split_item) {
1617 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1618 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1620 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1623 if (region_edit_menu_split_multichannel_item) {
1624 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1625 region_edit_menu_split_multichannel_item->set_sensitive (true);
1627 region_edit_menu_split_multichannel_item->set_sensitive (false);
1640 /* probably shouldn't happen but if it does, we don't care */
1644 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1646 /* Bounce to disk */
1648 using namespace Menu_Helpers;
1649 MenuList& edit_items = menu->items();
1651 edit_items.push_back (SeparatorElem());
1653 switch (clicked_routeview->audio_track()->freeze_state()) {
1654 case AudioTrack::NoFreeze:
1655 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1658 case AudioTrack::Frozen:
1659 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1662 case AudioTrack::UnFrozen:
1663 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1669 if (item_type == StreamItem && clicked_routeview) {
1670 clicked_routeview->build_underlay_menu(menu);
1673 /* When the region menu is opened, we setup the actions so that they look right
1676 sensitize_the_right_region_actions (false);
1677 _last_region_menu_was_main = false;
1679 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1680 menu->popup (button, time);
1684 Editor::build_track_context_menu ()
1686 using namespace Menu_Helpers;
1688 MenuList& edit_items = track_context_menu.items();
1691 add_dstream_context_items (edit_items);
1692 return &track_context_menu;
1696 Editor::build_track_bus_context_menu ()
1698 using namespace Menu_Helpers;
1700 MenuList& edit_items = track_context_menu.items();
1703 add_bus_context_items (edit_items);
1704 return &track_context_menu;
1708 Editor::build_track_region_context_menu ()
1710 using namespace Menu_Helpers;
1711 MenuList& edit_items = track_region_context_menu.items();
1714 /* we've just cleared the track region context menu, so the menu that these
1715 two items were on will have disappeared; stop them dangling.
1717 region_edit_menu_split_item = 0;
1718 region_edit_menu_split_multichannel_item = 0;
1720 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1723 boost::shared_ptr<Track> tr;
1724 boost::shared_ptr<Playlist> pl;
1726 if ((tr = rtv->track())) {
1727 add_region_context_items (edit_items, tr);
1731 add_dstream_context_items (edit_items);
1733 return &track_region_context_menu;
1737 Editor::loudness_analyze_region_selection ()
1742 Selection& s (PublicEditor::instance ().get_selection ());
1743 RegionSelection ars = s.regions;
1744 ARDOUR::AnalysisGraph ag (_session);
1745 samplecnt_t total_work = 0;
1747 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1748 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1752 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1755 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1756 total_work += arv->region ()->length ();
1759 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1761 ag.set_total_samples (total_work);
1762 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1765 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1766 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1770 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1774 ag.analyze_region (ar);
1777 if (!ag.canceled ()) {
1778 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1784 Editor::loudness_analyze_range_selection ()
1789 Selection& s (PublicEditor::instance ().get_selection ());
1790 TimeSelection ts = s.time;
1791 ARDOUR::AnalysisGraph ag (_session);
1792 samplecnt_t total_work = 0;
1794 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1795 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1799 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1803 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1804 total_work += j->length ();
1808 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1810 ag.set_total_samples (total_work);
1811 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1814 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1815 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1819 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1823 ag.analyze_range (rui->route (), pl, ts);
1826 if (!ag.canceled ()) {
1827 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1833 Editor::spectral_analyze_region_selection ()
1835 if (analysis_window == 0) {
1836 analysis_window = new AnalysisWindow();
1839 analysis_window->set_session(_session);
1841 analysis_window->show_all();
1844 analysis_window->set_regionmode();
1845 analysis_window->analyze();
1847 analysis_window->present();
1851 Editor::spectral_analyze_range_selection()
1853 if (analysis_window == 0) {
1854 analysis_window = new AnalysisWindow();
1857 analysis_window->set_session(_session);
1859 analysis_window->show_all();
1862 analysis_window->set_rangemode();
1863 analysis_window->analyze();
1865 analysis_window->present();
1869 Editor::build_track_selection_context_menu ()
1871 using namespace Menu_Helpers;
1872 MenuList& edit_items = track_selection_context_menu.items();
1873 edit_items.clear ();
1875 add_selection_context_items (edit_items);
1876 // edit_items.push_back (SeparatorElem());
1877 // add_dstream_context_items (edit_items);
1879 return &track_selection_context_menu;
1883 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1885 using namespace Menu_Helpers;
1887 /* OK, stick the region submenu at the top of the list, and then add
1891 RegionSelection rs = get_regions_from_selection_and_entered ();
1893 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1895 if (_popup_region_menu_item == 0) {
1896 _popup_region_menu_item = new MenuItem (menu_item_name, false);
1897 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1898 _popup_region_menu_item->show ();
1900 _popup_region_menu_item->set_label (menu_item_name);
1903 /* No layering allowed in later is higher layering model */
1904 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1905 if (act && Config->get_layer_model() == LaterHigher) {
1906 act->set_sensitive (false);
1908 act->set_sensitive (true);
1911 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1913 edit_items.push_back (*_popup_region_menu_item);
1914 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1915 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1917 edit_items.push_back (SeparatorElem());
1920 /** Add context menu items relevant to selection ranges.
1921 * @param edit_items List to add the items to.
1924 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1926 using namespace Menu_Helpers;
1928 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1929 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1931 edit_items.push_back (SeparatorElem());
1932 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1934 edit_items.push_back (SeparatorElem());
1935 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1936 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1938 edit_items.push_back (SeparatorElem());
1940 edit_items.push_back (
1942 _("Move Range Start to Previous Region Boundary"),
1943 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1947 edit_items.push_back (
1949 _("Move Range Start to Next Region Boundary"),
1950 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1954 edit_items.push_back (
1956 _("Move Range End to Previous Region Boundary"),
1957 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1961 edit_items.push_back (
1963 _("Move Range End to Next Region Boundary"),
1964 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1968 edit_items.push_back (SeparatorElem());
1969 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1970 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1972 edit_items.push_back (SeparatorElem());
1973 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1975 edit_items.push_back (SeparatorElem());
1976 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1977 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1978 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1980 edit_items.push_back (SeparatorElem());
1981 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1983 edit_items.push_back (SeparatorElem());
1984 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1985 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1987 edit_items.push_back (SeparatorElem());
1988 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1989 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1990 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1991 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1992 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1993 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1994 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2000 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2002 using namespace Menu_Helpers;
2006 Menu *play_menu = manage (new Menu);
2007 MenuList& play_items = play_menu->items();
2008 play_menu->set_name ("ArdourContextMenu");
2010 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2011 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2012 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2013 play_items.push_back (SeparatorElem());
2014 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2016 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2020 Menu *select_menu = manage (new Menu);
2021 MenuList& select_items = select_menu->items();
2022 select_menu->set_name ("ArdourContextMenu");
2024 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2025 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2026 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2027 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2028 select_items.push_back (SeparatorElem());
2029 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2030 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2031 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2032 select_items.push_back (SeparatorElem());
2033 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2034 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2035 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2036 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2037 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2038 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2039 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2041 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2045 Menu *cutnpaste_menu = manage (new Menu);
2046 MenuList& cutnpaste_items = cutnpaste_menu->items();
2047 cutnpaste_menu->set_name ("ArdourContextMenu");
2049 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2050 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2051 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2053 cutnpaste_items.push_back (SeparatorElem());
2055 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2056 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2058 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2060 /* Adding new material */
2062 edit_items.push_back (SeparatorElem());
2063 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2064 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2068 Menu *nudge_menu = manage (new Menu());
2069 MenuList& nudge_items = nudge_menu->items();
2070 nudge_menu->set_name ("ArdourContextMenu");
2072 edit_items.push_back (SeparatorElem());
2073 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2074 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2075 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2076 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2078 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2082 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2084 using namespace Menu_Helpers;
2088 Menu *play_menu = manage (new Menu);
2089 MenuList& play_items = play_menu->items();
2090 play_menu->set_name ("ArdourContextMenu");
2092 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2093 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2094 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2098 Menu *select_menu = manage (new Menu);
2099 MenuList& select_items = select_menu->items();
2100 select_menu->set_name ("ArdourContextMenu");
2102 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2103 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2104 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2105 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2106 select_items.push_back (SeparatorElem());
2107 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2108 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2109 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2110 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2112 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2116 Menu *cutnpaste_menu = manage (new Menu);
2117 MenuList& cutnpaste_items = cutnpaste_menu->items();
2118 cutnpaste_menu->set_name ("ArdourContextMenu");
2120 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2121 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2122 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2124 Menu *nudge_menu = manage (new Menu());
2125 MenuList& nudge_items = nudge_menu->items();
2126 nudge_menu->set_name ("ArdourContextMenu");
2128 edit_items.push_back (SeparatorElem());
2129 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2130 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2131 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2132 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2134 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2138 Editor::grid_type() const
2144 Editor::grid_musical() const
2146 switch (_grid_type) {
2147 case GridTypeBeatDiv32:
2148 case GridTypeBeatDiv28:
2149 case GridTypeBeatDiv24:
2150 case GridTypeBeatDiv20:
2151 case GridTypeBeatDiv16:
2152 case GridTypeBeatDiv14:
2153 case GridTypeBeatDiv12:
2154 case GridTypeBeatDiv10:
2155 case GridTypeBeatDiv8:
2156 case GridTypeBeatDiv7:
2157 case GridTypeBeatDiv6:
2158 case GridTypeBeatDiv5:
2159 case GridTypeBeatDiv4:
2160 case GridTypeBeatDiv3:
2161 case GridTypeBeatDiv2:
2166 case GridTypeTimecode:
2167 case GridTypeMinSec:
2168 case GridTypeCDFrame:
2175 Editor::grid_nonmusical() const
2177 switch (_grid_type) {
2178 case GridTypeTimecode:
2179 case GridTypeMinSec:
2180 case GridTypeCDFrame:
2182 case GridTypeBeatDiv32:
2183 case GridTypeBeatDiv28:
2184 case GridTypeBeatDiv24:
2185 case GridTypeBeatDiv20:
2186 case GridTypeBeatDiv16:
2187 case GridTypeBeatDiv14:
2188 case GridTypeBeatDiv12:
2189 case GridTypeBeatDiv10:
2190 case GridTypeBeatDiv8:
2191 case GridTypeBeatDiv7:
2192 case GridTypeBeatDiv6:
2193 case GridTypeBeatDiv5:
2194 case GridTypeBeatDiv4:
2195 case GridTypeBeatDiv3:
2196 case GridTypeBeatDiv2:
2205 Editor::snap_mode() const
2211 Editor::show_rulers_for_grid ()
2213 /* show appropriate rulers for this grid setting. */
2214 if (grid_musical()) {
2215 ruler_tempo_action->set_active(true);
2216 ruler_meter_action->set_active(true);
2217 ruler_bbt_action->set_active(true);
2219 if (UIConfiguration::instance().get_rulers_follow_grid()) {
2220 ruler_timecode_action->set_active(false);
2221 ruler_minsec_action->set_active(false);
2222 ruler_samples_action->set_active(false);
2224 } else if (_grid_type == GridTypeTimecode) {
2225 ruler_timecode_action->set_active(true);
2227 if (UIConfiguration::instance().get_rulers_follow_grid()) {
2228 ruler_tempo_action->set_active(false);
2229 ruler_meter_action->set_active(false);
2230 ruler_bbt_action->set_active(false);
2231 ruler_minsec_action->set_active(false);
2232 ruler_samples_action->set_active(false);
2234 } else if (_grid_type == GridTypeMinSec) {
2235 ruler_minsec_action->set_active(true);
2237 if (UIConfiguration::instance().get_rulers_follow_grid()) {
2238 ruler_tempo_action->set_active(false);
2239 ruler_meter_action->set_active(false);
2240 ruler_bbt_action->set_active(false);
2241 ruler_timecode_action->set_active(false);
2242 ruler_samples_action->set_active(false);
2244 } else if (_grid_type == GridTypeCDFrame) {
2245 ruler_cd_marker_action->set_active(true);
2246 ruler_minsec_action->set_active(true);
2248 if (UIConfiguration::instance().get_rulers_follow_grid()) {
2249 ruler_tempo_action->set_active(false);
2250 ruler_meter_action->set_active(false);
2251 ruler_bbt_action->set_active(false);
2252 ruler_timecode_action->set_active(false);
2253 ruler_samples_action->set_active(false);
2259 Editor::set_grid_to (GridType gt)
2261 if (_grid_type == gt) { // already set
2265 unsigned int grid_ind = (unsigned int)gt;
2267 if (internal_editing() && UIConfiguration::instance().get_grid_follows_internal()) {
2268 internal_grid_type = gt;
2270 pre_internal_grid_type = gt;
2275 if (grid_ind > grid_type_strings.size() - 1) {
2277 _grid_type = (GridType)grid_ind;
2280 string str = grid_type_strings[grid_ind];
2282 if (str != grid_type_selector.get_text()) {
2283 grid_type_selector.set_text (str);
2286 if (UIConfiguration::instance().get_show_grids_ruler()) {
2287 show_rulers_for_grid ();
2292 if (grid_musical()) {
2293 compute_bbt_ruler_scale (_leftmost_sample, _leftmost_sample + current_page_samples());
2294 update_tempo_based_rulers ();
2297 mark_region_boundary_cache_dirty ();
2299 redisplay_grid (false);
2301 SnapChanged (); /* EMIT SIGNAL */
2305 Editor::set_snap_mode (SnapMode mode)
2307 if (internal_editing()) {
2308 internal_snap_mode = mode;
2310 pre_internal_snap_mode = mode;
2315 if (_snap_mode == SnapOff) {
2316 snap_mode_button.set_active_state (Gtkmm2ext::Off);
2318 snap_mode_button.set_active_state (Gtkmm2ext::ExplicitActive);
2325 Editor::set_edit_point_preference (EditPoint ep, bool force)
2327 bool changed = (_edit_point != ep);
2330 if (Profile->get_mixbus())
2331 if (ep == EditAtSelectedMarker)
2332 ep = EditAtPlayhead;
2334 string str = edit_point_strings[(int)ep];
2335 if (str != edit_point_selector.get_text ()) {
2336 edit_point_selector.set_text (str);
2339 update_all_enter_cursors();
2341 if (!force && !changed) {
2345 const char* action=NULL;
2347 switch (_edit_point) {
2348 case EditAtPlayhead:
2349 action = "edit-at-playhead";
2351 case EditAtSelectedMarker:
2352 action = "edit-at-marker";
2355 action = "edit-at-mouse";
2359 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2361 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2365 bool in_track_canvas;
2367 if (!mouse_sample (foo, in_track_canvas)) {
2368 in_track_canvas = false;
2371 reset_canvas_action_sensitivity (in_track_canvas);
2372 sensitize_the_right_region_actions (false);
2378 Editor::set_state (const XMLNode& node, int version)
2381 PBD::Unwinder<bool> nsi (no_save_instant, true);
2384 Tabbable::set_state (node, version);
2387 if (_session && node.get_property ("playhead", ph_pos)) {
2389 playhead_cursor->set_position (ph_pos);
2391 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2392 playhead_cursor->set_position (0);
2395 playhead_cursor->set_position (0);
2398 node.get_property ("mixer-width", editor_mixer_strip_width);
2400 node.get_property ("zoom-focus", zoom_focus);
2401 zoom_focus_selection_done (zoom_focus);
2404 if (node.get_property ("zoom", z)) {
2405 /* older versions of ardour used floating point samples_per_pixel */
2406 reset_zoom (llrintf (z));
2408 reset_zoom (samples_per_pixel);
2412 if (node.get_property ("visible-track-count", cnt)) {
2413 set_visible_track_count (cnt);
2417 if (!node.get_property ("grid-type", grid_type)) {
2418 grid_type = _grid_type;
2420 set_grid_to (grid_type);
2423 if (node.get_property ("snap-mode", sm)) {
2424 snap_mode_selection_done(sm);
2425 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2426 * snap_mode_selection_done() will only mark an already active item as active
2427 * which does not trigger set_text().
2431 set_snap_mode (_snap_mode);
2434 node.get_property ("internal-grid-type", internal_grid_type);
2435 node.get_property ("internal-snap-mode", internal_snap_mode);
2436 node.get_property ("pre-internal-grid-type", pre_internal_grid_type);
2437 node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2440 if (node.get_property ("mouse-mode", mm_str)) {
2441 MouseMode m = str2mousemode(mm_str);
2442 set_mouse_mode (m, true);
2444 set_mouse_mode (MouseObject, true);
2448 if (node.get_property ("left-frame", lf_pos)) {
2452 reset_x_origin (lf_pos);
2456 if (node.get_property ("y-origin", y_origin)) {
2457 reset_y_origin (y_origin);
2460 if (node.get_property ("join-object-range", yn)) {
2461 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2463 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2464 tact->set_active (!yn);
2465 tact->set_active (yn);
2467 set_mouse_mode(mouse_mode, true);
2471 if (node.get_property ("edit-point", ep)) {
2472 set_edit_point_preference (ep, true);
2474 set_edit_point_preference (_edit_point);
2477 if (node.get_property ("follow-playhead", yn)) {
2478 set_follow_playhead (yn);
2481 if (node.get_property ("stationary-playhead", yn)) {
2482 set_stationary_playhead (yn);
2485 RegionListSortType sort_type;
2486 if (node.get_property ("region-list-sort-type", sort_type)) {
2487 _regions->reset_sort_type (sort_type, true);
2490 if (node.get_property ("show-editor-mixer", yn)) {
2492 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2495 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2497 /* do it twice to force the change */
2499 tact->set_active (!yn);
2500 tact->set_active (yn);
2503 if (node.get_property ("show-editor-list", yn)) {
2505 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2508 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2510 /* do it twice to force the change */
2512 tact->set_active (!yn);
2513 tact->set_active (yn);
2517 if (node.get_property (X_("editor-list-page"), el_page)) {
2518 _the_notebook.set_current_page (el_page);
2521 if (node.get_property (X_("show-marker-lines"), yn)) {
2522 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2524 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2526 tact->set_active (!yn);
2527 tact->set_active (yn);
2530 XMLNodeList children = node.children ();
2531 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2532 selection->set_state (**i, Stateful::current_state_version);
2533 _regions->set_state (**i);
2534 _locations->set_state (**i);
2537 if (node.get_property ("maximised", yn)) {
2538 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2540 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2541 bool fs = tact && tact->get_active();
2543 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2547 samplepos_t nudge_clock_value;
2548 if (node.get_property ("nudge-clock-value", nudge_clock_value)) {
2549 nudge_clock->set (nudge_clock_value);
2551 nudge_clock->set_mode (AudioClock::Timecode);
2552 nudge_clock->set (_session->sample_rate() * 5, true);
2557 * Not all properties may have been in XML, but
2558 * those that are linked to a private variable may need changing
2562 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2563 yn = _follow_playhead;
2565 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2566 if (tact->get_active() != yn) {
2567 tact->set_active (yn);
2571 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2572 yn = _stationary_playhead;
2574 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2575 if (tact->get_active() != yn) {
2576 tact->set_active (yn);
2581 return LuaInstance::instance()->set_state(node);
2585 Editor::get_state ()
2587 XMLNode* node = new XMLNode (X_("Editor"));
2589 node->set_property ("id", id().to_s ());
2591 node->add_child_nocopy (Tabbable::get_state());
2593 node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ());
2594 node->set_property("notebook-shrunk", _notebook_shrunk);
2595 node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider());
2597 maybe_add_mixer_strip_width (*node);
2599 node->set_property ("zoom-focus", zoom_focus);
2601 node->set_property ("zoom", samples_per_pixel);
2602 node->set_property ("grid-type", _grid_type);
2603 node->set_property ("snap-mode", _snap_mode);
2604 node->set_property ("internal-grid-type", internal_grid_type);
2605 node->set_property ("internal-snap-mode", internal_snap_mode);
2606 node->set_property ("pre-internal-grid-type", pre_internal_grid_type);
2607 node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2608 node->set_property ("edit-point", _edit_point);
2609 node->set_property ("visible-track-count", _visible_track_count);
2611 node->set_property ("playhead", playhead_cursor->current_sample ());
2612 node->set_property ("left-frame", _leftmost_sample);
2613 node->set_property ("y-origin", vertical_adjustment.get_value ());
2615 node->set_property ("maximised", _maximised);
2616 node->set_property ("follow-playhead", _follow_playhead);
2617 node->set_property ("stationary-playhead", _stationary_playhead);
2618 node->set_property ("region-list-sort-type", _regions->sort_type ());
2619 node->set_property ("mouse-mode", mouse_mode);
2620 node->set_property ("join-object-range", smart_mode_action->get_active ());
2622 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2624 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2625 node->set_property (X_("show-editor-mixer"), tact->get_active());
2628 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2630 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2631 node->set_property (X_("show-editor-list"), tact->get_active());
2634 node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
2636 if (button_bindings) {
2637 XMLNode* bb = new XMLNode (X_("Buttons"));
2638 button_bindings->save (*bb);
2639 node->add_child_nocopy (*bb);
2642 node->set_property (X_("show-marker-lines"), _show_marker_lines);
2644 node->add_child_nocopy (selection->get_state ());
2645 node->add_child_nocopy (_regions->get_state ());
2647 node->set_property ("nudge-clock-value", nudge_clock->current_duration());
2649 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2650 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2651 node->add_child_nocopy (_locations->get_state ());
2656 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2657 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2659 * @return pair: TimeAxisView that y is over, layer index.
2661 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2662 * in stacked or expanded region display mode, otherwise 0.
2664 std::pair<TimeAxisView *, double>
2665 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2667 if (!trackview_relative_offset) {
2668 y -= _trackview_group->canvas_origin().y;
2672 return std::make_pair ((TimeAxisView *) 0, 0);
2675 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2677 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2684 return std::make_pair ((TimeAxisView *) 0, 0);
2688 Editor::set_snapped_cursor_position (samplepos_t pos)
2690 if (_edit_point == EditAtMouse) {
2691 snapped_cursor->set_position(pos);
2696 /** Snap a position to the grid, if appropriate, taking into account current
2697 * grid settings and also the state of any snap modifier keys that may be pressed.
2698 * @param start Position to snap.
2699 * @param event Event to get current key modifier information from, or 0.
2702 Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, RoundMode direction, SnapPref pref)
2704 if (!_session || !event) {
2708 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2709 if (_snap_mode == SnapOff) {
2710 snap_to_internal (start, direction, pref);
2712 start.set (start.sample, 0);
2715 if (_snap_mode != SnapOff) {
2716 snap_to_internal (start, direction, pref);
2717 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2718 /* SnapOff, but we pressed the snap_delta modifier */
2719 snap_to_internal (start, direction, pref);
2721 start.set (start.sample, 0);
2727 Editor::snap_to (MusicSample& start, RoundMode direction, SnapPref pref, bool ensure_snap)
2729 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2730 start.set (start.sample, 0);
2734 snap_to_internal (start, direction, pref, ensure_snap);
2738 check_best_snap (samplepos_t presnap, samplepos_t &test, samplepos_t &dist, samplepos_t &best)
2740 samplepos_t diff = abs (test - presnap);
2746 test = max_samplepos; // reset this so it doesn't get accidentally reused
2750 Editor::snap_to_timecode (MusicSample presnap, RoundMode direction, SnapPref gpref)
2752 samplepos_t start = presnap.sample;
2753 const samplepos_t one_timecode_second = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2754 samplepos_t one_timecode_minute = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2756 TimecodeRulerScale scale = (gpref != SnapToGrid_Unscaled) ? timecode_ruler_scale : timecode_show_samples;
2759 case timecode_show_bits:
2760 case timecode_show_samples:
2761 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2762 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2763 /* start is already on a whole timecode frame, do nothing */
2764 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2765 start = (samplepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2767 start = (samplepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2771 case timecode_show_seconds:
2772 if (_session->config.get_timecode_offset_negative()) {
2773 start += _session->config.get_timecode_offset ();
2775 start -= _session->config.get_timecode_offset ();
2777 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2778 (start % one_timecode_second == 0)) {
2779 /* start is already on a whole second, do nothing */
2780 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2781 start = (samplepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2783 start = (samplepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2786 if (_session->config.get_timecode_offset_negative()) {
2787 start -= _session->config.get_timecode_offset ();
2789 start += _session->config.get_timecode_offset ();
2793 case timecode_show_minutes:
2794 case timecode_show_hours:
2795 case timecode_show_many_hours:
2796 if (_session->config.get_timecode_offset_negative()) {
2797 start += _session->config.get_timecode_offset ();
2799 start -= _session->config.get_timecode_offset ();
2801 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2802 (start % one_timecode_minute == 0)) {
2803 /* start is already on a whole minute, do nothing */
2804 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2805 start = (samplepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2807 start = (samplepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2809 if (_session->config.get_timecode_offset_negative()) {
2810 start -= _session->config.get_timecode_offset ();
2812 start += _session->config.get_timecode_offset ();
2816 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2819 MusicSample ret(start,0);
2824 Editor::snap_to_minsec (MusicSample presnap, RoundMode direction, SnapPref gpref)
2826 MusicSample ret(presnap);
2828 const samplepos_t one_second = _session->sample_rate();
2829 const samplepos_t one_minute = one_second * 60;
2830 const samplepos_t one_hour = one_minute * 60;
2832 MinsecRulerScale scale = (gpref != SnapToGrid_Unscaled) ? minsec_ruler_scale : minsec_show_seconds;
2835 case minsec_show_msecs:
2836 case minsec_show_seconds: {
2837 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2838 presnap.sample % one_second == 0) {
2839 /* start is already on a whole second, do nothing */
2840 } else if (((direction == 0) && (presnap.sample % one_second > one_second / 2)) || (direction > 0)) {
2841 ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_second) * one_second;
2843 ret.sample = (samplepos_t) floor ((double) presnap.sample / one_second) * one_second;
2847 case minsec_show_minutes: {
2848 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2849 presnap.sample % one_minute == 0) {
2850 /* start is already on a whole minute, do nothing */
2851 } else if (((direction == 0) && (presnap.sample % one_minute > one_minute / 2)) || (direction > 0)) {
2852 ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_minute) * one_minute;
2854 ret.sample = (samplepos_t) floor ((double) presnap.sample / one_minute) * one_minute;
2859 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2860 presnap.sample % one_hour == 0) {
2861 /* start is already on a whole hour, do nothing */
2862 } else if (((direction == 0) && (presnap.sample % one_hour > one_hour / 2)) || (direction > 0)) {
2863 ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_hour) * one_hour;
2865 ret.sample = (samplepos_t) floor ((double) presnap.sample / one_hour) * one_hour;
2874 Editor::snap_to_cd_frames (MusicSample presnap, RoundMode direction, SnapPref gpref)
2876 if ((gpref != SnapToGrid_Unscaled) && (minsec_ruler_scale != minsec_show_msecs)) {
2877 return snap_to_minsec (presnap, direction, gpref);
2880 const samplepos_t one_second = _session->sample_rate();
2882 MusicSample ret(presnap);
2884 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2885 presnap.sample % (one_second/75) == 0) {
2886 /* start is already on a whole CD sample, do nothing */
2887 } else if (((direction == 0) && (presnap.sample % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2888 ret.sample = (samplepos_t) ceil ((double) presnap.sample / (one_second / 75)) * (one_second / 75);
2890 ret.sample = (samplepos_t) floor ((double) presnap.sample / (one_second / 75)) * (one_second / 75);
2897 Editor::snap_to_bbt (MusicSample presnap, RoundMode direction, SnapPref gpref)
2899 MusicSample ret(presnap);
2901 if (gpref != SnapToGrid_Unscaled) { // use the visual grid lines which are limited by the zoom scale that the user selected
2904 switch (_grid_type) {
2905 case GridTypeBeatDiv3:
2906 case GridTypeBeatDiv6:
2907 case GridTypeBeatDiv12:
2908 case GridTypeBeatDiv24:
2911 case GridTypeBeatDiv5:
2912 case GridTypeBeatDiv10:
2913 case GridTypeBeatDiv20:
2916 case GridTypeBeatDiv7:
2917 case GridTypeBeatDiv14:
2918 case GridTypeBeatDiv28:
2925 BBTRulerScale scale = bbt_ruler_scale;
2932 ret = _session->tempo_map().round_to_bar (presnap.sample, direction);
2934 case bbt_show_quarters:
2935 ret = _session->tempo_map().round_to_beat (presnap.sample, direction);
2937 case bbt_show_eighths:
2938 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 1 * divisor, direction);
2940 case bbt_show_sixteenths:
2941 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 2 * divisor, direction);
2943 case bbt_show_thirtyseconds:
2944 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 4 * divisor, direction);
2948 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, get_grid_beat_divisions(_grid_type), direction);
2955 Editor::snap_to_grid (MusicSample presnap, RoundMode direction, SnapPref gpref)
2957 MusicSample ret(presnap);
2959 if (grid_musical()) {
2960 ret = snap_to_bbt (presnap, direction, gpref);
2963 switch (_grid_type) {
2964 case GridTypeTimecode:
2965 ret = snap_to_timecode(presnap, direction, gpref);
2967 case GridTypeMinSec:
2968 ret = snap_to_minsec(presnap, direction, gpref);
2970 case GridTypeCDFrame:
2971 ret = snap_to_cd_frames(presnap, direction, gpref);
2981 Editor::snap_to_marker (samplepos_t presnap, RoundMode direction)
2987 _session->locations()->marks_either_side (presnap, before, after);
2989 if (before == max_samplepos && after == max_samplepos) {
2990 /* No marks to snap to, so just don't snap */
2992 } else if (before == max_samplepos) {
2994 } else if (after == max_samplepos) {
2997 if ((direction == RoundUpMaybe || direction == RoundUpAlways)) {
2999 } else if ((direction == RoundDownMaybe || direction == RoundDownAlways)) {
3001 } else if (direction == 0) {
3002 if ((presnap - before) < (after - presnap)) {
3014 Editor::snap_to_internal (MusicSample& start, RoundMode direction, SnapPref pref, bool ensure_snap)
3016 const samplepos_t presnap = start.sample;
3018 samplepos_t test = max_samplepos; // for each snap, we'll use this value
3019 samplepos_t dist = max_samplepos; // this records the distance of the best snap result we've found so far
3020 samplepos_t best = max_samplepos; // this records the best snap-result we've found so far
3022 /* check snap-to-marker */
3023 if ((pref == SnapToAny_Visual) && UIConfiguration::instance().get_snap_to_marks()) {
3024 test = snap_to_marker (presnap, direction);
3025 check_best_snap(presnap, test, dist, best);
3028 /* check snap-to-region-{start/end/sync} */
3030 (pref == SnapToAny_Visual) &&
3031 (UIConfiguration::instance().get_snap_to_region_start() || UIConfiguration::instance().get_snap_to_region_end() || UIConfiguration::instance().get_snap_to_region_sync())
3033 if (!region_boundary_cache.empty()) {
3035 vector<samplepos_t>::iterator prev = region_boundary_cache.begin();
3036 vector<samplepos_t>::iterator next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
3037 if (next != region_boundary_cache.begin ()) {
3042 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
3044 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
3046 else if (direction == 0) {
3047 if ((presnap - *prev) < (*next - presnap)) {
3056 check_best_snap(presnap, test, dist, best);
3060 if (UIConfiguration::instance().get_snap_to_grid() && (_grid_type != GridTypeNone)) {
3061 MusicSample pre(presnap, 0);
3062 MusicSample post = snap_to_grid (pre, direction, pref);
3063 check_best_snap(presnap, post.sample, dist, best);
3066 /* now check "magnetic" state: is the grid within reasonable on-screen distance to trigger a snap?
3067 * this also helps to avoid snapping to somewhere the user can't see. (i.e.: I clicked on a region and it disappeared!!)
3068 * ToDo: Perhaps this should only occur if EditPointMouse?
3070 int snap_threshold_s = pixel_to_sample(UIConfiguration::instance().get_snap_threshold());
3072 start.set (best, 0);
3074 } else if (presnap > best) {
3075 if (presnap > (best+ snap_threshold_s)) {
3078 } else if (presnap < best) {
3079 if (presnap < (best - snap_threshold_s)) {
3084 start.set (best, 0);
3089 Editor::setup_toolbar ()
3091 HBox* mode_box = manage(new HBox);
3092 mode_box->set_border_width (2);
3093 mode_box->set_spacing(2);
3095 HBox* mouse_mode_box = manage (new HBox);
3096 HBox* mouse_mode_hbox = manage (new HBox);
3097 VBox* mouse_mode_vbox = manage (new VBox);
3098 Alignment* mouse_mode_align = manage (new Alignment);
3100 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3101 mouse_mode_size_group->add_widget (smart_mode_button);
3102 mouse_mode_size_group->add_widget (mouse_move_button);
3103 mouse_mode_size_group->add_widget (mouse_cut_button);
3104 mouse_mode_size_group->add_widget (mouse_select_button);
3105 mouse_mode_size_group->add_widget (mouse_timefx_button);
3106 mouse_mode_size_group->add_widget (mouse_audition_button);
3107 mouse_mode_size_group->add_widget (mouse_draw_button);
3108 mouse_mode_size_group->add_widget (mouse_content_button);
3110 if (!Profile->get_mixbus()) {
3111 mouse_mode_size_group->add_widget (zoom_in_button);
3112 mouse_mode_size_group->add_widget (zoom_out_button);
3113 mouse_mode_size_group->add_widget (zoom_out_full_button);
3114 mouse_mode_size_group->add_widget (zoom_focus_selector);
3115 mouse_mode_size_group->add_widget (tav_shrink_button);
3116 mouse_mode_size_group->add_widget (tav_expand_button);
3118 mouse_mode_size_group->add_widget (zoom_preset_selector);
3119 mouse_mode_size_group->add_widget (visible_tracks_selector);
3122 mouse_mode_size_group->add_widget (grid_type_selector);
3123 mouse_mode_size_group->add_widget (snap_mode_button);
3125 mouse_mode_size_group->add_widget (edit_point_selector);
3126 mouse_mode_size_group->add_widget (edit_mode_selector);
3128 mouse_mode_size_group->add_widget (*nudge_clock);
3129 mouse_mode_size_group->add_widget (nudge_forward_button);
3130 mouse_mode_size_group->add_widget (nudge_backward_button);
3132 mouse_mode_hbox->set_spacing (2);
3134 if (!ARDOUR::Profile->get_trx()) {
3135 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3138 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3139 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3141 if (!ARDOUR::Profile->get_mixbus()) {
3142 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3143 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3146 if (!ARDOUR::Profile->get_trx()) {
3147 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3148 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3149 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3152 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3154 mouse_mode_align->add (*mouse_mode_vbox);
3155 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3157 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3159 edit_mode_selector.set_name ("mouse mode button");
3161 if (!ARDOUR::Profile->get_trx()) {
3162 mode_box->pack_start (edit_mode_selector, false, false);
3163 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3164 mode_box->pack_start (edit_point_selector, false, false);
3165 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3168 mode_box->pack_start (*mouse_mode_box, false, false);
3172 _zoom_box.set_spacing (2);
3173 _zoom_box.set_border_width (2);
3177 zoom_preset_selector.set_name ("zoom button");
3178 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3180 zoom_in_button.set_name ("zoom button");
3181 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3182 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3183 zoom_in_button.set_related_action (act);
3185 zoom_out_button.set_name ("zoom button");
3186 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3187 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3188 zoom_out_button.set_related_action (act);
3190 zoom_out_full_button.set_name ("zoom button");
3191 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3192 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3193 zoom_out_full_button.set_related_action (act);
3195 zoom_focus_selector.set_name ("zoom button");
3197 if (ARDOUR::Profile->get_mixbus()) {
3198 _zoom_box.pack_start (zoom_preset_selector, false, false);
3199 } else if (ARDOUR::Profile->get_trx()) {
3200 mode_box->pack_start (zoom_out_button, false, false);
3201 mode_box->pack_start (zoom_in_button, false, false);
3203 _zoom_box.pack_start (zoom_out_button, false, false);
3204 _zoom_box.pack_start (zoom_in_button, false, false);
3205 _zoom_box.pack_start (zoom_out_full_button, false, false);
3206 _zoom_box.pack_start (zoom_focus_selector, false, false);
3209 /* Track zoom buttons */
3210 _track_box.set_spacing (2);
3211 _track_box.set_border_width (2);
3213 visible_tracks_selector.set_name ("zoom button");
3214 if (Profile->get_mixbus()) {
3215 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3217 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3220 tav_expand_button.set_name ("zoom button");
3221 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3222 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3223 tav_expand_button.set_related_action (act);
3225 tav_shrink_button.set_name ("zoom button");
3226 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3227 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3228 tav_shrink_button.set_related_action (act);
3230 if (ARDOUR::Profile->get_mixbus()) {
3231 _track_box.pack_start (visible_tracks_selector);
3232 } else if (ARDOUR::Profile->get_trx()) {
3233 _track_box.pack_start (tav_shrink_button);
3234 _track_box.pack_start (tav_expand_button);
3236 _track_box.pack_start (visible_tracks_selector);
3237 _track_box.pack_start (tav_shrink_button);
3238 _track_box.pack_start (tav_expand_button);
3241 snap_box.set_spacing (2);
3242 snap_box.set_border_width (2);
3244 grid_type_selector.set_name ("mouse mode button");
3246 snap_mode_button.set_name ("mouse mode button");
3248 edit_point_selector.set_name ("mouse mode button");
3250 snap_box.pack_start (snap_mode_button, false, false);
3251 snap_box.pack_start (grid_type_selector, false, false);
3255 HBox *nudge_box = manage (new HBox);
3256 nudge_box->set_spacing (2);
3257 nudge_box->set_border_width (2);
3259 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3260 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3262 nudge_box->pack_start (nudge_backward_button, false, false);
3263 nudge_box->pack_start (nudge_forward_button, false, false);
3264 nudge_box->pack_start (*nudge_clock, false, false);
3267 /* Pack everything in... */
3269 toolbar_hbox.set_spacing (2);
3270 toolbar_hbox.set_border_width (2);
3272 ArdourWidgets::ArdourDropShadow *tool_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
3273 tool_shadow->set_size_request (4, -1);
3274 tool_shadow->show();
3276 ebox_hpacker.pack_start (*tool_shadow, false, false);
3277 ebox_hpacker.pack_start(ebox_vpacker, true, true);
3279 Gtk::EventBox* spacer = manage (new Gtk::EventBox); // extra space under the mouse toolbar, for aesthetics
3280 spacer->set_name("EditorWindow");
3281 spacer->set_size_request(-1,4);
3284 ebox_vpacker.pack_start(toolbar_hbox, false, false);
3285 ebox_vpacker.pack_start(*spacer, false, false);
3286 ebox_vpacker.show();
3288 toolbar_hbox.pack_start (*mode_box, false, false);
3290 if (!ARDOUR::Profile->get_trx()) {
3292 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3294 toolbar_hbox.pack_start (snap_box, false, false);
3296 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3298 toolbar_hbox.pack_start (*nudge_box, false, false);
3300 toolbar_hbox.pack_end (_zoom_box, false, false, 2);
3302 toolbar_hbox.pack_end (*(manage (new ArdourVSpacer ())), false, false, 3);
3304 toolbar_hbox.pack_end (_track_box, false, false);
3308 toolbar_hbox.show_all ();
3312 Editor::build_edit_point_menu ()
3314 using namespace Menu_Helpers;
3316 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3317 if(!Profile->get_mixbus())
3318 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3319 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3321 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3325 Editor::build_edit_mode_menu ()
3327 using namespace Menu_Helpers;
3329 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3330 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3331 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3332 /* Note: Splice was removed */
3334 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3338 Editor::build_grid_type_menu ()
3340 using namespace Menu_Helpers;
3342 /* main grid: bars, quarter-notes, etc */
3343 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeNone], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeNone)));
3344 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBar], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBar)));
3345 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeat], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeat)));
3346 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv2)));
3347 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv4)));
3348 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv8)));
3349 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv16)));
3350 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv32)));
3353 grid_type_selector.AddMenuElem(SeparatorElem());
3354 Gtk::Menu *_triplet_menu = manage (new Menu);
3355 MenuList& triplet_items (_triplet_menu->items());
3357 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv3)));
3358 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv6)));
3359 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv12)));
3360 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv24)));
3362 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Triplets"), *_triplet_menu));
3364 /* quintuplet grid */
3365 Gtk::Menu *_quintuplet_menu = manage (new Menu);
3366 MenuList& quintuplet_items (_quintuplet_menu->items());
3368 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv5)));
3369 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv10)));
3370 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv20)));
3372 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Quintuplets"), *_quintuplet_menu));
3374 /* septuplet grid */
3375 Gtk::Menu *_septuplet_menu = manage (new Menu);
3376 MenuList& septuplet_items (_septuplet_menu->items());
3378 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv7)));
3379 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv14)));
3380 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv28)));
3382 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Septuplets"), *_septuplet_menu));
3384 grid_type_selector.AddMenuElem(SeparatorElem());
3385 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeTimecode], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeTimecode)));
3386 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeMinSec], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeMinSec)));
3387 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeCDFrame)));
3391 Editor::setup_tooltips ()
3393 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3394 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3395 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3396 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3397 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3398 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3399 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3400 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3401 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3402 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3403 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3404 set_tooltip (zoom_in_button, _("Zoom In"));
3405 set_tooltip (zoom_out_button, _("Zoom Out"));
3406 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3407 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3408 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3409 set_tooltip (tav_expand_button, _("Expand Tracks"));
3410 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3411 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3412 set_tooltip (grid_type_selector, _("Grid Mode"));
3413 set_tooltip (snap_mode_button, _("Snap Mode\n\nRight-click to visit Snap preferences."));
3414 set_tooltip (edit_point_selector, _("Edit Point"));
3415 set_tooltip (edit_mode_selector, _("Edit Mode"));
3416 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3420 Editor::convert_drop_to_paths (
3421 vector<string>& paths,
3422 const RefPtr<Gdk::DragContext>& /*context*/,
3425 const SelectionData& data,
3429 if (_session == 0) {
3433 vector<string> uris = data.get_uris();
3437 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3438 are actually URI lists. So do it by hand.
3441 if (data.get_target() != "text/plain") {
3445 /* Parse the "uri-list" format that Nautilus provides,
3446 where each pathname is delimited by \r\n.
3448 THERE MAY BE NO NULL TERMINATING CHAR!!!
3451 string txt = data.get_text();
3455 p = (char *) malloc (txt.length() + 1);
3456 txt.copy (p, txt.length(), 0);
3457 p[txt.length()] = '\0';
3463 while (g_ascii_isspace (*p))
3467 while (*q && (*q != '\n') && (*q != '\r')) {
3474 while (q > p && g_ascii_isspace (*q))
3479 uris.push_back (string (p, q - p + 1));
3483 p = strchr (p, '\n');
3495 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3496 if ((*i).substr (0,7) == "file://") {
3497 paths.push_back (Glib::filename_from_uri (*i));
3505 Editor::new_tempo_section ()
3510 Editor::map_transport_state ()
3512 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3514 if (_session && _session->transport_stopped()) {
3515 have_pending_keyboard_selection = false;
3518 update_loop_range_view ();
3522 Editor::transport_looped ()
3524 /* reset Playhead position interpolation.
3525 * see Editor::super_rapid_screen_update
3527 _last_update_time = 0;
3533 Editor::begin_selection_op_history ()
3535 selection_op_cmd_depth = 0;
3536 selection_op_history_it = 0;
3538 while(!selection_op_history.empty()) {
3539 delete selection_op_history.front();
3540 selection_op_history.pop_front();
3543 selection_undo_action->set_sensitive (false);
3544 selection_redo_action->set_sensitive (false);
3545 selection_op_history.push_front (&_selection_memento->get_state ());
3549 Editor::begin_reversible_selection_op (string name)
3552 //cerr << name << endl;
3553 /* begin/commit pairs can be nested */
3554 selection_op_cmd_depth++;
3559 Editor::commit_reversible_selection_op ()
3562 if (selection_op_cmd_depth == 1) {
3564 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3565 /* The user has undone some selection ops and then made a new one,
3566 * making anything earlier in the list invalid.
3569 list<XMLNode *>::iterator it = selection_op_history.begin();
3570 list<XMLNode *>::iterator e_it = it;
3571 advance (e_it, selection_op_history_it);
3573 for (; it != e_it; ++it) {
3576 selection_op_history.erase (selection_op_history.begin(), e_it);
3579 selection_op_history.push_front (&_selection_memento->get_state ());
3580 selection_op_history_it = 0;
3582 selection_undo_action->set_sensitive (true);
3583 selection_redo_action->set_sensitive (false);
3586 if (selection_op_cmd_depth > 0) {
3587 selection_op_cmd_depth--;
3593 Editor::undo_selection_op ()
3596 selection_op_history_it++;
3598 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3599 if (n == selection_op_history_it) {
3600 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3601 selection_redo_action->set_sensitive (true);
3605 /* is there an earlier entry? */
3606 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3607 selection_undo_action->set_sensitive (false);
3613 Editor::redo_selection_op ()
3616 if (selection_op_history_it > 0) {
3617 selection_op_history_it--;
3620 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3621 if (n == selection_op_history_it) {
3622 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3623 selection_undo_action->set_sensitive (true);
3628 if (selection_op_history_it == 0) {
3629 selection_redo_action->set_sensitive (false);
3635 Editor::begin_reversible_command (string name)
3638 before.push_back (&_selection_memento->get_state ());
3639 _session->begin_reversible_command (name);
3644 Editor::begin_reversible_command (GQuark q)
3647 before.push_back (&_selection_memento->get_state ());
3648 _session->begin_reversible_command (q);
3653 Editor::abort_reversible_command ()
3656 while(!before.empty()) {
3657 delete before.front();
3660 _session->abort_reversible_command ();
3665 Editor::commit_reversible_command ()
3668 if (before.size() == 1) {
3669 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3670 redo_action->set_sensitive(false);
3671 undo_action->set_sensitive(true);
3672 begin_selection_op_history ();
3675 if (before.empty()) {
3676 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3681 _session->commit_reversible_command ();
3686 Editor::history_changed ()
3690 if (undo_action && _session) {
3691 if (_session->undo_depth() == 0) {
3692 label = S_("Command|Undo");
3694 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3696 undo_action->property_label() = label;
3699 if (redo_action && _session) {
3700 if (_session->redo_depth() == 0) {
3702 redo_action->set_sensitive (false);
3704 label = string_compose(_("Redo (%1)"), _session->next_redo());
3705 redo_action->set_sensitive (true);
3707 redo_action->property_label() = label;
3712 Editor::duplicate_range (bool with_dialog)
3716 RegionSelection rs = get_regions_from_selection_and_entered ();
3718 if (selection->time.length() == 0 && rs.empty()) {
3724 ArdourDialog win (_("Duplicate"));
3725 Label label (_("Number of duplications:"));
3726 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3727 SpinButton spinner (adjustment, 0.0, 1);
3730 win.get_vbox()->set_spacing (12);
3731 win.get_vbox()->pack_start (hbox);
3732 hbox.set_border_width (6);
3733 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3735 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3736 place, visually. so do this by hand.
3739 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3740 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3741 spinner.grab_focus();
3747 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3748 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3749 win.set_default_response (RESPONSE_ACCEPT);
3751 spinner.grab_focus ();
3753 switch (win.run ()) {
3754 case RESPONSE_ACCEPT:
3760 times = adjustment.get_value();
3763 if ((current_mouse_mode() == MouseRange)) {
3764 if (selection->time.length()) {
3765 duplicate_selection (times);
3767 } else if (get_smart_mode()) {
3768 if (selection->time.length()) {
3769 duplicate_selection (times);
3771 duplicate_some_regions (rs, times);
3773 duplicate_some_regions (rs, times);
3778 Editor::set_edit_mode (EditMode m)
3780 Config->set_edit_mode (m);
3784 Editor::cycle_edit_mode ()
3786 switch (Config->get_edit_mode()) {
3788 Config->set_edit_mode (Ripple);
3792 Config->set_edit_mode (Lock);
3795 Config->set_edit_mode (Slide);
3801 Editor::edit_mode_selection_done (EditMode m)
3803 Config->set_edit_mode (m);
3807 Editor::grid_type_selection_done (GridType gridtype)
3809 RefPtr<RadioAction> ract = grid_type_action (gridtype);
3811 ract->set_active ();
3816 Editor::snap_mode_selection_done (SnapMode mode)
3818 RefPtr<RadioAction> ract = snap_mode_action (mode);
3821 ract->set_active (true);
3826 Editor::cycle_edit_point (bool with_marker)
3828 if(Profile->get_mixbus())
3829 with_marker = false;
3831 switch (_edit_point) {
3833 set_edit_point_preference (EditAtPlayhead);
3835 case EditAtPlayhead:
3837 set_edit_point_preference (EditAtSelectedMarker);
3839 set_edit_point_preference (EditAtMouse);
3842 case EditAtSelectedMarker:
3843 set_edit_point_preference (EditAtMouse);
3849 Editor::edit_point_selection_done (EditPoint ep)
3851 set_edit_point_preference (ep);
3855 Editor::build_zoom_focus_menu ()
3857 using namespace Menu_Helpers;
3859 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3860 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3861 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3862 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3863 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3864 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3866 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3870 Editor::zoom_focus_selection_done (ZoomFocus f)
3872 RefPtr<RadioAction> ract = zoom_focus_action (f);
3874 ract->set_active ();
3879 Editor::build_track_count_menu ()
3881 using namespace Menu_Helpers;
3883 if (!Profile->get_mixbus()) {
3884 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3885 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3886 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3887 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3888 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3889 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3890 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3891 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3892 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3893 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3894 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3895 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3896 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3898 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3899 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3900 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3901 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3902 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3903 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3904 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3905 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3906 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3907 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3909 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3910 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3911 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3912 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3913 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3914 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3915 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3916 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3917 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3918 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3919 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Extents"), sigc::mem_fun(*this, &Editor::temporal_zoom_extents)));
3920 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3925 Editor::set_zoom_preset (int64_t ms)
3928 temporal_zoom_session();
3932 ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3933 temporal_zoom ((sample_rate * ms / 1000) / _visible_canvas_width);
3937 Editor::set_visible_track_count (int32_t n)
3939 _visible_track_count = n;
3941 /* if the canvas hasn't really been allocated any size yet, just
3942 record the desired number of visible tracks and return. when canvas
3943 allocation happens, we will get called again and then we can do the
3947 if (_visible_canvas_height <= 1) {
3953 DisplaySuspender ds;
3955 if (_visible_track_count > 0) {
3956 h = trackviews_height() / _visible_track_count;
3957 std::ostringstream s;
3958 s << _visible_track_count;
3960 } else if (_visible_track_count == 0) {
3962 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
3963 if ((*i)->marked_for_display()) {
3965 TimeAxisView::Children cl ((*i)->get_child_list ());
3966 for (TimeAxisView::Children::const_iterator j = cl.begin(); j != cl.end(); ++j) {
3967 if ((*j)->marked_for_display()) {
3974 visible_tracks_selector.set_text (X_("*"));
3977 h = trackviews_height() / n;
3980 /* negative value means that the visible track count has
3981 been overridden by explicit track height changes.
3983 visible_tracks_selector.set_text (X_("*"));
3987 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3988 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3991 if (str != visible_tracks_selector.get_text()) {
3992 visible_tracks_selector.set_text (str);
3997 Editor::override_visible_track_count ()
3999 _visible_track_count = -1;
4000 visible_tracks_selector.set_text (_("*"));
4004 Editor::edit_controls_button_release (GdkEventButton* ev)
4006 if (Keyboard::is_context_menu_event (ev)) {
4007 ARDOUR_UI::instance()->add_route ();
4008 } else if (ev->button == 1) {
4009 selection->clear_tracks ();
4016 Editor::mouse_select_button_release (GdkEventButton* ev)
4018 /* this handles just right-clicks */
4020 if (ev->button != 3) {
4028 Editor::set_zoom_focus (ZoomFocus f)
4030 string str = zoom_focus_strings[(int)f];
4032 if (str != zoom_focus_selector.get_text()) {
4033 zoom_focus_selector.set_text (str);
4036 if (zoom_focus != f) {
4043 Editor::cycle_zoom_focus ()
4045 switch (zoom_focus) {
4047 set_zoom_focus (ZoomFocusRight);
4049 case ZoomFocusRight:
4050 set_zoom_focus (ZoomFocusCenter);
4052 case ZoomFocusCenter:
4053 set_zoom_focus (ZoomFocusPlayhead);
4055 case ZoomFocusPlayhead:
4056 set_zoom_focus (ZoomFocusMouse);
4058 case ZoomFocusMouse:
4059 set_zoom_focus (ZoomFocusEdit);
4062 set_zoom_focus (ZoomFocusLeft);
4068 Editor::update_grid ()
4070 if (grid_musical()) {
4071 std::vector<TempoMap::BBTPoint> grid;
4072 if (bbt_ruler_scale != bbt_show_many) {
4073 compute_current_bbt_points (grid, _leftmost_sample, _leftmost_sample + current_page_samples());
4075 maybe_draw_grid_lines ();
4076 } else if (grid_nonmusical()) {
4077 maybe_draw_grid_lines ();
4084 Editor::toggle_follow_playhead ()
4086 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
4088 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4089 set_follow_playhead (tact->get_active());
4093 /** @param yn true to follow playhead, otherwise false.
4094 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4097 Editor::set_follow_playhead (bool yn, bool catch_up)
4099 if (_follow_playhead != yn) {
4100 if ((_follow_playhead = yn) == true && catch_up) {
4102 reset_x_origin_to_follow_playhead ();
4109 Editor::toggle_stationary_playhead ()
4111 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4113 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4114 set_stationary_playhead (tact->get_active());
4119 Editor::set_stationary_playhead (bool yn)
4121 if (_stationary_playhead != yn) {
4122 if ((_stationary_playhead = yn) == true) {
4123 /* catch up -- FIXME need a 3.0 equivalent of this 2.X call */
4124 // update_current_screen ();
4131 Editor::playlist_selector () const
4133 return *_playlist_selector;
4137 Editor::get_paste_offset (samplepos_t pos, unsigned paste_count, samplecnt_t duration)
4139 if (paste_count == 0) {
4140 /* don't bother calculating an offset that will be zero anyway */
4144 /* calculate basic unsnapped multi-paste offset */
4145 samplecnt_t offset = paste_count * duration;
4147 /* snap offset so pos + offset is aligned to the grid */
4148 MusicSample offset_pos (pos + offset, 0);
4149 snap_to(offset_pos, RoundUpMaybe);
4150 offset = offset_pos.sample - pos;
4156 Editor::get_grid_beat_divisions(samplepos_t position)
4158 switch (_grid_type) {
4159 case GridTypeBeatDiv32: return 32;
4160 case GridTypeBeatDiv28: return 28;
4161 case GridTypeBeatDiv24: return 24;
4162 case GridTypeBeatDiv20: return 20;
4163 case GridTypeBeatDiv16: return 16;
4164 case GridTypeBeatDiv14: return 14;
4165 case GridTypeBeatDiv12: return 12;
4166 case GridTypeBeatDiv10: return 10;
4167 case GridTypeBeatDiv8: return 8;
4168 case GridTypeBeatDiv7: return 7;
4169 case GridTypeBeatDiv6: return 6;
4170 case GridTypeBeatDiv5: return 5;
4171 case GridTypeBeatDiv4: return 4;
4172 case GridTypeBeatDiv3: return 3;
4173 case GridTypeBeatDiv2: return 2;
4174 case GridTypeBeat: return 1;
4175 case GridTypeBar: return 1;
4177 case GridTypeNone: return 0;
4178 case GridTypeTimecode: return 0;
4179 case GridTypeMinSec: return 0;
4180 case GridTypeCDFrame: return 0;
4186 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4187 if the grid is non-musical, returns 0.
4188 if the grid is snapped to bars, returns -1.
4189 @param event_state the current keyboard modifier mask.
4192 Editor::get_grid_music_divisions (uint32_t event_state)
4194 if (snap_mode() == SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4198 if (snap_mode() != SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4202 switch (_grid_type) {
4203 case GridTypeBeatDiv32: return 32;
4204 case GridTypeBeatDiv28: return 28;
4205 case GridTypeBeatDiv24: return 24;
4206 case GridTypeBeatDiv20: return 20;
4207 case GridTypeBeatDiv16: return 16;
4208 case GridTypeBeatDiv14: return 14;
4209 case GridTypeBeatDiv12: return 12;
4210 case GridTypeBeatDiv10: return 10;
4211 case GridTypeBeatDiv8: return 8;
4212 case GridTypeBeatDiv7: return 7;
4213 case GridTypeBeatDiv6: return 6;
4214 case GridTypeBeatDiv5: return 5;
4215 case GridTypeBeatDiv4: return 4;
4216 case GridTypeBeatDiv3: return 3;
4217 case GridTypeBeatDiv2: return 2;
4218 case GridTypeBeat: return 1;
4219 case GridTypeBar : return -1;
4221 case GridTypeNone: return 0;
4222 case GridTypeTimecode: return 0;
4223 case GridTypeMinSec: return 0;
4224 case GridTypeCDFrame: return 0;
4230 Editor::get_grid_type_as_beats (bool& success, samplepos_t position)
4234 const unsigned divisions = get_grid_beat_divisions(position);
4236 return Temporal::Beats(1.0 / (double)get_grid_beat_divisions(position));
4239 switch (_grid_type) {
4241 return Temporal::Beats(4.0 / _session->tempo_map().meter_at_sample (position).note_divisor());
4244 const Meter& m = _session->tempo_map().meter_at_sample (position);
4245 return Temporal::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4253 return Temporal::Beats();
4257 Editor::get_nudge_distance (samplepos_t pos, samplecnt_t& next)
4261 ret = nudge_clock->current_duration (pos);
4262 next = ret + 1; /* XXXX fix me */
4268 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4270 ArdourDialog dialog (_("Playlist Deletion"));
4271 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4272 "If it is kept, its audio files will not be cleaned.\n"
4273 "If it is deleted, audio files used by it alone will be cleaned."),
4276 dialog.set_position (WIN_POS_CENTER);
4277 dialog.get_vbox()->pack_start (label);
4281 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4282 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4283 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4284 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4285 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4287 /* by default gtk uses the left most button */
4288 keep->grab_focus ();
4290 switch (dialog.run ()) {
4292 /* keep this and all remaining ones */
4297 /* delete this and all others */
4301 case RESPONSE_ACCEPT:
4302 /* delete the playlist */
4306 case RESPONSE_REJECT:
4307 /* keep the playlist */
4319 Editor::audio_region_selection_covers (samplepos_t where)
4321 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4322 if ((*a)->region()->covers (where)) {
4331 Editor::prepare_for_cleanup ()
4333 cut_buffer->clear_regions ();
4334 cut_buffer->clear_playlists ();
4336 selection->clear_regions ();
4337 selection->clear_playlists ();
4339 _regions->suspend_redisplay ();
4343 Editor::finish_cleanup ()
4345 _regions->resume_redisplay ();
4349 Editor::transport_loop_location()
4352 return _session->locations()->auto_loop_location();
4359 Editor::transport_punch_location()
4362 return _session->locations()->auto_punch_location();
4369 Editor::control_layout_scroll (GdkEventScroll* ev)
4371 /* Just forward to the normal canvas scroll method. The coordinate
4372 systems are different but since the canvas is always larger than the
4373 track headers, and aligned with the trackview area, this will work.
4375 In the not too distant future this layout is going away anyway and
4376 headers will be on the canvas.
4378 return canvas_scroll_event (ev, false);
4382 Editor::session_state_saved (string)
4385 _snapshots->redisplay ();
4389 Editor::maximise_editing_space ()
4395 Gtk::Window* toplevel = current_toplevel();
4398 toplevel->fullscreen ();
4404 Editor::restore_editing_space ()
4410 Gtk::Window* toplevel = current_toplevel();
4413 toplevel->unfullscreen();
4419 * Make new playlists for a given track and also any others that belong
4420 * to the same active route group with the `select' property.
4425 Editor::new_playlists (TimeAxisView* v)
4427 begin_reversible_command (_("new playlists"));
4428 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4429 _session->playlists->get (playlists);
4430 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4431 commit_reversible_command ();
4435 * Use a copy of the current playlist for a given track and also any others that belong
4436 * to the same active route group with the `select' property.
4441 Editor::copy_playlists (TimeAxisView* v)
4443 begin_reversible_command (_("copy playlists"));
4444 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4445 _session->playlists->get (playlists);
4446 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4447 commit_reversible_command ();
4450 /** Clear the current playlist for a given track and also any others that belong
4451 * to the same active route group with the `select' property.
4456 Editor::clear_playlists (TimeAxisView* v)
4458 begin_reversible_command (_("clear playlists"));
4459 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4460 _session->playlists->get (playlists);
4461 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4462 commit_reversible_command ();
4466 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4468 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4472 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4474 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4478 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4480 atv.clear_playlist ();
4484 Editor::get_y_origin () const
4486 return vertical_adjustment.get_value ();
4489 /** Queue up a change to the viewport x origin.
4490 * @param sample New x origin.
4493 Editor::reset_x_origin (samplepos_t sample)
4495 pending_visual_change.add (VisualChange::TimeOrigin);
4496 pending_visual_change.time_origin = sample;
4497 ensure_visual_change_idle_handler ();
4501 Editor::reset_y_origin (double y)
4503 pending_visual_change.add (VisualChange::YOrigin);
4504 pending_visual_change.y_origin = y;
4505 ensure_visual_change_idle_handler ();
4509 Editor::reset_zoom (samplecnt_t spp)
4511 if (spp == samples_per_pixel) {
4515 pending_visual_change.add (VisualChange::ZoomLevel);
4516 pending_visual_change.samples_per_pixel = spp;
4517 ensure_visual_change_idle_handler ();
4521 Editor::reposition_and_zoom (samplepos_t sample, double fpu)
4523 reset_x_origin (sample);
4526 if (!no_save_visual) {
4527 undo_visual_stack.push_back (current_visual_state(false));
4531 Editor::VisualState::VisualState (bool with_tracks)
4532 : gui_state (with_tracks ? new GUIObjectState : 0)
4536 Editor::VisualState::~VisualState ()
4541 Editor::VisualState*
4542 Editor::current_visual_state (bool with_tracks)
4544 VisualState* vs = new VisualState (with_tracks);
4545 vs->y_position = vertical_adjustment.get_value();
4546 vs->samples_per_pixel = samples_per_pixel;
4547 vs->_leftmost_sample = _leftmost_sample;
4548 vs->zoom_focus = zoom_focus;
4551 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4558 Editor::undo_visual_state ()
4560 if (undo_visual_stack.empty()) {
4564 VisualState* vs = undo_visual_stack.back();
4565 undo_visual_stack.pop_back();
4568 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4571 use_visual_state (*vs);
4576 Editor::redo_visual_state ()
4578 if (redo_visual_stack.empty()) {
4582 VisualState* vs = redo_visual_stack.back();
4583 redo_visual_stack.pop_back();
4585 /* XXX: can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack? */
4586 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4589 use_visual_state (*vs);
4594 Editor::swap_visual_state ()
4596 if (undo_visual_stack.empty()) {
4597 redo_visual_state ();
4599 undo_visual_state ();
4604 Editor::use_visual_state (VisualState& vs)
4606 PBD::Unwinder<bool> nsv (no_save_visual, true);
4607 DisplaySuspender ds;
4609 vertical_adjustment.set_value (vs.y_position);
4611 set_zoom_focus (vs.zoom_focus);
4612 reposition_and_zoom (vs._leftmost_sample, vs.samples_per_pixel);
4615 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4617 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4618 (*i)->clear_property_cache();
4619 (*i)->reset_visual_state ();
4623 _routes->update_visibility ();
4626 /** This is the core function that controls the zoom level of the canvas. It is called
4627 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4628 * @param spp new number of samples per pixel
4631 Editor::set_samples_per_pixel (samplecnt_t spp)
4637 const samplecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->sample_rate() : 48000);
4638 const samplecnt_t lots_of_pixels = 4000;
4640 /* if the zoom level is greater than what you'd get trying to display 3
4641 * days of audio on a really big screen, then it's too big.
4644 if (spp * lots_of_pixels > three_days) {
4648 samples_per_pixel = spp;
4652 Editor::on_samples_per_pixel_changed ()
4654 bool const showing_time_selection = selection->time.length() > 0;
4656 if (showing_time_selection && selection->time.start () != selection->time.end_sample ()) {
4657 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4658 (*i)->reshow_selection (selection->time);
4662 ZoomChanged (); /* EMIT_SIGNAL */
4664 ArdourCanvas::GtkCanvasViewport* c;
4666 c = get_track_canvas();
4668 c->canvas()->zoomed ();
4671 if (playhead_cursor) {
4672 playhead_cursor->set_position (playhead_cursor->current_sample ());
4675 refresh_location_display();
4676 _summary->set_overlays_dirty ();
4678 update_marker_labels ();
4684 Editor::playhead_cursor_sample () const
4686 return playhead_cursor->current_sample();
4690 Editor::queue_visual_videotimeline_update ()
4692 pending_visual_change.add (VisualChange::VideoTimeline);
4693 ensure_visual_change_idle_handler ();
4697 Editor::ensure_visual_change_idle_handler ()
4699 if (pending_visual_change.idle_handler_id < 0) {
4700 /* see comment in add_to_idle_resize above. */
4701 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4702 pending_visual_change.being_handled = false;
4707 Editor::_idle_visual_changer (void* arg)
4709 return static_cast<Editor*>(arg)->idle_visual_changer ();
4713 Editor::pre_render ()
4715 visual_change_queued = false;
4717 if (pending_visual_change.pending != 0) {
4718 ensure_visual_change_idle_handler();
4723 Editor::idle_visual_changer ()
4725 pending_visual_change.idle_handler_id = -1;
4727 if (pending_visual_change.pending == 0) {
4731 /* set_horizontal_position() below (and maybe other calls) call
4732 gtk_main_iteration(), so it's possible that a signal will be handled
4733 half-way through this method. If this signal wants an
4734 idle_visual_changer we must schedule another one after this one, so
4735 mark the idle_handler_id as -1 here to allow that. Also make a note
4736 that we are doing the visual change, so that changes in response to
4737 super-rapid-screen-update can be dropped if we are still processing
4741 if (visual_change_queued) {
4745 pending_visual_change.being_handled = true;
4747 VisualChange vc = pending_visual_change;
4749 pending_visual_change.pending = (VisualChange::Type) 0;
4751 visual_changer (vc);
4753 pending_visual_change.being_handled = false;
4755 visual_change_queued = true;
4757 return 0; /* this is always a one-shot call */
4761 Editor::visual_changer (const VisualChange& vc)
4764 * Changed first so the correct horizontal canvas position is calculated in
4765 * Editor::set_horizontal_position
4767 if (vc.pending & VisualChange::ZoomLevel) {
4768 set_samples_per_pixel (vc.samples_per_pixel);
4771 if (vc.pending & VisualChange::TimeOrigin) {
4772 double new_time_origin = sample_to_pixel_unrounded (vc.time_origin);
4773 set_horizontal_position (new_time_origin);
4776 if (vc.pending & VisualChange::YOrigin) {
4777 vertical_adjustment.set_value (vc.y_origin);
4781 * Now the canvas is in the final state before render the canvas items that
4782 * support the Item::prepare_for_render interface can calculate the correct
4783 * item to visible canvas intersection.
4785 if (vc.pending & VisualChange::ZoomLevel) {
4786 on_samples_per_pixel_changed ();
4788 compute_fixed_ruler_scale ();
4790 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4791 update_tempo_based_rulers ();
4794 if (!(vc.pending & VisualChange::ZoomLevel)) {
4795 /* If the canvas is not being zoomed then the canvas items will not change
4796 * and cause Item::prepare_for_render to be called so do it here manually.
4797 * Not ideal, but I can't think of a better solution atm.
4799 _track_canvas->prepare_for_render();
4802 /* If we are only scrolling vertically there is no need to update these */
4803 if (vc.pending != VisualChange::YOrigin) {
4804 update_fixed_rulers ();
4805 redisplay_grid (true);
4807 /* video frames & position need to be updated for zoom, horiz-scroll
4808 * and (explicitly) VisualChange::VideoTimeline.
4810 update_video_timeline();
4813 _summary->set_overlays_dirty ();
4816 struct EditorOrderTimeAxisSorter {
4817 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4818 return a->order () < b->order ();
4823 Editor::sort_track_selection (TrackViewList& sel)
4825 EditorOrderTimeAxisSorter cmp;
4830 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4833 samplepos_t where = 0;
4834 EditPoint ep = _edit_point;
4836 if (Profile->get_mixbus()) {
4837 if (ep == EditAtSelectedMarker) {
4838 ep = EditAtPlayhead;
4842 if (from_outside_canvas && (ep == EditAtMouse)) {
4843 ep = EditAtPlayhead;
4844 } else if (from_context_menu && (ep == EditAtMouse)) {
4845 return canvas_event_sample (&context_click_event, 0, 0);
4848 if (entered_marker) {
4849 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4850 return entered_marker->position();
4853 if ((ignore == EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4854 ep = EditAtSelectedMarker;
4857 if ((ignore == EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4858 ep = EditAtPlayhead;
4861 MusicSample snap_mf (0, 0);
4864 case EditAtPlayhead:
4865 if (_dragging_playhead) {
4866 /* NOTE: since the user is dragging with the mouse, this operation will implicitly be Snapped */
4867 where = playhead_cursor->current_sample();
4869 where = _session->audible_sample();
4871 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4874 case EditAtSelectedMarker:
4875 if (!selection->markers.empty()) {
4877 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4880 where = loc->start();
4884 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4892 if (!mouse_sample (where, ignored)) {
4893 /* XXX not right but what can we do ? */
4896 snap_mf.sample = where;
4898 where = snap_mf.sample;
4899 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4907 Editor::set_loop_range (samplepos_t start, samplepos_t end, string cmd)
4909 if (!_session) return;
4911 begin_reversible_command (cmd);
4915 if ((tll = transport_loop_location()) == 0) {
4916 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4917 XMLNode &before = _session->locations()->get_state();
4918 _session->locations()->add (loc, true);
4919 _session->set_auto_loop_location (loc);
4920 XMLNode &after = _session->locations()->get_state();
4921 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4923 XMLNode &before = tll->get_state();
4924 tll->set_hidden (false, this);
4925 tll->set (start, end);
4926 XMLNode &after = tll->get_state();
4927 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4930 commit_reversible_command ();
4934 Editor::set_punch_range (samplepos_t start, samplepos_t end, string cmd)
4936 if (!_session) return;
4938 begin_reversible_command (cmd);
4942 if ((tpl = transport_punch_location()) == 0) {
4943 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4944 XMLNode &before = _session->locations()->get_state();
4945 _session->locations()->add (loc, true);
4946 _session->set_auto_punch_location (loc);
4947 XMLNode &after = _session->locations()->get_state();
4948 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4950 XMLNode &before = tpl->get_state();
4951 tpl->set_hidden (false, this);
4952 tpl->set (start, end);
4953 XMLNode &after = tpl->get_state();
4954 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4957 commit_reversible_command ();
4960 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4961 * @param rs List to which found regions are added.
4962 * @param where Time to look at.
4963 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4966 Editor::get_regions_at (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4968 const TrackViewList* tracks;
4971 tracks = &track_views;
4976 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4978 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4981 boost::shared_ptr<Track> tr;
4982 boost::shared_ptr<Playlist> pl;
4984 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4986 boost::shared_ptr<RegionList> regions = pl->regions_at (where);
4988 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4989 RegionView* rv = rtv->view()->find_view (*i);
5000 Editor::get_regions_after (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
5002 const TrackViewList* tracks;
5005 tracks = &track_views;
5010 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
5011 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
5013 boost::shared_ptr<Track> tr;
5014 boost::shared_ptr<Playlist> pl;
5016 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
5018 boost::shared_ptr<RegionList> regions = pl->regions_touched (where, max_samplepos);
5020 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
5022 RegionView* rv = rtv->view()->find_view (*i);
5033 /** Get regions using the following method:
5035 * Make a region list using:
5036 * (a) any selected regions
5037 * (b) the intersection of any selected tracks and the edit point(*)
5038 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
5040 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
5042 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
5046 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
5048 RegionSelection regions;
5050 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
5051 regions.add (entered_regionview);
5053 regions = selection->regions;
5056 if (regions.empty()) {
5057 TrackViewList tracks = selection->tracks;
5059 if (!tracks.empty()) {
5060 /* no region selected or entered, but some selected tracks:
5061 * act on all regions on the selected tracks at the edit point
5063 samplepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
5064 get_regions_at(regions, where, tracks);
5071 /** Get regions using the following method:
5073 * Make a region list using:
5074 * (a) any selected regions
5075 * (b) the intersection of any selected tracks and the edit point(*)
5076 * (c) if neither exists, then whatever region is under the mouse
5078 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
5080 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
5083 Editor::get_regions_from_selection_and_mouse (samplepos_t pos)
5085 RegionSelection regions;
5087 if (entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
5088 regions.add (entered_regionview);
5090 regions = selection->regions;
5093 if (regions.empty()) {
5094 TrackViewList tracks = selection->tracks;
5096 if (!tracks.empty()) {
5097 /* no region selected or entered, but some selected tracks:
5098 * act on all regions on the selected tracks at the edit point
5100 get_regions_at(regions, pos, tracks);
5107 /** Start with regions that are selected, or the entered regionview if none are selected.
5108 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
5109 * of the regions that we started with.
5113 Editor::get_regions_from_selection_and_entered () const
5115 RegionSelection regions = selection->regions;
5117 if (regions.empty() && entered_regionview) {
5118 regions.add (entered_regionview);
5125 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
5127 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5128 RouteTimeAxisView* rtav;
5130 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5131 boost::shared_ptr<Playlist> pl;
5132 std::vector<boost::shared_ptr<Region> > results;
5133 boost::shared_ptr<Track> tr;
5135 if ((tr = rtav->track()) == 0) {
5140 if ((pl = (tr->playlist())) != 0) {
5141 boost::shared_ptr<Region> r = pl->region_by_id (id);
5143 RegionView* rv = rtav->view()->find_view (r);
5145 regions.push_back (rv);
5154 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > > &selection) const
5157 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5158 MidiTimeAxisView* mtav;
5160 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5162 mtav->get_per_region_note_selection (selection);
5169 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5171 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5173 RouteTimeAxisView* tatv;
5175 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5177 boost::shared_ptr<Playlist> pl;
5178 vector<boost::shared_ptr<Region> > results;
5180 boost::shared_ptr<Track> tr;
5182 if ((tr = tatv->track()) == 0) {
5187 if ((pl = (tr->playlist())) != 0) {
5188 if (src_comparison) {
5189 pl->get_source_equivalent_regions (region, results);
5191 pl->get_region_list_equivalent_regions (region, results);
5195 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5196 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5197 regions.push_back (marv);
5206 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5208 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5209 RouteTimeAxisView* tatv;
5210 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5211 if (!tatv->track()) {
5214 RegionView* marv = tatv->view()->find_view (region);
5224 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5226 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5227 RouteTimeAxisView* rtav;
5228 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5229 if (rtav->route() == route) {
5238 Editor::show_rhythm_ferret ()
5240 if (rhythm_ferret == 0) {
5241 rhythm_ferret = new RhythmFerret(*this);
5244 rhythm_ferret->set_session (_session);
5245 rhythm_ferret->show ();
5246 rhythm_ferret->present ();
5250 Editor::first_idle ()
5252 MessageDialog* dialog = 0;
5254 if (track_views.size() > 1) {
5255 Timers::TimerSuspender t;
5256 dialog = new MessageDialog (
5257 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5261 ARDOUR_UI::instance()->flush_pending (60);
5264 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5268 /* now that all regionviews should exist, setup region selection */
5272 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5273 /* this is cumulative: rs is NOT cleared each time */
5274 get_regionviews_by_id (*pr, rs);
5277 selection->set (rs);
5279 /* first idle adds route children (automation tracks), so we need to redisplay here */
5280 _routes->redisplay ();
5284 if (_session->undo_depth() == 0) {
5285 undo_action->set_sensitive(false);
5287 redo_action->set_sensitive(false);
5288 begin_selection_op_history ();
5294 Editor::_idle_resize (gpointer arg)
5296 return ((Editor*)arg)->idle_resize ();
5300 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5302 if (resize_idle_id < 0) {
5303 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5304 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5305 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5307 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5308 _pending_resize_amount = 0;
5311 /* make a note of the smallest resulting height, so that we can clamp the
5312 lower limit at TimeAxisView::hSmall */
5314 int32_t min_resulting = INT32_MAX;
5316 _pending_resize_amount += h;
5317 _pending_resize_view = view;
5319 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5321 if (selection->tracks.contains (_pending_resize_view)) {
5322 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5323 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5327 if (min_resulting < 0) {
5332 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5333 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5337 /** Handle pending resizing of tracks */
5339 Editor::idle_resize ()
5341 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5343 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5344 selection->tracks.contains (_pending_resize_view)) {
5346 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5347 if (*i != _pending_resize_view) {
5348 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5353 _pending_resize_amount = 0;
5354 _group_tabs->set_dirty ();
5355 resize_idle_id = -1;
5363 ENSURE_GUI_THREAD (*this, &Editor::located);
5366 playhead_cursor->set_position (_session->audible_sample ());
5367 if (_follow_playhead && !_pending_initial_locate) {
5368 reset_x_origin_to_follow_playhead ();
5372 _pending_locate_request = false;
5373 _pending_initial_locate = false;
5374 _last_update_time = 0;
5378 Editor::region_view_added (RegionView * rv)
5380 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5382 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5383 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5384 if (rv->region()->id () == (*rnote).first) {
5385 mrv->select_notes ((*rnote).second);
5386 selection->pending_midi_note_selection.erase(rnote);
5392 _summary->set_background_dirty ();
5394 mark_region_boundary_cache_dirty ();
5398 Editor::region_view_removed ()
5400 _summary->set_background_dirty ();
5402 mark_region_boundary_cache_dirty ();
5406 Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
5408 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5409 if ((*j)->stripable() == s) {
5418 Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
5420 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5421 if ((*j)->control() == c) {
5425 TimeAxisView::Children kids = (*j)->get_child_list ();
5427 for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) {
5428 if ((*k)->control() == c) {
5438 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5442 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5443 TimeAxisView* tv = time_axis_view_from_stripable (*i);
5453 Editor::suspend_route_redisplay ()
5456 _routes->suspend_redisplay();
5461 Editor::resume_route_redisplay ()
5464 _routes->redisplay(); // queue redisplay
5465 _routes->resume_redisplay();
5470 Editor::add_vcas (VCAList& vlist)
5474 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5475 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5478 add_stripables (sl);
5482 Editor::add_routes (RouteList& rlist)
5486 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5490 add_stripables (sl);
5494 Editor::add_stripables (StripableList& sl)
5496 list<TimeAxisView*> new_views;
5497 boost::shared_ptr<VCA> v;
5498 boost::shared_ptr<Route> r;
5499 TrackViewList new_selection;
5500 bool from_scratch = (track_views.size() == 0);
5502 sl.sort (Stripable::Sorter());
5504 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5506 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5508 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5510 new_views.push_back (vtv);
5512 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5514 if (r->is_auditioner() || r->is_monitor()) {
5518 RouteTimeAxisView* rtv;
5519 DataType dt = r->input()->default_type();
5521 if (dt == ARDOUR::DataType::AUDIO) {
5522 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5524 } else if (dt == ARDOUR::DataType::MIDI) {
5525 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5528 throw unknown_type();
5531 new_views.push_back (rtv);
5532 track_views.push_back (rtv);
5533 new_selection.push_back (rtv);
5535 rtv->effective_gain_display ();
5537 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5538 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5542 if (new_views.size() > 0) {
5543 _routes->time_axis_views_added (new_views);
5544 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5547 /* note: !new_selection.empty() means that we got some routes rather
5551 if (!from_scratch && !new_selection.empty()) {
5552 selection->set (new_selection);
5553 begin_selection_op_history();
5556 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5557 show_editor_mixer (true);
5560 editor_list_button.set_sensitive (true);
5564 Editor::timeaxisview_deleted (TimeAxisView *tv)
5566 if (tv == entered_track) {
5570 if (_session && _session->deletion_in_progress()) {
5571 /* the situation is under control */
5575 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5577 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5579 _routes->route_removed (tv);
5581 TimeAxisView::Children c = tv->get_child_list ();
5582 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5583 if (entered_track == i->get()) {
5588 /* remove it from the list of track views */
5590 TrackViewList::iterator i;
5592 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5593 i = track_views.erase (i);
5596 /* update whatever the current mixer strip is displaying, if revelant */
5598 boost::shared_ptr<Route> route;
5601 route = rtav->route ();
5604 if (current_mixer_strip && current_mixer_strip->route() == route) {
5606 TimeAxisView* next_tv;
5608 if (track_views.empty()) {
5610 } else if (i == track_views.end()) {
5611 next_tv = track_views.front();
5616 // skip VCAs (cannot be selected, n/a in editor-mixer)
5617 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5618 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5619 next_tv = track_views.front();
5621 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5622 /* just in case: no master, only a VCA remains */
5628 set_selected_mixer_strip (*next_tv);
5630 /* make the editor mixer strip go away setting the
5631 * button to inactive (which also unticks the menu option)
5634 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5640 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5646 DisplaySuspender ds;
5647 PresentationInfo::ChangeSuspender cs;
5649 if (apply_to_selection) {
5650 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end();) {
5652 TrackSelection::iterator j = i;
5655 hide_track_in_display (*i, false);
5660 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5662 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5663 /* this will hide the mixer strip */
5664 set_selected_mixer_strip (*tv);
5667 _routes->hide_track_in_display (*tv);
5672 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5677 _routes->show_track_in_display (*tv);
5678 if (move_into_view) {
5679 ensure_time_axis_view_is_visible (*tv, false);
5684 Editor::sync_track_view_list_and_routes ()
5686 track_views = TrackViewList (_routes->views ());
5688 _summary->set_background_dirty();
5689 _group_tabs->set_dirty ();
5691 return false; // do not call again (until needed)
5695 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5697 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5702 /** Find a StripableTimeAxisView by the ID of its stripable */
5703 StripableTimeAxisView*
5704 Editor::get_stripable_time_axis_by_id (const PBD::ID& id) const
5706 StripableTimeAxisView* v;
5708 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5709 if((v = dynamic_cast<StripableTimeAxisView*>(*i)) != 0) {
5710 if(v->stripable()->id() == id) {
5720 Editor::fit_route_group (RouteGroup *g)
5722 TrackViewList ts = axis_views_from_routes (g->route_list ());
5727 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5729 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5732 _session->cancel_audition ();
5736 if (_session->is_auditioning()) {
5737 _session->cancel_audition ();
5738 if (r == last_audition_region) {
5743 _session->audition_region (r);
5744 last_audition_region = r;
5749 Editor::hide_a_region (boost::shared_ptr<Region> r)
5751 r->set_hidden (true);
5755 Editor::show_a_region (boost::shared_ptr<Region> r)
5757 r->set_hidden (false);
5761 Editor::audition_region_from_region_list ()
5763 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5767 Editor::hide_region_from_region_list ()
5769 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5773 Editor::show_region_in_region_list ()
5775 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5779 Editor::step_edit_status_change (bool yn)
5782 start_step_editing ();
5784 stop_step_editing ();
5789 Editor::start_step_editing ()
5791 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5795 Editor::stop_step_editing ()
5797 step_edit_connection.disconnect ();
5801 Editor::check_step_edit ()
5803 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5804 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5806 mtv->check_step_edit ();
5810 return true; // do it again, till we stop
5814 Editor::scroll_press (Direction dir)
5816 ++_scroll_callbacks;
5818 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5819 /* delay the first auto-repeat */
5825 scroll_backward (1);
5833 scroll_up_one_track ();
5837 scroll_down_one_track ();
5841 /* do hacky auto-repeat */
5842 if (!_scroll_connection.connected ()) {
5844 _scroll_connection = Glib::signal_timeout().connect (
5845 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5848 _scroll_callbacks = 0;
5855 Editor::scroll_release ()
5857 _scroll_connection.disconnect ();
5860 /** Queue a change for the Editor viewport x origin to follow the playhead */
5862 Editor::reset_x_origin_to_follow_playhead ()
5864 samplepos_t const sample = playhead_cursor->current_sample ();
5866 if (sample < _leftmost_sample || sample > _leftmost_sample + current_page_samples()) {
5868 if (_session->transport_speed() < 0) {
5870 if (sample > (current_page_samples() / 2)) {
5871 center_screen (sample-(current_page_samples()/2));
5873 center_screen (current_page_samples()/2);
5880 if (sample < _leftmost_sample) {
5882 if (_session->transport_rolling()) {
5883 /* rolling; end up with the playhead at the right of the page */
5884 l = sample - current_page_samples ();
5886 /* not rolling: end up with the playhead 1/4 of the way along the page */
5887 l = sample - current_page_samples() / 4;
5891 if (_session->transport_rolling()) {
5892 /* rolling: end up with the playhead on the left of the page */
5895 /* not rolling: end up with the playhead 3/4 of the way along the page */
5896 l = sample - 3 * current_page_samples() / 4;
5904 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5910 Editor::super_rapid_screen_update ()
5912 if (!_session || !_session->engine().running()) {
5916 /* METERING / MIXER STRIPS */
5918 /* update track meters, if required */
5919 if (contents().is_mapped() && meters_running) {
5920 RouteTimeAxisView* rtv;
5921 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5922 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5923 rtv->fast_update ();
5928 /* and any current mixer strip */
5929 if (current_mixer_strip) {
5930 current_mixer_strip->fast_update ();
5933 bool latent_locate = false;
5934 samplepos_t sample = _session->audible_sample (&latent_locate);
5935 const int64_t now = g_get_monotonic_time ();
5938 if (_session->exporting ()) {
5939 /* freewheel/export may be faster or slower than transport_speed() / SR.
5940 * Also exporting multiple ranges locates/jumps without a _pending_locate_request.
5942 _last_update_time = 0;
5945 if (!_session->transport_rolling ()) {
5946 /* Do not interpolate the playhead position; just set it */
5947 _last_update_time = 0;
5950 if (_last_update_time > 0) {
5951 /* interpolate and smoothen playhead position */
5952 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_sample_rate () * 1e-6;
5953 samplepos_t guess = playhead_cursor->current_sample () + rint (ds);
5954 err = sample - guess;
5956 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5957 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5960 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5962 err, _err_screen_engine);
5967 _err_screen_engine = 0;
5970 if (err > 8192 || latent_locate) {
5971 // in case of x-runs or freewheeling
5972 _last_update_time = 0;
5973 sample = _session->audible_sample ();
5975 _last_update_time = now;
5978 /* snapped cursor stuff (the snapped_cursor shows where an operation is going to occur) */
5980 MusicSample where (sample, 0);
5981 if (!UIConfiguration::instance().get_show_snapped_cursor()) {
5982 snapped_cursor->hide ();
5983 } else if (_edit_point == EditAtPlayhead && !_dragging_playhead) {
5984 /* EditAtPlayhead does not snap */
5985 } else if (_edit_point == EditAtSelectedMarker) {
5986 /* NOTE: I don't think EditAtSelectedMarker should snap. They are what they are.
5987 * however, the current editing code -does- snap so I'll draw it that way for now.
5989 if (!selection->markers.empty()) {
5990 MusicSample ms (selection->markers.front()->position(), 0);
5991 snap_to (ms); // should use snap_to_with_modifier?
5992 snapped_cursor->set_position (ms.sample);
5993 snapped_cursor->show ();
5995 } else if (mouse_sample (where.sample, ignored)) { // cursor is in the editing canvas. show it.
5996 snapped_cursor->show ();
5997 } else { // mouse is out of the editing canvas. hide the snapped_cursor
5998 snapped_cursor->hide ();
6001 /* There are a few reasons why we might not update the playhead / viewport stuff:
6003 * 1. we don't update things when there's a pending locate request, otherwise
6004 * when the editor requests a locate there is a chance that this method
6005 * will move the playhead before the locate request is processed, causing
6007 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
6008 * 3. if we're still at the same frame that we were last time, there's nothing to do.
6010 if (_pending_locate_request) {
6011 _last_update_time = 0;
6015 if (_dragging_playhead) {
6016 _last_update_time = 0;
6020 if (playhead_cursor->current_sample () == sample) {
6024 playhead_cursor->set_position (sample);
6026 if (_session->requested_return_sample() >= 0) {
6027 _last_update_time = 0;
6031 if (!_follow_playhead || pending_visual_change.being_handled) {
6032 /* We only do this if we aren't already
6033 * handling a visual change (ie if
6034 * pending_visual_change.being_handled is
6035 * false) so that these requests don't stack
6036 * up there are too many of them to handle in
6042 if (!_stationary_playhead) {
6043 reset_x_origin_to_follow_playhead ();
6045 samplepos_t const sample = playhead_cursor->current_sample ();
6046 double target = ((double)sample - (double)current_page_samples() / 2.0);
6047 if (target <= 0.0) {
6050 /* compare to EditorCursor::set_position() */
6051 double const old_pos = sample_to_pixel_unrounded (_leftmost_sample);
6052 double const new_pos = sample_to_pixel_unrounded (target);
6053 if (rint (new_pos) != rint (old_pos)) {
6054 reset_x_origin (pixel_to_sample (new_pos));
6061 Editor::session_going_away ()
6063 _have_idled = false;
6065 _session_connections.drop_connections ();
6067 super_rapid_screen_update_connection.disconnect ();
6069 selection->clear ();
6070 cut_buffer->clear ();
6072 clicked_regionview = 0;
6073 clicked_axisview = 0;
6074 clicked_routeview = 0;
6075 entered_regionview = 0;
6077 _last_update_time = 0;
6080 playhead_cursor->hide ();
6082 /* rip everything out of the list displays */
6086 _route_groups->clear ();
6088 /* do this first so that deleting a track doesn't reset cms to null
6089 and thus cause a leak.
6092 if (current_mixer_strip) {
6093 if (current_mixer_strip->get_parent() != 0) {
6094 global_hpacker.remove (*current_mixer_strip);
6096 delete current_mixer_strip;
6097 current_mixer_strip = 0;
6100 /* delete all trackviews */
6102 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6105 track_views.clear ();
6107 nudge_clock->set_session (0);
6109 editor_list_button.set_active(false);
6110 editor_list_button.set_sensitive(false);
6112 /* clear tempo/meter rulers */
6113 remove_metric_marks ();
6114 clear_marker_display ();
6120 stop_step_editing ();
6124 /* get rid of any existing editor mixer strip */
6126 WindowTitle title(Glib::get_application_name());
6127 title += _("Editor");
6129 own_window()->set_title (title.get_string());
6132 SessionHandlePtr::session_going_away ();
6136 Editor::trigger_script (int i)
6138 LuaInstance::instance()-> call_action (i);
6142 Editor::show_editor_list (bool yn)
6145 _editor_list_vbox.show ();
6147 _editor_list_vbox.hide ();
6152 Editor::change_region_layering_order (bool from_context_menu)
6154 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
6156 if (!clicked_routeview) {
6157 if (layering_order_editor) {
6158 layering_order_editor->hide ();
6163 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
6169 boost::shared_ptr<Playlist> pl = track->playlist();
6175 if (layering_order_editor == 0) {
6176 layering_order_editor = new RegionLayeringOrderEditor (*this);
6179 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
6180 layering_order_editor->maybe_present ();
6184 Editor::update_region_layering_order_editor ()
6186 if (layering_order_editor && layering_order_editor->is_visible ()) {
6187 change_region_layering_order (true);
6192 Editor::setup_fade_images ()
6194 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
6195 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
6196 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
6197 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
6198 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
6200 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
6201 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
6202 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
6203 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
6204 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
6208 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
6210 Editor::action_menu_item (std::string const & name)
6212 Glib::RefPtr<Action> a = editor_actions->get_action (name);
6215 return *manage (a->create_menu_item ());
6219 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6221 EventBox* b = manage (new EventBox);
6222 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6223 Label* l = manage (new Label (name));
6227 _the_notebook.append_page (widget, *b);
6231 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6233 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6234 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6237 if (ev->type == GDK_2BUTTON_PRESS) {
6239 /* double-click on a notebook tab shrinks or expands the notebook */
6241 if (_notebook_shrunk) {
6242 if (pre_notebook_shrink_pane_width) {
6243 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6245 _notebook_shrunk = false;
6247 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6249 /* this expands the LHS of the edit pane to cover the notebook
6250 PAGE but leaves the tabs visible.
6252 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6253 _notebook_shrunk = true;
6261 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6263 using namespace Menu_Helpers;
6265 MenuList& items = _control_point_context_menu.items ();
6268 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6269 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6270 if (!can_remove_control_point (item)) {
6271 items.back().set_sensitive (false);
6274 _control_point_context_menu.popup (event->button.button, event->button.time);
6278 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6280 using namespace Menu_Helpers;
6282 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6287 /* We need to get the selection here and pass it to the operations, since
6288 popping up the menu will cause a region leave event which clears
6289 entered_regionview. */
6291 MidiRegionView& mrv = note->region_view();
6292 const RegionSelection rs = get_regions_from_selection_and_entered ();
6293 const uint32_t sel_size = mrv.selection_size ();
6295 MenuList& items = _note_context_menu.items();
6299 items.push_back(MenuElem(_("Delete"),
6300 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6303 items.push_back(MenuElem(_("Edit..."),
6304 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6305 if (sel_size != 1) {
6306 items.back().set_sensitive (false);
6309 items.push_back(MenuElem(_("Transpose..."),
6310 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6313 items.push_back(MenuElem(_("Legatize"),
6314 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6316 items.back().set_sensitive (false);
6319 items.push_back(MenuElem(_("Quantize..."),
6320 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6322 items.push_back(MenuElem(_("Remove Overlap"),
6323 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6325 items.back().set_sensitive (false);
6328 items.push_back(MenuElem(_("Transform..."),
6329 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6331 _note_context_menu.popup (event->button.button, event->button.time);
6335 Editor::zoom_vertical_modifier_released()
6337 _stepping_axis_view = 0;
6341 Editor::ui_parameter_changed (string parameter)
6343 if (parameter == "icon-set") {
6344 while (!_cursor_stack.empty()) {
6345 _cursor_stack.pop_back();
6347 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6348 _cursor_stack.push_back(_cursors->grabber);
6349 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6350 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6352 } else if (parameter == "draggable-playhead") {
6353 if (_verbose_cursor) {
6354 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6356 } else if (parameter == "use-note-bars-for-velocity") {
6357 ArdourCanvas::Note::set_show_velocity_bars (UIConfiguration::instance().get_use_note_bars_for_velocity());
6358 _track_canvas->request_redraw (_track_canvas->visible_area());
6359 } else if (parameter == "use-note-color-for-velocity") {
6360 /* handled individually by each MidiRegionView */
6365 Editor::use_own_window (bool and_fill_it)
6367 bool new_window = !own_window();
6369 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6371 if (win && new_window) {
6372 win->set_name ("EditorWindow");
6374 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6376 // win->signal_realize().connect (*this, &Editor::on_realize);
6377 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6378 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6379 win->set_data ("ardour-bindings", bindings);
6384 DisplaySuspender ds;
6385 contents().show_all ();
6387 /* XXX: this is a bit unfortunate; it would probably
6388 be nicer if we could just call show () above rather
6389 than needing the show_all ()
6392 /* re-hide stuff if necessary */
6393 editor_list_button_toggled ();
6394 parameter_changed ("show-summary");
6395 parameter_changed ("show-group-tabs");
6396 parameter_changed ("show-zoom-tools");
6398 /* now reset all audio_time_axis heights, because widgets might need
6404 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6405 tv = (static_cast<TimeAxisView*>(*i));
6406 tv->reset_height ();
6409 if (current_mixer_strip) {
6410 current_mixer_strip->hide_things ();
6411 current_mixer_strip->parameter_changed ("mixer-element-visibility");