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/lmath.h"
72 #include "ardour/location.h"
73 #include "ardour/profile.h"
74 #include "ardour/route_group.h"
75 #include "ardour/session_playlists.h"
76 #include "ardour/tempo.h"
77 #include "ardour/utils.h"
79 #include "canvas/debug.h"
80 #include "canvas/text.h"
82 #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 , _mouse_changed_selection (false)
255 /* time display buttons */
256 , minsec_label (_("Mins:Secs"))
257 , bbt_label (_("Bars:Beats"))
258 , timecode_label (_("Timecode"))
259 , samples_label (_("Samples"))
260 , tempo_label (_("Tempo"))
261 , meter_label (_("Meter"))
262 , mark_label (_("Location Markers"))
263 , range_mark_label (_("Range Markers"))
264 , transport_mark_label (_("Loop/Punch Ranges"))
265 , cd_mark_label (_("CD Markers"))
266 , videotl_label (_("Video Timeline"))
267 , edit_packer (4, 4, true)
269 /* the values here don't matter: layout widgets
270 reset them as needed.
273 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
274 , horizontal_adjustment (0.0, 0.0, 1e16)
275 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
277 , controls_layout (unused_adjustment, vertical_adjustment)
279 /* tool bar related */
281 , toolbar_selection_clock_table (2,3)
282 , _mouse_mode_tearoff (0)
283 , automation_mode_button (_("mode"))
287 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
288 , selection_op_cmd_depth (0)
289 , selection_op_history_it (0)
293 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
294 , meters_running(false)
295 , _pending_locate_request (false)
296 , _pending_initial_locate (false)
297 , _last_cut_copy_source_track (0)
299 , _region_selection_change_updates_region_list (true)
300 , _following_mixer_selection (false)
301 , _control_point_toggled_on_press (false)
302 , _stepping_axis_view (0)
306 /* we are a singleton */
308 PublicEditor::_instance = this;
312 selection = new Selection (this);
313 cut_buffer = new Selection (this);
314 _selection_memento = new SelectionMemento ();
315 selection_op_history.clear();
318 clicked_regionview = 0;
319 clicked_axisview = 0;
320 clicked_routeview = 0;
321 clicked_control_point = 0;
322 last_update_frame = 0;
325 _drags = new DragManager (this);
328 current_mixer_strip = 0;
331 snap_type_strings = I18N (_snap_type_strings);
332 snap_mode_strings = I18N (_snap_mode_strings);
333 zoom_focus_strings = I18N (_zoom_focus_strings);
334 edit_mode_strings = I18N (_edit_mode_strings);
335 edit_point_strings = I18N (_edit_point_strings);
336 #ifdef USE_RUBBERBAND
337 rb_opt_strings = I18N (_rb_opt_strings);
341 build_edit_mode_menu();
342 build_zoom_focus_menu();
343 build_track_count_menu();
344 build_snap_mode_menu();
345 build_snap_type_menu();
346 build_edit_point_menu();
348 snap_threshold = 5.0;
349 bbt_beat_subdivision = 4;
350 _visible_canvas_width = 0;
351 _visible_canvas_height = 0;
352 autoscroll_horizontal_allowed = false;
353 autoscroll_vertical_allowed = false;
358 current_interthread_info = 0;
359 _show_measures = true;
361 show_gain_after_trim = false;
363 have_pending_keyboard_selection = false;
364 _follow_playhead = true;
365 _stationary_playhead = false;
366 editor_ruler_menu = 0;
367 no_ruler_shown_update = false;
369 range_marker_menu = 0;
370 marker_menu_item = 0;
371 tempo_or_meter_marker_menu = 0;
372 transport_marker_menu = 0;
373 new_transport_marker_menu = 0;
374 editor_mixer_strip_width = Wide;
375 show_editor_mixer_when_tracks_arrive = false;
376 region_edit_menu_split_multichannel_item = 0;
377 region_edit_menu_split_item = 0;
380 current_stepping_trackview = 0;
382 entered_regionview = 0;
384 clear_entered_track = false;
387 button_release_can_deselect = true;
388 _dragging_playhead = false;
389 _dragging_edit_point = false;
390 select_new_marker = false;
392 layering_order_editor = 0;
393 no_save_visual = false;
395 within_track_canvas = false;
397 scrubbing_direction = 0;
401 location_marker_color = ARDOUR_UI::config()->color ("location marker");
402 location_range_color = ARDOUR_UI::config()->color ("location range");
403 location_cd_marker_color = ARDOUR_UI::config()->color ("location cd marker");
404 location_loop_color = ARDOUR_UI::config()->color ("location loop");
405 location_punch_color = ARDOUR_UI::config()->color ("location punch");
407 zoom_focus = ZoomFocusPlayhead;
408 _edit_point = EditAtMouse;
409 _visible_track_count = -1;
411 samples_per_pixel = 2048; /* too early to use reset_zoom () */
413 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
414 TimeAxisView::setup_sizes ();
415 Marker::setup_sizes (timebar_height);
417 _scroll_callbacks = 0;
419 bbt_label.set_name ("EditorRulerLabel");
420 bbt_label.set_size_request (-1, (int)timebar_height);
421 bbt_label.set_alignment (1.0, 0.5);
422 bbt_label.set_padding (5,0);
424 bbt_label.set_no_show_all();
425 minsec_label.set_name ("EditorRulerLabel");
426 minsec_label.set_size_request (-1, (int)timebar_height);
427 minsec_label.set_alignment (1.0, 0.5);
428 minsec_label.set_padding (5,0);
429 minsec_label.hide ();
430 minsec_label.set_no_show_all();
431 timecode_label.set_name ("EditorRulerLabel");
432 timecode_label.set_size_request (-1, (int)timebar_height);
433 timecode_label.set_alignment (1.0, 0.5);
434 timecode_label.set_padding (5,0);
435 timecode_label.hide ();
436 timecode_label.set_no_show_all();
437 samples_label.set_name ("EditorRulerLabel");
438 samples_label.set_size_request (-1, (int)timebar_height);
439 samples_label.set_alignment (1.0, 0.5);
440 samples_label.set_padding (5,0);
441 samples_label.hide ();
442 samples_label.set_no_show_all();
444 tempo_label.set_name ("EditorRulerLabel");
445 tempo_label.set_size_request (-1, (int)timebar_height);
446 tempo_label.set_alignment (1.0, 0.5);
447 tempo_label.set_padding (5,0);
449 tempo_label.set_no_show_all();
451 meter_label.set_name ("EditorRulerLabel");
452 meter_label.set_size_request (-1, (int)timebar_height);
453 meter_label.set_alignment (1.0, 0.5);
454 meter_label.set_padding (5,0);
456 meter_label.set_no_show_all();
458 if (Profile->get_trx()) {
459 mark_label.set_text (_("Markers"));
461 mark_label.set_name ("EditorRulerLabel");
462 mark_label.set_size_request (-1, (int)timebar_height);
463 mark_label.set_alignment (1.0, 0.5);
464 mark_label.set_padding (5,0);
466 mark_label.set_no_show_all();
468 cd_mark_label.set_name ("EditorRulerLabel");
469 cd_mark_label.set_size_request (-1, (int)timebar_height);
470 cd_mark_label.set_alignment (1.0, 0.5);
471 cd_mark_label.set_padding (5,0);
472 cd_mark_label.hide();
473 cd_mark_label.set_no_show_all();
475 videotl_bar_height = 4;
476 videotl_label.set_name ("EditorRulerLabel");
477 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
478 videotl_label.set_alignment (1.0, 0.5);
479 videotl_label.set_padding (5,0);
480 videotl_label.hide();
481 videotl_label.set_no_show_all();
483 range_mark_label.set_name ("EditorRulerLabel");
484 range_mark_label.set_size_request (-1, (int)timebar_height);
485 range_mark_label.set_alignment (1.0, 0.5);
486 range_mark_label.set_padding (5,0);
487 range_mark_label.hide();
488 range_mark_label.set_no_show_all();
490 transport_mark_label.set_name ("EditorRulerLabel");
491 transport_mark_label.set_size_request (-1, (int)timebar_height);
492 transport_mark_label.set_alignment (1.0, 0.5);
493 transport_mark_label.set_padding (5,0);
494 transport_mark_label.hide();
495 transport_mark_label.set_no_show_all();
497 initialize_canvas ();
499 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
501 _summary = new EditorSummary (this);
503 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
504 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
506 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
508 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
509 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
511 edit_controls_vbox.set_spacing (0);
512 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
513 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
515 HBox* h = manage (new HBox);
516 _group_tabs = new EditorGroupTabs (this);
517 if (!ARDOUR::Profile->get_trx()) {
518 h->pack_start (*_group_tabs, PACK_SHRINK);
520 h->pack_start (edit_controls_vbox);
521 controls_layout.add (*h);
523 controls_layout.set_name ("EditControlsBase");
524 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
525 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
526 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
528 _cursors = new MouseCursors;
529 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
530 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
532 /* Push default cursor to ever-present bottom of cursor stack. */
533 push_canvas_cursor(_cursors->grabber);
535 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
537 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
538 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
539 pad_line_1->set_outline_color (0xFF0000FF);
545 edit_packer.set_col_spacings (0);
546 edit_packer.set_row_spacings (0);
547 edit_packer.set_homogeneous (false);
548 edit_packer.set_border_width (0);
549 edit_packer.set_name ("EditorWindow");
551 time_bars_event_box.add (time_bars_vbox);
552 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
553 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
555 /* labels for the time bars */
556 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
558 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
560 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
562 bottom_hbox.set_border_width (2);
563 bottom_hbox.set_spacing (3);
565 _route_groups = new EditorRouteGroups (this);
566 _routes = new EditorRoutes (this);
567 _regions = new EditorRegions (this);
568 _snapshots = new EditorSnapshots (this);
569 _locations = new EditorLocations (this);
571 /* these are static location signals */
573 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
574 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
575 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
577 add_notebook_page (_("Regions"), _regions->widget ());
578 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
579 add_notebook_page (_("Snapshots"), _snapshots->widget ());
580 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
581 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
583 _the_notebook.set_show_tabs (true);
584 _the_notebook.set_scrollable (true);
585 _the_notebook.popup_disable ();
586 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
587 _the_notebook.show_all ();
589 _notebook_shrunk = false;
591 editor_summary_pane.pack1(edit_packer);
593 Button* summary_arrows_left_left = manage (new Button);
594 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
595 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
596 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
598 Button* summary_arrows_left_right = manage (new Button);
599 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
600 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
601 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
603 VBox* summary_arrows_left = manage (new VBox);
604 summary_arrows_left->pack_start (*summary_arrows_left_left);
605 summary_arrows_left->pack_start (*summary_arrows_left_right);
607 Button* summary_arrows_right_up = manage (new Button);
608 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
609 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
610 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
612 Button* summary_arrows_right_down = manage (new Button);
613 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
614 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
615 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
617 VBox* summary_arrows_right = manage (new VBox);
618 summary_arrows_right->pack_start (*summary_arrows_right_up);
619 summary_arrows_right->pack_start (*summary_arrows_right_down);
621 Frame* summary_frame = manage (new Frame);
622 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
624 summary_frame->add (*_summary);
625 summary_frame->show ();
627 _summary_hbox.pack_start (*summary_arrows_left, false, false);
628 _summary_hbox.pack_start (*summary_frame, true, true);
629 _summary_hbox.pack_start (*summary_arrows_right, false, false);
631 if (!ARDOUR::Profile->get_trx()) {
632 editor_summary_pane.pack2 (_summary_hbox);
635 edit_pane.pack1 (editor_summary_pane, true, true);
636 if (!ARDOUR::Profile->get_trx()) {
637 edit_pane.pack2 (_the_notebook, false, true);
640 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
642 /* XXX: editor_summary_pane might need similar to the edit_pane */
644 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
646 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
647 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
649 top_hbox.pack_start (toolbar_frame);
651 HBox *hbox = manage (new HBox);
652 hbox->pack_start (edit_pane, true, true);
654 global_vpacker.pack_start (top_hbox, false, false);
655 global_vpacker.pack_start (*hbox, true, true);
657 global_hpacker.pack_start (global_vpacker, true, true);
659 set_name ("EditorWindow");
660 add_accel_group (ActionManager::ui_manager->get_accel_group());
662 status_bar_hpacker.show ();
664 vpacker.pack_end (status_bar_hpacker, false, false);
665 vpacker.pack_end (global_hpacker, true, true);
667 /* register actions now so that set_state() can find them and set toggles/checks etc */
670 /* when we start using our own keybinding system for the editor, this
671 * will be uncommented
677 set_zoom_focus (zoom_focus);
678 set_visible_track_count (_visible_track_count);
679 _snap_type = SnapToBeat;
680 set_snap_to (_snap_type);
681 _snap_mode = SnapOff;
682 set_snap_mode (_snap_mode);
683 set_mouse_mode (MouseObject, true);
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 (EDIT_IGNORE_NONE, 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 Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1864 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1865 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), 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(*(ARDOUR_UI::instance()), &ARDOUR_UI::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;
2041 if (internal_editing()) {
2042 internal_snap_type = st;
2044 pre_internal_snap_type = st;
2049 if (snap_ind > snap_type_strings.size() - 1) {
2051 _snap_type = (SnapType)snap_ind;
2054 string str = snap_type_strings[snap_ind];
2056 if (str != snap_type_selector.get_text()) {
2057 snap_type_selector.set_text (str);
2062 switch (_snap_type) {
2063 case SnapToBeatDiv128:
2064 case SnapToBeatDiv64:
2065 case SnapToBeatDiv32:
2066 case SnapToBeatDiv28:
2067 case SnapToBeatDiv24:
2068 case SnapToBeatDiv20:
2069 case SnapToBeatDiv16:
2070 case SnapToBeatDiv14:
2071 case SnapToBeatDiv12:
2072 case SnapToBeatDiv10:
2073 case SnapToBeatDiv8:
2074 case SnapToBeatDiv7:
2075 case SnapToBeatDiv6:
2076 case SnapToBeatDiv5:
2077 case SnapToBeatDiv4:
2078 case SnapToBeatDiv3:
2079 case SnapToBeatDiv2: {
2080 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2081 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2083 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2084 current_bbt_points_begin, current_bbt_points_end);
2085 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2086 current_bbt_points_begin, current_bbt_points_end);
2087 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2091 case SnapToRegionStart:
2092 case SnapToRegionEnd:
2093 case SnapToRegionSync:
2094 case SnapToRegionBoundary:
2095 build_region_boundary_cache ();
2103 redisplay_tempo (false);
2105 SnapChanged (); /* EMIT SIGNAL */
2109 Editor::set_snap_mode (SnapMode mode)
2111 string str = snap_mode_strings[(int)mode];
2113 if (internal_editing()) {
2114 internal_snap_mode = mode;
2116 pre_internal_snap_mode = mode;
2121 if (str != snap_mode_selector.get_text ()) {
2122 snap_mode_selector.set_text (str);
2128 Editor::set_edit_point_preference (EditPoint ep, bool force)
2130 bool changed = (_edit_point != ep);
2133 if (Profile->get_mixbus())
2134 if (ep == EditAtSelectedMarker)
2135 ep = EditAtPlayhead;
2137 string str = edit_point_strings[(int)ep];
2138 if (str != edit_point_selector.get_text ()) {
2139 edit_point_selector.set_text (str);
2142 update_all_enter_cursors();
2144 if (!force && !changed) {
2148 const char* action=NULL;
2150 switch (_edit_point) {
2151 case EditAtPlayhead:
2152 action = "edit-at-playhead";
2154 case EditAtSelectedMarker:
2155 action = "edit-at-marker";
2158 action = "edit-at-mouse";
2162 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2164 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2168 bool in_track_canvas;
2170 if (!mouse_frame (foo, in_track_canvas)) {
2171 in_track_canvas = false;
2174 reset_canvas_action_sensitivity (in_track_canvas);
2180 Editor::set_state (const XMLNode& node, int /*version*/)
2182 const XMLProperty* prop;
2189 g.base_width = default_width;
2190 g.base_height = default_height;
2194 if ((geometry = find_named_node (node, "geometry")) != 0) {
2198 if ((prop = geometry->property("x_size")) == 0) {
2199 prop = geometry->property ("x-size");
2202 g.base_width = atoi(prop->value());
2204 if ((prop = geometry->property("y_size")) == 0) {
2205 prop = geometry->property ("y-size");
2208 g.base_height = atoi(prop->value());
2211 if ((prop = geometry->property ("x_pos")) == 0) {
2212 prop = geometry->property ("x-pos");
2215 x = atoi (prop->value());
2218 if ((prop = geometry->property ("y_pos")) == 0) {
2219 prop = geometry->property ("y-pos");
2222 y = atoi (prop->value());
2226 set_default_size (g.base_width, g.base_height);
2229 if (_session && (prop = node.property ("playhead"))) {
2231 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2233 playhead_cursor->set_position (pos);
2235 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2236 playhead_cursor->set_position (0);
2239 playhead_cursor->set_position (0);
2242 if ((prop = node.property ("mixer-width"))) {
2243 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2246 if ((prop = node.property ("zoom-focus"))) {
2247 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2250 if ((prop = node.property ("zoom"))) {
2251 /* older versions of ardour used floating point samples_per_pixel */
2252 double f = PBD::atof (prop->value());
2253 reset_zoom (llrintf (f));
2255 reset_zoom (samples_per_pixel);
2258 if ((prop = node.property ("visible-track-count"))) {
2259 set_visible_track_count (PBD::atoi (prop->value()));
2262 if ((prop = node.property ("snap-to"))) {
2263 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2266 if ((prop = node.property ("snap-mode"))) {
2267 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2270 if ((prop = node.property ("internal-snap-to"))) {
2271 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2274 if ((prop = node.property ("internal-snap-mode"))) {
2275 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2278 if ((prop = node.property ("pre-internal-snap-to"))) {
2279 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2282 if ((prop = node.property ("pre-internal-snap-mode"))) {
2283 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2286 if ((prop = node.property ("mouse-mode"))) {
2287 MouseMode m = str2mousemode(prop->value());
2288 set_mouse_mode (m, true);
2290 set_mouse_mode (MouseObject, true);
2293 if ((prop = node.property ("left-frame")) != 0) {
2295 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2299 reset_x_origin (pos);
2303 if ((prop = node.property ("y-origin")) != 0) {
2304 reset_y_origin (atof (prop->value ()));
2307 if ((prop = node.property ("join-object-range"))) {
2308 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2309 bool yn = string_is_affirmative (prop->value());
2311 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2312 tact->set_active (!yn);
2313 tact->set_active (yn);
2315 set_mouse_mode(mouse_mode, true);
2318 if ((prop = node.property ("edit-point"))) {
2319 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2322 if ((prop = node.property ("show-measures"))) {
2323 bool yn = string_is_affirmative (prop->value());
2324 _show_measures = yn;
2327 if ((prop = node.property ("follow-playhead"))) {
2328 bool yn = string_is_affirmative (prop->value());
2329 set_follow_playhead (yn);
2332 if ((prop = node.property ("stationary-playhead"))) {
2333 bool yn = string_is_affirmative (prop->value());
2334 set_stationary_playhead (yn);
2337 if ((prop = node.property ("region-list-sort-type"))) {
2338 RegionListSortType st;
2339 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2342 if ((prop = node.property ("show-editor-mixer"))) {
2344 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2347 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2348 bool yn = string_is_affirmative (prop->value());
2350 /* do it twice to force the change */
2352 tact->set_active (!yn);
2353 tact->set_active (yn);
2356 if ((prop = node.property ("show-editor-list"))) {
2358 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2361 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2362 bool yn = string_is_affirmative (prop->value());
2364 /* do it twice to force the change */
2366 tact->set_active (!yn);
2367 tact->set_active (yn);
2370 if ((prop = node.property (X_("editor-list-page")))) {
2371 _the_notebook.set_current_page (atoi (prop->value ()));
2374 if ((prop = node.property (X_("show-marker-lines")))) {
2375 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2377 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2378 bool yn = string_is_affirmative (prop->value ());
2380 tact->set_active (!yn);
2381 tact->set_active (yn);
2384 XMLNodeList children = node.children ();
2385 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2386 selection->set_state (**i, Stateful::current_state_version);
2387 _regions->set_state (**i);
2390 if ((prop = node.property ("maximised"))) {
2391 bool yn = string_is_affirmative (prop->value());
2392 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2394 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2395 bool fs = tact && tact->get_active();
2397 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2401 if ((prop = node.property ("nudge-clock-value"))) {
2403 sscanf (prop->value().c_str(), "%" PRId64, &f);
2404 nudge_clock->set (f);
2406 nudge_clock->set_mode (AudioClock::Timecode);
2407 nudge_clock->set (_session->frame_rate() * 5, true);
2412 * Not all properties may have been in XML, but
2413 * those that are linked to a private variable may need changing
2418 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2420 yn = _show_measures;
2421 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2422 /* do it twice to force the change */
2423 tact->set_active (!yn);
2424 tact->set_active (yn);
2427 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2428 yn = _follow_playhead;
2430 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2431 if (tact->get_active() != yn) {
2432 tact->set_active (yn);
2436 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2437 yn = _stationary_playhead;
2439 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2440 if (tact->get_active() != yn) {
2441 tact->set_active (yn);
2450 Editor::get_state ()
2452 XMLNode* node = new XMLNode ("Editor");
2455 id().print (buf, sizeof (buf));
2456 node->add_property ("id", buf);
2458 if (is_realized()) {
2459 Glib::RefPtr<Gdk::Window> win = get_window();
2461 int x, y, width, height;
2462 win->get_root_origin(x, y);
2463 win->get_size(width, height);
2465 XMLNode* geometry = new XMLNode ("geometry");
2467 snprintf(buf, sizeof(buf), "%d", width);
2468 geometry->add_property("x-size", string(buf));
2469 snprintf(buf, sizeof(buf), "%d", height);
2470 geometry->add_property("y-size", string(buf));
2471 snprintf(buf, sizeof(buf), "%d", x);
2472 geometry->add_property("x-pos", string(buf));
2473 snprintf(buf, sizeof(buf), "%d", y);
2474 geometry->add_property("y-pos", string(buf));
2475 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2476 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2477 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2478 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2479 geometry->add_property("edit-vertical-pane-pos", string(buf));
2481 node->add_child_nocopy (*geometry);
2484 maybe_add_mixer_strip_width (*node);
2486 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2488 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2489 node->add_property ("zoom", buf);
2490 node->add_property ("snap-to", enum_2_string (_snap_type));
2491 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2492 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2493 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2494 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2495 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2496 node->add_property ("edit-point", enum_2_string (_edit_point));
2497 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2498 node->add_property ("visible-track-count", buf);
2500 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2501 node->add_property ("playhead", buf);
2502 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2503 node->add_property ("left-frame", buf);
2504 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2505 node->add_property ("y-origin", buf);
2507 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2508 node->add_property ("maximised", _maximised ? "yes" : "no");
2509 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2510 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2511 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2512 node->add_property ("mouse-mode", enum2str(mouse_mode));
2513 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2515 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2517 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2518 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2521 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2523 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2524 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2527 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2528 node->add_property (X_("editor-list-page"), buf);
2530 if (button_bindings) {
2531 XMLNode* bb = new XMLNode (X_("Buttons"));
2532 button_bindings->save (*bb);
2533 node->add_child_nocopy (*bb);
2536 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2538 node->add_child_nocopy (selection->get_state ());
2539 node->add_child_nocopy (_regions->get_state ());
2541 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2542 node->add_property ("nudge-clock-value", buf);
2547 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2548 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2550 * @return pair: TimeAxisView that y is over, layer index.
2552 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2553 * in stacked or expanded region display mode, otherwise 0.
2555 std::pair<TimeAxisView *, double>
2556 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2558 if (!trackview_relative_offset) {
2559 y -= _trackview_group->canvas_origin().y;
2563 return std::make_pair ( (TimeAxisView *) 0, 0);
2566 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2568 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2575 return std::make_pair ( (TimeAxisView *) 0, 0);
2578 /** Snap a position to the grid, if appropriate, taking into account current
2579 * grid settings and also the state of any snap modifier keys that may be pressed.
2580 * @param start Position to snap.
2581 * @param event Event to get current key modifier information from, or 0.
2584 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2586 if (!_session || !event) {
2590 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2591 if (_snap_mode == SnapOff) {
2592 snap_to_internal (start, direction, for_mark);
2595 if (_snap_mode != SnapOff) {
2596 snap_to_internal (start, direction, for_mark);
2602 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark)
2604 if (!_session || _snap_mode == SnapOff) {
2608 snap_to_internal (start, direction, for_mark);
2612 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2614 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2615 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2617 switch (_snap_type) {
2618 case SnapToTimecodeFrame:
2619 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2620 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2621 /* start is already on a whole timecode frame, do nothing */
2622 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2623 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2625 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2629 case SnapToTimecodeSeconds:
2630 if (_session->config.get_timecode_offset_negative()) {
2631 start += _session->config.get_timecode_offset ();
2633 start -= _session->config.get_timecode_offset ();
2635 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2636 (start % one_timecode_second == 0)) {
2637 /* start is already on a whole second, do nothing */
2638 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2639 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2641 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2644 if (_session->config.get_timecode_offset_negative()) {
2645 start -= _session->config.get_timecode_offset ();
2647 start += _session->config.get_timecode_offset ();
2651 case SnapToTimecodeMinutes:
2652 if (_session->config.get_timecode_offset_negative()) {
2653 start += _session->config.get_timecode_offset ();
2655 start -= _session->config.get_timecode_offset ();
2657 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2658 (start % one_timecode_minute == 0)) {
2659 /* start is already on a whole minute, do nothing */
2660 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2661 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2663 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2665 if (_session->config.get_timecode_offset_negative()) {
2666 start -= _session->config.get_timecode_offset ();
2668 start += _session->config.get_timecode_offset ();
2672 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2673 abort(); /*NOTREACHED*/
2678 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark)
2680 const framepos_t one_second = _session->frame_rate();
2681 const framepos_t one_minute = _session->frame_rate() * 60;
2682 framepos_t presnap = start;
2686 switch (_snap_type) {
2687 case SnapToTimecodeFrame:
2688 case SnapToTimecodeSeconds:
2689 case SnapToTimecodeMinutes:
2690 return timecode_snap_to_internal (start, direction, for_mark);
2693 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2694 start % (one_second/75) == 0) {
2695 /* start is already on a whole CD frame, do nothing */
2696 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2697 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2699 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2704 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2705 start % one_second == 0) {
2706 /* start is already on a whole second, do nothing */
2707 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2708 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2710 start = (framepos_t) floor ((double) start / one_second) * one_second;
2715 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2716 start % one_minute == 0) {
2717 /* start is already on a whole minute, do nothing */
2718 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2719 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2721 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2726 start = _session->tempo_map().round_to_bar (start, direction);
2730 start = _session->tempo_map().round_to_beat (start, direction);
2733 case SnapToBeatDiv128:
2734 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2736 case SnapToBeatDiv64:
2737 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2739 case SnapToBeatDiv32:
2740 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2742 case SnapToBeatDiv28:
2743 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2745 case SnapToBeatDiv24:
2746 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2748 case SnapToBeatDiv20:
2749 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2751 case SnapToBeatDiv16:
2752 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2754 case SnapToBeatDiv14:
2755 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2757 case SnapToBeatDiv12:
2758 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2760 case SnapToBeatDiv10:
2761 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2763 case SnapToBeatDiv8:
2764 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2766 case SnapToBeatDiv7:
2767 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2769 case SnapToBeatDiv6:
2770 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2772 case SnapToBeatDiv5:
2773 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2775 case SnapToBeatDiv4:
2776 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2778 case SnapToBeatDiv3:
2779 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2781 case SnapToBeatDiv2:
2782 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2790 _session->locations()->marks_either_side (start, before, after);
2792 if (before == max_framepos && after == max_framepos) {
2793 /* No marks to snap to, so just don't snap */
2795 } else if (before == max_framepos) {
2797 } else if (after == max_framepos) {
2799 } else if (before != max_framepos && after != max_framepos) {
2800 /* have before and after */
2801 if ((start - before) < (after - start)) {
2810 case SnapToRegionStart:
2811 case SnapToRegionEnd:
2812 case SnapToRegionSync:
2813 case SnapToRegionBoundary:
2814 if (!region_boundary_cache.empty()) {
2816 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2817 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2819 if (direction > 0) {
2820 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2822 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2825 if (next != region_boundary_cache.begin ()) {
2830 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2831 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2833 if (start > (p + n) / 2) {
2842 switch (_snap_mode) {
2848 if (presnap > start) {
2849 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2853 } else if (presnap < start) {
2854 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2860 /* handled at entry */
2868 Editor::setup_toolbar ()
2870 HBox* mode_box = manage(new HBox);
2871 mode_box->set_border_width (2);
2872 mode_box->set_spacing(2);
2874 HBox* mouse_mode_box = manage (new HBox);
2875 HBox* mouse_mode_hbox = manage (new HBox);
2876 VBox* mouse_mode_vbox = manage (new VBox);
2877 Alignment* mouse_mode_align = manage (new Alignment);
2879 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2880 mouse_mode_size_group->add_widget (smart_mode_button);
2881 mouse_mode_size_group->add_widget (mouse_move_button);
2882 mouse_mode_size_group->add_widget (mouse_cut_button);
2883 mouse_mode_size_group->add_widget (mouse_select_button);
2884 mouse_mode_size_group->add_widget (mouse_timefx_button);
2885 mouse_mode_size_group->add_widget (mouse_audition_button);
2886 mouse_mode_size_group->add_widget (mouse_draw_button);
2887 mouse_mode_size_group->add_widget (mouse_content_button);
2889 mouse_mode_size_group->add_widget (zoom_in_button);
2890 mouse_mode_size_group->add_widget (zoom_out_button);
2891 mouse_mode_size_group->add_widget (zoom_preset_selector);
2892 mouse_mode_size_group->add_widget (zoom_out_full_button);
2893 mouse_mode_size_group->add_widget (zoom_focus_selector);
2895 mouse_mode_size_group->add_widget (tav_shrink_button);
2896 mouse_mode_size_group->add_widget (tav_expand_button);
2897 mouse_mode_size_group->add_widget (visible_tracks_selector);
2899 mouse_mode_size_group->add_widget (snap_type_selector);
2900 mouse_mode_size_group->add_widget (snap_mode_selector);
2902 mouse_mode_size_group->add_widget (edit_point_selector);
2903 mouse_mode_size_group->add_widget (edit_mode_selector);
2905 mouse_mode_size_group->add_widget (*nudge_clock);
2906 mouse_mode_size_group->add_widget (nudge_forward_button);
2907 mouse_mode_size_group->add_widget (nudge_backward_button);
2909 mouse_mode_hbox->set_spacing (2);
2911 if (!ARDOUR::Profile->get_trx()) {
2912 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2915 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2916 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2918 if (!ARDOUR::Profile->get_mixbus()) {
2919 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2922 if (!ARDOUR::Profile->get_trx()) {
2923 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2924 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2925 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2926 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2929 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2931 mouse_mode_align->add (*mouse_mode_vbox);
2932 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2934 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2936 edit_mode_selector.set_name ("mouse mode button");
2938 if (!ARDOUR::Profile->get_trx()) {
2939 mode_box->pack_start (edit_mode_selector, false, false);
2941 mode_box->pack_start (*mouse_mode_box, false, false);
2943 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2944 _mouse_mode_tearoff->set_name ("MouseModeBase");
2945 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2947 if (Profile->get_sae() || Profile->get_mixbus() ) {
2948 _mouse_mode_tearoff->set_can_be_torn_off (false);
2951 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2952 &_mouse_mode_tearoff->tearoff_window()));
2953 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2954 &_mouse_mode_tearoff->tearoff_window(), 1));
2955 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2956 &_mouse_mode_tearoff->tearoff_window()));
2957 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2958 &_mouse_mode_tearoff->tearoff_window(), 1));
2962 _zoom_box.set_spacing (2);
2963 _zoom_box.set_border_width (2);
2967 zoom_preset_selector.set_name ("zoom button");
2968 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2969 zoom_preset_selector.set_size_request (42, -1);
2971 zoom_in_button.set_name ("zoom button");
2972 zoom_in_button.set_image(::get_icon ("zoom_in"));
2973 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2974 zoom_in_button.set_related_action (act);
2976 zoom_out_button.set_name ("zoom button");
2977 zoom_out_button.set_image(::get_icon ("zoom_out"));
2978 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2979 zoom_out_button.set_related_action (act);
2981 zoom_out_full_button.set_name ("zoom button");
2982 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2983 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2984 zoom_out_full_button.set_related_action (act);
2986 zoom_focus_selector.set_name ("zoom button");
2988 if (ARDOUR::Profile->get_mixbus()) {
2989 _zoom_box.pack_start (zoom_preset_selector, false, false);
2990 } else if (ARDOUR::Profile->get_trx()) {
2991 mode_box->pack_start (zoom_out_button, false, false);
2992 mode_box->pack_start (zoom_in_button, false, false);
2994 _zoom_box.pack_start (zoom_out_button, false, false);
2995 _zoom_box.pack_start (zoom_in_button, false, false);
2996 _zoom_box.pack_start (zoom_out_full_button, false, false);
2997 _zoom_box.pack_start (zoom_focus_selector, false, false);
3000 /* Track zoom buttons */
3001 visible_tracks_selector.set_name ("zoom button");
3002 if (Profile->get_mixbus()) {
3003 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3004 visible_tracks_selector.set_size_request (42, -1);
3006 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3009 tav_expand_button.set_name ("zoom button");
3010 tav_expand_button.set_image(::get_icon ("tav_exp"));
3011 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3012 tav_expand_button.set_related_action (act);
3014 tav_shrink_button.set_name ("zoom button");
3015 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
3016 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3017 tav_shrink_button.set_related_action (act);
3019 if (ARDOUR::Profile->get_mixbus()) {
3020 _zoom_box.pack_start (visible_tracks_selector);
3021 } else if (ARDOUR::Profile->get_trx()) {
3022 _zoom_box.pack_start (tav_shrink_button);
3023 _zoom_box.pack_start (tav_expand_button);
3025 _zoom_box.pack_start (visible_tracks_selector);
3026 _zoom_box.pack_start (tav_shrink_button);
3027 _zoom_box.pack_start (tav_expand_button);
3030 if (!ARDOUR::Profile->get_trx()) {
3031 _zoom_tearoff = manage (new TearOff (_zoom_box));
3033 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3034 &_zoom_tearoff->tearoff_window()));
3035 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3036 &_zoom_tearoff->tearoff_window(), 0));
3037 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3038 &_zoom_tearoff->tearoff_window()));
3039 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3040 &_zoom_tearoff->tearoff_window(), 0));
3043 if (Profile->get_sae() || Profile->get_mixbus() ) {
3044 _zoom_tearoff->set_can_be_torn_off (false);
3047 snap_box.set_spacing (2);
3048 snap_box.set_border_width (2);
3050 snap_type_selector.set_name ("mouse mode button");
3052 snap_mode_selector.set_name ("mouse mode button");
3054 edit_point_selector.set_name ("mouse mode button");
3056 snap_box.pack_start (snap_mode_selector, false, false);
3057 snap_box.pack_start (snap_type_selector, false, false);
3058 snap_box.pack_start (edit_point_selector, false, false);
3062 HBox *nudge_box = manage (new HBox);
3063 nudge_box->set_spacing (2);
3064 nudge_box->set_border_width (2);
3066 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3067 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3069 nudge_box->pack_start (nudge_backward_button, false, false);
3070 nudge_box->pack_start (nudge_forward_button, false, false);
3071 nudge_box->pack_start (*nudge_clock, false, false);
3074 /* Pack everything in... */
3076 HBox* hbox = manage (new HBox);
3077 hbox->set_spacing(2);
3079 _tools_tearoff = manage (new TearOff (*hbox));
3080 _tools_tearoff->set_name ("MouseModeBase");
3081 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3083 if (Profile->get_sae() || Profile->get_mixbus()) {
3084 _tools_tearoff->set_can_be_torn_off (false);
3087 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3088 &_tools_tearoff->tearoff_window()));
3089 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3090 &_tools_tearoff->tearoff_window(), 0));
3091 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3092 &_tools_tearoff->tearoff_window()));
3093 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3094 &_tools_tearoff->tearoff_window(), 0));
3096 toolbar_hbox.set_spacing (2);
3097 toolbar_hbox.set_border_width (1);
3099 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3100 if (!ARDOUR::Profile->get_trx()) {
3101 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3102 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3105 if (!ARDOUR::Profile->get_trx()) {
3106 hbox->pack_start (snap_box, false, false);
3107 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3108 hbox->pack_start (*nudge_box, false, false);
3110 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3113 hbox->pack_start (panic_box, false, false);
3117 toolbar_base.set_name ("ToolBarBase");
3118 toolbar_base.add (toolbar_hbox);
3120 _toolbar_viewport.add (toolbar_base);
3121 /* stick to the required height but allow width to vary if there's not enough room */
3122 _toolbar_viewport.set_size_request (1, -1);
3124 toolbar_frame.set_shadow_type (SHADOW_OUT);
3125 toolbar_frame.set_name ("BaseFrame");
3126 toolbar_frame.add (_toolbar_viewport);
3130 Editor::build_edit_point_menu ()
3132 using namespace Menu_Helpers;
3134 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3135 if(!Profile->get_mixbus())
3136 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3137 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3139 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3143 Editor::build_edit_mode_menu ()
3145 using namespace Menu_Helpers;
3147 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3148 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3149 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3150 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3152 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3156 Editor::build_snap_mode_menu ()
3158 using namespace Menu_Helpers;
3160 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3161 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3162 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3164 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3168 Editor::build_snap_type_menu ()
3170 using namespace Menu_Helpers;
3172 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3173 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3174 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3175 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3176 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3177 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3178 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3179 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3180 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3181 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3182 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3183 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3184 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3185 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3186 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3187 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3188 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3189 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3190 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3191 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3192 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3193 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3194 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3195 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3196 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3197 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3198 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3199 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3200 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3201 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3203 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3208 Editor::setup_tooltips ()
3210 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Grab mode)"));
3211 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Grab Mode (select/move objects)"));
3212 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split regions)"));
3213 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select time ranges)"));
3214 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3215 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3216 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3217 ARDOUR_UI::instance()->set_tip (mouse_content_button, _("Internal Edit Mode (edit notes and gain curves inside regions)"));
3218 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3219 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3220 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3221 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3222 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3223 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3224 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3225 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3226 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3227 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3228 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3229 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3230 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3231 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3232 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3233 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3237 Editor::convert_drop_to_paths (
3238 vector<string>& paths,
3239 const RefPtr<Gdk::DragContext>& /*context*/,
3242 const SelectionData& data,
3246 if (_session == 0) {
3250 vector<string> uris = data.get_uris();
3254 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3255 are actually URI lists. So do it by hand.
3258 if (data.get_target() != "text/plain") {
3262 /* Parse the "uri-list" format that Nautilus provides,
3263 where each pathname is delimited by \r\n.
3265 THERE MAY BE NO NULL TERMINATING CHAR!!!
3268 string txt = data.get_text();
3272 p = (char *) malloc (txt.length() + 1);
3273 txt.copy (p, txt.length(), 0);
3274 p[txt.length()] = '\0';
3280 while (g_ascii_isspace (*p))
3284 while (*q && (*q != '\n') && (*q != '\r')) {
3291 while (q > p && g_ascii_isspace (*q))
3296 uris.push_back (string (p, q - p + 1));
3300 p = strchr (p, '\n');
3312 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3313 if ((*i).substr (0,7) == "file://") {
3314 paths.push_back (Glib::filename_from_uri (*i));
3322 Editor::new_tempo_section ()
3327 Editor::map_transport_state ()
3329 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3331 if (_session && _session->transport_stopped()) {
3332 have_pending_keyboard_selection = false;
3335 update_loop_range_view ();
3341 Editor::begin_selection_op_history ()
3343 selection_op_cmd_depth = 0;
3344 selection_op_history_it = 0;
3346 while(!selection_op_history.empty()) {
3347 delete selection_op_history.front();
3348 selection_op_history.pop_front();
3351 selection_undo_action->set_sensitive (false);
3352 selection_redo_action->set_sensitive (false);
3353 selection_op_history.push_front (&_selection_memento->get_state ());
3357 Editor::begin_reversible_selection_op (string name)
3360 //cerr << name << endl;
3361 /* begin/commit pairs can be nested */
3362 selection_op_cmd_depth++;
3367 Editor::commit_reversible_selection_op ()
3370 if (selection_op_cmd_depth == 1) {
3372 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3374 The user has undone some selection ops and then made a new one,
3375 making anything earlier in the list invalid.
3378 list<XMLNode *>::iterator it = selection_op_history.begin();
3379 list<XMLNode *>::iterator e_it = it;
3380 advance (e_it, selection_op_history_it);
3382 for ( ; it != e_it; ++it) {
3385 selection_op_history.erase (selection_op_history.begin(), e_it);
3388 selection_op_history.push_front (&_selection_memento->get_state ());
3389 selection_op_history_it = 0;
3391 selection_undo_action->set_sensitive (true);
3392 selection_redo_action->set_sensitive (false);
3395 if (selection_op_cmd_depth > 0) {
3396 selection_op_cmd_depth--;
3402 Editor::undo_selection_op ()
3405 selection_op_history_it++;
3407 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3408 if (n == selection_op_history_it) {
3409 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3410 selection_redo_action->set_sensitive (true);
3414 /* is there an earlier entry? */
3415 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3416 selection_undo_action->set_sensitive (false);
3422 Editor::redo_selection_op ()
3425 if (selection_op_history_it > 0) {
3426 selection_op_history_it--;
3429 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3430 if (n == selection_op_history_it) {
3431 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3432 selection_undo_action->set_sensitive (true);
3437 if (selection_op_history_it == 0) {
3438 selection_redo_action->set_sensitive (false);
3444 Editor::begin_reversible_command (string name)
3447 before.push_back (&_selection_memento->get_state ());
3448 _session->begin_reversible_command (name);
3453 Editor::begin_reversible_command (GQuark q)
3456 before.push_back (&_selection_memento->get_state ());
3457 _session->begin_reversible_command (q);
3462 Editor::abort_reversible_command ()
3465 while(!before.empty()) {
3466 delete before.front();
3469 _session->abort_reversible_command ();
3474 Editor::commit_reversible_command ()
3477 if (before.size() == 1) {
3478 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3479 redo_action->set_sensitive(false);
3480 undo_action->set_sensitive(true);
3481 begin_selection_op_history ();
3484 if (before.empty()) {
3485 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3490 _session->commit_reversible_command ();
3495 Editor::history_changed ()
3499 if (undo_action && _session) {
3500 if (_session->undo_depth() == 0) {
3501 label = S_("Command|Undo");
3503 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3505 undo_action->property_label() = label;
3508 if (redo_action && _session) {
3509 if (_session->redo_depth() == 0) {
3512 label = string_compose(_("Redo (%1)"), _session->next_redo());
3514 redo_action->property_label() = label;
3519 Editor::duplicate_range (bool with_dialog)
3523 RegionSelection rs = get_regions_from_selection_and_entered ();
3525 if ( selection->time.length() == 0 && rs.empty()) {
3531 ArdourDialog win (_("Duplicate"));
3532 Label label (_("Number of duplications:"));
3533 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3534 SpinButton spinner (adjustment, 0.0, 1);
3537 win.get_vbox()->set_spacing (12);
3538 win.get_vbox()->pack_start (hbox);
3539 hbox.set_border_width (6);
3540 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3542 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3543 place, visually. so do this by hand.
3546 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3547 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3548 spinner.grab_focus();
3554 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3555 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3556 win.set_default_response (RESPONSE_ACCEPT);
3558 spinner.grab_focus ();
3560 switch (win.run ()) {
3561 case RESPONSE_ACCEPT:
3567 times = adjustment.get_value();
3570 if ((current_mouse_mode() == Editing::MouseRange)) {
3571 if (selection->time.length()) {
3572 duplicate_selection (times);
3574 } else if (get_smart_mode()) {
3575 if (selection->time.length()) {
3576 duplicate_selection (times);
3578 duplicate_some_regions (rs, times);
3580 duplicate_some_regions (rs, times);
3585 Editor::set_edit_mode (EditMode m)
3587 Config->set_edit_mode (m);
3591 Editor::cycle_edit_mode ()
3593 switch (Config->get_edit_mode()) {
3595 if (Profile->get_sae()) {
3596 Config->set_edit_mode (Lock);
3598 Config->set_edit_mode (Ripple);
3603 Config->set_edit_mode (Lock);
3606 Config->set_edit_mode (Slide);
3612 Editor::edit_mode_selection_done ( EditMode m )
3614 Config->set_edit_mode ( m );
3618 Editor::snap_type_selection_done (SnapType snaptype)
3620 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3622 ract->set_active ();
3627 Editor::snap_mode_selection_done (SnapMode mode)
3629 RefPtr<RadioAction> ract = snap_mode_action (mode);
3632 ract->set_active (true);
3637 Editor::cycle_edit_point (bool with_marker)
3639 if(Profile->get_mixbus())
3640 with_marker = false;
3642 switch (_edit_point) {
3644 set_edit_point_preference (EditAtPlayhead);
3646 case EditAtPlayhead:
3648 set_edit_point_preference (EditAtSelectedMarker);
3650 set_edit_point_preference (EditAtMouse);
3653 case EditAtSelectedMarker:
3654 set_edit_point_preference (EditAtMouse);
3660 Editor::edit_point_selection_done (EditPoint ep)
3662 set_edit_point_preference ( ep );
3666 Editor::build_zoom_focus_menu ()
3668 using namespace Menu_Helpers;
3670 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3671 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3672 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3673 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3674 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3675 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3677 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3681 Editor::zoom_focus_selection_done ( ZoomFocus f )
3683 RefPtr<RadioAction> ract = zoom_focus_action (f);
3685 ract->set_active ();
3690 Editor::build_track_count_menu ()
3692 using namespace Menu_Helpers;
3694 if (!Profile->get_mixbus()) {
3695 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3696 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3697 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3698 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3699 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3700 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3701 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3702 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3703 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3704 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3705 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3706 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3707 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3709 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3710 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3711 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3712 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3713 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3714 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3715 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3716 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3717 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3718 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3720 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3721 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3722 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3723 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3724 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3725 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3726 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3727 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3728 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3729 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3730 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3735 Editor::set_zoom_preset (int64_t ms)
3738 temporal_zoom_session();
3742 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3743 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3747 Editor::set_visible_track_count (int32_t n)
3749 _visible_track_count = n;
3751 /* if the canvas hasn't really been allocated any size yet, just
3752 record the desired number of visible tracks and return. when canvas
3753 allocation happens, we will get called again and then we can do the
3757 if (_visible_canvas_height <= 1) {
3763 DisplaySuspender ds;
3765 if (_visible_track_count > 0) {
3766 h = trackviews_height() / _visible_track_count;
3767 std::ostringstream s;
3768 s << _visible_track_count;
3770 } else if (_visible_track_count == 0) {
3772 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3773 if ((*i)->marked_for_display()) {
3777 h = trackviews_height() / n;
3780 /* negative value means that the visible track count has
3781 been overridden by explicit track height changes.
3783 visible_tracks_selector.set_text (X_("*"));
3787 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3788 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3791 if (str != visible_tracks_selector.get_text()) {
3792 visible_tracks_selector.set_text (str);
3797 Editor::override_visible_track_count ()
3799 _visible_track_count = -1;
3800 visible_tracks_selector.set_text ( _("*") );
3804 Editor::edit_controls_button_release (GdkEventButton* ev)
3806 if (Keyboard::is_context_menu_event (ev)) {
3807 ARDOUR_UI::instance()->add_route (this);
3808 } else if (ev->button == 1) {
3809 selection->clear_tracks ();
3816 Editor::mouse_select_button_release (GdkEventButton* ev)
3818 /* this handles just right-clicks */
3820 if (ev->button != 3) {
3828 Editor::set_zoom_focus (ZoomFocus f)
3830 string str = zoom_focus_strings[(int)f];
3832 if (str != zoom_focus_selector.get_text()) {
3833 zoom_focus_selector.set_text (str);
3836 if (zoom_focus != f) {
3843 Editor::cycle_zoom_focus ()
3845 switch (zoom_focus) {
3847 set_zoom_focus (ZoomFocusRight);
3849 case ZoomFocusRight:
3850 set_zoom_focus (ZoomFocusCenter);
3852 case ZoomFocusCenter:
3853 set_zoom_focus (ZoomFocusPlayhead);
3855 case ZoomFocusPlayhead:
3856 set_zoom_focus (ZoomFocusMouse);
3858 case ZoomFocusMouse:
3859 set_zoom_focus (ZoomFocusEdit);
3862 set_zoom_focus (ZoomFocusLeft);
3868 Editor::ensure_float (Window& win)
3870 win.set_transient_for (*this);
3874 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3876 /* recover or initialize pane positions. do this here rather than earlier because
3877 we don't want the positions to change the child allocations, which they seem to do.
3883 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3892 XMLNode* geometry = find_named_node (*node, "geometry");
3894 if (which == static_cast<Paned*> (&edit_pane)) {
3896 if (done & Horizontal) {
3900 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3901 _notebook_shrunk = string_is_affirmative (prop->value ());
3904 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3905 /* initial allocation is 90% to canvas, 10% to notebook */
3906 pos = (int) floor (alloc.get_width() * 0.90f);
3907 snprintf (buf, sizeof(buf), "%d", pos);
3909 pos = atoi (prop->value());
3912 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3913 edit_pane.set_position (pos);
3916 done = (Pane) (done | Horizontal);
3918 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3920 if (done & Vertical) {
3924 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3925 /* initial allocation is 90% to canvas, 10% to summary */
3926 pos = (int) floor (alloc.get_height() * 0.90f);
3927 snprintf (buf, sizeof(buf), "%d", pos);
3930 pos = atoi (prop->value());
3933 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3934 editor_summary_pane.set_position (pos);
3937 done = (Pane) (done | Vertical);
3942 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3944 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3945 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3946 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3947 top_hbox.remove (toolbar_frame);
3952 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3954 if (toolbar_frame.get_parent() == 0) {
3955 top_hbox.pack_end (toolbar_frame);
3960 Editor::set_show_measures (bool yn)
3962 if (_show_measures != yn) {
3965 if ((_show_measures = yn) == true) {
3967 tempo_lines->show();
3970 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3971 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3973 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3974 draw_measures (begin, end);
3982 Editor::toggle_follow_playhead ()
3984 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3986 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3987 set_follow_playhead (tact->get_active());
3991 /** @param yn true to follow playhead, otherwise false.
3992 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3995 Editor::set_follow_playhead (bool yn, bool catch_up)
3997 if (_follow_playhead != yn) {
3998 if ((_follow_playhead = yn) == true && catch_up) {
4000 reset_x_origin_to_follow_playhead ();
4007 Editor::toggle_stationary_playhead ()
4009 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4011 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4012 set_stationary_playhead (tact->get_active());
4017 Editor::set_stationary_playhead (bool yn)
4019 if (_stationary_playhead != yn) {
4020 if ((_stationary_playhead = yn) == true) {
4022 // FIXME need a 3.0 equivalent of this 2.X call
4023 // update_current_screen ();
4030 Editor::playlist_selector () const
4032 return *_playlist_selector;
4036 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4038 if (paste_count == 0) {
4039 /* don't bother calculating an offset that will be zero anyway */
4043 /* calculate basic unsnapped multi-paste offset */
4044 framecnt_t offset = paste_count * duration;
4046 /* snap offset so pos + offset is aligned to the grid */
4047 framepos_t offset_pos = pos + offset;
4048 snap_to(offset_pos, RoundUpMaybe);
4049 offset = offset_pos - pos;
4055 Editor::get_grid_beat_divisions(framepos_t position)
4057 switch (_snap_type) {
4058 case SnapToBeatDiv128: return 128;
4059 case SnapToBeatDiv64: return 64;
4060 case SnapToBeatDiv32: return 32;
4061 case SnapToBeatDiv28: return 28;
4062 case SnapToBeatDiv24: return 24;
4063 case SnapToBeatDiv20: return 20;
4064 case SnapToBeatDiv16: return 16;
4065 case SnapToBeatDiv14: return 14;
4066 case SnapToBeatDiv12: return 12;
4067 case SnapToBeatDiv10: return 10;
4068 case SnapToBeatDiv8: return 8;
4069 case SnapToBeatDiv7: return 7;
4070 case SnapToBeatDiv6: return 6;
4071 case SnapToBeatDiv5: return 5;
4072 case SnapToBeatDiv4: return 4;
4073 case SnapToBeatDiv3: return 3;
4074 case SnapToBeatDiv2: return 2;
4081 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4085 const unsigned divisions = get_grid_beat_divisions(position);
4087 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4090 switch (_snap_type) {
4092 return Evoral::Beats(1.0);
4095 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
4103 return Evoral::Beats();
4107 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4111 ret = nudge_clock->current_duration (pos);
4112 next = ret + 1; /* XXXX fix me */
4118 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4120 ArdourDialog dialog (_("Playlist Deletion"));
4121 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4122 "If it is kept, its audio files will not be cleaned.\n"
4123 "If it is deleted, audio files used by it alone will be cleaned."),
4126 dialog.set_position (WIN_POS_CENTER);
4127 dialog.get_vbox()->pack_start (label);
4131 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4132 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4133 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4135 switch (dialog.run ()) {
4136 case RESPONSE_ACCEPT:
4137 /* delete the playlist */
4141 case RESPONSE_REJECT:
4142 /* keep the playlist */
4154 Editor::audio_region_selection_covers (framepos_t where)
4156 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4157 if ((*a)->region()->covers (where)) {
4166 Editor::prepare_for_cleanup ()
4168 cut_buffer->clear_regions ();
4169 cut_buffer->clear_playlists ();
4171 selection->clear_regions ();
4172 selection->clear_playlists ();
4174 _regions->suspend_redisplay ();
4178 Editor::finish_cleanup ()
4180 _regions->resume_redisplay ();
4184 Editor::transport_loop_location()
4187 return _session->locations()->auto_loop_location();
4194 Editor::transport_punch_location()
4197 return _session->locations()->auto_punch_location();
4204 Editor::control_layout_scroll (GdkEventScroll* ev)
4206 /* Just forward to the normal canvas scroll method. The coordinate
4207 systems are different but since the canvas is always larger than the
4208 track headers, and aligned with the trackview area, this will work.
4210 In the not too distant future this layout is going away anyway and
4211 headers will be on the canvas.
4213 return canvas_scroll_event (ev, false);
4217 Editor::session_state_saved (string)
4220 _snapshots->redisplay ();
4224 Editor::update_tearoff_visibility()
4226 bool visible = ARDOUR_UI::config()->get_keep_tearoffs();
4227 _mouse_mode_tearoff->set_visible (visible);
4228 _tools_tearoff->set_visible (visible);
4229 if (_zoom_tearoff) {
4230 _zoom_tearoff->set_visible (visible);
4235 Editor::reattach_all_tearoffs ()
4237 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4238 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4239 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4243 Editor::maximise_editing_space ()
4255 Editor::restore_editing_space ()
4267 * Make new playlists for a given track and also any others that belong
4268 * to the same active route group with the `select' property.
4273 Editor::new_playlists (TimeAxisView* v)
4275 begin_reversible_command (_("new 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_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4279 commit_reversible_command ();
4283 * Use a copy of the current playlist for a given track and also any others that belong
4284 * to the same active route group with the `select' property.
4289 Editor::copy_playlists (TimeAxisView* v)
4291 begin_reversible_command (_("copy playlists"));
4292 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4293 _session->playlists->get (playlists);
4294 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4295 commit_reversible_command ();
4298 /** Clear the current playlist for a given track and also any others that belong
4299 * to the same active route group with the `select' property.
4304 Editor::clear_playlists (TimeAxisView* v)
4306 begin_reversible_command (_("clear playlists"));
4307 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4308 _session->playlists->get (playlists);
4309 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4310 commit_reversible_command ();
4314 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4316 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4320 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4322 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4326 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4328 atv.clear_playlist ();
4332 Editor::on_key_press_event (GdkEventKey* ev)
4334 return key_press_focus_accelerator_handler (*this, ev);
4338 Editor::on_key_release_event (GdkEventKey* ev)
4340 return Gtk::Window::on_key_release_event (ev);
4341 // return key_press_focus_accelerator_handler (*this, ev);
4345 Editor::get_y_origin () const
4347 return vertical_adjustment.get_value ();
4350 /** Queue up a change to the viewport x origin.
4351 * @param frame New x origin.
4354 Editor::reset_x_origin (framepos_t frame)
4356 pending_visual_change.add (VisualChange::TimeOrigin);
4357 pending_visual_change.time_origin = frame;
4358 ensure_visual_change_idle_handler ();
4362 Editor::reset_y_origin (double y)
4364 pending_visual_change.add (VisualChange::YOrigin);
4365 pending_visual_change.y_origin = y;
4366 ensure_visual_change_idle_handler ();
4370 Editor::reset_zoom (framecnt_t spp)
4372 if (spp == samples_per_pixel) {
4376 pending_visual_change.add (VisualChange::ZoomLevel);
4377 pending_visual_change.samples_per_pixel = spp;
4378 ensure_visual_change_idle_handler ();
4382 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4384 reset_x_origin (frame);
4387 if (!no_save_visual) {
4388 undo_visual_stack.push_back (current_visual_state(false));
4392 Editor::VisualState::VisualState (bool with_tracks)
4393 : gui_state (with_tracks ? new GUIObjectState : 0)
4397 Editor::VisualState::~VisualState ()
4402 Editor::VisualState*
4403 Editor::current_visual_state (bool with_tracks)
4405 VisualState* vs = new VisualState (with_tracks);
4406 vs->y_position = vertical_adjustment.get_value();
4407 vs->samples_per_pixel = samples_per_pixel;
4408 vs->leftmost_frame = leftmost_frame;
4409 vs->zoom_focus = zoom_focus;
4412 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4419 Editor::undo_visual_state ()
4421 if (undo_visual_stack.empty()) {
4425 VisualState* vs = undo_visual_stack.back();
4426 undo_visual_stack.pop_back();
4429 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4432 use_visual_state (*vs);
4437 Editor::redo_visual_state ()
4439 if (redo_visual_stack.empty()) {
4443 VisualState* vs = redo_visual_stack.back();
4444 redo_visual_stack.pop_back();
4446 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4447 // why do we check here?
4448 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4451 use_visual_state (*vs);
4456 Editor::swap_visual_state ()
4458 if (undo_visual_stack.empty()) {
4459 redo_visual_state ();
4461 undo_visual_state ();
4466 Editor::use_visual_state (VisualState& vs)
4468 PBD::Unwinder<bool> nsv (no_save_visual, true);
4469 DisplaySuspender ds;
4471 vertical_adjustment.set_value (vs.y_position);
4473 set_zoom_focus (vs.zoom_focus);
4474 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4477 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4479 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4480 (*i)->clear_property_cache();
4481 (*i)->reset_visual_state ();
4485 _routes->update_visibility ();
4488 /** This is the core function that controls the zoom level of the canvas. It is called
4489 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4490 * @param spp new number of samples per pixel
4493 Editor::set_samples_per_pixel (framecnt_t spp)
4499 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4500 const framecnt_t lots_of_pixels = 4000;
4502 /* if the zoom level is greater than what you'd get trying to display 3
4503 * days of audio on a really big screen, then it's too big.
4506 if (spp * lots_of_pixels > three_days) {
4510 samples_per_pixel = spp;
4513 tempo_lines->tempo_map_changed();
4516 bool const showing_time_selection = selection->time.length() > 0;
4518 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4519 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4520 (*i)->reshow_selection (selection->time);
4524 ZoomChanged (); /* EMIT_SIGNAL */
4526 ArdourCanvas::GtkCanvasViewport* c;
4528 c = get_track_canvas();
4530 c->canvas()->zoomed ();
4533 if (playhead_cursor) {
4534 playhead_cursor->set_position (playhead_cursor->current_frame ());
4537 refresh_location_display();
4538 _summary->set_overlays_dirty ();
4540 update_marker_labels ();
4546 Editor::queue_visual_videotimeline_update ()
4549 * pending_visual_change.add (VisualChange::VideoTimeline);
4550 * or maybe even more specific: which videotimeline-image
4551 * currently it calls update_video_timeline() to update
4552 * _all outdated_ images on the video-timeline.
4553 * see 'exposeimg()' in video_image_frame.cc
4555 ensure_visual_change_idle_handler ();
4559 Editor::ensure_visual_change_idle_handler ()
4561 if (pending_visual_change.idle_handler_id < 0) {
4562 // see comment in add_to_idle_resize above.
4563 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4564 pending_visual_change.being_handled = false;
4569 Editor::_idle_visual_changer (void* arg)
4571 return static_cast<Editor*>(arg)->idle_visual_changer ();
4575 Editor::idle_visual_changer ()
4577 /* set_horizontal_position() below (and maybe other calls) call
4578 gtk_main_iteration(), so it's possible that a signal will be handled
4579 half-way through this method. If this signal wants an
4580 idle_visual_changer we must schedule another one after this one, so
4581 mark the idle_handler_id as -1 here to allow that. Also make a note
4582 that we are doing the visual change, so that changes in response to
4583 super-rapid-screen-update can be dropped if we are still processing
4587 pending_visual_change.idle_handler_id = -1;
4588 pending_visual_change.being_handled = true;
4590 VisualChange vc = pending_visual_change;
4592 pending_visual_change.pending = (VisualChange::Type) 0;
4594 visual_changer (vc);
4596 pending_visual_change.being_handled = false;
4598 return 0; /* this is always a one-shot call */
4602 Editor::visual_changer (const VisualChange& vc)
4604 double const last_time_origin = horizontal_position ();
4606 if (vc.pending & VisualChange::ZoomLevel) {
4607 set_samples_per_pixel (vc.samples_per_pixel);
4609 compute_fixed_ruler_scale ();
4611 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4612 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4614 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4615 current_bbt_points_begin, current_bbt_points_end);
4616 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4617 current_bbt_points_begin, current_bbt_points_end);
4618 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4620 update_video_timeline();
4623 if (vc.pending & VisualChange::TimeOrigin) {
4624 set_horizontal_position (vc.time_origin / samples_per_pixel);
4627 if (vc.pending & VisualChange::YOrigin) {
4628 vertical_adjustment.set_value (vc.y_origin);
4631 if (last_time_origin == horizontal_position ()) {
4632 /* changed signal not emitted */
4633 update_fixed_rulers ();
4634 redisplay_tempo (true);
4637 if (!(vc.pending & VisualChange::ZoomLevel)) {
4638 update_video_timeline();
4641 _summary->set_overlays_dirty ();
4644 struct EditorOrderTimeAxisSorter {
4645 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4646 return a->order () < b->order ();
4651 Editor::sort_track_selection (TrackViewList& sel)
4653 EditorOrderTimeAxisSorter cmp;
4658 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4661 framepos_t where = 0;
4662 EditPoint ep = _edit_point;
4664 if (Profile->get_mixbus())
4665 if (ep == EditAtSelectedMarker)
4666 ep = EditAtPlayhead;
4668 if (from_outside_canvas && (ep == EditAtMouse)) {
4669 ep = EditAtPlayhead;
4670 } else if (from_context_menu && (ep == EditAtMouse)) {
4671 return canvas_event_sample (&context_click_event, 0, 0);
4674 if (entered_marker) {
4675 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4676 return entered_marker->position();
4679 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4680 ep = EditAtSelectedMarker;
4683 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4684 ep = EditAtPlayhead;
4688 case EditAtPlayhead:
4689 if (_dragging_playhead) {
4690 if (!mouse_frame (where, ignored)) {
4691 /* XXX not right but what can we do ? */
4695 where = _session->audible_frame();
4697 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4700 case EditAtSelectedMarker:
4701 if (!selection->markers.empty()) {
4703 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4706 where = loc->start();
4710 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4718 if (!mouse_frame (where, ignored)) {
4719 /* XXX not right but what can we do ? */
4723 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4731 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4733 if (!_session) return;
4735 begin_reversible_command (cmd);
4739 if ((tll = transport_loop_location()) == 0) {
4740 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4741 XMLNode &before = _session->locations()->get_state();
4742 _session->locations()->add (loc, true);
4743 _session->set_auto_loop_location (loc);
4744 XMLNode &after = _session->locations()->get_state();
4745 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4747 XMLNode &before = tll->get_state();
4748 tll->set_hidden (false, this);
4749 tll->set (start, end);
4750 XMLNode &after = tll->get_state();
4751 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4754 commit_reversible_command ();
4758 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4760 if (!_session) return;
4762 begin_reversible_command (cmd);
4766 if ((tpl = transport_punch_location()) == 0) {
4767 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4768 XMLNode &before = _session->locations()->get_state();
4769 _session->locations()->add (loc, true);
4770 _session->set_auto_punch_location (loc);
4771 XMLNode &after = _session->locations()->get_state();
4772 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4774 XMLNode &before = tpl->get_state();
4775 tpl->set_hidden (false, this);
4776 tpl->set (start, end);
4777 XMLNode &after = tpl->get_state();
4778 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4781 commit_reversible_command ();
4784 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4785 * @param rs List to which found regions are added.
4786 * @param where Time to look at.
4787 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4790 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4792 const TrackViewList* tracks;
4795 tracks = &track_views;
4800 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4802 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4805 boost::shared_ptr<Track> tr;
4806 boost::shared_ptr<Playlist> pl;
4808 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4810 boost::shared_ptr<RegionList> regions = pl->regions_at (
4811 (framepos_t) floor ( (double) where * tr->speed()));
4813 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4814 RegionView* rv = rtv->view()->find_view (*i);
4825 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4827 const TrackViewList* tracks;
4830 tracks = &track_views;
4835 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4836 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4838 boost::shared_ptr<Track> tr;
4839 boost::shared_ptr<Playlist> pl;
4841 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4843 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4844 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4846 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4848 RegionView* rv = rtv->view()->find_view (*i);
4859 /** Get regions using the following method:
4861 * Make a region list using:
4862 * (a) any selected regions
4863 * (b) the intersection of any selected tracks and the edit point(*)
4864 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4866 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4868 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4872 Editor::get_regions_from_selection_and_edit_point ()
4874 RegionSelection regions;
4876 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4877 regions.add (entered_regionview);
4879 regions = selection->regions;
4882 if ( regions.empty() ) {
4883 TrackViewList tracks = selection->tracks;
4885 if (!tracks.empty()) {
4886 /* no region selected or entered, but some selected tracks:
4887 * act on all regions on the selected tracks at the edit point
4889 framepos_t const where = get_preferred_edit_position ();
4890 get_regions_at(regions, where, tracks);
4897 /** Get regions using the following method:
4899 * Make a region list using:
4900 * (a) any selected regions
4901 * (b) the intersection of any selected tracks and the edit point(*)
4902 * (c) if neither exists, then whatever region is under the mouse
4904 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4906 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4909 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4911 RegionSelection regions;
4913 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4914 regions.add (entered_regionview);
4916 regions = selection->regions;
4919 if ( regions.empty() ) {
4920 TrackViewList tracks = selection->tracks;
4922 if (!tracks.empty()) {
4923 /* no region selected or entered, but some selected tracks:
4924 * act on all regions on the selected tracks at the edit point
4926 get_regions_at(regions, pos, tracks);
4933 /** Start with regions that are selected, or the entered regionview if none are selected.
4934 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4935 * of the regions that we started with.
4939 Editor::get_regions_from_selection_and_entered ()
4941 RegionSelection regions = selection->regions;
4943 if (regions.empty() && entered_regionview) {
4944 regions.add (entered_regionview);
4951 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4953 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4954 RouteTimeAxisView* rtav;
4956 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4957 boost::shared_ptr<Playlist> pl;
4958 std::vector<boost::shared_ptr<Region> > results;
4959 boost::shared_ptr<Track> tr;
4961 if ((tr = rtav->track()) == 0) {
4966 if ((pl = (tr->playlist())) != 0) {
4967 boost::shared_ptr<Region> r = pl->region_by_id (id);
4969 RegionView* rv = rtav->view()->find_view (r);
4971 regions.push_back (rv);
4980 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4983 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4984 MidiTimeAxisView* mtav;
4986 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4988 mtav->get_per_region_note_selection (selection);
4995 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4997 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4999 RouteTimeAxisView* tatv;
5001 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5003 boost::shared_ptr<Playlist> pl;
5004 vector<boost::shared_ptr<Region> > results;
5006 boost::shared_ptr<Track> tr;
5008 if ((tr = tatv->track()) == 0) {
5013 if ((pl = (tr->playlist())) != 0) {
5014 if (src_comparison) {
5015 pl->get_source_equivalent_regions (region, results);
5017 pl->get_region_list_equivalent_regions (region, results);
5021 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5022 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5023 regions.push_back (marv);
5032 Editor::show_rhythm_ferret ()
5034 if (rhythm_ferret == 0) {
5035 rhythm_ferret = new RhythmFerret(*this);
5038 rhythm_ferret->set_session (_session);
5039 rhythm_ferret->show ();
5040 rhythm_ferret->present ();
5044 Editor::first_idle ()
5046 MessageDialog* dialog = 0;
5048 if (track_views.size() > 1) {
5049 dialog = new MessageDialog (
5051 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5055 ARDOUR_UI::instance()->flush_pending ();
5058 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5062 // first idle adds route children (automation tracks), so we need to redisplay here
5063 _routes->redisplay ();
5067 if (_session->undo_depth() == 0) {
5068 undo_action->set_sensitive(false);
5070 redo_action->set_sensitive(false);
5071 begin_selection_op_history ();
5077 Editor::_idle_resize (gpointer arg)
5079 return ((Editor*)arg)->idle_resize ();
5083 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5085 if (resize_idle_id < 0) {
5086 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5087 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5088 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5090 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5091 _pending_resize_amount = 0;
5094 /* make a note of the smallest resulting height, so that we can clamp the
5095 lower limit at TimeAxisView::hSmall */
5097 int32_t min_resulting = INT32_MAX;
5099 _pending_resize_amount += h;
5100 _pending_resize_view = view;
5102 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5104 if (selection->tracks.contains (_pending_resize_view)) {
5105 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5106 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5110 if (min_resulting < 0) {
5115 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5116 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5120 /** Handle pending resizing of tracks */
5122 Editor::idle_resize ()
5124 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5126 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5127 selection->tracks.contains (_pending_resize_view)) {
5129 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5130 if (*i != _pending_resize_view) {
5131 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5136 _pending_resize_amount = 0;
5137 _group_tabs->set_dirty ();
5138 resize_idle_id = -1;
5146 ENSURE_GUI_THREAD (*this, &Editor::located);
5149 playhead_cursor->set_position (_session->audible_frame ());
5150 if (_follow_playhead && !_pending_initial_locate) {
5151 reset_x_origin_to_follow_playhead ();
5155 _pending_locate_request = false;
5156 _pending_initial_locate = false;
5160 Editor::region_view_added (RegionView * rv)
5162 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5163 if (rv->region ()->id () == (*pr)) {
5164 selection->add (rv);
5165 selection->regions.pending.erase (pr);
5170 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5172 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5173 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5174 if (rv->region()->id () == (*rnote).first) {
5175 mrv->select_notes ((*rnote).second);
5176 selection->pending_midi_note_selection.erase(rnote);
5182 _summary->set_background_dirty ();
5186 Editor::region_view_removed ()
5188 _summary->set_background_dirty ();
5192 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5194 TrackViewList::const_iterator j = track_views.begin ();
5195 while (j != track_views.end()) {
5196 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5197 if (rtv && rtv->route() == r) {
5208 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5212 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5213 TimeAxisView* tv = axis_view_from_route (*i);
5223 Editor::suspend_route_redisplay ()
5226 _routes->suspend_redisplay();
5231 Editor::resume_route_redisplay ()
5234 _routes->resume_redisplay();
5239 Editor::add_routes (RouteList& routes)
5241 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5243 RouteTimeAxisView *rtv;
5244 list<RouteTimeAxisView*> new_views;
5245 TrackViewList new_selection;
5246 bool from_scratch = (track_views.size() == 0);
5248 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5249 boost::shared_ptr<Route> route = (*x);
5251 if (route->is_auditioner() || route->is_monitor()) {
5255 DataType dt = route->input()->default_type();
5257 if (dt == ARDOUR::DataType::AUDIO) {
5258 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5259 rtv->set_route (route);
5260 } else if (dt == ARDOUR::DataType::MIDI) {
5261 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5262 rtv->set_route (route);
5264 throw unknown_type();
5267 new_views.push_back (rtv);
5268 track_views.push_back (rtv);
5269 new_selection.push_back (rtv);
5271 rtv->effective_gain_display ();
5273 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5274 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5277 if (new_views.size() > 0) {
5278 _routes->routes_added (new_views);
5279 _summary->routes_added (new_views);
5282 if (!from_scratch) {
5283 selection->tracks.clear();
5284 selection->add (new_selection);
5285 begin_selection_op_history();
5288 if (show_editor_mixer_when_tracks_arrive) {
5289 show_editor_mixer (true);
5292 editor_list_button.set_sensitive (true);
5296 Editor::timeaxisview_deleted (TimeAxisView *tv)
5298 if (tv == entered_track) {
5302 if (_session && _session->deletion_in_progress()) {
5303 /* the situation is under control */
5307 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5309 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5311 _routes->route_removed (tv);
5313 TimeAxisView::Children c = tv->get_child_list ();
5314 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5315 if (entered_track == i->get()) {
5320 /* remove it from the list of track views */
5322 TrackViewList::iterator i;
5324 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5325 i = track_views.erase (i);
5328 /* update whatever the current mixer strip is displaying, if revelant */
5330 boost::shared_ptr<Route> route;
5333 route = rtav->route ();
5336 if (current_mixer_strip && current_mixer_strip->route() == route) {
5338 TimeAxisView* next_tv;
5340 if (track_views.empty()) {
5342 } else if (i == track_views.end()) {
5343 next_tv = track_views.front();
5350 set_selected_mixer_strip (*next_tv);
5352 /* make the editor mixer strip go away setting the
5353 * button to inactive (which also unticks the menu option)
5356 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5362 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5364 if (apply_to_selection) {
5365 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5367 TrackSelection::iterator j = i;
5370 hide_track_in_display (*i, false);
5375 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5377 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5378 // this will hide the mixer strip
5379 set_selected_mixer_strip (*tv);
5382 _routes->hide_track_in_display (*tv);
5387 Editor::sync_track_view_list_and_routes ()
5389 track_views = TrackViewList (_routes->views ());
5391 _summary->set_dirty ();
5392 _group_tabs->set_dirty ();
5394 return false; // do not call again (until needed)
5398 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5400 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5405 /** Find a RouteTimeAxisView by the ID of its route */
5407 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5409 RouteTimeAxisView* v;
5411 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5412 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5413 if(v->route()->id() == id) {
5423 Editor::fit_route_group (RouteGroup *g)
5425 TrackViewList ts = axis_views_from_routes (g->route_list ());
5430 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5432 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5435 _session->cancel_audition ();
5439 if (_session->is_auditioning()) {
5440 _session->cancel_audition ();
5441 if (r == last_audition_region) {
5446 _session->audition_region (r);
5447 last_audition_region = r;
5452 Editor::hide_a_region (boost::shared_ptr<Region> r)
5454 r->set_hidden (true);
5458 Editor::show_a_region (boost::shared_ptr<Region> r)
5460 r->set_hidden (false);
5464 Editor::audition_region_from_region_list ()
5466 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5470 Editor::hide_region_from_region_list ()
5472 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5476 Editor::show_region_in_region_list ()
5478 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5482 Editor::step_edit_status_change (bool yn)
5485 start_step_editing ();
5487 stop_step_editing ();
5492 Editor::start_step_editing ()
5494 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5498 Editor::stop_step_editing ()
5500 step_edit_connection.disconnect ();
5504 Editor::check_step_edit ()
5506 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5507 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5509 mtv->check_step_edit ();
5513 return true; // do it again, till we stop
5517 Editor::scroll_press (Direction dir)
5519 ++_scroll_callbacks;
5521 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5522 /* delay the first auto-repeat */
5528 scroll_backward (1);
5536 scroll_up_one_track ();
5540 scroll_down_one_track ();
5544 /* do hacky auto-repeat */
5545 if (!_scroll_connection.connected ()) {
5547 _scroll_connection = Glib::signal_timeout().connect (
5548 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5551 _scroll_callbacks = 0;
5558 Editor::scroll_release ()
5560 _scroll_connection.disconnect ();
5563 /** Queue a change for the Editor viewport x origin to follow the playhead */
5565 Editor::reset_x_origin_to_follow_playhead ()
5567 framepos_t const frame = playhead_cursor->current_frame ();
5569 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5571 if (_session->transport_speed() < 0) {
5573 if (frame > (current_page_samples() / 2)) {
5574 center_screen (frame-(current_page_samples()/2));
5576 center_screen (current_page_samples()/2);
5583 if (frame < leftmost_frame) {
5585 if (_session->transport_rolling()) {
5586 /* rolling; end up with the playhead at the right of the page */
5587 l = frame - current_page_samples ();
5589 /* not rolling: end up with the playhead 1/4 of the way along the page */
5590 l = frame - current_page_samples() / 4;
5594 if (_session->transport_rolling()) {
5595 /* rolling: end up with the playhead on the left of the page */
5598 /* not rolling: end up with the playhead 3/4 of the way along the page */
5599 l = frame - 3 * current_page_samples() / 4;
5607 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5613 Editor::super_rapid_screen_update ()
5615 if (!_session || !_session->engine().running()) {
5619 /* METERING / MIXER STRIPS */
5621 /* update track meters, if required */
5622 if (is_mapped() && meters_running) {
5623 RouteTimeAxisView* rtv;
5624 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5625 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5626 rtv->fast_update ();
5631 /* and any current mixer strip */
5632 if (current_mixer_strip) {
5633 current_mixer_strip->fast_update ();
5636 /* PLAYHEAD AND VIEWPORT */
5638 framepos_t const frame = _session->audible_frame();
5640 /* There are a few reasons why we might not update the playhead / viewport stuff:
5642 * 1. we don't update things when there's a pending locate request, otherwise
5643 * when the editor requests a locate there is a chance that this method
5644 * will move the playhead before the locate request is processed, causing
5646 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5647 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5650 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5652 last_update_frame = frame;
5654 if (!_dragging_playhead) {
5655 playhead_cursor->set_position (frame);
5658 if (!_stationary_playhead) {
5660 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5661 /* We only do this if we aren't already
5662 handling a visual change (ie if
5663 pending_visual_change.being_handled is
5664 false) so that these requests don't stack
5665 up there are too many of them to handle in
5668 reset_x_origin_to_follow_playhead ();
5673 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5677 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5678 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5679 if (target <= 0.0) {
5682 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5683 target = (target * 0.15) + (current * 0.85);
5689 set_horizontal_position (current);
5698 Editor::session_going_away ()
5700 _have_idled = false;
5702 _session_connections.drop_connections ();
5704 super_rapid_screen_update_connection.disconnect ();
5706 selection->clear ();
5707 cut_buffer->clear ();
5709 clicked_regionview = 0;
5710 clicked_axisview = 0;
5711 clicked_routeview = 0;
5712 entered_regionview = 0;
5714 last_update_frame = 0;
5717 playhead_cursor->hide ();
5719 /* rip everything out of the list displays */
5723 _route_groups->clear ();
5725 /* do this first so that deleting a track doesn't reset cms to null
5726 and thus cause a leak.
5729 if (current_mixer_strip) {
5730 if (current_mixer_strip->get_parent() != 0) {
5731 global_hpacker.remove (*current_mixer_strip);
5733 delete current_mixer_strip;
5734 current_mixer_strip = 0;
5737 /* delete all trackviews */
5739 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5742 track_views.clear ();
5744 nudge_clock->set_session (0);
5746 editor_list_button.set_active(false);
5747 editor_list_button.set_sensitive(false);
5749 /* clear tempo/meter rulers */
5750 remove_metric_marks ();
5752 clear_marker_display ();
5754 stop_step_editing ();
5756 /* get rid of any existing editor mixer strip */
5758 WindowTitle title(Glib::get_application_name());
5759 title += _("Editor");
5761 set_title (title.get_string());
5763 SessionHandlePtr::session_going_away ();
5768 Editor::show_editor_list (bool yn)
5771 _the_notebook.show ();
5773 _the_notebook.hide ();
5778 Editor::change_region_layering_order (bool from_context_menu)
5780 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5782 if (!clicked_routeview) {
5783 if (layering_order_editor) {
5784 layering_order_editor->hide ();
5789 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5795 boost::shared_ptr<Playlist> pl = track->playlist();
5801 if (layering_order_editor == 0) {
5802 layering_order_editor = new RegionLayeringOrderEditor (*this);
5805 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5806 layering_order_editor->maybe_present ();
5810 Editor::update_region_layering_order_editor ()
5812 if (layering_order_editor && layering_order_editor->is_visible ()) {
5813 change_region_layering_order (true);
5818 Editor::setup_fade_images ()
5820 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5821 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5822 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5823 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5824 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5826 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5827 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5828 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5829 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5830 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5832 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5833 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5834 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5835 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5836 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5838 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5839 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5840 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5841 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5842 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5846 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5848 Editor::action_menu_item (std::string const & name)
5850 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5853 return *manage (a->create_menu_item ());
5857 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5859 EventBox* b = manage (new EventBox);
5860 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5861 Label* l = manage (new Label (name));
5865 _the_notebook.append_page (widget, *b);
5869 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5871 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5872 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5875 if (ev->type == GDK_2BUTTON_PRESS) {
5877 /* double-click on a notebook tab shrinks or expands the notebook */
5879 if (_notebook_shrunk) {
5880 if (pre_notebook_shrink_pane_width) {
5881 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5883 _notebook_shrunk = false;
5885 pre_notebook_shrink_pane_width = edit_pane.get_position();
5887 /* this expands the LHS of the edit pane to cover the notebook
5888 PAGE but leaves the tabs visible.
5890 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5891 _notebook_shrunk = true;
5899 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5901 using namespace Menu_Helpers;
5903 MenuList& items = _control_point_context_menu.items ();
5906 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5907 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5908 if (!can_remove_control_point (item)) {
5909 items.back().set_sensitive (false);
5912 _control_point_context_menu.popup (event->button.button, event->button.time);
5916 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5918 using namespace Menu_Helpers;
5920 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5925 /* We need to get the selection here and pass it to the operations, since
5926 popping up the menu will cause a region leave event which clears
5927 entered_regionview. */
5929 MidiRegionView& mrv = note->region_view();
5930 const RegionSelection rs = get_regions_from_selection_and_entered ();
5932 MenuList& items = _note_context_menu.items();
5935 items.push_back(MenuElem(_("Delete"),
5936 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5937 items.push_back(MenuElem(_("Edit..."),
5938 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5939 items.push_back(MenuElem(_("Legatize"),
5940 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5941 items.push_back(MenuElem(_("Quantize..."),
5942 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5943 items.push_back(MenuElem(_("Remove Overlap"),
5944 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5945 items.push_back(MenuElem(_("Transform..."),
5946 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5948 _note_context_menu.popup (event->button.button, event->button.time);
5952 Editor::zoom_vertical_modifier_released()
5954 _stepping_axis_view = 0;
5958 Editor::ui_parameter_changed (string parameter)
5960 if (parameter == "icon-set") {
5961 while (!_cursor_stack.empty()) {
5962 _cursor_stack.pop_back();
5964 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5965 _cursor_stack.push_back(_cursors->grabber);
5966 } else if (parameter == "draggable-playhead") {
5967 if (_verbose_cursor) {
5968 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());