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_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_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 undo_action->set_sensitive(true);
3431 begin_selection_op_history ();
3434 if (before.empty()) {
3435 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3440 _session->commit_reversible_command ();
3445 Editor::history_changed ()
3449 if (undo_action && _session) {
3450 if (_session->undo_depth() == 0) {
3451 label = S_("Command|Undo");
3453 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3455 undo_action->property_label() = label;
3458 if (redo_action && _session) {
3459 if (_session->redo_depth() == 0) {
3462 label = string_compose(_("Redo (%1)"), _session->next_redo());
3464 redo_action->property_label() = label;
3469 Editor::duplicate_range (bool with_dialog)
3473 RegionSelection rs = get_regions_from_selection_and_entered ();
3475 if ( selection->time.length() == 0 && rs.empty()) {
3481 ArdourDialog win (_("Duplicate"));
3482 Label label (_("Number of duplications:"));
3483 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3484 SpinButton spinner (adjustment, 0.0, 1);
3487 win.get_vbox()->set_spacing (12);
3488 win.get_vbox()->pack_start (hbox);
3489 hbox.set_border_width (6);
3490 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3492 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3493 place, visually. so do this by hand.
3496 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3497 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3498 spinner.grab_focus();
3504 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3505 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3506 win.set_default_response (RESPONSE_ACCEPT);
3508 spinner.grab_focus ();
3510 switch (win.run ()) {
3511 case RESPONSE_ACCEPT:
3517 times = adjustment.get_value();
3520 if ((current_mouse_mode() == Editing::MouseRange)) {
3521 if (selection->time.length()) {
3522 duplicate_selection (times);
3524 } else if (get_smart_mode()) {
3525 if (selection->time.length()) {
3526 duplicate_selection (times);
3528 duplicate_some_regions (rs, times);
3530 duplicate_some_regions (rs, times);
3535 Editor::set_edit_mode (EditMode m)
3537 Config->set_edit_mode (m);
3541 Editor::cycle_edit_mode ()
3543 switch (Config->get_edit_mode()) {
3545 if (Profile->get_sae()) {
3546 Config->set_edit_mode (Lock);
3548 Config->set_edit_mode (Ripple);
3553 Config->set_edit_mode (Lock);
3556 Config->set_edit_mode (Slide);
3562 Editor::edit_mode_selection_done ( EditMode m )
3564 Config->set_edit_mode ( m );
3568 Editor::snap_type_selection_done (SnapType snaptype)
3570 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3572 ract->set_active ();
3577 Editor::snap_mode_selection_done (SnapMode mode)
3579 RefPtr<RadioAction> ract = snap_mode_action (mode);
3582 ract->set_active (true);
3587 Editor::cycle_edit_point (bool with_marker)
3589 if(Profile->get_mixbus())
3590 with_marker = false;
3592 switch (_edit_point) {
3594 set_edit_point_preference (EditAtPlayhead);
3596 case EditAtPlayhead:
3598 set_edit_point_preference (EditAtSelectedMarker);
3600 set_edit_point_preference (EditAtMouse);
3603 case EditAtSelectedMarker:
3604 set_edit_point_preference (EditAtMouse);
3610 Editor::edit_point_selection_done (EditPoint ep)
3612 set_edit_point_preference ( ep );
3616 Editor::build_zoom_focus_menu ()
3618 using namespace Menu_Helpers;
3620 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3621 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3622 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3623 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3624 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3625 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3627 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3631 Editor::zoom_focus_selection_done ( ZoomFocus f )
3633 RefPtr<RadioAction> ract = zoom_focus_action (f);
3635 ract->set_active ();
3640 Editor::build_track_count_menu ()
3642 using namespace Menu_Helpers;
3644 if (!Profile->get_mixbus()) {
3645 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3646 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3647 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3648 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3649 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3650 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3651 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3652 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3653 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3654 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3655 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3656 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3657 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3659 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3660 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3661 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3662 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3663 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3664 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3665 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3666 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3667 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3668 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3670 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3671 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3672 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3673 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3674 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3675 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3676 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3677 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3678 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3679 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3680 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3685 Editor::set_zoom_preset (int64_t ms)
3688 temporal_zoom_session();
3692 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3693 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3697 Editor::set_visible_track_count (int32_t n)
3699 _visible_track_count = n;
3701 /* if the canvas hasn't really been allocated any size yet, just
3702 record the desired number of visible tracks and return. when canvas
3703 allocation happens, we will get called again and then we can do the
3707 if (_visible_canvas_height <= 1) {
3713 DisplaySuspender ds;
3715 if (_visible_track_count > 0) {
3716 h = trackviews_height() / _visible_track_count;
3717 std::ostringstream s;
3718 s << _visible_track_count;
3720 } else if (_visible_track_count == 0) {
3722 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3723 if ((*i)->marked_for_display()) {
3727 h = trackviews_height() / n;
3730 /* negative value means that the visible track count has
3731 been overridden by explicit track height changes.
3733 visible_tracks_selector.set_text (X_("*"));
3737 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3738 (*i)->set_height (h);
3741 if (str != visible_tracks_selector.get_text()) {
3742 visible_tracks_selector.set_text (str);
3747 Editor::override_visible_track_count ()
3749 _visible_track_count = -1;
3750 visible_tracks_selector.set_text ( _("*") );
3754 Editor::edit_controls_button_release (GdkEventButton* ev)
3756 if (Keyboard::is_context_menu_event (ev)) {
3757 ARDOUR_UI::instance()->add_route (this);
3758 } else if (ev->button == 1) {
3759 selection->clear_tracks ();
3766 Editor::mouse_select_button_release (GdkEventButton* ev)
3768 /* this handles just right-clicks */
3770 if (ev->button != 3) {
3778 Editor::set_zoom_focus (ZoomFocus f)
3780 string str = zoom_focus_strings[(int)f];
3782 if (str != zoom_focus_selector.get_text()) {
3783 zoom_focus_selector.set_text (str);
3786 if (zoom_focus != f) {
3793 Editor::cycle_zoom_focus ()
3795 switch (zoom_focus) {
3797 set_zoom_focus (ZoomFocusRight);
3799 case ZoomFocusRight:
3800 set_zoom_focus (ZoomFocusCenter);
3802 case ZoomFocusCenter:
3803 set_zoom_focus (ZoomFocusPlayhead);
3805 case ZoomFocusPlayhead:
3806 set_zoom_focus (ZoomFocusMouse);
3808 case ZoomFocusMouse:
3809 set_zoom_focus (ZoomFocusEdit);
3812 set_zoom_focus (ZoomFocusLeft);
3818 Editor::ensure_float (Window& win)
3820 win.set_transient_for (*this);
3824 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3826 /* recover or initialize pane positions. do this here rather than earlier because
3827 we don't want the positions to change the child allocations, which they seem to do.
3833 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3842 XMLNode* geometry = find_named_node (*node, "geometry");
3844 if (which == static_cast<Paned*> (&edit_pane)) {
3846 if (done & Horizontal) {
3850 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3851 _notebook_shrunk = string_is_affirmative (prop->value ());
3854 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3855 /* initial allocation is 90% to canvas, 10% to notebook */
3856 pos = (int) floor (alloc.get_width() * 0.90f);
3857 snprintf (buf, sizeof(buf), "%d", pos);
3859 pos = atoi (prop->value());
3862 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3863 edit_pane.set_position (pos);
3866 done = (Pane) (done | Horizontal);
3868 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3870 if (done & Vertical) {
3874 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3875 /* initial allocation is 90% to canvas, 10% to summary */
3876 pos = (int) floor (alloc.get_height() * 0.90f);
3877 snprintf (buf, sizeof(buf), "%d", pos);
3880 pos = atoi (prop->value());
3883 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3884 editor_summary_pane.set_position (pos);
3887 done = (Pane) (done | Vertical);
3892 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3894 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3895 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3896 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3897 top_hbox.remove (toolbar_frame);
3902 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3904 if (toolbar_frame.get_parent() == 0) {
3905 top_hbox.pack_end (toolbar_frame);
3910 Editor::set_show_measures (bool yn)
3912 if (_show_measures != yn) {
3915 if ((_show_measures = yn) == true) {
3917 tempo_lines->show();
3920 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3921 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3923 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3924 draw_measures (begin, end);
3932 Editor::toggle_follow_playhead ()
3934 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3936 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3937 set_follow_playhead (tact->get_active());
3941 /** @param yn true to follow playhead, otherwise false.
3942 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3945 Editor::set_follow_playhead (bool yn, bool catch_up)
3947 if (_follow_playhead != yn) {
3948 if ((_follow_playhead = yn) == true && catch_up) {
3950 reset_x_origin_to_follow_playhead ();
3957 Editor::toggle_stationary_playhead ()
3959 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3961 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3962 set_stationary_playhead (tact->get_active());
3967 Editor::set_stationary_playhead (bool yn)
3969 if (_stationary_playhead != yn) {
3970 if ((_stationary_playhead = yn) == true) {
3972 // FIXME need a 3.0 equivalent of this 2.X call
3973 // update_current_screen ();
3980 Editor::playlist_selector () const
3982 return *_playlist_selector;
3986 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3988 if (paste_count == 0) {
3989 /* don't bother calculating an offset that will be zero anyway */
3993 /* calculate basic unsnapped multi-paste offset */
3994 framecnt_t offset = paste_count * duration;
3996 /* snap offset so pos + offset is aligned to the grid */
3997 framepos_t offset_pos = pos + offset;
3998 snap_to(offset_pos, RoundUpMaybe);
3999 offset = offset_pos - pos;
4005 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4009 switch (_snap_type) {
4011 return Evoral::MusicalTime(1.0);
4014 case SnapToBeatDiv128:
4015 return Evoral::MusicalTime(1.0/128.0);
4017 case SnapToBeatDiv64:
4018 return Evoral::MusicalTime(1.0/64.0);
4020 case SnapToBeatDiv32:
4021 return Evoral::MusicalTime(1.0/32.0);
4023 case SnapToBeatDiv28:
4024 return Evoral::MusicalTime(1.0/28.0);
4026 case SnapToBeatDiv24:
4027 return Evoral::MusicalTime(1.0/24.0);
4029 case SnapToBeatDiv20:
4030 return Evoral::MusicalTime(1.0/20.0);
4032 case SnapToBeatDiv16:
4033 return Evoral::MusicalTime(1.0/16.0);
4035 case SnapToBeatDiv14:
4036 return Evoral::MusicalTime(1.0/14.0);
4038 case SnapToBeatDiv12:
4039 return Evoral::MusicalTime(1.0/12.0);
4041 case SnapToBeatDiv10:
4042 return Evoral::MusicalTime(1.0/10.0);
4044 case SnapToBeatDiv8:
4045 return Evoral::MusicalTime(1.0/8.0);
4047 case SnapToBeatDiv7:
4048 return Evoral::MusicalTime(1.0/7.0);
4050 case SnapToBeatDiv6:
4051 return Evoral::MusicalTime(1.0/6.0);
4053 case SnapToBeatDiv5:
4054 return Evoral::MusicalTime(1.0/5.0);
4056 case SnapToBeatDiv4:
4057 return Evoral::MusicalTime(1.0/4.0);
4059 case SnapToBeatDiv3:
4060 return Evoral::MusicalTime(1.0/3.0);
4062 case SnapToBeatDiv2:
4063 return Evoral::MusicalTime(1.0/2.0);
4068 return Evoral::MusicalTime(_session->tempo_map().meter_at (position).divisions_per_bar());
4073 case SnapToTimecodeFrame:
4074 case SnapToTimecodeSeconds:
4075 case SnapToTimecodeMinutes:
4078 case SnapToRegionStart:
4079 case SnapToRegionEnd:
4080 case SnapToRegionSync:
4081 case SnapToRegionBoundary:
4087 return Evoral::MusicalTime();
4091 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4095 ret = nudge_clock->current_duration (pos);
4096 next = ret + 1; /* XXXX fix me */
4102 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4104 ArdourDialog dialog (_("Playlist Deletion"));
4105 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4106 "If it is kept, its audio files will not be cleaned.\n"
4107 "If it is deleted, audio files used by it alone will be cleaned."),
4110 dialog.set_position (WIN_POS_CENTER);
4111 dialog.get_vbox()->pack_start (label);
4115 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4116 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4117 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4119 switch (dialog.run ()) {
4120 case RESPONSE_ACCEPT:
4121 /* delete the playlist */
4125 case RESPONSE_REJECT:
4126 /* keep the playlist */
4138 Editor::audio_region_selection_covers (framepos_t where)
4140 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4141 if ((*a)->region()->covers (where)) {
4150 Editor::prepare_for_cleanup ()
4152 cut_buffer->clear_regions ();
4153 cut_buffer->clear_playlists ();
4155 selection->clear_regions ();
4156 selection->clear_playlists ();
4158 _regions->suspend_redisplay ();
4162 Editor::finish_cleanup ()
4164 _regions->resume_redisplay ();
4168 Editor::transport_loop_location()
4171 return _session->locations()->auto_loop_location();
4178 Editor::transport_punch_location()
4181 return _session->locations()->auto_punch_location();
4188 Editor::control_layout_scroll (GdkEventScroll* ev)
4190 /* Just forward to the normal canvas scroll method. The coordinate
4191 systems are different but since the canvas is always larger than the
4192 track headers, and aligned with the trackview area, this will work.
4194 In the not too distant future this layout is going away anyway and
4195 headers will be on the canvas.
4197 return canvas_scroll_event (ev, false);
4201 Editor::session_state_saved (string)
4204 _snapshots->redisplay ();
4208 Editor::update_tearoff_visibility()
4210 bool visible = ARDOUR_UI::config()->get_keep_tearoffs();
4211 _mouse_mode_tearoff->set_visible (visible);
4212 _tools_tearoff->set_visible (visible);
4213 if (_zoom_tearoff) {
4214 _zoom_tearoff->set_visible (visible);
4219 Editor::reattach_all_tearoffs ()
4221 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4222 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4223 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4227 Editor::maximise_editing_space ()
4239 Editor::restore_editing_space ()
4251 * Make new playlists for a given track and also any others that belong
4252 * to the same active route group with the `select' property.
4257 Editor::new_playlists (TimeAxisView* v)
4259 begin_reversible_command (_("new playlists"));
4260 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4261 _session->playlists->get (playlists);
4262 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4263 commit_reversible_command ();
4267 * Use a copy of the current playlist for a given track and also any others that belong
4268 * to the same active route group with the `select' property.
4273 Editor::copy_playlists (TimeAxisView* v)
4275 begin_reversible_command (_("copy playlists"));
4276 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4277 _session->playlists->get (playlists);
4278 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4279 commit_reversible_command ();
4282 /** Clear the current playlist for a given track and also any others that belong
4283 * to the same active route group with the `select' property.
4288 Editor::clear_playlists (TimeAxisView* v)
4290 begin_reversible_command (_("clear playlists"));
4291 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4292 _session->playlists->get (playlists);
4293 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4294 commit_reversible_command ();
4298 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4300 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4304 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4306 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4310 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4312 atv.clear_playlist ();
4316 Editor::on_key_press_event (GdkEventKey* ev)
4318 return key_press_focus_accelerator_handler (*this, ev);
4322 Editor::on_key_release_event (GdkEventKey* ev)
4324 return Gtk::Window::on_key_release_event (ev);
4325 // return key_press_focus_accelerator_handler (*this, ev);
4329 Editor::get_y_origin () const
4331 return vertical_adjustment.get_value ();
4334 /** Queue up a change to the viewport x origin.
4335 * @param frame New x origin.
4338 Editor::reset_x_origin (framepos_t frame)
4340 pending_visual_change.add (VisualChange::TimeOrigin);
4341 pending_visual_change.time_origin = frame;
4342 ensure_visual_change_idle_handler ();
4346 Editor::reset_y_origin (double y)
4348 pending_visual_change.add (VisualChange::YOrigin);
4349 pending_visual_change.y_origin = y;
4350 ensure_visual_change_idle_handler ();
4354 Editor::reset_zoom (framecnt_t spp)
4356 if (spp == samples_per_pixel) {
4360 pending_visual_change.add (VisualChange::ZoomLevel);
4361 pending_visual_change.samples_per_pixel = spp;
4362 ensure_visual_change_idle_handler ();
4366 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4368 reset_x_origin (frame);
4371 if (!no_save_visual) {
4372 undo_visual_stack.push_back (current_visual_state(false));
4376 Editor::VisualState::VisualState (bool with_tracks)
4377 : gui_state (with_tracks ? new GUIObjectState : 0)
4381 Editor::VisualState::~VisualState ()
4386 Editor::VisualState*
4387 Editor::current_visual_state (bool with_tracks)
4389 VisualState* vs = new VisualState (with_tracks);
4390 vs->y_position = vertical_adjustment.get_value();
4391 vs->samples_per_pixel = samples_per_pixel;
4392 vs->leftmost_frame = leftmost_frame;
4393 vs->zoom_focus = zoom_focus;
4396 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4403 Editor::undo_visual_state ()
4405 if (undo_visual_stack.empty()) {
4409 VisualState* vs = undo_visual_stack.back();
4410 undo_visual_stack.pop_back();
4413 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4416 use_visual_state (*vs);
4421 Editor::redo_visual_state ()
4423 if (redo_visual_stack.empty()) {
4427 VisualState* vs = redo_visual_stack.back();
4428 redo_visual_stack.pop_back();
4430 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4431 // why do we check here?
4432 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4435 use_visual_state (*vs);
4440 Editor::swap_visual_state ()
4442 if (undo_visual_stack.empty()) {
4443 redo_visual_state ();
4445 undo_visual_state ();
4450 Editor::use_visual_state (VisualState& vs)
4452 PBD::Unwinder<bool> nsv (no_save_visual, true);
4453 DisplaySuspender ds;
4455 vertical_adjustment.set_value (vs.y_position);
4457 set_zoom_focus (vs.zoom_focus);
4458 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4461 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4463 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4464 (*i)->reset_visual_state ();
4468 _routes->update_visibility ();
4471 /** This is the core function that controls the zoom level of the canvas. It is called
4472 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4473 * @param spp new number of samples per pixel
4476 Editor::set_samples_per_pixel (framecnt_t spp)
4482 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4483 const framecnt_t lots_of_pixels = 4000;
4485 /* if the zoom level is greater than what you'd get trying to display 3
4486 * days of audio on a really big screen, then it's too big.
4489 if (spp * lots_of_pixels > three_days) {
4493 samples_per_pixel = spp;
4496 tempo_lines->tempo_map_changed();
4499 bool const showing_time_selection = selection->time.length() > 0;
4501 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4502 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4503 (*i)->reshow_selection (selection->time);
4507 ZoomChanged (); /* EMIT_SIGNAL */
4509 ArdourCanvas::GtkCanvasViewport* c;
4511 c = get_track_canvas();
4513 c->canvas()->zoomed ();
4516 if (playhead_cursor) {
4517 playhead_cursor->set_position (playhead_cursor->current_frame ());
4520 refresh_location_display();
4521 _summary->set_overlays_dirty ();
4523 update_marker_labels ();
4529 Editor::queue_visual_videotimeline_update ()
4532 * pending_visual_change.add (VisualChange::VideoTimeline);
4533 * or maybe even more specific: which videotimeline-image
4534 * currently it calls update_video_timeline() to update
4535 * _all outdated_ images on the video-timeline.
4536 * see 'exposeimg()' in video_image_frame.cc
4538 ensure_visual_change_idle_handler ();
4542 Editor::ensure_visual_change_idle_handler ()
4544 if (pending_visual_change.idle_handler_id < 0) {
4545 // see comment in add_to_idle_resize above.
4546 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4547 pending_visual_change.being_handled = false;
4552 Editor::_idle_visual_changer (void* arg)
4554 return static_cast<Editor*>(arg)->idle_visual_changer ();
4558 Editor::idle_visual_changer ()
4560 /* set_horizontal_position() below (and maybe other calls) call
4561 gtk_main_iteration(), so it's possible that a signal will be handled
4562 half-way through this method. If this signal wants an
4563 idle_visual_changer we must schedule another one after this one, so
4564 mark the idle_handler_id as -1 here to allow that. Also make a note
4565 that we are doing the visual change, so that changes in response to
4566 super-rapid-screen-update can be dropped if we are still processing
4570 pending_visual_change.idle_handler_id = -1;
4571 pending_visual_change.being_handled = true;
4573 VisualChange vc = pending_visual_change;
4575 pending_visual_change.pending = (VisualChange::Type) 0;
4577 visual_changer (vc);
4579 pending_visual_change.being_handled = false;
4581 return 0; /* this is always a one-shot call */
4585 Editor::visual_changer (const VisualChange& vc)
4587 double const last_time_origin = horizontal_position ();
4589 if (vc.pending & VisualChange::ZoomLevel) {
4590 set_samples_per_pixel (vc.samples_per_pixel);
4592 compute_fixed_ruler_scale ();
4594 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4595 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4597 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4598 current_bbt_points_begin, current_bbt_points_end);
4599 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4600 current_bbt_points_begin, current_bbt_points_end);
4601 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4603 update_video_timeline();
4606 if (vc.pending & VisualChange::TimeOrigin) {
4607 set_horizontal_position (vc.time_origin / samples_per_pixel);
4610 if (vc.pending & VisualChange::YOrigin) {
4611 vertical_adjustment.set_value (vc.y_origin);
4614 if (last_time_origin == horizontal_position ()) {
4615 /* changed signal not emitted */
4616 update_fixed_rulers ();
4617 redisplay_tempo (true);
4620 if (!(vc.pending & VisualChange::ZoomLevel)) {
4621 update_video_timeline();
4624 _summary->set_overlays_dirty ();
4627 struct EditorOrderTimeAxisSorter {
4628 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4629 return a->order () < b->order ();
4634 Editor::sort_track_selection (TrackViewList& sel)
4636 EditorOrderTimeAxisSorter cmp;
4641 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4644 framepos_t where = 0;
4645 EditPoint ep = _edit_point;
4647 if(Profile->get_mixbus())
4648 if (ep == EditAtSelectedMarker)
4651 if (from_context_menu && (ep == EditAtMouse)) {
4652 return canvas_event_sample (&context_click_event, 0, 0);
4655 if (entered_marker) {
4656 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4657 return entered_marker->position();
4660 if (ignore_playhead && ep == EditAtPlayhead) {
4661 ep = EditAtSelectedMarker;
4665 case EditAtPlayhead:
4666 where = _session->audible_frame();
4667 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4670 case EditAtSelectedMarker:
4671 if (!selection->markers.empty()) {
4673 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4676 where = loc->start();
4680 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4688 if (!mouse_frame (where, ignored)) {
4689 /* XXX not right but what can we do ? */
4693 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4701 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4703 if (!_session) return;
4705 begin_reversible_command (cmd);
4709 if ((tll = transport_loop_location()) == 0) {
4710 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4711 XMLNode &before = _session->locations()->get_state();
4712 _session->locations()->add (loc, true);
4713 _session->set_auto_loop_location (loc);
4714 XMLNode &after = _session->locations()->get_state();
4715 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4717 XMLNode &before = tll->get_state();
4718 tll->set_hidden (false, this);
4719 tll->set (start, end);
4720 XMLNode &after = tll->get_state();
4721 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4724 commit_reversible_command ();
4728 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4730 if (!_session) return;
4732 begin_reversible_command (cmd);
4736 if ((tpl = transport_punch_location()) == 0) {
4737 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4738 XMLNode &before = _session->locations()->get_state();
4739 _session->locations()->add (loc, true);
4740 _session->set_auto_punch_location (loc);
4741 XMLNode &after = _session->locations()->get_state();
4742 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4744 XMLNode &before = tpl->get_state();
4745 tpl->set_hidden (false, this);
4746 tpl->set (start, end);
4747 XMLNode &after = tpl->get_state();
4748 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4751 commit_reversible_command ();
4754 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4755 * @param rs List to which found regions are added.
4756 * @param where Time to look at.
4757 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4760 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4762 const TrackViewList* tracks;
4765 tracks = &track_views;
4770 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4772 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4775 boost::shared_ptr<Track> tr;
4776 boost::shared_ptr<Playlist> pl;
4778 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4780 boost::shared_ptr<RegionList> regions = pl->regions_at (
4781 (framepos_t) floor ( (double) where * tr->speed()));
4783 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4784 RegionView* rv = rtv->view()->find_view (*i);
4795 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4797 const TrackViewList* tracks;
4800 tracks = &track_views;
4805 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4806 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4808 boost::shared_ptr<Track> tr;
4809 boost::shared_ptr<Playlist> pl;
4811 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4813 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4814 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4816 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4818 RegionView* rv = rtv->view()->find_view (*i);
4829 /** Get regions using the following method:
4831 * Make a region list using:
4832 * (a) any selected regions
4833 * (b) the intersection of any selected tracks and the edit point(*)
4834 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4836 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4838 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4842 Editor::get_regions_from_selection_and_edit_point ()
4844 RegionSelection regions;
4846 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4847 regions.add (entered_regionview);
4849 regions = selection->regions;
4852 if ( regions.empty() ) {
4853 TrackViewList tracks = selection->tracks;
4855 if (!tracks.empty()) {
4856 /* no region selected or entered, but some selected tracks:
4857 * act on all regions on the selected tracks at the edit point
4859 framepos_t const where = get_preferred_edit_position ();
4860 get_regions_at(regions, where, tracks);
4867 /** Get regions using the following method:
4869 * Make a region list using:
4870 * (a) any selected regions
4871 * (b) the intersection of any selected tracks and the edit point(*)
4872 * (c) if neither exists, then whatever region is under the mouse
4874 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4876 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4879 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4881 RegionSelection regions;
4883 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4884 regions.add (entered_regionview);
4886 regions = selection->regions;
4889 if ( regions.empty() ) {
4890 TrackViewList tracks = selection->tracks;
4892 if (!tracks.empty()) {
4893 /* no region selected or entered, but some selected tracks:
4894 * act on all regions on the selected tracks at the edit point
4896 get_regions_at(regions, pos, tracks);
4903 /** Start with regions that are selected, or the entered regionview if none are selected.
4904 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4905 * of the regions that we started with.
4909 Editor::get_regions_from_selection_and_entered ()
4911 RegionSelection regions = selection->regions;
4913 if (regions.empty() && entered_regionview) {
4914 regions.add (entered_regionview);
4921 Editor::get_regionviews_by_id (PBD::ID const & id, RegionSelection & regions) const
4923 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4924 RouteTimeAxisView* tatv;
4926 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4927 boost::shared_ptr<Playlist> pl;
4928 std::vector<boost::shared_ptr<Region> > results;
4929 boost::shared_ptr<Track> tr;
4931 if ((tr = tatv->track()) == 0) {
4936 if ((pl = (tr->playlist())) != 0) {
4937 boost::shared_ptr<Region> r = pl->region_by_id (id);
4939 RegionView* marv = tatv->view()->find_view (r);
4941 regions.push_back (marv);
4950 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4952 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4954 RouteTimeAxisView* tatv;
4956 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4958 boost::shared_ptr<Playlist> pl;
4959 vector<boost::shared_ptr<Region> > results;
4961 boost::shared_ptr<Track> tr;
4963 if ((tr = tatv->track()) == 0) {
4968 if ((pl = (tr->playlist())) != 0) {
4969 if (src_comparison) {
4970 pl->get_source_equivalent_regions (region, results);
4972 pl->get_region_list_equivalent_regions (region, results);
4976 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4977 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4978 regions.push_back (marv);
4987 Editor::show_rhythm_ferret ()
4989 if (rhythm_ferret == 0) {
4990 rhythm_ferret = new RhythmFerret(*this);
4993 rhythm_ferret->set_session (_session);
4994 rhythm_ferret->show ();
4995 rhythm_ferret->present ();
4999 Editor::first_idle ()
5001 MessageDialog* dialog = 0;
5003 if (track_views.size() > 1) {
5004 dialog = new MessageDialog (
5006 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5010 ARDOUR_UI::instance()->flush_pending ();
5013 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5017 // first idle adds route children (automation tracks), so we need to redisplay here
5018 _routes->redisplay ();
5022 if (_session->undo_depth() == 0) {
5023 undo_action->set_sensitive(false);
5025 redo_action->set_sensitive(false);
5026 begin_selection_op_history ();
5032 Editor::_idle_resize (gpointer arg)
5034 return ((Editor*)arg)->idle_resize ();
5038 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5040 if (resize_idle_id < 0) {
5041 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5042 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5043 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5045 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5046 _pending_resize_amount = 0;
5049 /* make a note of the smallest resulting height, so that we can clamp the
5050 lower limit at TimeAxisView::hSmall */
5052 int32_t min_resulting = INT32_MAX;
5054 _pending_resize_amount += h;
5055 _pending_resize_view = view;
5057 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5059 if (selection->tracks.contains (_pending_resize_view)) {
5060 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5061 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5065 if (min_resulting < 0) {
5070 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5071 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5075 /** Handle pending resizing of tracks */
5077 Editor::idle_resize ()
5079 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5081 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5082 selection->tracks.contains (_pending_resize_view)) {
5084 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5085 if (*i != _pending_resize_view) {
5086 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5091 _pending_resize_amount = 0;
5092 _group_tabs->set_dirty ();
5093 resize_idle_id = -1;
5101 ENSURE_GUI_THREAD (*this, &Editor::located);
5104 playhead_cursor->set_position (_session->audible_frame ());
5105 if (_follow_playhead && !_pending_initial_locate) {
5106 reset_x_origin_to_follow_playhead ();
5110 _pending_locate_request = false;
5111 _pending_initial_locate = false;
5115 Editor::region_view_added (RegionView * rv)
5117 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5118 if (rv->region ()->id () == (*pr)) {
5119 selection->add (rv);
5120 selection->regions.pending.erase (pr);
5124 _summary->set_background_dirty ();
5128 Editor::region_view_removed ()
5130 _summary->set_background_dirty ();
5134 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5136 TrackViewList::const_iterator j = track_views.begin ();
5137 while (j != track_views.end()) {
5138 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5139 if (rtv && rtv->route() == r) {
5150 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5154 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5155 TimeAxisView* tv = axis_view_from_route (*i);
5165 Editor::suspend_route_redisplay ()
5168 _routes->suspend_redisplay();
5173 Editor::resume_route_redisplay ()
5176 _routes->resume_redisplay();
5181 Editor::add_routes (RouteList& routes)
5183 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5185 RouteTimeAxisView *rtv;
5186 list<RouteTimeAxisView*> new_views;
5188 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5189 boost::shared_ptr<Route> route = (*x);
5191 if (route->is_auditioner() || route->is_monitor()) {
5195 DataType dt = route->input()->default_type();
5197 if (dt == ARDOUR::DataType::AUDIO) {
5198 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5199 rtv->set_route (route);
5200 } else if (dt == ARDOUR::DataType::MIDI) {
5201 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5202 rtv->set_route (route);
5204 throw unknown_type();
5207 new_views.push_back (rtv);
5208 track_views.push_back (rtv);
5210 rtv->effective_gain_display ();
5212 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5213 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5216 if (new_views.size() > 0) {
5217 _routes->routes_added (new_views);
5218 _summary->routes_added (new_views);
5221 if (show_editor_mixer_when_tracks_arrive) {
5222 show_editor_mixer (true);
5225 editor_list_button.set_sensitive (true);
5229 Editor::timeaxisview_deleted (TimeAxisView *tv)
5231 if (tv == entered_track) {
5235 if (_session && _session->deletion_in_progress()) {
5236 /* the situation is under control */
5240 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5242 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5244 _routes->route_removed (tv);
5246 TimeAxisView::Children c = tv->get_child_list ();
5247 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5248 if (entered_track == i->get()) {
5253 /* remove it from the list of track views */
5255 TrackViewList::iterator i;
5257 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5258 i = track_views.erase (i);
5261 /* update whatever the current mixer strip is displaying, if revelant */
5263 boost::shared_ptr<Route> route;
5266 route = rtav->route ();
5269 if (current_mixer_strip && current_mixer_strip->route() == route) {
5271 TimeAxisView* next_tv;
5273 if (track_views.empty()) {
5275 } else if (i == track_views.end()) {
5276 next_tv = track_views.front();
5283 set_selected_mixer_strip (*next_tv);
5285 /* make the editor mixer strip go away setting the
5286 * button to inactive (which also unticks the menu option)
5289 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5295 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5297 if (apply_to_selection) {
5298 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5300 TrackSelection::iterator j = i;
5303 hide_track_in_display (*i, false);
5308 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5310 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5311 // this will hide the mixer strip
5312 set_selected_mixer_strip (*tv);
5315 _routes->hide_track_in_display (*tv);
5320 Editor::sync_track_view_list_and_routes ()
5322 track_views = TrackViewList (_routes->views ());
5324 _summary->set_dirty ();
5325 _group_tabs->set_dirty ();
5327 return false; // do not call again (until needed)
5331 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5333 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5338 /** Find a RouteTimeAxisView by the ID of its route */
5340 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5342 RouteTimeAxisView* v;
5344 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5345 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5346 if(v->route()->id() == id) {
5356 Editor::fit_route_group (RouteGroup *g)
5358 TrackViewList ts = axis_views_from_routes (g->route_list ());
5363 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5365 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5368 _session->cancel_audition ();
5372 if (_session->is_auditioning()) {
5373 _session->cancel_audition ();
5374 if (r == last_audition_region) {
5379 _session->audition_region (r);
5380 last_audition_region = r;
5385 Editor::hide_a_region (boost::shared_ptr<Region> r)
5387 r->set_hidden (true);
5391 Editor::show_a_region (boost::shared_ptr<Region> r)
5393 r->set_hidden (false);
5397 Editor::audition_region_from_region_list ()
5399 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5403 Editor::hide_region_from_region_list ()
5405 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5409 Editor::show_region_in_region_list ()
5411 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5415 Editor::step_edit_status_change (bool yn)
5418 start_step_editing ();
5420 stop_step_editing ();
5425 Editor::start_step_editing ()
5427 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5431 Editor::stop_step_editing ()
5433 step_edit_connection.disconnect ();
5437 Editor::check_step_edit ()
5439 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5440 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5442 mtv->check_step_edit ();
5446 return true; // do it again, till we stop
5450 Editor::scroll_press (Direction dir)
5452 ++_scroll_callbacks;
5454 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5455 /* delay the first auto-repeat */
5461 scroll_backward (1);
5469 scroll_up_one_track ();
5473 scroll_down_one_track ();
5477 /* do hacky auto-repeat */
5478 if (!_scroll_connection.connected ()) {
5480 _scroll_connection = Glib::signal_timeout().connect (
5481 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5484 _scroll_callbacks = 0;
5491 Editor::scroll_release ()
5493 _scroll_connection.disconnect ();
5496 /** Queue a change for the Editor viewport x origin to follow the playhead */
5498 Editor::reset_x_origin_to_follow_playhead ()
5500 framepos_t const frame = playhead_cursor->current_frame ();
5502 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5504 if (_session->transport_speed() < 0) {
5506 if (frame > (current_page_samples() / 2)) {
5507 center_screen (frame-(current_page_samples()/2));
5509 center_screen (current_page_samples()/2);
5516 if (frame < leftmost_frame) {
5518 if (_session->transport_rolling()) {
5519 /* rolling; end up with the playhead at the right of the page */
5520 l = frame - current_page_samples ();
5522 /* not rolling: end up with the playhead 1/4 of the way along the page */
5523 l = frame - current_page_samples() / 4;
5527 if (_session->transport_rolling()) {
5528 /* rolling: end up with the playhead on the left of the page */
5531 /* not rolling: end up with the playhead 3/4 of the way along the page */
5532 l = frame - 3 * current_page_samples() / 4;
5540 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5546 Editor::super_rapid_screen_update ()
5548 if (!_session || !_session->engine().running()) {
5552 /* METERING / MIXER STRIPS */
5554 /* update track meters, if required */
5555 if (is_mapped() && meters_running) {
5556 RouteTimeAxisView* rtv;
5557 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5558 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5559 rtv->fast_update ();
5564 /* and any current mixer strip */
5565 if (current_mixer_strip) {
5566 current_mixer_strip->fast_update ();
5569 /* PLAYHEAD AND VIEWPORT */
5571 framepos_t const frame = _session->audible_frame();
5573 /* There are a few reasons why we might not update the playhead / viewport stuff:
5575 * 1. we don't update things when there's a pending locate request, otherwise
5576 * when the editor requests a locate there is a chance that this method
5577 * will move the playhead before the locate request is processed, causing
5579 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5580 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5583 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5585 last_update_frame = frame;
5587 if (!_dragging_playhead) {
5588 playhead_cursor->set_position (frame);
5591 if (!_stationary_playhead) {
5593 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5594 /* We only do this if we aren't already
5595 handling a visual change (ie if
5596 pending_visual_change.being_handled is
5597 false) so that these requests don't stack
5598 up there are too many of them to handle in
5601 reset_x_origin_to_follow_playhead ();
5606 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5610 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5611 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5612 if (target <= 0.0) {
5615 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5616 target = (target * 0.15) + (current * 0.85);
5622 set_horizontal_position (current);
5631 Editor::session_going_away ()
5633 _have_idled = false;
5635 _session_connections.drop_connections ();
5637 super_rapid_screen_update_connection.disconnect ();
5639 selection->clear ();
5640 cut_buffer->clear ();
5642 clicked_regionview = 0;
5643 clicked_axisview = 0;
5644 clicked_routeview = 0;
5645 entered_regionview = 0;
5647 last_update_frame = 0;
5650 playhead_cursor->hide ();
5652 /* rip everything out of the list displays */
5656 _route_groups->clear ();
5658 /* do this first so that deleting a track doesn't reset cms to null
5659 and thus cause a leak.
5662 if (current_mixer_strip) {
5663 if (current_mixer_strip->get_parent() != 0) {
5664 global_hpacker.remove (*current_mixer_strip);
5666 delete current_mixer_strip;
5667 current_mixer_strip = 0;
5670 /* delete all trackviews */
5672 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5675 track_views.clear ();
5677 nudge_clock->set_session (0);
5679 editor_list_button.set_active(false);
5680 editor_list_button.set_sensitive(false);
5682 /* clear tempo/meter rulers */
5683 remove_metric_marks ();
5685 clear_marker_display ();
5687 stop_step_editing ();
5689 /* get rid of any existing editor mixer strip */
5691 WindowTitle title(Glib::get_application_name());
5692 title += _("Editor");
5694 set_title (title.get_string());
5696 SessionHandlePtr::session_going_away ();
5701 Editor::show_editor_list (bool yn)
5704 _the_notebook.show ();
5706 _the_notebook.hide ();
5711 Editor::change_region_layering_order (bool from_context_menu)
5713 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5715 if (!clicked_routeview) {
5716 if (layering_order_editor) {
5717 layering_order_editor->hide ();
5722 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5728 boost::shared_ptr<Playlist> pl = track->playlist();
5734 if (layering_order_editor == 0) {
5735 layering_order_editor = new RegionLayeringOrderEditor (*this);
5738 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5739 layering_order_editor->maybe_present ();
5743 Editor::update_region_layering_order_editor ()
5745 if (layering_order_editor && layering_order_editor->is_visible ()) {
5746 change_region_layering_order (true);
5751 Editor::setup_fade_images ()
5753 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5754 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5755 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5756 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5757 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5759 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5760 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5761 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5762 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5763 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5765 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5766 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5767 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5768 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5769 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5771 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5772 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5773 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5774 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5775 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5779 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5781 Editor::action_menu_item (std::string const & name)
5783 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5786 return *manage (a->create_menu_item ());
5790 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5792 EventBox* b = manage (new EventBox);
5793 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5794 Label* l = manage (new Label (name));
5798 _the_notebook.append_page (widget, *b);
5802 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5804 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5805 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5808 if (ev->type == GDK_2BUTTON_PRESS) {
5810 /* double-click on a notebook tab shrinks or expands the notebook */
5812 if (_notebook_shrunk) {
5813 if (pre_notebook_shrink_pane_width) {
5814 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5816 _notebook_shrunk = false;
5818 pre_notebook_shrink_pane_width = edit_pane.get_position();
5820 /* this expands the LHS of the edit pane to cover the notebook
5821 PAGE but leaves the tabs visible.
5823 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5824 _notebook_shrunk = true;
5832 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5834 using namespace Menu_Helpers;
5836 MenuList& items = _control_point_context_menu.items ();
5839 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5840 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5841 if (!can_remove_control_point (item)) {
5842 items.back().set_sensitive (false);
5845 _control_point_context_menu.popup (event->button.button, event->button.time);
5849 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5851 using namespace Menu_Helpers;
5853 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5858 /* We need to get the selection here and pass it to the operations, since
5859 popping up the menu will cause a region leave event which clears
5860 entered_regionview. */
5862 MidiRegionView& mrv = note->region_view();
5863 const RegionSelection rs = get_regions_from_selection_and_entered ();
5865 MenuList& items = _note_context_menu.items();
5868 items.push_back(MenuElem(_("Delete"),
5869 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5870 items.push_back(MenuElem(_("Edit..."),
5871 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5872 items.push_back(MenuElem(_("Legatize"),
5873 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5874 items.push_back(MenuElem(_("Quantize..."),
5875 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5876 items.push_back(MenuElem(_("Remove Overlap"),
5877 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5878 items.push_back(MenuElem(_("Transform..."),
5879 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5881 _note_context_menu.popup (event->button.button, event->button.time);
5885 Editor::zoom_vertical_modifier_released()
5887 _stepping_axis_view = 0;
5891 Editor::ui_parameter_changed (string parameter)
5893 if (parameter == "icon-set") {
5894 while (!_cursor_stack.empty()) {
5895 _cursor_stack.pop_back();
5897 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5898 _cursor_stack.push_back(_cursors->grabber);
5899 } else if (parameter == "draggable-playhead") {
5900 if (_verbose_cursor) {
5901 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());