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/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include "gtkmm2ext/tearoff.h"
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/audio_track.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/audioregion.h"
71 #include "ardour/location.h"
72 #include "ardour/profile.h"
73 #include "ardour/route_group.h"
74 #include "ardour/session_playlists.h"
75 #include "ardour/tempo.h"
76 #include "ardour/utils.h"
78 #include "canvas/debug.h"
79 #include "canvas/text.h"
81 #include "control_protocol/control_protocol.h"
85 #include "analysis_window.h"
86 #include "audio_clock.h"
87 #include "audio_region_view.h"
88 #include "audio_streamview.h"
89 #include "audio_time_axis.h"
90 #include "automation_time_axis.h"
91 #include "bundle_manager.h"
92 #include "crossfade_edit.h"
96 #include "editor_cursors.h"
97 #include "editor_drag.h"
98 #include "editor_group_tabs.h"
99 #include "editor_locations.h"
100 #include "editor_regions.h"
101 #include "editor_route_groups.h"
102 #include "editor_routes.h"
103 #include "editor_snapshots.h"
104 #include "editor_summary.h"
105 #include "global_port_matrix.h"
106 #include "gui_object.h"
107 #include "gui_thread.h"
108 #include "keyboard.h"
110 #include "midi_region_view.h"
111 #include "midi_time_axis.h"
112 #include "mixer_strip.h"
113 #include "mixer_ui.h"
114 #include "mouse_cursors.h"
115 #include "note_base.h"
116 #include "playlist_selector.h"
117 #include "public_editor.h"
118 #include "region_layering_order_editor.h"
119 #include "rgb_macros.h"
120 #include "rhythm_ferret.h"
121 #include "selection.h"
123 #include "tempo_lines.h"
124 #include "time_axis_view.h"
127 #include "verbose_cursor.h"
132 using namespace ARDOUR;
133 using namespace ARDOUR_UI_UTILS;
136 using namespace Glib;
137 using namespace Gtkmm2ext;
138 using namespace Editing;
140 using PBD::internationalize;
142 using Gtkmm2ext::Keyboard;
144 double Editor::timebar_height = 15.0;
146 static const gchar *_snap_type_strings[] = {
180 static const gchar *_snap_mode_strings[] = {
187 static const gchar *_edit_point_strings[] = {
194 static const gchar *_edit_mode_strings[] = {
202 static const gchar *_zoom_focus_strings[] = {
212 #ifdef USE_RUBBERBAND
213 static const gchar *_rb_opt_strings[] = {
216 N_("Balanced multitimbral mixture"),
217 N_("Unpitched percussion with stable notes"),
218 N_("Crisp monophonic instrumental"),
219 N_("Unpitched solo percussion"),
220 N_("Resample without preserving pitch"),
225 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
228 pane_size_watcher (Paned* pane)
230 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
234 Quartz: impossible to access
236 so stop that by preventing it from ever getting too narrow. 35
237 pixels is basically a rough guess at the tab width.
242 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
244 gint pos = pane->get_position ();
246 if (pos > max_width_of_lhs) {
247 pane->set_position (max_width_of_lhs);
252 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
254 /* time display buttons */
255 , minsec_label (_("Mins:Secs"))
256 , bbt_label (_("Bars:Beats"))
257 , timecode_label (_("Timecode"))
258 , samples_label (_("Samples"))
259 , tempo_label (_("Tempo"))
260 , meter_label (_("Meter"))
261 , mark_label (_("Location Markers"))
262 , range_mark_label (_("Range Markers"))
263 , transport_mark_label (_("Loop/Punch Ranges"))
264 , cd_mark_label (_("CD Markers"))
265 , videotl_label (_("Video Timeline"))
266 , edit_packer (4, 4, true)
268 /* the values here don't matter: layout widgets
269 reset them as needed.
272 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
273 , horizontal_adjustment (0.0, 0.0, 1e16)
274 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
276 , controls_layout (unused_adjustment, vertical_adjustment)
278 /* tool bar related */
280 , toolbar_selection_clock_table (2,3)
281 , _mouse_mode_tearoff (0)
282 , automation_mode_button (_("mode"))
286 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
287 , selection_op_cmd_depth (0)
288 , selection_op_history_it (0)
292 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
293 , meters_running(false)
294 , _pending_locate_request (false)
295 , _pending_initial_locate (false)
296 , _last_cut_copy_source_track (0)
298 , _region_selection_change_updates_region_list (true)
299 , _following_mixer_selection (false)
300 , _control_point_toggled_on_press (false)
301 , _stepping_axis_view (0)
305 /* we are a singleton */
307 PublicEditor::_instance = this;
311 selection = new Selection (this);
312 cut_buffer = new Selection (this);
313 _selection_memento = new SelectionMemento ();
314 selection_op_history.clear();
317 clicked_regionview = 0;
318 clicked_axisview = 0;
319 clicked_routeview = 0;
320 clicked_control_point = 0;
321 last_update_frame = 0;
324 _drags = new DragManager (this);
327 current_mixer_strip = 0;
330 snap_type_strings = I18N (_snap_type_strings);
331 snap_mode_strings = I18N (_snap_mode_strings);
332 zoom_focus_strings = I18N (_zoom_focus_strings);
333 edit_mode_strings = I18N (_edit_mode_strings);
334 edit_point_strings = I18N (_edit_point_strings);
335 #ifdef USE_RUBBERBAND
336 rb_opt_strings = I18N (_rb_opt_strings);
340 build_edit_mode_menu();
341 build_zoom_focus_menu();
342 build_track_count_menu();
343 build_snap_mode_menu();
344 build_snap_type_menu();
345 build_edit_point_menu();
347 snap_threshold = 5.0;
348 bbt_beat_subdivision = 4;
349 _visible_canvas_width = 0;
350 _visible_canvas_height = 0;
351 autoscroll_horizontal_allowed = false;
352 autoscroll_vertical_allowed = false;
357 current_interthread_info = 0;
358 _show_measures = true;
360 show_gain_after_trim = false;
362 have_pending_keyboard_selection = false;
363 _follow_playhead = true;
364 _stationary_playhead = false;
365 editor_ruler_menu = 0;
366 no_ruler_shown_update = false;
368 range_marker_menu = 0;
369 marker_menu_item = 0;
370 tempo_or_meter_marker_menu = 0;
371 transport_marker_menu = 0;
372 new_transport_marker_menu = 0;
373 editor_mixer_strip_width = Wide;
374 show_editor_mixer_when_tracks_arrive = false;
375 region_edit_menu_split_multichannel_item = 0;
376 region_edit_menu_split_item = 0;
379 current_stepping_trackview = 0;
381 entered_regionview = 0;
383 clear_entered_track = false;
386 button_release_can_deselect = true;
387 _dragging_playhead = false;
388 _dragging_edit_point = false;
389 select_new_marker = false;
391 layering_order_editor = 0;
392 no_save_visual = false;
394 within_track_canvas = false;
396 scrubbing_direction = 0;
400 location_marker_color = ARDOUR_UI::config()->color ("location marker");
401 location_range_color = ARDOUR_UI::config()->color ("location range");
402 location_cd_marker_color = ARDOUR_UI::config()->color ("location cd marker");
403 location_loop_color = ARDOUR_UI::config()->color ("location loop");
404 location_punch_color = ARDOUR_UI::config()->color ("location punch");
406 zoom_focus = ZoomFocusLeft;
407 _edit_point = EditAtMouse;
408 _visible_track_count = -1;
410 samples_per_pixel = 2048; /* too early to use reset_zoom () */
412 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::config()->get_font_scale() / 102400.));
413 TimeAxisView::setup_sizes ();
414 Marker::setup_sizes (timebar_height);
416 _scroll_callbacks = 0;
418 bbt_label.set_name ("EditorRulerLabel");
419 bbt_label.set_size_request (-1, (int)timebar_height);
420 bbt_label.set_alignment (1.0, 0.5);
421 bbt_label.set_padding (5,0);
423 bbt_label.set_no_show_all();
424 minsec_label.set_name ("EditorRulerLabel");
425 minsec_label.set_size_request (-1, (int)timebar_height);
426 minsec_label.set_alignment (1.0, 0.5);
427 minsec_label.set_padding (5,0);
428 minsec_label.hide ();
429 minsec_label.set_no_show_all();
430 timecode_label.set_name ("EditorRulerLabel");
431 timecode_label.set_size_request (-1, (int)timebar_height);
432 timecode_label.set_alignment (1.0, 0.5);
433 timecode_label.set_padding (5,0);
434 timecode_label.hide ();
435 timecode_label.set_no_show_all();
436 samples_label.set_name ("EditorRulerLabel");
437 samples_label.set_size_request (-1, (int)timebar_height);
438 samples_label.set_alignment (1.0, 0.5);
439 samples_label.set_padding (5,0);
440 samples_label.hide ();
441 samples_label.set_no_show_all();
443 tempo_label.set_name ("EditorRulerLabel");
444 tempo_label.set_size_request (-1, (int)timebar_height);
445 tempo_label.set_alignment (1.0, 0.5);
446 tempo_label.set_padding (5,0);
448 tempo_label.set_no_show_all();
450 meter_label.set_name ("EditorRulerLabel");
451 meter_label.set_size_request (-1, (int)timebar_height);
452 meter_label.set_alignment (1.0, 0.5);
453 meter_label.set_padding (5,0);
455 meter_label.set_no_show_all();
457 if (Profile->get_trx()) {
458 mark_label.set_text (_("Markers"));
460 mark_label.set_name ("EditorRulerLabel");
461 mark_label.set_size_request (-1, (int)timebar_height);
462 mark_label.set_alignment (1.0, 0.5);
463 mark_label.set_padding (5,0);
465 mark_label.set_no_show_all();
467 cd_mark_label.set_name ("EditorRulerLabel");
468 cd_mark_label.set_size_request (-1, (int)timebar_height);
469 cd_mark_label.set_alignment (1.0, 0.5);
470 cd_mark_label.set_padding (5,0);
471 cd_mark_label.hide();
472 cd_mark_label.set_no_show_all();
474 videotl_bar_height = 4;
475 videotl_label.set_name ("EditorRulerLabel");
476 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
477 videotl_label.set_alignment (1.0, 0.5);
478 videotl_label.set_padding (5,0);
479 videotl_label.hide();
480 videotl_label.set_no_show_all();
482 range_mark_label.set_name ("EditorRulerLabel");
483 range_mark_label.set_size_request (-1, (int)timebar_height);
484 range_mark_label.set_alignment (1.0, 0.5);
485 range_mark_label.set_padding (5,0);
486 range_mark_label.hide();
487 range_mark_label.set_no_show_all();
489 transport_mark_label.set_name ("EditorRulerLabel");
490 transport_mark_label.set_size_request (-1, (int)timebar_height);
491 transport_mark_label.set_alignment (1.0, 0.5);
492 transport_mark_label.set_padding (5,0);
493 transport_mark_label.hide();
494 transport_mark_label.set_no_show_all();
496 initialize_canvas ();
498 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
500 _summary = new EditorSummary (this);
502 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
503 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
505 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
507 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
508 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
510 edit_controls_vbox.set_spacing (0);
511 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
512 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
514 HBox* h = manage (new HBox);
515 _group_tabs = new EditorGroupTabs (this);
516 if (!ARDOUR::Profile->get_trx()) {
517 h->pack_start (*_group_tabs, PACK_SHRINK);
519 h->pack_start (edit_controls_vbox);
520 controls_layout.add (*h);
522 controls_layout.set_name ("EditControlsBase");
523 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
524 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
525 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
527 _cursors = new MouseCursors;
528 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
529 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
531 /* Push default cursor to ever-present bottom of cursor stack. */
532 push_canvas_cursor(_cursors->grabber);
534 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
536 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
537 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
538 pad_line_1->set_outline_color (0xFF0000FF);
544 edit_packer.set_col_spacings (0);
545 edit_packer.set_row_spacings (0);
546 edit_packer.set_homogeneous (false);
547 edit_packer.set_border_width (0);
548 edit_packer.set_name ("EditorWindow");
550 time_bars_event_box.add (time_bars_vbox);
551 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
552 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
554 /* labels for the time bars */
555 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
557 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
559 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
561 bottom_hbox.set_border_width (2);
562 bottom_hbox.set_spacing (3);
564 _route_groups = new EditorRouteGroups (this);
565 _routes = new EditorRoutes (this);
566 _regions = new EditorRegions (this);
567 _snapshots = new EditorSnapshots (this);
568 _locations = new EditorLocations (this);
570 /* these are static location signals */
572 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
573 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
574 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
576 add_notebook_page (_("Regions"), _regions->widget ());
577 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
578 add_notebook_page (_("Snapshots"), _snapshots->widget ());
579 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
580 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
582 _the_notebook.set_show_tabs (true);
583 _the_notebook.set_scrollable (true);
584 _the_notebook.popup_disable ();
585 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
586 _the_notebook.show_all ();
588 _notebook_shrunk = false;
590 editor_summary_pane.pack1(edit_packer);
592 Button* summary_arrows_left_left = manage (new Button);
593 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
594 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
595 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
597 Button* summary_arrows_left_right = manage (new Button);
598 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
599 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
600 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
602 VBox* summary_arrows_left = manage (new VBox);
603 summary_arrows_left->pack_start (*summary_arrows_left_left);
604 summary_arrows_left->pack_start (*summary_arrows_left_right);
606 Button* summary_arrows_right_up = manage (new Button);
607 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
608 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
609 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
611 Button* summary_arrows_right_down = manage (new Button);
612 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
613 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
614 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
616 VBox* summary_arrows_right = manage (new VBox);
617 summary_arrows_right->pack_start (*summary_arrows_right_up);
618 summary_arrows_right->pack_start (*summary_arrows_right_down);
620 Frame* summary_frame = manage (new Frame);
621 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
623 summary_frame->add (*_summary);
624 summary_frame->show ();
626 _summary_hbox.pack_start (*summary_arrows_left, false, false);
627 _summary_hbox.pack_start (*summary_frame, true, true);
628 _summary_hbox.pack_start (*summary_arrows_right, false, false);
630 if (!ARDOUR::Profile->get_trx()) {
631 editor_summary_pane.pack2 (_summary_hbox);
634 edit_pane.pack1 (editor_summary_pane, true, true);
635 if (!ARDOUR::Profile->get_trx()) {
636 edit_pane.pack2 (_the_notebook, false, true);
639 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
641 /* XXX: editor_summary_pane might need similar to the edit_pane */
643 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
645 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
646 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
648 top_hbox.pack_start (toolbar_frame);
650 HBox *hbox = manage (new HBox);
651 hbox->pack_start (edit_pane, true, true);
653 global_vpacker.pack_start (top_hbox, false, false);
654 global_vpacker.pack_start (*hbox, true, true);
656 global_hpacker.pack_start (global_vpacker, true, true);
658 set_name ("EditorWindow");
659 add_accel_group (ActionManager::ui_manager->get_accel_group());
661 status_bar_hpacker.show ();
663 vpacker.pack_end (status_bar_hpacker, false, false);
664 vpacker.pack_end (global_hpacker, true, true);
666 /* register actions now so that set_state() can find them and set toggles/checks etc */
669 /* when we start using our own keybinding system for the editor, this
670 * will be uncommented
676 set_zoom_focus (zoom_focus);
677 set_visible_track_count (_visible_track_count);
678 _snap_type = SnapToBeat;
679 set_snap_to (_snap_type);
680 _snap_mode = SnapOff;
681 set_snap_mode (_snap_mode);
682 set_mouse_mode (MouseObject, true);
683 pre_internal_mouse_mode = MouseObject;
684 pre_internal_snap_type = _snap_type;
685 pre_internal_snap_mode = _snap_mode;
686 internal_snap_type = _snap_type;
687 internal_snap_mode = _snap_mode;
688 set_edit_point_preference (EditAtMouse, true);
690 _playlist_selector = new PlaylistSelector();
691 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
693 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
697 nudge_forward_button.set_name ("nudge button");
698 nudge_forward_button.set_image(::get_icon("nudge_right"));
700 nudge_backward_button.set_name ("nudge button");
701 nudge_backward_button.set_image(::get_icon("nudge_left"));
703 fade_context_menu.set_name ("ArdourContextMenu");
705 /* icons, titles, WM stuff */
707 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
708 Glib::RefPtr<Gdk::Pixbuf> icon;
710 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
711 window_icons.push_back (icon);
713 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
714 window_icons.push_back (icon);
716 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
717 window_icons.push_back (icon);
719 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
720 window_icons.push_back (icon);
722 if (!window_icons.empty()) {
723 // set_icon_list (window_icons);
724 set_default_icon_list (window_icons);
727 WindowTitle title(Glib::get_application_name());
728 title += _("Editor");
729 set_title (title.get_string());
730 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
733 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
735 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
736 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
738 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
740 /* allow external control surfaces/protocols to do various things */
742 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
743 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
744 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
745 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
746 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
747 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
748 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
749 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
750 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
751 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
752 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
753 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
754 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
755 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
757 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
758 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
759 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
760 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
761 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
763 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
765 /* problematic: has to return a value and thus cannot be x-thread */
767 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
769 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
770 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
772 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
774 _ignore_region_action = false;
775 _last_region_menu_was_main = false;
776 _popup_region_menu_item = 0;
778 _ignore_follow_edits = false;
780 _show_marker_lines = false;
782 /* Button bindings */
784 button_bindings = new Bindings;
786 XMLNode* node = button_settings();
788 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
789 button_bindings->load (**i);
795 /* grab current parameter state */
796 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
797 ARDOUR_UI::config()->map_parameters (pc);
799 setup_fade_images ();
806 delete button_bindings;
808 delete _route_groups;
809 delete _track_canvas_viewport;
815 Editor::button_settings () const
817 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
818 XMLNode* node = find_named_node (*settings, X_("Buttons"));
821 node = new XMLNode (X_("Buttons"));
828 Editor::add_toplevel_menu (Container& cont)
830 vpacker.pack_start (cont, false, false);
835 Editor::add_transport_frame (Container& cont)
837 if(ARDOUR::Profile->get_mixbus()) {
838 global_vpacker.pack_start (cont, false, false);
839 global_vpacker.reorder_child (cont, 0);
842 vpacker.pack_start (cont, false, false);
847 Editor::get_smart_mode () const
849 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
853 Editor::catch_vanishing_regionview (RegionView *rv)
855 /* note: the selection will take care of the vanishing
856 audioregionview by itself.
859 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
863 if (clicked_regionview == rv) {
864 clicked_regionview = 0;
867 if (entered_regionview == rv) {
868 set_entered_regionview (0);
871 if (!_all_region_actions_sensitized) {
872 sensitize_all_region_actions (true);
877 Editor::set_entered_regionview (RegionView* rv)
879 if (rv == entered_regionview) {
883 if (entered_regionview) {
884 entered_regionview->exited ();
887 entered_regionview = rv;
889 if (entered_regionview != 0) {
890 entered_regionview->entered ();
893 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
894 /* This RegionView entry might have changed what region actions
895 are allowed, so sensitize them all in case a key is pressed.
897 sensitize_all_region_actions (true);
902 Editor::set_entered_track (TimeAxisView* tav)
905 entered_track->exited ();
911 entered_track->entered ();
916 Editor::show_window ()
918 if (!is_visible ()) {
922 /* XXX: this is a bit unfortunate; it would probably
923 be nicer if we could just call show () above rather
924 than needing the show_all ()
927 /* re-hide stuff if necessary */
928 editor_list_button_toggled ();
929 parameter_changed ("show-summary");
930 parameter_changed ("show-group-tabs");
931 parameter_changed ("show-zoom-tools");
933 /* now reset all audio_time_axis heights, because widgets might need
939 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
940 tv = (static_cast<TimeAxisView*>(*i));
944 if (current_mixer_strip) {
945 current_mixer_strip->hide_things ();
946 current_mixer_strip->parameter_changed ("mixer-element-visibility");
954 Editor::instant_save ()
956 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
961 _session->add_instant_xml(get_state());
963 Config->add_instant_xml(get_state());
968 Editor::control_vertical_zoom_in_all ()
970 tav_zoom_smooth (false, true);
974 Editor::control_vertical_zoom_out_all ()
976 tav_zoom_smooth (true, true);
980 Editor::control_vertical_zoom_in_selected ()
982 tav_zoom_smooth (false, false);
986 Editor::control_vertical_zoom_out_selected ()
988 tav_zoom_smooth (true, false);
992 Editor::control_view (uint32_t view)
994 goto_visual_state (view);
998 Editor::control_unselect ()
1000 selection->clear_tracks ();
1004 Editor::control_select (uint32_t rid, Selection::Operation op)
1006 /* handles the (static) signal from the ControlProtocol class that
1007 * requests setting the selected track to a given RID
1014 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1020 TimeAxisView* tav = axis_view_from_route (r);
1024 case Selection::Add:
1025 selection->add (tav);
1027 case Selection::Toggle:
1028 selection->toggle (tav);
1030 case Selection::Extend:
1032 case Selection::Set:
1033 selection->set (tav);
1037 selection->clear_tracks ();
1042 Editor::control_step_tracks_up ()
1044 scroll_tracks_up_line ();
1048 Editor::control_step_tracks_down ()
1050 scroll_tracks_down_line ();
1054 Editor::control_scroll (float fraction)
1056 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1062 double step = fraction * current_page_samples();
1065 _control_scroll_target is an optional<T>
1067 it acts like a pointer to an framepos_t, with
1068 a operator conversion to boolean to check
1069 that it has a value could possibly use
1070 playhead_cursor->current_frame to store the
1071 value and a boolean in the class to know
1072 when it's out of date
1075 if (!_control_scroll_target) {
1076 _control_scroll_target = _session->transport_frame();
1077 _dragging_playhead = true;
1080 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1081 *_control_scroll_target = 0;
1082 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1083 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1085 *_control_scroll_target += (framepos_t) trunc (step);
1088 /* move visuals, we'll catch up with it later */
1090 playhead_cursor->set_position (*_control_scroll_target);
1091 UpdateAllTransportClocks (*_control_scroll_target);
1093 if (*_control_scroll_target > (current_page_samples() / 2)) {
1094 /* try to center PH in window */
1095 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1101 Now we do a timeout to actually bring the session to the right place
1102 according to the playhead. This is to avoid reading disk buffers on every
1103 call to control_scroll, which is driven by ScrollTimeline and therefore
1104 probably by a control surface wheel which can generate lots of events.
1106 /* cancel the existing timeout */
1108 control_scroll_connection.disconnect ();
1110 /* add the next timeout */
1112 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1116 Editor::deferred_control_scroll (framepos_t /*target*/)
1118 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1119 // reset for next stream
1120 _control_scroll_target = boost::none;
1121 _dragging_playhead = false;
1126 Editor::access_action (std::string action_group, std::string action_item)
1132 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1135 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1143 Editor::on_realize ()
1145 Window::on_realize ();
1148 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1149 start_lock_event_timing ();
1152 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1156 Editor::start_lock_event_timing ()
1158 /* check if we should lock the GUI every 30 seconds */
1160 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1164 Editor::generic_event_handler (GdkEvent* ev)
1167 case GDK_BUTTON_PRESS:
1168 case GDK_BUTTON_RELEASE:
1169 case GDK_MOTION_NOTIFY:
1171 case GDK_KEY_RELEASE:
1172 gettimeofday (&last_event_time, 0);
1175 case GDK_LEAVE_NOTIFY:
1176 switch (ev->crossing.detail) {
1177 case GDK_NOTIFY_UNKNOWN:
1178 case GDK_NOTIFY_INFERIOR:
1179 case GDK_NOTIFY_ANCESTOR:
1181 case GDK_NOTIFY_VIRTUAL:
1182 case GDK_NOTIFY_NONLINEAR:
1183 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1184 /* leaving window, so reset focus, thus ending any and
1185 all text entry operations.
1200 Editor::lock_timeout_callback ()
1202 struct timeval now, delta;
1204 gettimeofday (&now, 0);
1206 timersub (&now, &last_event_time, &delta);
1208 if (delta.tv_sec > (time_t) ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1210 /* don't call again. Returning false will effectively
1211 disconnect us from the timer callback.
1213 unlock() will call start_lock_event_timing() to get things
1223 Editor::map_position_change (framepos_t frame)
1225 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1227 if (_session == 0) {
1231 if (_follow_playhead) {
1232 center_screen (frame);
1235 playhead_cursor->set_position (frame);
1239 Editor::center_screen (framepos_t frame)
1241 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1243 /* if we're off the page, then scroll.
1246 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1247 center_screen_internal (frame, page);
1252 Editor::center_screen_internal (framepos_t frame, float page)
1257 frame -= (framepos_t) page;
1262 reset_x_origin (frame);
1267 Editor::update_title ()
1269 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1272 bool dirty = _session->dirty();
1274 string session_name;
1276 if (_session->snap_name() != _session->name()) {
1277 session_name = _session->snap_name();
1279 session_name = _session->name();
1283 session_name = "*" + session_name;
1286 WindowTitle title(session_name);
1287 title += Glib::get_application_name();
1288 set_title (title.get_string());
1290 /* ::session_going_away() will have taken care of it */
1295 Editor::set_session (Session *t)
1297 SessionHandlePtr::set_session (t);
1303 _playlist_selector->set_session (_session);
1304 nudge_clock->set_session (_session);
1305 _summary->set_session (_session);
1306 _group_tabs->set_session (_session);
1307 _route_groups->set_session (_session);
1308 _regions->set_session (_session);
1309 _snapshots->set_session (_session);
1310 _routes->set_session (_session);
1311 _locations->set_session (_session);
1313 if (rhythm_ferret) {
1314 rhythm_ferret->set_session (_session);
1317 if (analysis_window) {
1318 analysis_window->set_session (_session);
1322 sfbrowser->set_session (_session);
1325 compute_fixed_ruler_scale ();
1327 /* Make sure we have auto loop and auto punch ranges */
1329 Location* loc = _session->locations()->auto_loop_location();
1331 loc->set_name (_("Loop"));
1334 loc = _session->locations()->auto_punch_location();
1337 loc->set_name (_("Punch"));
1340 refresh_location_display ();
1342 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1343 the selected Marker; this needs the LocationMarker list to be available.
1345 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1346 set_state (*node, Stateful::loading_state_version);
1348 /* catch up with the playhead */
1350 _session->request_locate (playhead_cursor->current_frame ());
1351 _pending_initial_locate = true;
1355 /* These signals can all be emitted by a non-GUI thread. Therefore the
1356 handlers for them must not attempt to directly interact with the GUI,
1357 but use PBD::Signal<T>::connect() which accepts an event loop
1358 ("context") where the handler will be asked to run.
1361 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1362 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1363 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1364 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1365 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1366 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1367 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1368 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1369 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1370 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1371 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1372 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1373 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1375 playhead_cursor->show ();
1377 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1378 Config->map_parameters (pc);
1379 _session->config.map_parameters (pc);
1381 restore_ruler_visibility ();
1382 //tempo_map_changed (PropertyChange (0));
1383 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1385 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1386 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1389 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1390 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1393 switch (_snap_type) {
1394 case SnapToRegionStart:
1395 case SnapToRegionEnd:
1396 case SnapToRegionSync:
1397 case SnapToRegionBoundary:
1398 build_region_boundary_cache ();
1405 /* register for undo history */
1406 _session->register_with_memento_command_factory(id(), this);
1407 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1409 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1411 start_updating_meters ();
1415 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1417 if (a->get_name() == "RegionMenu") {
1418 /* When the main menu's region menu is opened, we setup the actions so that they look right
1419 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1420 so we resensitize all region actions when the entered regionview or the region selection
1421 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1422 happens after the region context menu is opened. So we set a flag here, too.
1426 sensitize_the_right_region_actions ();
1427 _last_region_menu_was_main = true;
1432 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1434 using namespace Menu_Helpers;
1436 void (Editor::*emf)(FadeShape);
1437 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1440 images = &_xfade_in_images;
1441 emf = &Editor::set_fade_in_shape;
1443 images = &_xfade_out_images;
1444 emf = &Editor::set_fade_out_shape;
1449 _("Linear (for highly correlated material)"),
1450 *(*images)[FadeLinear],
1451 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1455 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1459 _("Constant power"),
1460 *(*images)[FadeConstantPower],
1461 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1464 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1469 *(*images)[FadeSymmetric],
1470 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1474 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1479 *(*images)[FadeSlow],
1480 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1483 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1488 *(*images)[FadeFast],
1489 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1492 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1495 /** Pop up a context menu for when the user clicks on a start crossfade */
1497 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1499 using namespace Menu_Helpers;
1500 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1505 MenuList& items (xfade_in_context_menu.items());
1508 if (arv->audio_region()->fade_in_active()) {
1509 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1511 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1514 items.push_back (SeparatorElem());
1515 fill_xfade_menu (items, true);
1517 xfade_in_context_menu.popup (button, time);
1520 /** Pop up a context menu for when the user clicks on an end crossfade */
1522 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1524 using namespace Menu_Helpers;
1525 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1530 MenuList& items (xfade_out_context_menu.items());
1533 if (arv->audio_region()->fade_out_active()) {
1534 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1536 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1539 items.push_back (SeparatorElem());
1540 fill_xfade_menu (items, false);
1542 xfade_out_context_menu.popup (button, time);
1546 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1548 using namespace Menu_Helpers;
1549 Menu* (Editor::*build_menu_function)();
1552 switch (item_type) {
1554 case RegionViewName:
1555 case RegionViewNameHighlight:
1556 case LeftFrameHandle:
1557 case RightFrameHandle:
1558 if (with_selection) {
1559 build_menu_function = &Editor::build_track_selection_context_menu;
1561 build_menu_function = &Editor::build_track_region_context_menu;
1566 if (with_selection) {
1567 build_menu_function = &Editor::build_track_selection_context_menu;
1569 build_menu_function = &Editor::build_track_context_menu;
1574 if (clicked_routeview->track()) {
1575 build_menu_function = &Editor::build_track_context_menu;
1577 build_menu_function = &Editor::build_track_bus_context_menu;
1582 /* probably shouldn't happen but if it does, we don't care */
1586 menu = (this->*build_menu_function)();
1587 menu->set_name ("ArdourContextMenu");
1589 /* now handle specific situations */
1591 switch (item_type) {
1593 case RegionViewName:
1594 case RegionViewNameHighlight:
1595 case LeftFrameHandle:
1596 case RightFrameHandle:
1597 if (!with_selection) {
1598 if (region_edit_menu_split_item) {
1599 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1600 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1602 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1605 if (region_edit_menu_split_multichannel_item) {
1606 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1607 region_edit_menu_split_multichannel_item->set_sensitive (true);
1609 region_edit_menu_split_multichannel_item->set_sensitive (false);
1622 /* probably shouldn't happen but if it does, we don't care */
1626 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1628 /* Bounce to disk */
1630 using namespace Menu_Helpers;
1631 MenuList& edit_items = menu->items();
1633 edit_items.push_back (SeparatorElem());
1635 switch (clicked_routeview->audio_track()->freeze_state()) {
1636 case AudioTrack::NoFreeze:
1637 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1640 case AudioTrack::Frozen:
1641 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1644 case AudioTrack::UnFrozen:
1645 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1651 if (item_type == StreamItem && clicked_routeview) {
1652 clicked_routeview->build_underlay_menu(menu);
1655 /* When the region menu is opened, we setup the actions so that they look right
1658 sensitize_the_right_region_actions ();
1659 _last_region_menu_was_main = false;
1661 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1662 menu->popup (button, time);
1666 Editor::build_track_context_menu ()
1668 using namespace Menu_Helpers;
1670 MenuList& edit_items = track_context_menu.items();
1673 add_dstream_context_items (edit_items);
1674 return &track_context_menu;
1678 Editor::build_track_bus_context_menu ()
1680 using namespace Menu_Helpers;
1682 MenuList& edit_items = track_context_menu.items();
1685 add_bus_context_items (edit_items);
1686 return &track_context_menu;
1690 Editor::build_track_region_context_menu ()
1692 using namespace Menu_Helpers;
1693 MenuList& edit_items = track_region_context_menu.items();
1696 /* we've just cleared the track region context menu, so the menu that these
1697 two items were on will have disappeared; stop them dangling.
1699 region_edit_menu_split_item = 0;
1700 region_edit_menu_split_multichannel_item = 0;
1702 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1705 boost::shared_ptr<Track> tr;
1706 boost::shared_ptr<Playlist> pl;
1708 if ((tr = rtv->track())) {
1709 add_region_context_items (edit_items, tr);
1713 add_dstream_context_items (edit_items);
1715 return &track_region_context_menu;
1719 Editor::analyze_region_selection ()
1721 if (analysis_window == 0) {
1722 analysis_window = new AnalysisWindow();
1725 analysis_window->set_session(_session);
1727 analysis_window->show_all();
1730 analysis_window->set_regionmode();
1731 analysis_window->analyze();
1733 analysis_window->present();
1737 Editor::analyze_range_selection()
1739 if (analysis_window == 0) {
1740 analysis_window = new AnalysisWindow();
1743 analysis_window->set_session(_session);
1745 analysis_window->show_all();
1748 analysis_window->set_rangemode();
1749 analysis_window->analyze();
1751 analysis_window->present();
1755 Editor::build_track_selection_context_menu ()
1757 using namespace Menu_Helpers;
1758 MenuList& edit_items = track_selection_context_menu.items();
1759 edit_items.clear ();
1761 add_selection_context_items (edit_items);
1762 // edit_items.push_back (SeparatorElem());
1763 // add_dstream_context_items (edit_items);
1765 return &track_selection_context_menu;
1769 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1771 using namespace Menu_Helpers;
1773 /* OK, stick the region submenu at the top of the list, and then add
1777 RegionSelection rs = get_regions_from_selection_and_entered ();
1779 string::size_type pos = 0;
1780 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1782 /* we have to hack up the region name because "_" has a special
1783 meaning for menu titles.
1786 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1787 menu_item_name.replace (pos, 1, "__");
1791 if (_popup_region_menu_item == 0) {
1792 _popup_region_menu_item = new MenuItem (menu_item_name);
1793 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1794 _popup_region_menu_item->show ();
1796 _popup_region_menu_item->set_label (menu_item_name);
1799 const framepos_t position = get_preferred_edit_position (false, true);
1801 edit_items.push_back (*_popup_region_menu_item);
1802 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1803 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1805 edit_items.push_back (SeparatorElem());
1808 /** Add context menu items relevant to selection ranges.
1809 * @param edit_items List to add the items to.
1812 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1814 using namespace Menu_Helpers;
1816 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1817 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1819 edit_items.push_back (SeparatorElem());
1820 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1822 edit_items.push_back (SeparatorElem());
1823 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1825 edit_items.push_back (SeparatorElem());
1827 edit_items.push_back (
1829 _("Move Range Start to Previous Region Boundary"),
1830 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1834 edit_items.push_back (
1836 _("Move Range Start to Next Region Boundary"),
1837 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1841 edit_items.push_back (
1843 _("Move Range End to Previous Region Boundary"),
1844 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1848 edit_items.push_back (
1850 _("Move Range End to Next Region Boundary"),
1851 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1855 edit_items.push_back (SeparatorElem());
1856 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1857 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1859 edit_items.push_back (SeparatorElem());
1860 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1862 edit_items.push_back (SeparatorElem());
1863 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1864 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1865 edit_items.push_back (MenuElem (_("Set Session Start/End from Range"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1867 edit_items.push_back (SeparatorElem());
1868 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1870 edit_items.push_back (SeparatorElem());
1871 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1872 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1873 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1875 edit_items.push_back (SeparatorElem());
1876 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1877 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1878 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1879 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1880 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1881 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1882 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1888 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1890 using namespace Menu_Helpers;
1894 Menu *play_menu = manage (new Menu);
1895 MenuList& play_items = play_menu->items();
1896 play_menu->set_name ("ArdourContextMenu");
1898 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1899 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1900 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1901 play_items.push_back (SeparatorElem());
1902 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1904 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1908 Menu *select_menu = manage (new Menu);
1909 MenuList& select_items = select_menu->items();
1910 select_menu->set_name ("ArdourContextMenu");
1912 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1913 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1914 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1915 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1916 select_items.push_back (SeparatorElem());
1917 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1918 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1919 select_items.push_back (SeparatorElem());
1920 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1921 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1922 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1923 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1924 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1925 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1926 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1928 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1932 Menu *cutnpaste_menu = manage (new Menu);
1933 MenuList& cutnpaste_items = cutnpaste_menu->items();
1934 cutnpaste_menu->set_name ("ArdourContextMenu");
1936 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1937 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1938 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1940 cutnpaste_items.push_back (SeparatorElem());
1942 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1943 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1945 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1947 /* Adding new material */
1949 edit_items.push_back (SeparatorElem());
1950 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1951 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1955 Menu *nudge_menu = manage (new Menu());
1956 MenuList& nudge_items = nudge_menu->items();
1957 nudge_menu->set_name ("ArdourContextMenu");
1959 edit_items.push_back (SeparatorElem());
1960 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1961 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1962 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1963 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1965 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1969 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1971 using namespace Menu_Helpers;
1975 Menu *play_menu = manage (new Menu);
1976 MenuList& play_items = play_menu->items();
1977 play_menu->set_name ("ArdourContextMenu");
1979 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1980 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1981 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1985 Menu *select_menu = manage (new Menu);
1986 MenuList& select_items = select_menu->items();
1987 select_menu->set_name ("ArdourContextMenu");
1989 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1990 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1991 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1992 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1993 select_items.push_back (SeparatorElem());
1994 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1995 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1996 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1997 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1999 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2003 Menu *cutnpaste_menu = manage (new Menu);
2004 MenuList& cutnpaste_items = cutnpaste_menu->items();
2005 cutnpaste_menu->set_name ("ArdourContextMenu");
2007 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2008 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2009 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2011 Menu *nudge_menu = manage (new Menu());
2012 MenuList& nudge_items = nudge_menu->items();
2013 nudge_menu->set_name ("ArdourContextMenu");
2015 edit_items.push_back (SeparatorElem());
2016 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2017 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2018 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2019 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2021 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2025 Editor::snap_type() const
2031 Editor::snap_mode() const
2037 Editor::set_snap_to (SnapType st)
2039 unsigned int snap_ind = (unsigned int)st;
2043 if (snap_ind > snap_type_strings.size() - 1) {
2045 _snap_type = (SnapType)snap_ind;
2048 string str = snap_type_strings[snap_ind];
2050 if (str != snap_type_selector.get_text()) {
2051 snap_type_selector.set_text (str);
2056 switch (_snap_type) {
2057 case SnapToBeatDiv128:
2058 case SnapToBeatDiv64:
2059 case SnapToBeatDiv32:
2060 case SnapToBeatDiv28:
2061 case SnapToBeatDiv24:
2062 case SnapToBeatDiv20:
2063 case SnapToBeatDiv16:
2064 case SnapToBeatDiv14:
2065 case SnapToBeatDiv12:
2066 case SnapToBeatDiv10:
2067 case SnapToBeatDiv8:
2068 case SnapToBeatDiv7:
2069 case SnapToBeatDiv6:
2070 case SnapToBeatDiv5:
2071 case SnapToBeatDiv4:
2072 case SnapToBeatDiv3:
2073 case SnapToBeatDiv2: {
2074 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2075 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2077 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2078 current_bbt_points_begin, current_bbt_points_end);
2079 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2080 current_bbt_points_begin, current_bbt_points_end);
2081 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2085 case SnapToRegionStart:
2086 case SnapToRegionEnd:
2087 case SnapToRegionSync:
2088 case SnapToRegionBoundary:
2089 build_region_boundary_cache ();
2097 SnapChanged (); /* EMIT SIGNAL */
2101 Editor::set_snap_mode (SnapMode mode)
2103 string str = snap_mode_strings[(int)mode];
2105 if (internal_editing()) {
2106 internal_snap_mode = mode;
2108 pre_internal_snap_mode = mode;
2113 if (str != snap_mode_selector.get_text ()) {
2114 snap_mode_selector.set_text (str);
2120 Editor::set_edit_point_preference (EditPoint ep, bool force)
2122 bool changed = (_edit_point != ep);
2125 if (Profile->get_mixbus())
2126 if (ep == EditAtSelectedMarker)
2127 ep = EditAtPlayhead;
2129 string str = edit_point_strings[(int)ep];
2130 if (str != edit_point_selector.get_text ()) {
2131 edit_point_selector.set_text (str);
2134 update_all_enter_cursors();
2136 if (!force && !changed) {
2140 const char* action=NULL;
2142 switch (_edit_point) {
2143 case EditAtPlayhead:
2144 action = "edit-at-playhead";
2146 case EditAtSelectedMarker:
2147 action = "edit-at-marker";
2150 action = "edit-at-mouse";
2154 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2156 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2160 bool in_track_canvas;
2162 if (!mouse_frame (foo, in_track_canvas)) {
2163 in_track_canvas = false;
2166 reset_canvas_action_sensitivity (in_track_canvas);
2172 Editor::set_state (const XMLNode& node, int /*version*/)
2174 const XMLProperty* prop;
2181 g.base_width = default_width;
2182 g.base_height = default_height;
2186 if ((geometry = find_named_node (node, "geometry")) != 0) {
2190 if ((prop = geometry->property("x_size")) == 0) {
2191 prop = geometry->property ("x-size");
2194 g.base_width = atoi(prop->value());
2196 if ((prop = geometry->property("y_size")) == 0) {
2197 prop = geometry->property ("y-size");
2200 g.base_height = atoi(prop->value());
2203 if ((prop = geometry->property ("x_pos")) == 0) {
2204 prop = geometry->property ("x-pos");
2207 x = atoi (prop->value());
2210 if ((prop = geometry->property ("y_pos")) == 0) {
2211 prop = geometry->property ("y-pos");
2214 y = atoi (prop->value());
2218 set_default_size (g.base_width, g.base_height);
2221 if (_session && (prop = node.property ("playhead"))) {
2223 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2225 playhead_cursor->set_position (pos);
2227 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2228 playhead_cursor->set_position (0);
2231 playhead_cursor->set_position (0);
2234 if ((prop = node.property ("mixer-width"))) {
2235 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2238 if ((prop = node.property ("zoom-focus"))) {
2239 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2242 if ((prop = node.property ("zoom"))) {
2243 /* older versions of ardour used floating point samples_per_pixel */
2244 double f = PBD::atof (prop->value());
2245 reset_zoom (llrintf (f));
2247 reset_zoom (samples_per_pixel);
2250 if ((prop = node.property ("visible-track-count"))) {
2251 set_visible_track_count (PBD::atoi (prop->value()));
2254 if ((prop = node.property ("snap-to"))) {
2255 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2258 if ((prop = node.property ("snap-mode"))) {
2259 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2262 if ((prop = node.property ("internal-snap-to"))) {
2263 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2266 if ((prop = node.property ("internal-snap-mode"))) {
2267 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2270 if ((prop = node.property ("pre-internal-snap-to"))) {
2271 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2274 if ((prop = node.property ("pre-internal-snap-mode"))) {
2275 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2278 if ((prop = node.property ("mouse-mode"))) {
2279 MouseMode m = str2mousemode(prop->value());
2280 set_mouse_mode (m, true);
2282 set_mouse_mode (MouseObject, true);
2285 if ((prop = node.property ("left-frame")) != 0) {
2287 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2291 reset_x_origin (pos);
2295 if ((prop = node.property ("y-origin")) != 0) {
2296 reset_y_origin (atof (prop->value ()));
2299 if ((prop = node.property ("join-object-range"))) {
2300 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2301 bool yn = string_is_affirmative (prop->value());
2303 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2304 tact->set_active (!yn);
2305 tact->set_active (yn);
2307 set_mouse_mode(mouse_mode, true);
2310 if ((prop = node.property ("edit-point"))) {
2311 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2314 if ((prop = node.property ("show-measures"))) {
2315 bool yn = string_is_affirmative (prop->value());
2316 _show_measures = yn;
2317 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2319 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2320 /* do it twice to force the change */
2321 tact->set_active (!yn);
2322 tact->set_active (yn);
2326 if ((prop = node.property ("follow-playhead"))) {
2327 bool yn = string_is_affirmative (prop->value());
2328 set_follow_playhead (yn);
2329 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2331 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2332 if (tact->get_active() != yn) {
2333 tact->set_active (yn);
2338 if ((prop = node.property ("stationary-playhead"))) {
2339 bool yn = string_is_affirmative (prop->value());
2340 set_stationary_playhead (yn);
2341 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2343 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2344 if (tact->get_active() != yn) {
2345 tact->set_active (yn);
2350 if ((prop = node.property ("region-list-sort-type"))) {
2351 RegionListSortType st;
2352 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2355 if ((prop = node.property ("show-editor-mixer"))) {
2357 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2360 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2361 bool yn = string_is_affirmative (prop->value());
2363 /* do it twice to force the change */
2365 tact->set_active (!yn);
2366 tact->set_active (yn);
2369 if ((prop = node.property ("show-editor-list"))) {
2371 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2374 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2375 bool yn = string_is_affirmative (prop->value());
2377 /* do it twice to force the change */
2379 tact->set_active (!yn);
2380 tact->set_active (yn);
2383 if ((prop = node.property (X_("editor-list-page")))) {
2384 _the_notebook.set_current_page (atoi (prop->value ()));
2387 if ((prop = node.property (X_("show-marker-lines")))) {
2388 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2390 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2391 bool yn = string_is_affirmative (prop->value ());
2393 tact->set_active (!yn);
2394 tact->set_active (yn);
2397 XMLNodeList children = node.children ();
2398 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2399 selection->set_state (**i, Stateful::current_state_version);
2400 _regions->set_state (**i);
2403 if ((prop = node.property ("maximised"))) {
2404 bool yn = string_is_affirmative (prop->value());
2405 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2407 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2408 bool fs = tact && tact->get_active();
2410 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2414 if ((prop = node.property ("nudge-clock-value"))) {
2416 sscanf (prop->value().c_str(), "%" PRId64, &f);
2417 nudge_clock->set (f);
2419 nudge_clock->set_mode (AudioClock::Timecode);
2420 nudge_clock->set (_session->frame_rate() * 5, true);
2427 Editor::get_state ()
2429 XMLNode* node = new XMLNode ("Editor");
2432 id().print (buf, sizeof (buf));
2433 node->add_property ("id", buf);
2435 if (is_realized()) {
2436 Glib::RefPtr<Gdk::Window> win = get_window();
2438 int x, y, width, height;
2439 win->get_root_origin(x, y);
2440 win->get_size(width, height);
2442 XMLNode* geometry = new XMLNode ("geometry");
2444 snprintf(buf, sizeof(buf), "%d", width);
2445 geometry->add_property("x-size", string(buf));
2446 snprintf(buf, sizeof(buf), "%d", height);
2447 geometry->add_property("y-size", string(buf));
2448 snprintf(buf, sizeof(buf), "%d", x);
2449 geometry->add_property("x-pos", string(buf));
2450 snprintf(buf, sizeof(buf), "%d", y);
2451 geometry->add_property("y-pos", string(buf));
2452 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2453 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2454 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2455 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2456 geometry->add_property("edit-vertical-pane-pos", string(buf));
2458 node->add_child_nocopy (*geometry);
2461 maybe_add_mixer_strip_width (*node);
2463 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2465 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2466 node->add_property ("zoom", buf);
2467 node->add_property ("snap-to", enum_2_string (_snap_type));
2468 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2469 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2470 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2471 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2472 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2473 node->add_property ("edit-point", enum_2_string (_edit_point));
2474 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2475 node->add_property ("visible-track-count", buf);
2477 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2478 node->add_property ("playhead", buf);
2479 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2480 node->add_property ("left-frame", buf);
2481 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2482 node->add_property ("y-origin", buf);
2484 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2485 node->add_property ("maximised", _maximised ? "yes" : "no");
2486 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2487 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2488 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2489 node->add_property ("mouse-mode", enum2str(mouse_mode));
2490 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2492 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2494 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2495 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2498 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2500 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2501 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2504 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2505 node->add_property (X_("editor-list-page"), buf);
2507 if (button_bindings) {
2508 XMLNode* bb = new XMLNode (X_("Buttons"));
2509 button_bindings->save (*bb);
2510 node->add_child_nocopy (*bb);
2513 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2515 node->add_child_nocopy (selection->get_state ());
2516 node->add_child_nocopy (_regions->get_state ());
2518 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2519 node->add_property ("nudge-clock-value", buf);
2524 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2525 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2527 * @return pair: TimeAxisView that y is over, layer index.
2529 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2530 * in stacked or expanded region display mode, otherwise 0.
2532 std::pair<TimeAxisView *, double>
2533 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2535 if (!trackview_relative_offset) {
2536 y -= _trackview_group->canvas_origin().y;
2540 return std::make_pair ( (TimeAxisView *) 0, 0);
2543 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2545 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2552 return std::make_pair ( (TimeAxisView *) 0, 0);
2555 /** Snap a position to the grid, if appropriate, taking into account current
2556 * grid settings and also the state of any snap modifier keys that may be pressed.
2557 * @param start Position to snap.
2558 * @param event Event to get current key modifier information from, or 0.
2561 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2563 if (!_session || !event) {
2567 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2568 if (_snap_mode == SnapOff) {
2569 snap_to_internal (start, direction, for_mark);
2572 if (_snap_mode != SnapOff) {
2573 snap_to_internal (start, direction, for_mark);
2579 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark)
2581 if (!_session || _snap_mode == SnapOff) {
2585 snap_to_internal (start, direction, for_mark);
2589 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2591 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2592 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2594 switch (_snap_type) {
2595 case SnapToTimecodeFrame:
2596 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2597 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2598 /* start is already on a whole timecode frame, do nothing */
2599 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2600 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2602 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2606 case SnapToTimecodeSeconds:
2607 if (_session->config.get_timecode_offset_negative()) {
2608 start += _session->config.get_timecode_offset ();
2610 start -= _session->config.get_timecode_offset ();
2612 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2613 (start % one_timecode_second == 0)) {
2614 /* start is already on a whole second, do nothing */
2615 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2616 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2618 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2621 if (_session->config.get_timecode_offset_negative()) {
2622 start -= _session->config.get_timecode_offset ();
2624 start += _session->config.get_timecode_offset ();
2628 case SnapToTimecodeMinutes:
2629 if (_session->config.get_timecode_offset_negative()) {
2630 start += _session->config.get_timecode_offset ();
2632 start -= _session->config.get_timecode_offset ();
2634 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2635 (start % one_timecode_minute == 0)) {
2636 /* start is already on a whole minute, do nothing */
2637 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2638 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2640 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2642 if (_session->config.get_timecode_offset_negative()) {
2643 start -= _session->config.get_timecode_offset ();
2645 start += _session->config.get_timecode_offset ();
2649 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2650 abort(); /*NOTREACHED*/
2655 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark)
2657 const framepos_t one_second = _session->frame_rate();
2658 const framepos_t one_minute = _session->frame_rate() * 60;
2659 framepos_t presnap = start;
2663 switch (_snap_type) {
2664 case SnapToTimecodeFrame:
2665 case SnapToTimecodeSeconds:
2666 case SnapToTimecodeMinutes:
2667 return timecode_snap_to_internal (start, direction, for_mark);
2670 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2671 start % (one_second/75) == 0) {
2672 /* start is already on a whole CD frame, do nothing */
2673 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2674 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2676 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2681 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2682 start % one_second == 0) {
2683 /* start is already on a whole second, do nothing */
2684 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2685 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2687 start = (framepos_t) floor ((double) start / one_second) * one_second;
2692 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2693 start % one_minute == 0) {
2694 /* start is already on a whole minute, do nothing */
2695 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2696 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2698 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2703 start = _session->tempo_map().round_to_bar (start, direction);
2707 start = _session->tempo_map().round_to_beat (start, direction);
2710 case SnapToBeatDiv128:
2711 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2713 case SnapToBeatDiv64:
2714 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2716 case SnapToBeatDiv32:
2717 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2719 case SnapToBeatDiv28:
2720 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2722 case SnapToBeatDiv24:
2723 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2725 case SnapToBeatDiv20:
2726 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2728 case SnapToBeatDiv16:
2729 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2731 case SnapToBeatDiv14:
2732 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2734 case SnapToBeatDiv12:
2735 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2737 case SnapToBeatDiv10:
2738 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2740 case SnapToBeatDiv8:
2741 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2743 case SnapToBeatDiv7:
2744 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2746 case SnapToBeatDiv6:
2747 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2749 case SnapToBeatDiv5:
2750 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2752 case SnapToBeatDiv4:
2753 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2755 case SnapToBeatDiv3:
2756 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2758 case SnapToBeatDiv2:
2759 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2767 _session->locations()->marks_either_side (start, before, after);
2769 if (before == max_framepos && after == max_framepos) {
2770 /* No marks to snap to, so just don't snap */
2772 } else if (before == max_framepos) {
2774 } else if (after == max_framepos) {
2776 } else if (before != max_framepos && after != max_framepos) {
2777 /* have before and after */
2778 if ((start - before) < (after - start)) {
2787 case SnapToRegionStart:
2788 case SnapToRegionEnd:
2789 case SnapToRegionSync:
2790 case SnapToRegionBoundary:
2791 if (!region_boundary_cache.empty()) {
2793 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2794 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2796 if (direction > 0) {
2797 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2799 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2802 if (next != region_boundary_cache.begin ()) {
2807 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2808 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2810 if (start > (p + n) / 2) {
2819 switch (_snap_mode) {
2825 if (presnap > start) {
2826 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2830 } else if (presnap < start) {
2831 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2837 /* handled at entry */
2845 Editor::setup_toolbar ()
2847 HBox* mode_box = manage(new HBox);
2848 mode_box->set_border_width (2);
2849 mode_box->set_spacing(2);
2851 HBox* mouse_mode_box = manage (new HBox);
2852 HBox* mouse_mode_hbox = manage (new HBox);
2853 VBox* mouse_mode_vbox = manage (new VBox);
2854 Alignment* mouse_mode_align = manage (new Alignment);
2856 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2857 mouse_mode_size_group->add_widget (smart_mode_button);
2858 mouse_mode_size_group->add_widget (mouse_move_button);
2859 mouse_mode_size_group->add_widget (mouse_cut_button);
2860 mouse_mode_size_group->add_widget (mouse_select_button);
2861 mouse_mode_size_group->add_widget (mouse_timefx_button);
2862 mouse_mode_size_group->add_widget (mouse_audition_button);
2863 mouse_mode_size_group->add_widget (mouse_draw_button);
2864 mouse_mode_size_group->add_widget (mouse_content_button);
2866 mouse_mode_size_group->add_widget (zoom_in_button);
2867 mouse_mode_size_group->add_widget (zoom_out_button);
2868 mouse_mode_size_group->add_widget (zoom_preset_selector);
2869 mouse_mode_size_group->add_widget (zoom_out_full_button);
2870 mouse_mode_size_group->add_widget (zoom_focus_selector);
2872 mouse_mode_size_group->add_widget (tav_shrink_button);
2873 mouse_mode_size_group->add_widget (tav_expand_button);
2874 mouse_mode_size_group->add_widget (visible_tracks_selector);
2876 mouse_mode_size_group->add_widget (snap_type_selector);
2877 mouse_mode_size_group->add_widget (snap_mode_selector);
2879 mouse_mode_size_group->add_widget (edit_point_selector);
2880 mouse_mode_size_group->add_widget (edit_mode_selector);
2882 mouse_mode_size_group->add_widget (*nudge_clock);
2883 mouse_mode_size_group->add_widget (nudge_forward_button);
2884 mouse_mode_size_group->add_widget (nudge_backward_button);
2886 mouse_mode_hbox->set_spacing (2);
2888 if (!ARDOUR::Profile->get_trx()) {
2889 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2892 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2893 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2895 if (!ARDOUR::Profile->get_mixbus()) {
2896 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2899 if (!ARDOUR::Profile->get_trx()) {
2900 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2901 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2902 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2903 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2906 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2908 mouse_mode_align->add (*mouse_mode_vbox);
2909 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2911 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2913 edit_mode_selector.set_name ("mouse mode button");
2915 if (!ARDOUR::Profile->get_trx()) {
2916 mode_box->pack_start (edit_mode_selector, false, false);
2918 mode_box->pack_start (*mouse_mode_box, false, false);
2920 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2921 _mouse_mode_tearoff->set_name ("MouseModeBase");
2922 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2924 if (Profile->get_sae() || Profile->get_mixbus() ) {
2925 _mouse_mode_tearoff->set_can_be_torn_off (false);
2928 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2929 &_mouse_mode_tearoff->tearoff_window()));
2930 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2931 &_mouse_mode_tearoff->tearoff_window(), 1));
2932 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2933 &_mouse_mode_tearoff->tearoff_window()));
2934 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2935 &_mouse_mode_tearoff->tearoff_window(), 1));
2939 _zoom_box.set_spacing (2);
2940 _zoom_box.set_border_width (2);
2944 zoom_preset_selector.set_name ("zoom button");
2945 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2946 zoom_preset_selector.set_size_request (42, -1);
2948 zoom_in_button.set_name ("zoom button");
2949 zoom_in_button.set_image(::get_icon ("zoom_in"));
2950 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2951 zoom_in_button.set_related_action (act);
2953 zoom_out_button.set_name ("zoom button");
2954 zoom_out_button.set_image(::get_icon ("zoom_out"));
2955 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2956 zoom_out_button.set_related_action (act);
2958 zoom_out_full_button.set_name ("zoom button");
2959 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2960 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2961 zoom_out_full_button.set_related_action (act);
2963 zoom_focus_selector.set_name ("zoom button");
2965 if (ARDOUR::Profile->get_mixbus()) {
2966 _zoom_box.pack_start (zoom_preset_selector, false, false);
2967 } else if (ARDOUR::Profile->get_trx()) {
2968 mode_box->pack_start (zoom_out_button, false, false);
2969 mode_box->pack_start (zoom_in_button, false, false);
2971 _zoom_box.pack_start (zoom_out_button, false, false);
2972 _zoom_box.pack_start (zoom_in_button, false, false);
2973 _zoom_box.pack_start (zoom_out_full_button, false, false);
2974 _zoom_box.pack_start (zoom_focus_selector, false, false);
2977 /* Track zoom buttons */
2978 visible_tracks_selector.set_name ("zoom button");
2979 if (Profile->get_mixbus()) {
2980 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2981 visible_tracks_selector.set_size_request (42, -1);
2983 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2986 tav_expand_button.set_name ("zoom button");
2987 tav_expand_button.set_image(::get_icon ("tav_exp"));
2988 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2989 tav_expand_button.set_related_action (act);
2991 tav_shrink_button.set_name ("zoom button");
2992 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2993 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2994 tav_shrink_button.set_related_action (act);
2996 if (ARDOUR::Profile->get_mixbus()) {
2997 _zoom_box.pack_start (visible_tracks_selector);
2998 } else if (ARDOUR::Profile->get_trx()) {
2999 _zoom_box.pack_start (tav_shrink_button);
3000 _zoom_box.pack_start (tav_expand_button);
3002 _zoom_box.pack_start (visible_tracks_selector);
3003 _zoom_box.pack_start (tav_shrink_button);
3004 _zoom_box.pack_start (tav_expand_button);
3007 if (!ARDOUR::Profile->get_trx()) {
3008 _zoom_tearoff = manage (new TearOff (_zoom_box));
3010 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3011 &_zoom_tearoff->tearoff_window()));
3012 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3013 &_zoom_tearoff->tearoff_window(), 0));
3014 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3015 &_zoom_tearoff->tearoff_window()));
3016 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3017 &_zoom_tearoff->tearoff_window(), 0));
3020 if (Profile->get_sae() || Profile->get_mixbus() ) {
3021 _zoom_tearoff->set_can_be_torn_off (false);
3024 snap_box.set_spacing (2);
3025 snap_box.set_border_width (2);
3027 snap_type_selector.set_name ("mouse mode button");
3029 snap_mode_selector.set_name ("mouse mode button");
3031 edit_point_selector.set_name ("mouse mode button");
3033 snap_box.pack_start (snap_mode_selector, false, false);
3034 snap_box.pack_start (snap_type_selector, false, false);
3035 snap_box.pack_start (edit_point_selector, false, false);
3039 HBox *nudge_box = manage (new HBox);
3040 nudge_box->set_spacing (2);
3041 nudge_box->set_border_width (2);
3043 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3044 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3046 nudge_box->pack_start (nudge_backward_button, false, false);
3047 nudge_box->pack_start (nudge_forward_button, false, false);
3048 nudge_box->pack_start (*nudge_clock, false, false);
3051 /* Pack everything in... */
3053 HBox* hbox = manage (new HBox);
3054 hbox->set_spacing(2);
3056 _tools_tearoff = manage (new TearOff (*hbox));
3057 _tools_tearoff->set_name ("MouseModeBase");
3058 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3060 if (Profile->get_sae() || Profile->get_mixbus()) {
3061 _tools_tearoff->set_can_be_torn_off (false);
3064 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3065 &_tools_tearoff->tearoff_window()));
3066 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3067 &_tools_tearoff->tearoff_window(), 0));
3068 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3069 &_tools_tearoff->tearoff_window()));
3070 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3071 &_tools_tearoff->tearoff_window(), 0));
3073 toolbar_hbox.set_spacing (2);
3074 toolbar_hbox.set_border_width (1);
3076 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3077 if (!ARDOUR::Profile->get_trx()) {
3078 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3079 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3082 if (!ARDOUR::Profile->get_trx()) {
3083 hbox->pack_start (snap_box, false, false);
3084 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3085 hbox->pack_start (*nudge_box, false, false);
3087 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3090 hbox->pack_start (panic_box, false, false);
3094 toolbar_base.set_name ("ToolBarBase");
3095 toolbar_base.add (toolbar_hbox);
3097 _toolbar_viewport.add (toolbar_base);
3098 /* stick to the required height but allow width to vary if there's not enough room */
3099 _toolbar_viewport.set_size_request (1, -1);
3101 toolbar_frame.set_shadow_type (SHADOW_OUT);
3102 toolbar_frame.set_name ("BaseFrame");
3103 toolbar_frame.add (_toolbar_viewport);
3107 Editor::build_edit_point_menu ()
3109 using namespace Menu_Helpers;
3111 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3112 if(!Profile->get_mixbus())
3113 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3114 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3116 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3120 Editor::build_edit_mode_menu ()
3122 using namespace Menu_Helpers;
3124 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3125 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3126 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3127 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3129 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3133 Editor::build_snap_mode_menu ()
3135 using namespace Menu_Helpers;
3137 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3138 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3139 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3141 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3145 Editor::build_snap_type_menu ()
3147 using namespace Menu_Helpers;
3149 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3150 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3151 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3152 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3153 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3154 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3155 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3156 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3157 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3158 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3159 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3160 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3161 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3162 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3163 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3164 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3165 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3166 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3167 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3168 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3169 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3170 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3171 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3172 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3173 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3174 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3175 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3176 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3177 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3178 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3180 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3185 Editor::setup_tooltips ()
3187 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3188 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3189 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3190 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Grab/Select Objects"));
3191 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit Gain/Notes/Automation"));
3192 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3193 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3194 ARDOUR_UI::instance()->set_tip (mouse_content_button, _("Edit Contents (notes and automation)"));
3195 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3196 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3197 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3198 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3199 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3200 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3201 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3202 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3203 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3204 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3205 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3206 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3207 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3208 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3209 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3210 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3214 Editor::convert_drop_to_paths (
3215 vector<string>& paths,
3216 const RefPtr<Gdk::DragContext>& /*context*/,
3219 const SelectionData& data,
3223 if (_session == 0) {
3227 vector<string> uris = data.get_uris();
3231 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3232 are actually URI lists. So do it by hand.
3235 if (data.get_target() != "text/plain") {
3239 /* Parse the "uri-list" format that Nautilus provides,
3240 where each pathname is delimited by \r\n.
3242 THERE MAY BE NO NULL TERMINATING CHAR!!!
3245 string txt = data.get_text();
3249 p = (char *) malloc (txt.length() + 1);
3250 txt.copy (p, txt.length(), 0);
3251 p[txt.length()] = '\0';
3257 while (g_ascii_isspace (*p))
3261 while (*q && (*q != '\n') && (*q != '\r')) {
3268 while (q > p && g_ascii_isspace (*q))
3273 uris.push_back (string (p, q - p + 1));
3277 p = strchr (p, '\n');
3289 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3290 if ((*i).substr (0,7) == "file://") {
3291 paths.push_back (Glib::filename_from_uri (*i));
3299 Editor::new_tempo_section ()
3304 Editor::map_transport_state ()
3306 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3308 if (_session && _session->transport_stopped()) {
3309 have_pending_keyboard_selection = false;
3312 update_loop_range_view ();
3318 Editor::begin_selection_op_history ()
3320 selection_op_cmd_depth = 0;
3321 selection_op_history_it = 0;
3322 selection_op_history.clear();
3323 selection_undo_action->set_sensitive (false);
3324 selection_redo_action->set_sensitive (false);
3325 selection_op_history.push_front (&_selection_memento->get_state ());
3329 Editor::begin_reversible_selection_op (string name)
3332 //cerr << name << endl;
3333 /* begin/commit pairs can be nested */
3334 selection_op_cmd_depth++;
3339 Editor::commit_reversible_selection_op ()
3342 if (selection_op_cmd_depth == 1) {
3344 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3345 list<XMLNode *>::iterator it = selection_op_history.begin();
3346 advance (it, selection_op_history_it);
3347 selection_op_history.erase (selection_op_history.begin(), it);
3349 selection_op_history.push_front (&_selection_memento->get_state ());
3350 selection_op_history_it = 0;
3353 if (selection_op_cmd_depth > 0) {
3354 selection_op_cmd_depth--;
3357 selection_undo_action->set_sensitive (true);
3358 selection_redo_action->set_sensitive (false);
3363 Editor::undo_reversible_selection_op ()
3366 selection_op_history_it++;
3368 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3369 if (n == selection_op_history_it) {
3370 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3371 selection_redo_action->set_sensitive (true);
3376 /* is there an earlier entry? */
3377 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3378 selection_undo_action->set_sensitive (false);
3384 Editor::redo_reversible_selection_op ()
3387 if (selection_op_history_it > 0) {
3388 selection_op_history_it--;
3391 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3392 if (n == selection_op_history_it) {
3393 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3394 selection_undo_action->set_sensitive (true);
3400 if (selection_op_history_it == 0) {
3401 selection_redo_action->set_sensitive (false);
3407 Editor::begin_reversible_command (string name)
3410 before.push_back (&_selection_memento->get_state ());
3411 _session->begin_reversible_command (name);
3416 Editor::begin_reversible_command (GQuark q)
3419 before.push_back (&_selection_memento->get_state ());
3420 _session->begin_reversible_command (q);
3425 Editor::commit_reversible_command ()
3428 if (before.size() == 1) {
3429 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3430 begin_selection_op_history ();
3433 if (before.empty()) {
3434 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3439 _session->commit_reversible_command ();
3444 Editor::history_changed ()
3448 if (undo_action && _session) {
3449 if (_session->undo_depth() == 0) {
3450 label = S_("Command|Undo");
3452 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3454 undo_action->property_label() = label;
3457 if (redo_action && _session) {
3458 if (_session->redo_depth() == 0) {
3461 label = string_compose(_("Redo (%1)"), _session->next_redo());
3463 redo_action->property_label() = label;
3468 Editor::duplicate_range (bool with_dialog)
3472 RegionSelection rs = get_regions_from_selection_and_entered ();
3474 if ( selection->time.length() == 0 && rs.empty()) {
3480 ArdourDialog win (_("Duplicate"));
3481 Label label (_("Number of duplications:"));
3482 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3483 SpinButton spinner (adjustment, 0.0, 1);
3486 win.get_vbox()->set_spacing (12);
3487 win.get_vbox()->pack_start (hbox);
3488 hbox.set_border_width (6);
3489 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3491 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3492 place, visually. so do this by hand.
3495 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3496 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3497 spinner.grab_focus();
3503 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3504 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3505 win.set_default_response (RESPONSE_ACCEPT);
3507 spinner.grab_focus ();
3509 switch (win.run ()) {
3510 case RESPONSE_ACCEPT:
3516 times = adjustment.get_value();
3519 if ((current_mouse_mode() == Editing::MouseRange)) {
3520 if (selection->time.length()) {
3521 duplicate_selection (times);
3523 } else if (get_smart_mode()) {
3524 if (selection->time.length()) {
3525 duplicate_selection (times);
3527 duplicate_some_regions (rs, times);
3529 duplicate_some_regions (rs, times);
3534 Editor::set_edit_mode (EditMode m)
3536 Config->set_edit_mode (m);
3540 Editor::cycle_edit_mode ()
3542 switch (Config->get_edit_mode()) {
3544 if (Profile->get_sae()) {
3545 Config->set_edit_mode (Lock);
3547 Config->set_edit_mode (Ripple);
3552 Config->set_edit_mode (Lock);
3555 Config->set_edit_mode (Slide);
3561 Editor::edit_mode_selection_done ( EditMode m )
3563 Config->set_edit_mode ( m );
3567 Editor::snap_type_selection_done (SnapType snaptype)
3569 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3571 ract->set_active ();
3576 Editor::snap_mode_selection_done (SnapMode mode)
3578 RefPtr<RadioAction> ract = snap_mode_action (mode);
3581 ract->set_active (true);
3586 Editor::cycle_edit_point (bool with_marker)
3588 if(Profile->get_mixbus())
3589 with_marker = false;
3591 switch (_edit_point) {
3593 set_edit_point_preference (EditAtPlayhead);
3595 case EditAtPlayhead:
3597 set_edit_point_preference (EditAtSelectedMarker);
3599 set_edit_point_preference (EditAtMouse);
3602 case EditAtSelectedMarker:
3603 set_edit_point_preference (EditAtMouse);
3609 Editor::edit_point_selection_done (EditPoint ep)
3611 set_edit_point_preference ( ep );
3615 Editor::build_zoom_focus_menu ()
3617 using namespace Menu_Helpers;
3619 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3620 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3621 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3622 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3623 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3624 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3626 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3630 Editor::zoom_focus_selection_done ( ZoomFocus f )
3632 RefPtr<RadioAction> ract = zoom_focus_action (f);
3634 ract->set_active ();
3639 Editor::build_track_count_menu ()
3641 using namespace Menu_Helpers;
3643 if (!Profile->get_mixbus()) {
3644 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3645 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3646 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3647 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3648 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3649 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3650 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3651 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3652 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3653 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3654 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3655 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3656 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3658 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3659 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3660 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3661 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3662 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3663 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3664 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3665 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3666 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3667 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3669 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3670 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3671 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3672 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3673 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3674 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3675 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3676 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3677 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3678 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3679 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3684 Editor::set_zoom_preset (int64_t ms)
3687 temporal_zoom_session();
3691 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3692 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3696 Editor::set_visible_track_count (int32_t n)
3698 _visible_track_count = n;
3700 /* if the canvas hasn't really been allocated any size yet, just
3701 record the desired number of visible tracks and return. when canvas
3702 allocation happens, we will get called again and then we can do the
3706 if (_visible_canvas_height <= 1) {
3712 DisplaySuspender ds;
3714 if (_visible_track_count > 0) {
3715 h = trackviews_height() / _visible_track_count;
3716 std::ostringstream s;
3717 s << _visible_track_count;
3719 } else if (_visible_track_count == 0) {
3721 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3722 if ((*i)->marked_for_display()) {
3726 h = trackviews_height() / n;
3729 /* negative value means that the visible track count has
3730 been overridden by explicit track height changes.
3732 visible_tracks_selector.set_text (X_("*"));
3736 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3737 (*i)->set_height (h);
3740 if (str != visible_tracks_selector.get_text()) {
3741 visible_tracks_selector.set_text (str);
3746 Editor::override_visible_track_count ()
3748 _visible_track_count = -1;
3749 visible_tracks_selector.set_text ( _("*") );
3753 Editor::edit_controls_button_release (GdkEventButton* ev)
3755 if (Keyboard::is_context_menu_event (ev)) {
3756 ARDOUR_UI::instance()->add_route (this);
3757 } else if (ev->button == 1) {
3758 selection->clear_tracks ();
3765 Editor::mouse_select_button_release (GdkEventButton* ev)
3767 /* this handles just right-clicks */
3769 if (ev->button != 3) {
3777 Editor::set_zoom_focus (ZoomFocus f)
3779 string str = zoom_focus_strings[(int)f];
3781 if (str != zoom_focus_selector.get_text()) {
3782 zoom_focus_selector.set_text (str);
3785 if (zoom_focus != f) {
3792 Editor::cycle_zoom_focus ()
3794 switch (zoom_focus) {
3796 set_zoom_focus (ZoomFocusRight);
3798 case ZoomFocusRight:
3799 set_zoom_focus (ZoomFocusCenter);
3801 case ZoomFocusCenter:
3802 set_zoom_focus (ZoomFocusPlayhead);
3804 case ZoomFocusPlayhead:
3805 set_zoom_focus (ZoomFocusMouse);
3807 case ZoomFocusMouse:
3808 set_zoom_focus (ZoomFocusEdit);
3811 set_zoom_focus (ZoomFocusLeft);
3817 Editor::ensure_float (Window& win)
3819 win.set_transient_for (*this);
3823 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3825 /* recover or initialize pane positions. do this here rather than earlier because
3826 we don't want the positions to change the child allocations, which they seem to do.
3832 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3841 XMLNode* geometry = find_named_node (*node, "geometry");
3843 if (which == static_cast<Paned*> (&edit_pane)) {
3845 if (done & Horizontal) {
3849 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3850 _notebook_shrunk = string_is_affirmative (prop->value ());
3853 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3854 /* initial allocation is 90% to canvas, 10% to notebook */
3855 pos = (int) floor (alloc.get_width() * 0.90f);
3856 snprintf (buf, sizeof(buf), "%d", pos);
3858 pos = atoi (prop->value());
3861 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3862 edit_pane.set_position (pos);
3865 done = (Pane) (done | Horizontal);
3867 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3869 if (done & Vertical) {
3873 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3874 /* initial allocation is 90% to canvas, 10% to summary */
3875 pos = (int) floor (alloc.get_height() * 0.90f);
3876 snprintf (buf, sizeof(buf), "%d", pos);
3879 pos = atoi (prop->value());
3882 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3883 editor_summary_pane.set_position (pos);
3886 done = (Pane) (done | Vertical);
3891 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3893 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3894 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3895 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3896 top_hbox.remove (toolbar_frame);
3901 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3903 if (toolbar_frame.get_parent() == 0) {
3904 top_hbox.pack_end (toolbar_frame);
3909 Editor::set_show_measures (bool yn)
3911 if (_show_measures != yn) {
3914 if ((_show_measures = yn) == true) {
3916 tempo_lines->show();
3919 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3920 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3922 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3923 draw_measures (begin, end);
3931 Editor::toggle_follow_playhead ()
3933 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3935 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3936 set_follow_playhead (tact->get_active());
3940 /** @param yn true to follow playhead, otherwise false.
3941 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3944 Editor::set_follow_playhead (bool yn, bool catch_up)
3946 if (_follow_playhead != yn) {
3947 if ((_follow_playhead = yn) == true && catch_up) {
3949 reset_x_origin_to_follow_playhead ();
3956 Editor::toggle_stationary_playhead ()
3958 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3960 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3961 set_stationary_playhead (tact->get_active());
3966 Editor::set_stationary_playhead (bool yn)
3968 if (_stationary_playhead != yn) {
3969 if ((_stationary_playhead = yn) == true) {
3971 // FIXME need a 3.0 equivalent of this 2.X call
3972 // update_current_screen ();
3979 Editor::playlist_selector () const
3981 return *_playlist_selector;
3985 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3987 if (paste_count == 0) {
3988 /* don't bother calculating an offset that will be zero anyway */
3992 /* calculate basic unsnapped multi-paste offset */
3993 framecnt_t offset = paste_count * duration;
3995 /* snap offset so pos + offset is aligned to the grid */
3996 framepos_t offset_pos = pos + offset;
3997 snap_to(offset_pos, RoundUpMaybe);
3998 offset = offset_pos - pos;
4004 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4008 switch (_snap_type) {
4010 return Evoral::MusicalTime(1.0);
4013 case SnapToBeatDiv128:
4014 return Evoral::MusicalTime(1.0/128.0);
4016 case SnapToBeatDiv64:
4017 return Evoral::MusicalTime(1.0/64.0);
4019 case SnapToBeatDiv32:
4020 return Evoral::MusicalTime(1.0/32.0);
4022 case SnapToBeatDiv28:
4023 return Evoral::MusicalTime(1.0/28.0);
4025 case SnapToBeatDiv24:
4026 return Evoral::MusicalTime(1.0/24.0);
4028 case SnapToBeatDiv20:
4029 return Evoral::MusicalTime(1.0/20.0);
4031 case SnapToBeatDiv16:
4032 return Evoral::MusicalTime(1.0/16.0);
4034 case SnapToBeatDiv14:
4035 return Evoral::MusicalTime(1.0/14.0);
4037 case SnapToBeatDiv12:
4038 return Evoral::MusicalTime(1.0/12.0);
4040 case SnapToBeatDiv10:
4041 return Evoral::MusicalTime(1.0/10.0);
4043 case SnapToBeatDiv8:
4044 return Evoral::MusicalTime(1.0/8.0);
4046 case SnapToBeatDiv7:
4047 return Evoral::MusicalTime(1.0/7.0);
4049 case SnapToBeatDiv6:
4050 return Evoral::MusicalTime(1.0/6.0);
4052 case SnapToBeatDiv5:
4053 return Evoral::MusicalTime(1.0/5.0);
4055 case SnapToBeatDiv4:
4056 return Evoral::MusicalTime(1.0/4.0);
4058 case SnapToBeatDiv3:
4059 return Evoral::MusicalTime(1.0/3.0);
4061 case SnapToBeatDiv2:
4062 return Evoral::MusicalTime(1.0/2.0);
4067 return Evoral::MusicalTime(_session->tempo_map().meter_at (position).divisions_per_bar());
4072 case SnapToTimecodeFrame:
4073 case SnapToTimecodeSeconds:
4074 case SnapToTimecodeMinutes:
4077 case SnapToRegionStart:
4078 case SnapToRegionEnd:
4079 case SnapToRegionSync:
4080 case SnapToRegionBoundary:
4086 return Evoral::MusicalTime();
4090 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4094 ret = nudge_clock->current_duration (pos);
4095 next = ret + 1; /* XXXX fix me */
4101 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4103 ArdourDialog dialog (_("Playlist Deletion"));
4104 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4105 "If it is kept, its audio files will not be cleaned.\n"
4106 "If it is deleted, audio files used by it alone will be cleaned."),
4109 dialog.set_position (WIN_POS_CENTER);
4110 dialog.get_vbox()->pack_start (label);
4114 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4115 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4116 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4118 switch (dialog.run ()) {
4119 case RESPONSE_ACCEPT:
4120 /* delete the playlist */
4124 case RESPONSE_REJECT:
4125 /* keep the playlist */
4137 Editor::audio_region_selection_covers (framepos_t where)
4139 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4140 if ((*a)->region()->covers (where)) {
4149 Editor::prepare_for_cleanup ()
4151 cut_buffer->clear_regions ();
4152 cut_buffer->clear_playlists ();
4154 selection->clear_regions ();
4155 selection->clear_playlists ();
4157 _regions->suspend_redisplay ();
4161 Editor::finish_cleanup ()
4163 _regions->resume_redisplay ();
4167 Editor::transport_loop_location()
4170 return _session->locations()->auto_loop_location();
4177 Editor::transport_punch_location()
4180 return _session->locations()->auto_punch_location();
4187 Editor::control_layout_scroll (GdkEventScroll* ev)
4189 /* Just forward to the normal canvas scroll method. The coordinate
4190 systems are different but since the canvas is always larger than the
4191 track headers, and aligned with the trackview area, this will work.
4193 In the not too distant future this layout is going away anyway and
4194 headers will be on the canvas.
4196 return canvas_scroll_event (ev, false);
4200 Editor::session_state_saved (string)
4203 _snapshots->redisplay ();
4207 Editor::update_tearoff_visibility()
4209 bool visible = ARDOUR_UI::config()->get_keep_tearoffs();
4210 _mouse_mode_tearoff->set_visible (visible);
4211 _tools_tearoff->set_visible (visible);
4212 if (_zoom_tearoff) {
4213 _zoom_tearoff->set_visible (visible);
4218 Editor::reattach_all_tearoffs ()
4220 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4221 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4222 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4226 Editor::maximise_editing_space ()
4238 Editor::restore_editing_space ()
4250 * Make new playlists for a given track and also any others that belong
4251 * to the same active route group with the `select' property.
4256 Editor::new_playlists (TimeAxisView* v)
4258 begin_reversible_command (_("new playlists"));
4259 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4260 _session->playlists->get (playlists);
4261 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4262 commit_reversible_command ();
4266 * Use a copy of the current playlist for a given track and also any others that belong
4267 * to the same active route group with the `select' property.
4272 Editor::copy_playlists (TimeAxisView* v)
4274 begin_reversible_command (_("copy playlists"));
4275 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4276 _session->playlists->get (playlists);
4277 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4278 commit_reversible_command ();
4281 /** Clear the current playlist for a given track and also any others that belong
4282 * to the same active route group with the `select' property.
4287 Editor::clear_playlists (TimeAxisView* v)
4289 begin_reversible_command (_("clear playlists"));
4290 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4291 _session->playlists->get (playlists);
4292 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4293 commit_reversible_command ();
4297 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4299 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4303 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4305 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4309 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4311 atv.clear_playlist ();
4315 Editor::on_key_press_event (GdkEventKey* ev)
4317 return key_press_focus_accelerator_handler (*this, ev);
4321 Editor::on_key_release_event (GdkEventKey* ev)
4323 return Gtk::Window::on_key_release_event (ev);
4324 // return key_press_focus_accelerator_handler (*this, ev);
4328 Editor::get_y_origin () const
4330 return vertical_adjustment.get_value ();
4333 /** Queue up a change to the viewport x origin.
4334 * @param frame New x origin.
4337 Editor::reset_x_origin (framepos_t frame)
4339 pending_visual_change.add (VisualChange::TimeOrigin);
4340 pending_visual_change.time_origin = frame;
4341 ensure_visual_change_idle_handler ();
4345 Editor::reset_y_origin (double y)
4347 pending_visual_change.add (VisualChange::YOrigin);
4348 pending_visual_change.y_origin = y;
4349 ensure_visual_change_idle_handler ();
4353 Editor::reset_zoom (framecnt_t spp)
4355 if (spp == samples_per_pixel) {
4359 pending_visual_change.add (VisualChange::ZoomLevel);
4360 pending_visual_change.samples_per_pixel = spp;
4361 ensure_visual_change_idle_handler ();
4365 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4367 reset_x_origin (frame);
4370 if (!no_save_visual) {
4371 undo_visual_stack.push_back (current_visual_state(false));
4375 Editor::VisualState::VisualState (bool with_tracks)
4376 : gui_state (with_tracks ? new GUIObjectState : 0)
4380 Editor::VisualState::~VisualState ()
4385 Editor::VisualState*
4386 Editor::current_visual_state (bool with_tracks)
4388 VisualState* vs = new VisualState (with_tracks);
4389 vs->y_position = vertical_adjustment.get_value();
4390 vs->samples_per_pixel = samples_per_pixel;
4391 vs->leftmost_frame = leftmost_frame;
4392 vs->zoom_focus = zoom_focus;
4395 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4402 Editor::undo_visual_state ()
4404 if (undo_visual_stack.empty()) {
4408 VisualState* vs = undo_visual_stack.back();
4409 undo_visual_stack.pop_back();
4412 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4415 use_visual_state (*vs);
4420 Editor::redo_visual_state ()
4422 if (redo_visual_stack.empty()) {
4426 VisualState* vs = redo_visual_stack.back();
4427 redo_visual_stack.pop_back();
4429 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4430 // why do we check here?
4431 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4434 use_visual_state (*vs);
4439 Editor::swap_visual_state ()
4441 if (undo_visual_stack.empty()) {
4442 redo_visual_state ();
4444 undo_visual_state ();
4449 Editor::use_visual_state (VisualState& vs)
4451 PBD::Unwinder<bool> nsv (no_save_visual, true);
4452 DisplaySuspender ds;
4454 vertical_adjustment.set_value (vs.y_position);
4456 set_zoom_focus (vs.zoom_focus);
4457 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4460 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4462 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4463 (*i)->reset_visual_state ();
4467 _routes->update_visibility ();
4470 /** This is the core function that controls the zoom level of the canvas. It is called
4471 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4472 * @param spp new number of samples per pixel
4475 Editor::set_samples_per_pixel (framecnt_t spp)
4481 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4482 const framecnt_t lots_of_pixels = 4000;
4484 /* if the zoom level is greater than what you'd get trying to display 3
4485 * days of audio on a really big screen, then it's too big.
4488 if (spp * lots_of_pixels > three_days) {
4492 samples_per_pixel = spp;
4495 tempo_lines->tempo_map_changed();
4498 bool const showing_time_selection = selection->time.length() > 0;
4500 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4501 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4502 (*i)->reshow_selection (selection->time);
4506 ZoomChanged (); /* EMIT_SIGNAL */
4508 ArdourCanvas::GtkCanvasViewport* c;
4510 c = get_track_canvas();
4512 c->canvas()->zoomed ();
4515 if (playhead_cursor) {
4516 playhead_cursor->set_position (playhead_cursor->current_frame ());
4519 refresh_location_display();
4520 _summary->set_overlays_dirty ();
4522 update_marker_labels ();
4528 Editor::queue_visual_videotimeline_update ()
4531 * pending_visual_change.add (VisualChange::VideoTimeline);
4532 * or maybe even more specific: which videotimeline-image
4533 * currently it calls update_video_timeline() to update
4534 * _all outdated_ images on the video-timeline.
4535 * see 'exposeimg()' in video_image_frame.cc
4537 ensure_visual_change_idle_handler ();
4541 Editor::ensure_visual_change_idle_handler ()
4543 if (pending_visual_change.idle_handler_id < 0) {
4544 // see comment in add_to_idle_resize above.
4545 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4546 pending_visual_change.being_handled = false;
4551 Editor::_idle_visual_changer (void* arg)
4553 return static_cast<Editor*>(arg)->idle_visual_changer ();
4557 Editor::idle_visual_changer ()
4559 /* set_horizontal_position() below (and maybe other calls) call
4560 gtk_main_iteration(), so it's possible that a signal will be handled
4561 half-way through this method. If this signal wants an
4562 idle_visual_changer we must schedule another one after this one, so
4563 mark the idle_handler_id as -1 here to allow that. Also make a note
4564 that we are doing the visual change, so that changes in response to
4565 super-rapid-screen-update can be dropped if we are still processing
4569 pending_visual_change.idle_handler_id = -1;
4570 pending_visual_change.being_handled = true;
4572 VisualChange vc = pending_visual_change;
4574 pending_visual_change.pending = (VisualChange::Type) 0;
4576 visual_changer (vc);
4578 pending_visual_change.being_handled = false;
4580 return 0; /* this is always a one-shot call */
4584 Editor::visual_changer (const VisualChange& vc)
4586 double const last_time_origin = horizontal_position ();
4588 if (vc.pending & VisualChange::ZoomLevel) {
4589 set_samples_per_pixel (vc.samples_per_pixel);
4591 compute_fixed_ruler_scale ();
4593 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4594 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4596 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4597 current_bbt_points_begin, current_bbt_points_end);
4598 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4599 current_bbt_points_begin, current_bbt_points_end);
4600 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4602 update_video_timeline();
4605 if (vc.pending & VisualChange::TimeOrigin) {
4606 set_horizontal_position (vc.time_origin / samples_per_pixel);
4609 if (vc.pending & VisualChange::YOrigin) {
4610 vertical_adjustment.set_value (vc.y_origin);
4613 if (last_time_origin == horizontal_position ()) {
4614 /* changed signal not emitted */
4615 update_fixed_rulers ();
4616 redisplay_tempo (true);
4619 if (!(vc.pending & VisualChange::ZoomLevel)) {
4620 update_video_timeline();
4623 _summary->set_overlays_dirty ();
4626 struct EditorOrderTimeAxisSorter {
4627 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4628 return a->order () < b->order ();
4633 Editor::sort_track_selection (TrackViewList& sel)
4635 EditorOrderTimeAxisSorter cmp;
4640 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4643 framepos_t where = 0;
4644 EditPoint ep = _edit_point;
4646 if(Profile->get_mixbus())
4647 if (ep == EditAtSelectedMarker)
4650 if (from_context_menu && (ep == EditAtMouse)) {
4651 return canvas_event_sample (&context_click_event, 0, 0);
4654 if (entered_marker) {
4655 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4656 return entered_marker->position();
4659 if (ignore_playhead && ep == EditAtPlayhead) {
4660 ep = EditAtSelectedMarker;
4664 case EditAtPlayhead:
4665 where = _session->audible_frame();
4666 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4669 case EditAtSelectedMarker:
4670 if (!selection->markers.empty()) {
4672 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4675 where = loc->start();
4679 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4687 if (!mouse_frame (where, ignored)) {
4688 /* XXX not right but what can we do ? */
4692 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4700 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4702 if (!_session) return;
4704 begin_reversible_command (cmd);
4708 if ((tll = transport_loop_location()) == 0) {
4709 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4710 XMLNode &before = _session->locations()->get_state();
4711 _session->locations()->add (loc, true);
4712 _session->set_auto_loop_location (loc);
4713 XMLNode &after = _session->locations()->get_state();
4714 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4716 XMLNode &before = tll->get_state();
4717 tll->set_hidden (false, this);
4718 tll->set (start, end);
4719 XMLNode &after = tll->get_state();
4720 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4723 commit_reversible_command ();
4727 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4729 if (!_session) return;
4731 begin_reversible_command (cmd);
4735 if ((tpl = transport_punch_location()) == 0) {
4736 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4737 XMLNode &before = _session->locations()->get_state();
4738 _session->locations()->add (loc, true);
4739 _session->set_auto_punch_location (loc);
4740 XMLNode &after = _session->locations()->get_state();
4741 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4743 XMLNode &before = tpl->get_state();
4744 tpl->set_hidden (false, this);
4745 tpl->set (start, end);
4746 XMLNode &after = tpl->get_state();
4747 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4750 commit_reversible_command ();
4753 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4754 * @param rs List to which found regions are added.
4755 * @param where Time to look at.
4756 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4759 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4761 const TrackViewList* tracks;
4764 tracks = &track_views;
4769 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4771 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4774 boost::shared_ptr<Track> tr;
4775 boost::shared_ptr<Playlist> pl;
4777 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4779 boost::shared_ptr<RegionList> regions = pl->regions_at (
4780 (framepos_t) floor ( (double) where * tr->speed()));
4782 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4783 RegionView* rv = rtv->view()->find_view (*i);
4794 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4796 const TrackViewList* tracks;
4799 tracks = &track_views;
4804 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4805 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4807 boost::shared_ptr<Track> tr;
4808 boost::shared_ptr<Playlist> pl;
4810 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4812 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4813 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4815 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4817 RegionView* rv = rtv->view()->find_view (*i);
4828 /** Get regions using the following method:
4830 * Make a region list using:
4831 * (a) any selected regions
4832 * (b) the intersection of any selected tracks and the edit point(*)
4833 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4835 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4837 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4841 Editor::get_regions_from_selection_and_edit_point ()
4843 RegionSelection regions;
4845 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4846 regions.add (entered_regionview);
4848 regions = selection->regions;
4851 if ( regions.empty() ) {
4852 TrackViewList tracks = selection->tracks;
4854 if (!tracks.empty()) {
4855 /* no region selected or entered, but some selected tracks:
4856 * act on all regions on the selected tracks at the edit point
4858 framepos_t const where = get_preferred_edit_position ();
4859 get_regions_at(regions, where, tracks);
4866 /** Get regions using the following method:
4868 * Make a region list using:
4869 * (a) any selected regions
4870 * (b) the intersection of any selected tracks and the edit point(*)
4871 * (c) if neither exists, then whatever region is under the mouse
4873 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4875 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4878 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4880 RegionSelection regions;
4882 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4883 regions.add (entered_regionview);
4885 regions = selection->regions;
4888 if ( regions.empty() ) {
4889 TrackViewList tracks = selection->tracks;
4891 if (!tracks.empty()) {
4892 /* no region selected or entered, but some selected tracks:
4893 * act on all regions on the selected tracks at the edit point
4895 get_regions_at(regions, pos, tracks);
4902 /** Start with regions that are selected, or the entered regionview if none are selected.
4903 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4904 * of the regions that we started with.
4908 Editor::get_regions_from_selection_and_entered ()
4910 RegionSelection regions = selection->regions;
4912 if (regions.empty() && entered_regionview) {
4913 regions.add (entered_regionview);
4920 Editor::get_regionviews_by_id (PBD::ID const & id, RegionSelection & regions) const
4922 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4923 RouteTimeAxisView* tatv;
4925 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4926 boost::shared_ptr<Playlist> pl;
4927 std::vector<boost::shared_ptr<Region> > results;
4928 boost::shared_ptr<Track> tr;
4930 if ((tr = tatv->track()) == 0) {
4935 if ((pl = (tr->playlist())) != 0) {
4936 boost::shared_ptr<Region> r = pl->region_by_id (id);
4938 RegionView* marv = tatv->view()->find_view (r);
4940 regions.push_back (marv);
4949 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4951 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4953 RouteTimeAxisView* tatv;
4955 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4957 boost::shared_ptr<Playlist> pl;
4958 vector<boost::shared_ptr<Region> > results;
4960 boost::shared_ptr<Track> tr;
4962 if ((tr = tatv->track()) == 0) {
4967 if ((pl = (tr->playlist())) != 0) {
4968 if (src_comparison) {
4969 pl->get_source_equivalent_regions (region, results);
4971 pl->get_region_list_equivalent_regions (region, results);
4975 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4976 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4977 regions.push_back (marv);
4986 Editor::show_rhythm_ferret ()
4988 if (rhythm_ferret == 0) {
4989 rhythm_ferret = new RhythmFerret(*this);
4992 rhythm_ferret->set_session (_session);
4993 rhythm_ferret->show ();
4994 rhythm_ferret->present ();
4998 Editor::first_idle ()
5000 MessageDialog* dialog = 0;
5002 if (track_views.size() > 1) {
5003 dialog = new MessageDialog (
5005 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5009 ARDOUR_UI::instance()->flush_pending ();
5012 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5016 // first idle adds route children (automation tracks), so we need to redisplay here
5017 _routes->redisplay ();
5021 begin_selection_op_history ();
5027 Editor::_idle_resize (gpointer arg)
5029 return ((Editor*)arg)->idle_resize ();
5033 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5035 if (resize_idle_id < 0) {
5036 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5037 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5038 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5040 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5041 _pending_resize_amount = 0;
5044 /* make a note of the smallest resulting height, so that we can clamp the
5045 lower limit at TimeAxisView::hSmall */
5047 int32_t min_resulting = INT32_MAX;
5049 _pending_resize_amount += h;
5050 _pending_resize_view = view;
5052 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5054 if (selection->tracks.contains (_pending_resize_view)) {
5055 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5056 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5060 if (min_resulting < 0) {
5065 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5066 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5070 /** Handle pending resizing of tracks */
5072 Editor::idle_resize ()
5074 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5076 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5077 selection->tracks.contains (_pending_resize_view)) {
5079 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5080 if (*i != _pending_resize_view) {
5081 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5086 _pending_resize_amount = 0;
5087 _group_tabs->set_dirty ();
5088 resize_idle_id = -1;
5096 ENSURE_GUI_THREAD (*this, &Editor::located);
5099 playhead_cursor->set_position (_session->audible_frame ());
5100 if (_follow_playhead && !_pending_initial_locate) {
5101 reset_x_origin_to_follow_playhead ();
5105 _pending_locate_request = false;
5106 _pending_initial_locate = false;
5110 Editor::region_view_added (RegionView * rv)
5112 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5113 if (rv->region ()->id () == (*pr)) {
5114 selection->add (rv);
5115 selection->regions.pending.erase (pr);
5119 _summary->set_background_dirty ();
5123 Editor::region_view_removed ()
5125 _summary->set_background_dirty ();
5129 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5131 TrackViewList::const_iterator j = track_views.begin ();
5132 while (j != track_views.end()) {
5133 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5134 if (rtv && rtv->route() == r) {
5145 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5149 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5150 TimeAxisView* tv = axis_view_from_route (*i);
5160 Editor::suspend_route_redisplay ()
5163 _routes->suspend_redisplay();
5168 Editor::resume_route_redisplay ()
5171 _routes->resume_redisplay();
5176 Editor::add_routes (RouteList& routes)
5178 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5180 RouteTimeAxisView *rtv;
5181 list<RouteTimeAxisView*> new_views;
5183 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5184 boost::shared_ptr<Route> route = (*x);
5186 if (route->is_auditioner() || route->is_monitor()) {
5190 DataType dt = route->input()->default_type();
5192 if (dt == ARDOUR::DataType::AUDIO) {
5193 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5194 rtv->set_route (route);
5195 } else if (dt == ARDOUR::DataType::MIDI) {
5196 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5197 rtv->set_route (route);
5199 throw unknown_type();
5202 new_views.push_back (rtv);
5203 track_views.push_back (rtv);
5205 rtv->effective_gain_display ();
5207 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5208 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5211 if (new_views.size() > 0) {
5212 _routes->routes_added (new_views);
5213 _summary->routes_added (new_views);
5216 if (show_editor_mixer_when_tracks_arrive) {
5217 show_editor_mixer (true);
5220 editor_list_button.set_sensitive (true);
5224 Editor::timeaxisview_deleted (TimeAxisView *tv)
5226 if (tv == entered_track) {
5230 if (_session && _session->deletion_in_progress()) {
5231 /* the situation is under control */
5235 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5237 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5239 _routes->route_removed (tv);
5241 TimeAxisView::Children c = tv->get_child_list ();
5242 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5243 if (entered_track == i->get()) {
5248 /* remove it from the list of track views */
5250 TrackViewList::iterator i;
5252 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5253 i = track_views.erase (i);
5256 /* update whatever the current mixer strip is displaying, if revelant */
5258 boost::shared_ptr<Route> route;
5261 route = rtav->route ();
5264 if (current_mixer_strip && current_mixer_strip->route() == route) {
5266 TimeAxisView* next_tv;
5268 if (track_views.empty()) {
5270 } else if (i == track_views.end()) {
5271 next_tv = track_views.front();
5278 set_selected_mixer_strip (*next_tv);
5280 /* make the editor mixer strip go away setting the
5281 * button to inactive (which also unticks the menu option)
5284 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5290 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5292 if (apply_to_selection) {
5293 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5295 TrackSelection::iterator j = i;
5298 hide_track_in_display (*i, false);
5303 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5305 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5306 // this will hide the mixer strip
5307 set_selected_mixer_strip (*tv);
5310 _routes->hide_track_in_display (*tv);
5315 Editor::sync_track_view_list_and_routes ()
5317 track_views = TrackViewList (_routes->views ());
5319 _summary->set_dirty ();
5320 _group_tabs->set_dirty ();
5322 return false; // do not call again (until needed)
5326 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5328 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5333 /** Find a RouteTimeAxisView by the ID of its route */
5335 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5337 RouteTimeAxisView* v;
5339 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5340 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5341 if(v->route()->id() == id) {
5351 Editor::fit_route_group (RouteGroup *g)
5353 TrackViewList ts = axis_views_from_routes (g->route_list ());
5358 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5360 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5363 _session->cancel_audition ();
5367 if (_session->is_auditioning()) {
5368 _session->cancel_audition ();
5369 if (r == last_audition_region) {
5374 _session->audition_region (r);
5375 last_audition_region = r;
5380 Editor::hide_a_region (boost::shared_ptr<Region> r)
5382 r->set_hidden (true);
5386 Editor::show_a_region (boost::shared_ptr<Region> r)
5388 r->set_hidden (false);
5392 Editor::audition_region_from_region_list ()
5394 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5398 Editor::hide_region_from_region_list ()
5400 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5404 Editor::show_region_in_region_list ()
5406 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5410 Editor::step_edit_status_change (bool yn)
5413 start_step_editing ();
5415 stop_step_editing ();
5420 Editor::start_step_editing ()
5422 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5426 Editor::stop_step_editing ()
5428 step_edit_connection.disconnect ();
5432 Editor::check_step_edit ()
5434 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5435 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5437 mtv->check_step_edit ();
5441 return true; // do it again, till we stop
5445 Editor::scroll_press (Direction dir)
5447 ++_scroll_callbacks;
5449 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5450 /* delay the first auto-repeat */
5456 scroll_backward (1);
5464 scroll_up_one_track ();
5468 scroll_down_one_track ();
5472 /* do hacky auto-repeat */
5473 if (!_scroll_connection.connected ()) {
5475 _scroll_connection = Glib::signal_timeout().connect (
5476 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5479 _scroll_callbacks = 0;
5486 Editor::scroll_release ()
5488 _scroll_connection.disconnect ();
5491 /** Queue a change for the Editor viewport x origin to follow the playhead */
5493 Editor::reset_x_origin_to_follow_playhead ()
5495 framepos_t const frame = playhead_cursor->current_frame ();
5497 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5499 if (_session->transport_speed() < 0) {
5501 if (frame > (current_page_samples() / 2)) {
5502 center_screen (frame-(current_page_samples()/2));
5504 center_screen (current_page_samples()/2);
5511 if (frame < leftmost_frame) {
5513 if (_session->transport_rolling()) {
5514 /* rolling; end up with the playhead at the right of the page */
5515 l = frame - current_page_samples ();
5517 /* not rolling: end up with the playhead 1/4 of the way along the page */
5518 l = frame - current_page_samples() / 4;
5522 if (_session->transport_rolling()) {
5523 /* rolling: end up with the playhead on the left of the page */
5526 /* not rolling: end up with the playhead 3/4 of the way along the page */
5527 l = frame - 3 * current_page_samples() / 4;
5535 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5541 Editor::super_rapid_screen_update ()
5543 if (!_session || !_session->engine().running()) {
5547 /* METERING / MIXER STRIPS */
5549 /* update track meters, if required */
5550 if (is_mapped() && meters_running) {
5551 RouteTimeAxisView* rtv;
5552 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5553 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5554 rtv->fast_update ();
5559 /* and any current mixer strip */
5560 if (current_mixer_strip) {
5561 current_mixer_strip->fast_update ();
5564 /* PLAYHEAD AND VIEWPORT */
5566 framepos_t const frame = _session->audible_frame();
5568 /* There are a few reasons why we might not update the playhead / viewport stuff:
5570 * 1. we don't update things when there's a pending locate request, otherwise
5571 * when the editor requests a locate there is a chance that this method
5572 * will move the playhead before the locate request is processed, causing
5574 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5575 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5578 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5580 last_update_frame = frame;
5582 if (!_dragging_playhead) {
5583 playhead_cursor->set_position (frame);
5586 if (!_stationary_playhead) {
5588 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5589 /* We only do this if we aren't already
5590 handling a visual change (ie if
5591 pending_visual_change.being_handled is
5592 false) so that these requests don't stack
5593 up there are too many of them to handle in
5596 reset_x_origin_to_follow_playhead ();
5601 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5605 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5606 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5607 if (target <= 0.0) {
5610 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5611 target = (target * 0.15) + (current * 0.85);
5617 set_horizontal_position (current);
5626 Editor::session_going_away ()
5628 _have_idled = false;
5630 _session_connections.drop_connections ();
5632 super_rapid_screen_update_connection.disconnect ();
5634 selection->clear ();
5635 cut_buffer->clear ();
5637 clicked_regionview = 0;
5638 clicked_axisview = 0;
5639 clicked_routeview = 0;
5640 entered_regionview = 0;
5642 last_update_frame = 0;
5645 playhead_cursor->hide ();
5647 /* rip everything out of the list displays */
5651 _route_groups->clear ();
5653 /* do this first so that deleting a track doesn't reset cms to null
5654 and thus cause a leak.
5657 if (current_mixer_strip) {
5658 if (current_mixer_strip->get_parent() != 0) {
5659 global_hpacker.remove (*current_mixer_strip);
5661 delete current_mixer_strip;
5662 current_mixer_strip = 0;
5665 /* delete all trackviews */
5667 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5670 track_views.clear ();
5672 nudge_clock->set_session (0);
5674 editor_list_button.set_active(false);
5675 editor_list_button.set_sensitive(false);
5677 /* clear tempo/meter rulers */
5678 remove_metric_marks ();
5680 clear_marker_display ();
5682 stop_step_editing ();
5684 /* get rid of any existing editor mixer strip */
5686 WindowTitle title(Glib::get_application_name());
5687 title += _("Editor");
5689 set_title (title.get_string());
5691 SessionHandlePtr::session_going_away ();
5696 Editor::show_editor_list (bool yn)
5699 _the_notebook.show ();
5701 _the_notebook.hide ();
5706 Editor::change_region_layering_order (bool from_context_menu)
5708 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5710 if (!clicked_routeview) {
5711 if (layering_order_editor) {
5712 layering_order_editor->hide ();
5717 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5723 boost::shared_ptr<Playlist> pl = track->playlist();
5729 if (layering_order_editor == 0) {
5730 layering_order_editor = new RegionLayeringOrderEditor (*this);
5733 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5734 layering_order_editor->maybe_present ();
5738 Editor::update_region_layering_order_editor ()
5740 if (layering_order_editor && layering_order_editor->is_visible ()) {
5741 change_region_layering_order (true);
5746 Editor::setup_fade_images ()
5748 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5749 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5750 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5751 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5752 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5754 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5755 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5756 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5757 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5758 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5760 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5761 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5762 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5763 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5764 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5766 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5767 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5768 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5769 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5770 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5774 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5776 Editor::action_menu_item (std::string const & name)
5778 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5781 return *manage (a->create_menu_item ());
5785 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5787 EventBox* b = manage (new EventBox);
5788 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5789 Label* l = manage (new Label (name));
5793 _the_notebook.append_page (widget, *b);
5797 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5799 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5800 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5803 if (ev->type == GDK_2BUTTON_PRESS) {
5805 /* double-click on a notebook tab shrinks or expands the notebook */
5807 if (_notebook_shrunk) {
5808 if (pre_notebook_shrink_pane_width) {
5809 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5811 _notebook_shrunk = false;
5813 pre_notebook_shrink_pane_width = edit_pane.get_position();
5815 /* this expands the LHS of the edit pane to cover the notebook
5816 PAGE but leaves the tabs visible.
5818 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5819 _notebook_shrunk = true;
5827 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5829 using namespace Menu_Helpers;
5831 MenuList& items = _control_point_context_menu.items ();
5834 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5835 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5836 if (!can_remove_control_point (item)) {
5837 items.back().set_sensitive (false);
5840 _control_point_context_menu.popup (event->button.button, event->button.time);
5844 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5846 using namespace Menu_Helpers;
5848 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5853 /* We need to get the selection here and pass it to the operations, since
5854 popping up the menu will cause a region leave event which clears
5855 entered_regionview. */
5857 MidiRegionView& mrv = note->region_view();
5858 const RegionSelection rs = get_regions_from_selection_and_entered ();
5860 MenuList& items = _note_context_menu.items();
5863 items.push_back(MenuElem(_("Delete"),
5864 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5865 items.push_back(MenuElem(_("Edit..."),
5866 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5867 items.push_back(MenuElem(_("Legatize"),
5868 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5869 items.push_back(MenuElem(_("Quantize..."),
5870 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5871 items.push_back(MenuElem(_("Remove Overlap"),
5872 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5873 items.push_back(MenuElem(_("Transform..."),
5874 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5876 _note_context_menu.popup (event->button.button, event->button.time);
5880 Editor::zoom_vertical_modifier_released()
5882 _stepping_axis_view = 0;
5886 Editor::ui_parameter_changed (string parameter)
5888 if (parameter == "icon-set") {
5889 while (!_cursor_stack.empty()) {
5890 _cursor_stack.pop_back();
5892 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5893 _cursor_stack.push_back(_cursors->grabber);
5894 } else if (parameter == "draggable-playhead") {
5895 if (_verbose_cursor) {
5896 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());