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 (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
1920 select_items.push_back (SeparatorElem());
1921 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1922 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1923 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1924 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1925 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1926 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1927 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1929 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1933 Menu *cutnpaste_menu = manage (new Menu);
1934 MenuList& cutnpaste_items = cutnpaste_menu->items();
1935 cutnpaste_menu->set_name ("ArdourContextMenu");
1937 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1938 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1939 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1941 cutnpaste_items.push_back (SeparatorElem());
1943 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1944 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1946 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1948 /* Adding new material */
1950 edit_items.push_back (SeparatorElem());
1951 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1952 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1956 Menu *nudge_menu = manage (new Menu());
1957 MenuList& nudge_items = nudge_menu->items();
1958 nudge_menu->set_name ("ArdourContextMenu");
1960 edit_items.push_back (SeparatorElem());
1961 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1962 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1963 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1964 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1966 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1970 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1972 using namespace Menu_Helpers;
1976 Menu *play_menu = manage (new Menu);
1977 MenuList& play_items = play_menu->items();
1978 play_menu->set_name ("ArdourContextMenu");
1980 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1981 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1982 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1986 Menu *select_menu = manage (new Menu);
1987 MenuList& select_items = select_menu->items();
1988 select_menu->set_name ("ArdourContextMenu");
1990 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1991 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1992 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1993 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1994 select_items.push_back (SeparatorElem());
1995 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1996 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1997 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1998 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2000 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2004 Menu *cutnpaste_menu = manage (new Menu);
2005 MenuList& cutnpaste_items = cutnpaste_menu->items();
2006 cutnpaste_menu->set_name ("ArdourContextMenu");
2008 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2009 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2010 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2012 Menu *nudge_menu = manage (new Menu());
2013 MenuList& nudge_items = nudge_menu->items();
2014 nudge_menu->set_name ("ArdourContextMenu");
2016 edit_items.push_back (SeparatorElem());
2017 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2018 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2019 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2020 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2022 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2026 Editor::snap_type() const
2032 Editor::snap_mode() const
2038 Editor::set_snap_to (SnapType st)
2040 unsigned int snap_ind = (unsigned int)st;
2042 if (internal_editing()) {
2043 internal_snap_type = st;
2045 pre_internal_snap_type = st;
2050 if (snap_ind > snap_type_strings.size() - 1) {
2052 _snap_type = (SnapType)snap_ind;
2055 string str = snap_type_strings[snap_ind];
2057 if (str != snap_type_selector.get_text()) {
2058 snap_type_selector.set_text (str);
2063 switch (_snap_type) {
2064 case SnapToBeatDiv128:
2065 case SnapToBeatDiv64:
2066 case SnapToBeatDiv32:
2067 case SnapToBeatDiv28:
2068 case SnapToBeatDiv24:
2069 case SnapToBeatDiv20:
2070 case SnapToBeatDiv16:
2071 case SnapToBeatDiv14:
2072 case SnapToBeatDiv12:
2073 case SnapToBeatDiv10:
2074 case SnapToBeatDiv8:
2075 case SnapToBeatDiv7:
2076 case SnapToBeatDiv6:
2077 case SnapToBeatDiv5:
2078 case SnapToBeatDiv4:
2079 case SnapToBeatDiv3:
2080 case SnapToBeatDiv2: {
2081 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2082 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2084 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2085 current_bbt_points_begin, current_bbt_points_end);
2086 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2087 current_bbt_points_begin, current_bbt_points_end);
2088 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2092 case SnapToRegionStart:
2093 case SnapToRegionEnd:
2094 case SnapToRegionSync:
2095 case SnapToRegionBoundary:
2096 build_region_boundary_cache ();
2104 redisplay_tempo (false);
2106 SnapChanged (); /* EMIT SIGNAL */
2110 Editor::set_snap_mode (SnapMode mode)
2112 string str = snap_mode_strings[(int)mode];
2114 if (internal_editing()) {
2115 internal_snap_mode = mode;
2117 pre_internal_snap_mode = mode;
2122 if (str != snap_mode_selector.get_text ()) {
2123 snap_mode_selector.set_text (str);
2129 Editor::set_edit_point_preference (EditPoint ep, bool force)
2131 bool changed = (_edit_point != ep);
2134 if (Profile->get_mixbus())
2135 if (ep == EditAtSelectedMarker)
2136 ep = EditAtPlayhead;
2138 string str = edit_point_strings[(int)ep];
2139 if (str != edit_point_selector.get_text ()) {
2140 edit_point_selector.set_text (str);
2143 update_all_enter_cursors();
2145 if (!force && !changed) {
2149 const char* action=NULL;
2151 switch (_edit_point) {
2152 case EditAtPlayhead:
2153 action = "edit-at-playhead";
2155 case EditAtSelectedMarker:
2156 action = "edit-at-marker";
2159 action = "edit-at-mouse";
2163 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2165 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2169 bool in_track_canvas;
2171 if (!mouse_frame (foo, in_track_canvas)) {
2172 in_track_canvas = false;
2175 reset_canvas_action_sensitivity (in_track_canvas);
2181 Editor::set_state (const XMLNode& node, int /*version*/)
2183 const XMLProperty* prop;
2190 g.base_width = default_width;
2191 g.base_height = default_height;
2195 if ((geometry = find_named_node (node, "geometry")) != 0) {
2199 if ((prop = geometry->property("x_size")) == 0) {
2200 prop = geometry->property ("x-size");
2203 g.base_width = atoi(prop->value());
2205 if ((prop = geometry->property("y_size")) == 0) {
2206 prop = geometry->property ("y-size");
2209 g.base_height = atoi(prop->value());
2212 if ((prop = geometry->property ("x_pos")) == 0) {
2213 prop = geometry->property ("x-pos");
2216 x = atoi (prop->value());
2219 if ((prop = geometry->property ("y_pos")) == 0) {
2220 prop = geometry->property ("y-pos");
2223 y = atoi (prop->value());
2227 set_default_size (g.base_width, g.base_height);
2230 if (_session && (prop = node.property ("playhead"))) {
2232 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2234 playhead_cursor->set_position (pos);
2236 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2237 playhead_cursor->set_position (0);
2240 playhead_cursor->set_position (0);
2243 if ((prop = node.property ("mixer-width"))) {
2244 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2247 if ((prop = node.property ("zoom-focus"))) {
2248 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2251 if ((prop = node.property ("zoom"))) {
2252 /* older versions of ardour used floating point samples_per_pixel */
2253 double f = PBD::atof (prop->value());
2254 reset_zoom (llrintf (f));
2256 reset_zoom (samples_per_pixel);
2259 if ((prop = node.property ("visible-track-count"))) {
2260 set_visible_track_count (PBD::atoi (prop->value()));
2263 if ((prop = node.property ("snap-to"))) {
2264 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2267 if ((prop = node.property ("snap-mode"))) {
2268 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2271 if ((prop = node.property ("internal-snap-to"))) {
2272 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2275 if ((prop = node.property ("internal-snap-mode"))) {
2276 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2279 if ((prop = node.property ("pre-internal-snap-to"))) {
2280 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2283 if ((prop = node.property ("pre-internal-snap-mode"))) {
2284 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2287 if ((prop = node.property ("mouse-mode"))) {
2288 MouseMode m = str2mousemode(prop->value());
2289 set_mouse_mode (m, true);
2291 set_mouse_mode (MouseObject, true);
2294 if ((prop = node.property ("left-frame")) != 0) {
2296 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2300 reset_x_origin (pos);
2304 if ((prop = node.property ("y-origin")) != 0) {
2305 reset_y_origin (atof (prop->value ()));
2308 if ((prop = node.property ("join-object-range"))) {
2309 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2310 bool yn = string_is_affirmative (prop->value());
2312 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2313 tact->set_active (!yn);
2314 tact->set_active (yn);
2316 set_mouse_mode(mouse_mode, true);
2319 if ((prop = node.property ("edit-point"))) {
2320 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2323 if ((prop = node.property ("show-measures"))) {
2324 bool yn = string_is_affirmative (prop->value());
2325 _show_measures = yn;
2328 if ((prop = node.property ("follow-playhead"))) {
2329 bool yn = string_is_affirmative (prop->value());
2330 set_follow_playhead (yn);
2333 if ((prop = node.property ("stationary-playhead"))) {
2334 bool yn = string_is_affirmative (prop->value());
2335 set_stationary_playhead (yn);
2338 if ((prop = node.property ("region-list-sort-type"))) {
2339 RegionListSortType st;
2340 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2343 if ((prop = node.property ("show-editor-mixer"))) {
2345 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2348 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2349 bool yn = string_is_affirmative (prop->value());
2351 /* do it twice to force the change */
2353 tact->set_active (!yn);
2354 tact->set_active (yn);
2357 if ((prop = node.property ("show-editor-list"))) {
2359 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2362 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2363 bool yn = string_is_affirmative (prop->value());
2365 /* do it twice to force the change */
2367 tact->set_active (!yn);
2368 tact->set_active (yn);
2371 if ((prop = node.property (X_("editor-list-page")))) {
2372 _the_notebook.set_current_page (atoi (prop->value ()));
2375 if ((prop = node.property (X_("show-marker-lines")))) {
2376 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2378 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2379 bool yn = string_is_affirmative (prop->value ());
2381 tact->set_active (!yn);
2382 tact->set_active (yn);
2385 XMLNodeList children = node.children ();
2386 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2387 selection->set_state (**i, Stateful::current_state_version);
2388 _regions->set_state (**i);
2391 if ((prop = node.property ("maximised"))) {
2392 bool yn = string_is_affirmative (prop->value());
2393 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2395 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2396 bool fs = tact && tact->get_active();
2398 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2402 if ((prop = node.property ("nudge-clock-value"))) {
2404 sscanf (prop->value().c_str(), "%" PRId64, &f);
2405 nudge_clock->set (f);
2407 nudge_clock->set_mode (AudioClock::Timecode);
2408 nudge_clock->set (_session->frame_rate() * 5, true);
2413 * Not all properties may have been in XML, but
2414 * those that are linked to a private variable may need changing
2419 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2421 yn = _show_measures;
2422 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2423 /* do it twice to force the change */
2424 tact->set_active (!yn);
2425 tact->set_active (yn);
2428 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2429 yn = _follow_playhead;
2431 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2432 if (tact->get_active() != yn) {
2433 tact->set_active (yn);
2437 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2438 yn = _stationary_playhead;
2440 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2441 if (tact->get_active() != yn) {
2442 tact->set_active (yn);
2451 Editor::get_state ()
2453 XMLNode* node = new XMLNode ("Editor");
2456 id().print (buf, sizeof (buf));
2457 node->add_property ("id", buf);
2459 if (is_realized()) {
2460 Glib::RefPtr<Gdk::Window> win = get_window();
2462 int x, y, width, height;
2463 win->get_root_origin(x, y);
2464 win->get_size(width, height);
2466 XMLNode* geometry = new XMLNode ("geometry");
2468 snprintf(buf, sizeof(buf), "%d", width);
2469 geometry->add_property("x-size", string(buf));
2470 snprintf(buf, sizeof(buf), "%d", height);
2471 geometry->add_property("y-size", string(buf));
2472 snprintf(buf, sizeof(buf), "%d", x);
2473 geometry->add_property("x-pos", string(buf));
2474 snprintf(buf, sizeof(buf), "%d", y);
2475 geometry->add_property("y-pos", string(buf));
2476 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2477 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2478 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2479 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2480 geometry->add_property("edit-vertical-pane-pos", string(buf));
2482 node->add_child_nocopy (*geometry);
2485 maybe_add_mixer_strip_width (*node);
2487 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2489 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2490 node->add_property ("zoom", buf);
2491 node->add_property ("snap-to", enum_2_string (_snap_type));
2492 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2493 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2494 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2495 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2496 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2497 node->add_property ("edit-point", enum_2_string (_edit_point));
2498 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2499 node->add_property ("visible-track-count", buf);
2501 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2502 node->add_property ("playhead", buf);
2503 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2504 node->add_property ("left-frame", buf);
2505 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2506 node->add_property ("y-origin", buf);
2508 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2509 node->add_property ("maximised", _maximised ? "yes" : "no");
2510 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2511 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2512 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2513 node->add_property ("mouse-mode", enum2str(mouse_mode));
2514 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2516 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2518 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2519 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2522 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2524 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2525 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2528 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2529 node->add_property (X_("editor-list-page"), buf);
2531 if (button_bindings) {
2532 XMLNode* bb = new XMLNode (X_("Buttons"));
2533 button_bindings->save (*bb);
2534 node->add_child_nocopy (*bb);
2537 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2539 node->add_child_nocopy (selection->get_state ());
2540 node->add_child_nocopy (_regions->get_state ());
2542 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2543 node->add_property ("nudge-clock-value", buf);
2548 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2549 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2551 * @return pair: TimeAxisView that y is over, layer index.
2553 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2554 * in stacked or expanded region display mode, otherwise 0.
2556 std::pair<TimeAxisView *, double>
2557 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2559 if (!trackview_relative_offset) {
2560 y -= _trackview_group->canvas_origin().y;
2564 return std::make_pair ( (TimeAxisView *) 0, 0);
2567 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2569 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2576 return std::make_pair ( (TimeAxisView *) 0, 0);
2579 /** Snap a position to the grid, if appropriate, taking into account current
2580 * grid settings and also the state of any snap modifier keys that may be pressed.
2581 * @param start Position to snap.
2582 * @param event Event to get current key modifier information from, or 0.
2585 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2587 if (!_session || !event) {
2591 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2592 if (_snap_mode == SnapOff) {
2593 snap_to_internal (start, direction, for_mark);
2596 if (_snap_mode != SnapOff) {
2597 snap_to_internal (start, direction, for_mark);
2603 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark)
2605 if (!_session || _snap_mode == SnapOff) {
2609 snap_to_internal (start, direction, for_mark);
2613 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2615 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2616 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2618 switch (_snap_type) {
2619 case SnapToTimecodeFrame:
2620 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2621 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2622 /* start is already on a whole timecode frame, do nothing */
2623 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2624 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2626 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2630 case SnapToTimecodeSeconds:
2631 if (_session->config.get_timecode_offset_negative()) {
2632 start += _session->config.get_timecode_offset ();
2634 start -= _session->config.get_timecode_offset ();
2636 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2637 (start % one_timecode_second == 0)) {
2638 /* start is already on a whole second, do nothing */
2639 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2640 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2642 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2645 if (_session->config.get_timecode_offset_negative()) {
2646 start -= _session->config.get_timecode_offset ();
2648 start += _session->config.get_timecode_offset ();
2652 case SnapToTimecodeMinutes:
2653 if (_session->config.get_timecode_offset_negative()) {
2654 start += _session->config.get_timecode_offset ();
2656 start -= _session->config.get_timecode_offset ();
2658 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2659 (start % one_timecode_minute == 0)) {
2660 /* start is already on a whole minute, do nothing */
2661 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2662 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2664 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2666 if (_session->config.get_timecode_offset_negative()) {
2667 start -= _session->config.get_timecode_offset ();
2669 start += _session->config.get_timecode_offset ();
2673 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2674 abort(); /*NOTREACHED*/
2679 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark)
2681 const framepos_t one_second = _session->frame_rate();
2682 const framepos_t one_minute = _session->frame_rate() * 60;
2683 framepos_t presnap = start;
2687 switch (_snap_type) {
2688 case SnapToTimecodeFrame:
2689 case SnapToTimecodeSeconds:
2690 case SnapToTimecodeMinutes:
2691 return timecode_snap_to_internal (start, direction, for_mark);
2694 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2695 start % (one_second/75) == 0) {
2696 /* start is already on a whole CD frame, do nothing */
2697 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2698 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2700 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2705 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2706 start % one_second == 0) {
2707 /* start is already on a whole second, do nothing */
2708 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2709 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2711 start = (framepos_t) floor ((double) start / one_second) * one_second;
2716 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2717 start % one_minute == 0) {
2718 /* start is already on a whole minute, do nothing */
2719 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2720 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2722 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2727 start = _session->tempo_map().round_to_bar (start, direction);
2731 start = _session->tempo_map().round_to_beat (start, direction);
2734 case SnapToBeatDiv128:
2735 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2737 case SnapToBeatDiv64:
2738 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2740 case SnapToBeatDiv32:
2741 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2743 case SnapToBeatDiv28:
2744 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2746 case SnapToBeatDiv24:
2747 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2749 case SnapToBeatDiv20:
2750 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2752 case SnapToBeatDiv16:
2753 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2755 case SnapToBeatDiv14:
2756 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2758 case SnapToBeatDiv12:
2759 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2761 case SnapToBeatDiv10:
2762 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2764 case SnapToBeatDiv8:
2765 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2767 case SnapToBeatDiv7:
2768 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2770 case SnapToBeatDiv6:
2771 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2773 case SnapToBeatDiv5:
2774 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2776 case SnapToBeatDiv4:
2777 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2779 case SnapToBeatDiv3:
2780 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2782 case SnapToBeatDiv2:
2783 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2791 _session->locations()->marks_either_side (start, before, after);
2793 if (before == max_framepos && after == max_framepos) {
2794 /* No marks to snap to, so just don't snap */
2796 } else if (before == max_framepos) {
2798 } else if (after == max_framepos) {
2800 } else if (before != max_framepos && after != max_framepos) {
2801 /* have before and after */
2802 if ((start - before) < (after - start)) {
2811 case SnapToRegionStart:
2812 case SnapToRegionEnd:
2813 case SnapToRegionSync:
2814 case SnapToRegionBoundary:
2815 if (!region_boundary_cache.empty()) {
2817 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2818 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2820 if (direction > 0) {
2821 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2823 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2826 if (next != region_boundary_cache.begin ()) {
2831 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2832 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2834 if (start > (p + n) / 2) {
2843 switch (_snap_mode) {
2849 if (presnap > start) {
2850 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2854 } else if (presnap < start) {
2855 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2861 /* handled at entry */
2869 Editor::setup_toolbar ()
2871 HBox* mode_box = manage(new HBox);
2872 mode_box->set_border_width (2);
2873 mode_box->set_spacing(2);
2875 HBox* mouse_mode_box = manage (new HBox);
2876 HBox* mouse_mode_hbox = manage (new HBox);
2877 VBox* mouse_mode_vbox = manage (new VBox);
2878 Alignment* mouse_mode_align = manage (new Alignment);
2880 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2881 mouse_mode_size_group->add_widget (smart_mode_button);
2882 mouse_mode_size_group->add_widget (mouse_move_button);
2883 mouse_mode_size_group->add_widget (mouse_cut_button);
2884 mouse_mode_size_group->add_widget (mouse_select_button);
2885 mouse_mode_size_group->add_widget (mouse_timefx_button);
2886 mouse_mode_size_group->add_widget (mouse_audition_button);
2887 mouse_mode_size_group->add_widget (mouse_draw_button);
2888 mouse_mode_size_group->add_widget (mouse_content_button);
2890 mouse_mode_size_group->add_widget (zoom_in_button);
2891 mouse_mode_size_group->add_widget (zoom_out_button);
2892 mouse_mode_size_group->add_widget (zoom_preset_selector);
2893 mouse_mode_size_group->add_widget (zoom_out_full_button);
2894 mouse_mode_size_group->add_widget (zoom_focus_selector);
2896 mouse_mode_size_group->add_widget (tav_shrink_button);
2897 mouse_mode_size_group->add_widget (tav_expand_button);
2898 mouse_mode_size_group->add_widget (visible_tracks_selector);
2900 mouse_mode_size_group->add_widget (snap_type_selector);
2901 mouse_mode_size_group->add_widget (snap_mode_selector);
2903 mouse_mode_size_group->add_widget (edit_point_selector);
2904 mouse_mode_size_group->add_widget (edit_mode_selector);
2906 mouse_mode_size_group->add_widget (*nudge_clock);
2907 mouse_mode_size_group->add_widget (nudge_forward_button);
2908 mouse_mode_size_group->add_widget (nudge_backward_button);
2910 mouse_mode_hbox->set_spacing (2);
2912 if (!ARDOUR::Profile->get_trx()) {
2913 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2916 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2917 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2919 if (!ARDOUR::Profile->get_mixbus()) {
2920 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2923 if (!ARDOUR::Profile->get_trx()) {
2924 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2925 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2926 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2927 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2930 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2932 mouse_mode_align->add (*mouse_mode_vbox);
2933 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2935 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2937 edit_mode_selector.set_name ("mouse mode button");
2939 if (!ARDOUR::Profile->get_trx()) {
2940 mode_box->pack_start (edit_mode_selector, false, false);
2942 mode_box->pack_start (*mouse_mode_box, false, false);
2944 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2945 _mouse_mode_tearoff->set_name ("MouseModeBase");
2946 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2948 if (Profile->get_sae() || Profile->get_mixbus() ) {
2949 _mouse_mode_tearoff->set_can_be_torn_off (false);
2952 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2953 &_mouse_mode_tearoff->tearoff_window()));
2954 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2955 &_mouse_mode_tearoff->tearoff_window(), 1));
2956 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2957 &_mouse_mode_tearoff->tearoff_window()));
2958 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2959 &_mouse_mode_tearoff->tearoff_window(), 1));
2963 _zoom_box.set_spacing (2);
2964 _zoom_box.set_border_width (2);
2968 zoom_preset_selector.set_name ("zoom button");
2969 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2970 zoom_preset_selector.set_size_request (42, -1);
2972 zoom_in_button.set_name ("zoom button");
2973 zoom_in_button.set_image(::get_icon ("zoom_in"));
2974 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2975 zoom_in_button.set_related_action (act);
2977 zoom_out_button.set_name ("zoom button");
2978 zoom_out_button.set_image(::get_icon ("zoom_out"));
2979 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2980 zoom_out_button.set_related_action (act);
2982 zoom_out_full_button.set_name ("zoom button");
2983 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2984 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2985 zoom_out_full_button.set_related_action (act);
2987 zoom_focus_selector.set_name ("zoom button");
2989 if (ARDOUR::Profile->get_mixbus()) {
2990 _zoom_box.pack_start (zoom_preset_selector, false, false);
2991 } else if (ARDOUR::Profile->get_trx()) {
2992 mode_box->pack_start (zoom_out_button, false, false);
2993 mode_box->pack_start (zoom_in_button, false, false);
2995 _zoom_box.pack_start (zoom_out_button, false, false);
2996 _zoom_box.pack_start (zoom_in_button, false, false);
2997 _zoom_box.pack_start (zoom_out_full_button, false, false);
2998 _zoom_box.pack_start (zoom_focus_selector, false, false);
3001 /* Track zoom buttons */
3002 visible_tracks_selector.set_name ("zoom button");
3003 if (Profile->get_mixbus()) {
3004 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3005 visible_tracks_selector.set_size_request (42, -1);
3007 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3010 tav_expand_button.set_name ("zoom button");
3011 tav_expand_button.set_image(::get_icon ("tav_exp"));
3012 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3013 tav_expand_button.set_related_action (act);
3015 tav_shrink_button.set_name ("zoom button");
3016 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
3017 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3018 tav_shrink_button.set_related_action (act);
3020 if (ARDOUR::Profile->get_mixbus()) {
3021 _zoom_box.pack_start (visible_tracks_selector);
3022 } else if (ARDOUR::Profile->get_trx()) {
3023 _zoom_box.pack_start (tav_shrink_button);
3024 _zoom_box.pack_start (tav_expand_button);
3026 _zoom_box.pack_start (visible_tracks_selector);
3027 _zoom_box.pack_start (tav_shrink_button);
3028 _zoom_box.pack_start (tav_expand_button);
3031 if (!ARDOUR::Profile->get_trx()) {
3032 _zoom_tearoff = manage (new TearOff (_zoom_box));
3034 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3035 &_zoom_tearoff->tearoff_window()));
3036 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3037 &_zoom_tearoff->tearoff_window(), 0));
3038 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3039 &_zoom_tearoff->tearoff_window()));
3040 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3041 &_zoom_tearoff->tearoff_window(), 0));
3044 if (Profile->get_sae() || Profile->get_mixbus() ) {
3045 _zoom_tearoff->set_can_be_torn_off (false);
3048 snap_box.set_spacing (2);
3049 snap_box.set_border_width (2);
3051 snap_type_selector.set_name ("mouse mode button");
3053 snap_mode_selector.set_name ("mouse mode button");
3055 edit_point_selector.set_name ("mouse mode button");
3057 snap_box.pack_start (snap_mode_selector, false, false);
3058 snap_box.pack_start (snap_type_selector, false, false);
3059 snap_box.pack_start (edit_point_selector, false, false);
3063 HBox *nudge_box = manage (new HBox);
3064 nudge_box->set_spacing (2);
3065 nudge_box->set_border_width (2);
3067 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3068 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3070 nudge_box->pack_start (nudge_backward_button, false, false);
3071 nudge_box->pack_start (nudge_forward_button, false, false);
3072 nudge_box->pack_start (*nudge_clock, false, false);
3075 /* Pack everything in... */
3077 HBox* hbox = manage (new HBox);
3078 hbox->set_spacing(2);
3080 _tools_tearoff = manage (new TearOff (*hbox));
3081 _tools_tearoff->set_name ("MouseModeBase");
3082 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3084 if (Profile->get_sae() || Profile->get_mixbus()) {
3085 _tools_tearoff->set_can_be_torn_off (false);
3088 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3089 &_tools_tearoff->tearoff_window()));
3090 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3091 &_tools_tearoff->tearoff_window(), 0));
3092 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3093 &_tools_tearoff->tearoff_window()));
3094 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3095 &_tools_tearoff->tearoff_window(), 0));
3097 toolbar_hbox.set_spacing (2);
3098 toolbar_hbox.set_border_width (1);
3100 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3101 if (!ARDOUR::Profile->get_trx()) {
3102 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3103 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3106 if (!ARDOUR::Profile->get_trx()) {
3107 hbox->pack_start (snap_box, false, false);
3108 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3109 hbox->pack_start (*nudge_box, false, false);
3111 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3114 hbox->pack_start (panic_box, false, false);
3118 toolbar_base.set_name ("ToolBarBase");
3119 toolbar_base.add (toolbar_hbox);
3121 _toolbar_viewport.add (toolbar_base);
3122 /* stick to the required height but allow width to vary if there's not enough room */
3123 _toolbar_viewport.set_size_request (1, -1);
3125 toolbar_frame.set_shadow_type (SHADOW_OUT);
3126 toolbar_frame.set_name ("BaseFrame");
3127 toolbar_frame.add (_toolbar_viewport);
3131 Editor::build_edit_point_menu ()
3133 using namespace Menu_Helpers;
3135 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3136 if(!Profile->get_mixbus())
3137 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3138 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3140 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3144 Editor::build_edit_mode_menu ()
3146 using namespace Menu_Helpers;
3148 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3149 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3150 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3151 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3153 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3157 Editor::build_snap_mode_menu ()
3159 using namespace Menu_Helpers;
3161 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3162 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3163 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3165 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3169 Editor::build_snap_type_menu ()
3171 using namespace Menu_Helpers;
3173 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3174 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3175 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3176 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3177 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3178 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3179 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3180 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3181 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3182 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3183 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3184 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3185 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3186 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3187 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3188 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3189 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3190 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3191 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3192 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3193 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3194 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3195 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3196 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3197 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3198 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3199 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3200 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3201 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3202 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3204 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3209 Editor::setup_tooltips ()
3211 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Grab mode)"));
3212 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Grab Mode (select/move objects)"));
3213 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split regions)"));
3214 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select time ranges)"));
3215 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3216 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3217 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3218 ARDOUR_UI::instance()->set_tip (mouse_content_button, _("Internal Edit Mode (edit notes and gain curves inside regions)"));
3219 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3220 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3221 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3222 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3223 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3224 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3225 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3226 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3227 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3228 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3229 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3230 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3231 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3232 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3233 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3234 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3238 Editor::convert_drop_to_paths (
3239 vector<string>& paths,
3240 const RefPtr<Gdk::DragContext>& /*context*/,
3243 const SelectionData& data,
3247 if (_session == 0) {
3251 vector<string> uris = data.get_uris();
3255 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3256 are actually URI lists. So do it by hand.
3259 if (data.get_target() != "text/plain") {
3263 /* Parse the "uri-list" format that Nautilus provides,
3264 where each pathname is delimited by \r\n.
3266 THERE MAY BE NO NULL TERMINATING CHAR!!!
3269 string txt = data.get_text();
3273 p = (char *) malloc (txt.length() + 1);
3274 txt.copy (p, txt.length(), 0);
3275 p[txt.length()] = '\0';
3281 while (g_ascii_isspace (*p))
3285 while (*q && (*q != '\n') && (*q != '\r')) {
3292 while (q > p && g_ascii_isspace (*q))
3297 uris.push_back (string (p, q - p + 1));
3301 p = strchr (p, '\n');
3313 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3314 if ((*i).substr (0,7) == "file://") {
3315 paths.push_back (Glib::filename_from_uri (*i));
3323 Editor::new_tempo_section ()
3328 Editor::map_transport_state ()
3330 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3332 if (_session && _session->transport_stopped()) {
3333 have_pending_keyboard_selection = false;
3336 update_loop_range_view ();
3342 Editor::begin_selection_op_history ()
3344 selection_op_cmd_depth = 0;
3345 selection_op_history_it = 0;
3347 while(!selection_op_history.empty()) {
3348 delete selection_op_history.front();
3349 selection_op_history.pop_front();
3352 selection_undo_action->set_sensitive (false);
3353 selection_redo_action->set_sensitive (false);
3354 selection_op_history.push_front (&_selection_memento->get_state ());
3358 Editor::begin_reversible_selection_op (string name)
3361 //cerr << name << endl;
3362 /* begin/commit pairs can be nested */
3363 selection_op_cmd_depth++;
3368 Editor::commit_reversible_selection_op ()
3371 if (selection_op_cmd_depth == 1) {
3373 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3375 The user has undone some selection ops and then made a new one,
3376 making anything earlier in the list invalid.
3379 list<XMLNode *>::iterator it = selection_op_history.begin();
3380 list<XMLNode *>::iterator e_it = it;
3381 advance (e_it, selection_op_history_it);
3383 for ( ; it != e_it; ++it) {
3386 selection_op_history.erase (selection_op_history.begin(), e_it);
3389 selection_op_history.push_front (&_selection_memento->get_state ());
3390 selection_op_history_it = 0;
3392 selection_undo_action->set_sensitive (true);
3393 selection_redo_action->set_sensitive (false);
3396 if (selection_op_cmd_depth > 0) {
3397 selection_op_cmd_depth--;
3403 Editor::undo_selection_op ()
3406 selection_op_history_it++;
3408 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3409 if (n == selection_op_history_it) {
3410 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3411 selection_redo_action->set_sensitive (true);
3415 /* is there an earlier entry? */
3416 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3417 selection_undo_action->set_sensitive (false);
3423 Editor::redo_selection_op ()
3426 if (selection_op_history_it > 0) {
3427 selection_op_history_it--;
3430 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3431 if (n == selection_op_history_it) {
3432 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3433 selection_undo_action->set_sensitive (true);
3438 if (selection_op_history_it == 0) {
3439 selection_redo_action->set_sensitive (false);
3445 Editor::begin_reversible_command (string name)
3448 before.push_back (&_selection_memento->get_state ());
3449 _session->begin_reversible_command (name);
3454 Editor::begin_reversible_command (GQuark q)
3457 before.push_back (&_selection_memento->get_state ());
3458 _session->begin_reversible_command (q);
3463 Editor::abort_reversible_command ()
3466 while(!before.empty()) {
3467 delete before.front();
3470 _session->abort_reversible_command ();
3475 Editor::commit_reversible_command ()
3478 if (before.size() == 1) {
3479 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3480 redo_action->set_sensitive(false);
3481 undo_action->set_sensitive(true);
3482 begin_selection_op_history ();
3485 if (before.empty()) {
3486 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3491 _session->commit_reversible_command ();
3496 Editor::history_changed ()
3500 if (undo_action && _session) {
3501 if (_session->undo_depth() == 0) {
3502 label = S_("Command|Undo");
3504 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3506 undo_action->property_label() = label;
3509 if (redo_action && _session) {
3510 if (_session->redo_depth() == 0) {
3513 label = string_compose(_("Redo (%1)"), _session->next_redo());
3515 redo_action->property_label() = label;
3520 Editor::duplicate_range (bool with_dialog)
3524 RegionSelection rs = get_regions_from_selection_and_entered ();
3526 if ( selection->time.length() == 0 && rs.empty()) {
3532 ArdourDialog win (_("Duplicate"));
3533 Label label (_("Number of duplications:"));
3534 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3535 SpinButton spinner (adjustment, 0.0, 1);
3538 win.get_vbox()->set_spacing (12);
3539 win.get_vbox()->pack_start (hbox);
3540 hbox.set_border_width (6);
3541 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3543 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3544 place, visually. so do this by hand.
3547 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3548 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3549 spinner.grab_focus();
3555 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3556 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3557 win.set_default_response (RESPONSE_ACCEPT);
3559 spinner.grab_focus ();
3561 switch (win.run ()) {
3562 case RESPONSE_ACCEPT:
3568 times = adjustment.get_value();
3571 if ((current_mouse_mode() == Editing::MouseRange)) {
3572 if (selection->time.length()) {
3573 duplicate_selection (times);
3575 } else if (get_smart_mode()) {
3576 if (selection->time.length()) {
3577 duplicate_selection (times);
3579 duplicate_some_regions (rs, times);
3581 duplicate_some_regions (rs, times);
3586 Editor::set_edit_mode (EditMode m)
3588 Config->set_edit_mode (m);
3592 Editor::cycle_edit_mode ()
3594 switch (Config->get_edit_mode()) {
3596 if (Profile->get_sae()) {
3597 Config->set_edit_mode (Lock);
3599 Config->set_edit_mode (Ripple);
3604 Config->set_edit_mode (Lock);
3607 Config->set_edit_mode (Slide);
3613 Editor::edit_mode_selection_done ( EditMode m )
3615 Config->set_edit_mode ( m );
3619 Editor::snap_type_selection_done (SnapType snaptype)
3621 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3623 ract->set_active ();
3628 Editor::snap_mode_selection_done (SnapMode mode)
3630 RefPtr<RadioAction> ract = snap_mode_action (mode);
3633 ract->set_active (true);
3638 Editor::cycle_edit_point (bool with_marker)
3640 if(Profile->get_mixbus())
3641 with_marker = false;
3643 switch (_edit_point) {
3645 set_edit_point_preference (EditAtPlayhead);
3647 case EditAtPlayhead:
3649 set_edit_point_preference (EditAtSelectedMarker);
3651 set_edit_point_preference (EditAtMouse);
3654 case EditAtSelectedMarker:
3655 set_edit_point_preference (EditAtMouse);
3661 Editor::edit_point_selection_done (EditPoint ep)
3663 set_edit_point_preference ( ep );
3667 Editor::build_zoom_focus_menu ()
3669 using namespace Menu_Helpers;
3671 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3672 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3673 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3674 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3675 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3676 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3678 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3682 Editor::zoom_focus_selection_done ( ZoomFocus f )
3684 RefPtr<RadioAction> ract = zoom_focus_action (f);
3686 ract->set_active ();
3691 Editor::build_track_count_menu ()
3693 using namespace Menu_Helpers;
3695 if (!Profile->get_mixbus()) {
3696 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3697 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3698 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3699 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3700 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3701 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3702 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3703 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3704 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3705 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3706 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3707 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3708 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3710 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3711 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3712 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3713 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3714 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3715 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3716 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3717 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3718 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3719 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3721 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3722 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3723 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3724 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3725 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3726 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3727 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3728 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3729 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3730 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3731 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3736 Editor::set_zoom_preset (int64_t ms)
3739 temporal_zoom_session();
3743 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3744 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3748 Editor::set_visible_track_count (int32_t n)
3750 _visible_track_count = n;
3752 /* if the canvas hasn't really been allocated any size yet, just
3753 record the desired number of visible tracks and return. when canvas
3754 allocation happens, we will get called again and then we can do the
3758 if (_visible_canvas_height <= 1) {
3764 DisplaySuspender ds;
3766 if (_visible_track_count > 0) {
3767 h = trackviews_height() / _visible_track_count;
3768 std::ostringstream s;
3769 s << _visible_track_count;
3771 } else if (_visible_track_count == 0) {
3773 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3774 if ((*i)->marked_for_display()) {
3778 h = trackviews_height() / n;
3781 /* negative value means that the visible track count has
3782 been overridden by explicit track height changes.
3784 visible_tracks_selector.set_text (X_("*"));
3788 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3789 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3792 if (str != visible_tracks_selector.get_text()) {
3793 visible_tracks_selector.set_text (str);
3798 Editor::override_visible_track_count ()
3800 _visible_track_count = -1;
3801 visible_tracks_selector.set_text ( _("*") );
3805 Editor::edit_controls_button_release (GdkEventButton* ev)
3807 if (Keyboard::is_context_menu_event (ev)) {
3808 ARDOUR_UI::instance()->add_route (this);
3809 } else if (ev->button == 1) {
3810 selection->clear_tracks ();
3817 Editor::mouse_select_button_release (GdkEventButton* ev)
3819 /* this handles just right-clicks */
3821 if (ev->button != 3) {
3829 Editor::set_zoom_focus (ZoomFocus f)
3831 string str = zoom_focus_strings[(int)f];
3833 if (str != zoom_focus_selector.get_text()) {
3834 zoom_focus_selector.set_text (str);
3837 if (zoom_focus != f) {
3844 Editor::cycle_zoom_focus ()
3846 switch (zoom_focus) {
3848 set_zoom_focus (ZoomFocusRight);
3850 case ZoomFocusRight:
3851 set_zoom_focus (ZoomFocusCenter);
3853 case ZoomFocusCenter:
3854 set_zoom_focus (ZoomFocusPlayhead);
3856 case ZoomFocusPlayhead:
3857 set_zoom_focus (ZoomFocusMouse);
3859 case ZoomFocusMouse:
3860 set_zoom_focus (ZoomFocusEdit);
3863 set_zoom_focus (ZoomFocusLeft);
3869 Editor::ensure_float (Window& win)
3871 win.set_transient_for (*this);
3875 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3877 /* recover or initialize pane positions. do this here rather than earlier because
3878 we don't want the positions to change the child allocations, which they seem to do.
3884 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3893 XMLNode* geometry = find_named_node (*node, "geometry");
3895 if (which == static_cast<Paned*> (&edit_pane)) {
3897 if (done & Horizontal) {
3901 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3902 _notebook_shrunk = string_is_affirmative (prop->value ());
3905 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3906 /* initial allocation is 90% to canvas, 10% to notebook */
3907 pos = (int) floor (alloc.get_width() * 0.90f);
3908 snprintf (buf, sizeof(buf), "%d", pos);
3910 pos = atoi (prop->value());
3913 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3914 edit_pane.set_position (pos);
3917 done = (Pane) (done | Horizontal);
3919 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3921 if (done & Vertical) {
3925 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3926 /* initial allocation is 90% to canvas, 10% to summary */
3927 pos = (int) floor (alloc.get_height() * 0.90f);
3928 snprintf (buf, sizeof(buf), "%d", pos);
3931 pos = atoi (prop->value());
3934 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3935 editor_summary_pane.set_position (pos);
3938 done = (Pane) (done | Vertical);
3943 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3945 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3946 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3947 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3948 top_hbox.remove (toolbar_frame);
3953 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3955 if (toolbar_frame.get_parent() == 0) {
3956 top_hbox.pack_end (toolbar_frame);
3961 Editor::set_show_measures (bool yn)
3963 if (_show_measures != yn) {
3966 if ((_show_measures = yn) == true) {
3968 tempo_lines->show();
3971 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3972 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3974 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3975 draw_measures (begin, end);
3983 Editor::toggle_follow_playhead ()
3985 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3987 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3988 set_follow_playhead (tact->get_active());
3992 /** @param yn true to follow playhead, otherwise false.
3993 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3996 Editor::set_follow_playhead (bool yn, bool catch_up)
3998 if (_follow_playhead != yn) {
3999 if ((_follow_playhead = yn) == true && catch_up) {
4001 reset_x_origin_to_follow_playhead ();
4008 Editor::toggle_stationary_playhead ()
4010 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4012 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4013 set_stationary_playhead (tact->get_active());
4018 Editor::set_stationary_playhead (bool yn)
4020 if (_stationary_playhead != yn) {
4021 if ((_stationary_playhead = yn) == true) {
4023 // FIXME need a 3.0 equivalent of this 2.X call
4024 // update_current_screen ();
4031 Editor::playlist_selector () const
4033 return *_playlist_selector;
4037 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4039 if (paste_count == 0) {
4040 /* don't bother calculating an offset that will be zero anyway */
4044 /* calculate basic unsnapped multi-paste offset */
4045 framecnt_t offset = paste_count * duration;
4047 /* snap offset so pos + offset is aligned to the grid */
4048 framepos_t offset_pos = pos + offset;
4049 snap_to(offset_pos, RoundUpMaybe);
4050 offset = offset_pos - pos;
4056 Editor::get_grid_beat_divisions(framepos_t position)
4058 switch (_snap_type) {
4059 case SnapToBeatDiv128: return 128;
4060 case SnapToBeatDiv64: return 64;
4061 case SnapToBeatDiv32: return 32;
4062 case SnapToBeatDiv28: return 28;
4063 case SnapToBeatDiv24: return 24;
4064 case SnapToBeatDiv20: return 20;
4065 case SnapToBeatDiv16: return 16;
4066 case SnapToBeatDiv14: return 14;
4067 case SnapToBeatDiv12: return 12;
4068 case SnapToBeatDiv10: return 10;
4069 case SnapToBeatDiv8: return 8;
4070 case SnapToBeatDiv7: return 7;
4071 case SnapToBeatDiv6: return 6;
4072 case SnapToBeatDiv5: return 5;
4073 case SnapToBeatDiv4: return 4;
4074 case SnapToBeatDiv3: return 3;
4075 case SnapToBeatDiv2: return 2;
4082 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4086 const unsigned divisions = get_grid_beat_divisions(position);
4088 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4091 switch (_snap_type) {
4093 return Evoral::Beats(1.0);
4096 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
4104 return Evoral::Beats();
4108 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4112 ret = nudge_clock->current_duration (pos);
4113 next = ret + 1; /* XXXX fix me */
4119 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4121 ArdourDialog dialog (_("Playlist Deletion"));
4122 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4123 "If it is kept, its audio files will not be cleaned.\n"
4124 "If it is deleted, audio files used by it alone will be cleaned."),
4127 dialog.set_position (WIN_POS_CENTER);
4128 dialog.get_vbox()->pack_start (label);
4132 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4133 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4134 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4136 switch (dialog.run ()) {
4137 case RESPONSE_ACCEPT:
4138 /* delete the playlist */
4142 case RESPONSE_REJECT:
4143 /* keep the playlist */
4155 Editor::audio_region_selection_covers (framepos_t where)
4157 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4158 if ((*a)->region()->covers (where)) {
4167 Editor::prepare_for_cleanup ()
4169 cut_buffer->clear_regions ();
4170 cut_buffer->clear_playlists ();
4172 selection->clear_regions ();
4173 selection->clear_playlists ();
4175 _regions->suspend_redisplay ();
4179 Editor::finish_cleanup ()
4181 _regions->resume_redisplay ();
4185 Editor::transport_loop_location()
4188 return _session->locations()->auto_loop_location();
4195 Editor::transport_punch_location()
4198 return _session->locations()->auto_punch_location();
4205 Editor::control_layout_scroll (GdkEventScroll* ev)
4207 /* Just forward to the normal canvas scroll method. The coordinate
4208 systems are different but since the canvas is always larger than the
4209 track headers, and aligned with the trackview area, this will work.
4211 In the not too distant future this layout is going away anyway and
4212 headers will be on the canvas.
4214 return canvas_scroll_event (ev, false);
4218 Editor::session_state_saved (string)
4221 _snapshots->redisplay ();
4225 Editor::update_tearoff_visibility()
4227 bool visible = ARDOUR_UI::config()->get_keep_tearoffs();
4228 _mouse_mode_tearoff->set_visible (visible);
4229 _tools_tearoff->set_visible (visible);
4230 if (_zoom_tearoff) {
4231 _zoom_tearoff->set_visible (visible);
4236 Editor::reattach_all_tearoffs ()
4238 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4239 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4240 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4244 Editor::maximise_editing_space ()
4256 Editor::restore_editing_space ()
4268 * Make new playlists for a given track and also any others that belong
4269 * to the same active route group with the `select' property.
4274 Editor::new_playlists (TimeAxisView* v)
4276 begin_reversible_command (_("new playlists"));
4277 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4278 _session->playlists->get (playlists);
4279 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4280 commit_reversible_command ();
4284 * Use a copy of the current playlist for a given track and also any others that belong
4285 * to the same active route group with the `select' property.
4290 Editor::copy_playlists (TimeAxisView* v)
4292 begin_reversible_command (_("copy playlists"));
4293 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4294 _session->playlists->get (playlists);
4295 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4296 commit_reversible_command ();
4299 /** Clear the current playlist for a given track and also any others that belong
4300 * to the same active route group with the `select' property.
4305 Editor::clear_playlists (TimeAxisView* v)
4307 begin_reversible_command (_("clear playlists"));
4308 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4309 _session->playlists->get (playlists);
4310 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4311 commit_reversible_command ();
4315 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4317 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4321 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4323 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4327 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4329 atv.clear_playlist ();
4333 Editor::on_key_press_event (GdkEventKey* ev)
4335 return key_press_focus_accelerator_handler (*this, ev);
4339 Editor::on_key_release_event (GdkEventKey* ev)
4341 return Gtk::Window::on_key_release_event (ev);
4342 // return key_press_focus_accelerator_handler (*this, ev);
4346 Editor::get_y_origin () const
4348 return vertical_adjustment.get_value ();
4351 /** Queue up a change to the viewport x origin.
4352 * @param frame New x origin.
4355 Editor::reset_x_origin (framepos_t frame)
4357 pending_visual_change.add (VisualChange::TimeOrigin);
4358 pending_visual_change.time_origin = frame;
4359 ensure_visual_change_idle_handler ();
4363 Editor::reset_y_origin (double y)
4365 pending_visual_change.add (VisualChange::YOrigin);
4366 pending_visual_change.y_origin = y;
4367 ensure_visual_change_idle_handler ();
4371 Editor::reset_zoom (framecnt_t spp)
4373 if (spp == samples_per_pixel) {
4377 pending_visual_change.add (VisualChange::ZoomLevel);
4378 pending_visual_change.samples_per_pixel = spp;
4379 ensure_visual_change_idle_handler ();
4383 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4385 reset_x_origin (frame);
4388 if (!no_save_visual) {
4389 undo_visual_stack.push_back (current_visual_state(false));
4393 Editor::VisualState::VisualState (bool with_tracks)
4394 : gui_state (with_tracks ? new GUIObjectState : 0)
4398 Editor::VisualState::~VisualState ()
4403 Editor::VisualState*
4404 Editor::current_visual_state (bool with_tracks)
4406 VisualState* vs = new VisualState (with_tracks);
4407 vs->y_position = vertical_adjustment.get_value();
4408 vs->samples_per_pixel = samples_per_pixel;
4409 vs->leftmost_frame = leftmost_frame;
4410 vs->zoom_focus = zoom_focus;
4413 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4420 Editor::undo_visual_state ()
4422 if (undo_visual_stack.empty()) {
4426 VisualState* vs = undo_visual_stack.back();
4427 undo_visual_stack.pop_back();
4430 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4433 use_visual_state (*vs);
4438 Editor::redo_visual_state ()
4440 if (redo_visual_stack.empty()) {
4444 VisualState* vs = redo_visual_stack.back();
4445 redo_visual_stack.pop_back();
4447 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4448 // why do we check here?
4449 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4452 use_visual_state (*vs);
4457 Editor::swap_visual_state ()
4459 if (undo_visual_stack.empty()) {
4460 redo_visual_state ();
4462 undo_visual_state ();
4467 Editor::use_visual_state (VisualState& vs)
4469 PBD::Unwinder<bool> nsv (no_save_visual, true);
4470 DisplaySuspender ds;
4472 vertical_adjustment.set_value (vs.y_position);
4474 set_zoom_focus (vs.zoom_focus);
4475 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4478 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4480 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4481 (*i)->clear_property_cache();
4482 (*i)->reset_visual_state ();
4486 _routes->update_visibility ();
4489 /** This is the core function that controls the zoom level of the canvas. It is called
4490 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4491 * @param spp new number of samples per pixel
4494 Editor::set_samples_per_pixel (framecnt_t spp)
4500 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4501 const framecnt_t lots_of_pixels = 4000;
4503 /* if the zoom level is greater than what you'd get trying to display 3
4504 * days of audio on a really big screen, then it's too big.
4507 if (spp * lots_of_pixels > three_days) {
4511 samples_per_pixel = spp;
4514 tempo_lines->tempo_map_changed();
4517 bool const showing_time_selection = selection->time.length() > 0;
4519 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4520 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4521 (*i)->reshow_selection (selection->time);
4525 ZoomChanged (); /* EMIT_SIGNAL */
4527 ArdourCanvas::GtkCanvasViewport* c;
4529 c = get_track_canvas();
4531 c->canvas()->zoomed ();
4534 if (playhead_cursor) {
4535 playhead_cursor->set_position (playhead_cursor->current_frame ());
4538 refresh_location_display();
4539 _summary->set_overlays_dirty ();
4541 update_marker_labels ();
4547 Editor::queue_visual_videotimeline_update ()
4550 * pending_visual_change.add (VisualChange::VideoTimeline);
4551 * or maybe even more specific: which videotimeline-image
4552 * currently it calls update_video_timeline() to update
4553 * _all outdated_ images on the video-timeline.
4554 * see 'exposeimg()' in video_image_frame.cc
4556 ensure_visual_change_idle_handler ();
4560 Editor::ensure_visual_change_idle_handler ()
4562 if (pending_visual_change.idle_handler_id < 0) {
4563 // see comment in add_to_idle_resize above.
4564 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4565 pending_visual_change.being_handled = false;
4570 Editor::_idle_visual_changer (void* arg)
4572 return static_cast<Editor*>(arg)->idle_visual_changer ();
4576 Editor::idle_visual_changer ()
4578 /* set_horizontal_position() below (and maybe other calls) call
4579 gtk_main_iteration(), so it's possible that a signal will be handled
4580 half-way through this method. If this signal wants an
4581 idle_visual_changer we must schedule another one after this one, so
4582 mark the idle_handler_id as -1 here to allow that. Also make a note
4583 that we are doing the visual change, so that changes in response to
4584 super-rapid-screen-update can be dropped if we are still processing
4588 pending_visual_change.idle_handler_id = -1;
4589 pending_visual_change.being_handled = true;
4591 VisualChange vc = pending_visual_change;
4593 pending_visual_change.pending = (VisualChange::Type) 0;
4595 visual_changer (vc);
4597 pending_visual_change.being_handled = false;
4599 return 0; /* this is always a one-shot call */
4603 Editor::visual_changer (const VisualChange& vc)
4605 double const last_time_origin = horizontal_position ();
4607 if (vc.pending & VisualChange::ZoomLevel) {
4608 set_samples_per_pixel (vc.samples_per_pixel);
4610 compute_fixed_ruler_scale ();
4612 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4613 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4615 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4616 current_bbt_points_begin, current_bbt_points_end);
4617 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4618 current_bbt_points_begin, current_bbt_points_end);
4619 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4621 update_video_timeline();
4624 if (vc.pending & VisualChange::TimeOrigin) {
4625 set_horizontal_position (vc.time_origin / samples_per_pixel);
4628 if (vc.pending & VisualChange::YOrigin) {
4629 vertical_adjustment.set_value (vc.y_origin);
4632 if (last_time_origin == horizontal_position ()) {
4633 /* changed signal not emitted */
4634 update_fixed_rulers ();
4635 redisplay_tempo (true);
4638 if (!(vc.pending & VisualChange::ZoomLevel)) {
4639 update_video_timeline();
4642 _summary->set_overlays_dirty ();
4645 struct EditorOrderTimeAxisSorter {
4646 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4647 return a->order () < b->order ();
4652 Editor::sort_track_selection (TrackViewList& sel)
4654 EditorOrderTimeAxisSorter cmp;
4659 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4662 framepos_t where = 0;
4663 EditPoint ep = _edit_point;
4665 if (Profile->get_mixbus())
4666 if (ep == EditAtSelectedMarker)
4667 ep = EditAtPlayhead;
4669 if (from_outside_canvas && (ep == EditAtMouse)) {
4670 ep = EditAtPlayhead;
4671 } else if (from_context_menu && (ep == EditAtMouse)) {
4672 return canvas_event_sample (&context_click_event, 0, 0);
4675 if (entered_marker) {
4676 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4677 return entered_marker->position();
4680 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4681 ep = EditAtSelectedMarker;
4684 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4685 ep = EditAtPlayhead;
4689 case EditAtPlayhead:
4690 if (_dragging_playhead) {
4691 if (!mouse_frame (where, ignored)) {
4692 /* XXX not right but what can we do ? */
4696 where = _session->audible_frame();
4698 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4701 case EditAtSelectedMarker:
4702 if (!selection->markers.empty()) {
4704 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4707 where = loc->start();
4711 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4719 if (!mouse_frame (where, ignored)) {
4720 /* XXX not right but what can we do ? */
4724 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4732 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4734 if (!_session) return;
4736 begin_reversible_command (cmd);
4740 if ((tll = transport_loop_location()) == 0) {
4741 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4742 XMLNode &before = _session->locations()->get_state();
4743 _session->locations()->add (loc, true);
4744 _session->set_auto_loop_location (loc);
4745 XMLNode &after = _session->locations()->get_state();
4746 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4748 XMLNode &before = tll->get_state();
4749 tll->set_hidden (false, this);
4750 tll->set (start, end);
4751 XMLNode &after = tll->get_state();
4752 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4755 commit_reversible_command ();
4759 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4761 if (!_session) return;
4763 begin_reversible_command (cmd);
4767 if ((tpl = transport_punch_location()) == 0) {
4768 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4769 XMLNode &before = _session->locations()->get_state();
4770 _session->locations()->add (loc, true);
4771 _session->set_auto_punch_location (loc);
4772 XMLNode &after = _session->locations()->get_state();
4773 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4775 XMLNode &before = tpl->get_state();
4776 tpl->set_hidden (false, this);
4777 tpl->set (start, end);
4778 XMLNode &after = tpl->get_state();
4779 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4782 commit_reversible_command ();
4785 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4786 * @param rs List to which found regions are added.
4787 * @param where Time to look at.
4788 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4791 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4793 const TrackViewList* tracks;
4796 tracks = &track_views;
4801 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4803 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4806 boost::shared_ptr<Track> tr;
4807 boost::shared_ptr<Playlist> pl;
4809 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4811 boost::shared_ptr<RegionList> regions = pl->regions_at (
4812 (framepos_t) floor ( (double) where * tr->speed()));
4814 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4815 RegionView* rv = rtv->view()->find_view (*i);
4826 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4828 const TrackViewList* tracks;
4831 tracks = &track_views;
4836 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4837 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4839 boost::shared_ptr<Track> tr;
4840 boost::shared_ptr<Playlist> pl;
4842 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4844 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4845 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4847 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4849 RegionView* rv = rtv->view()->find_view (*i);
4860 /** Get regions using the following method:
4862 * Make a region list using:
4863 * (a) any selected regions
4864 * (b) the intersection of any selected tracks and the edit point(*)
4865 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4867 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4869 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4873 Editor::get_regions_from_selection_and_edit_point ()
4875 RegionSelection regions;
4877 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4878 regions.add (entered_regionview);
4880 regions = selection->regions;
4883 if ( regions.empty() ) {
4884 TrackViewList tracks = selection->tracks;
4886 if (!tracks.empty()) {
4887 /* no region selected or entered, but some selected tracks:
4888 * act on all regions on the selected tracks at the edit point
4890 framepos_t const where = get_preferred_edit_position ();
4891 get_regions_at(regions, where, tracks);
4898 /** Get regions using the following method:
4900 * Make a region list using:
4901 * (a) any selected regions
4902 * (b) the intersection of any selected tracks and the edit point(*)
4903 * (c) if neither exists, then whatever region is under the mouse
4905 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4907 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4910 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4912 RegionSelection regions;
4914 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4915 regions.add (entered_regionview);
4917 regions = selection->regions;
4920 if ( regions.empty() ) {
4921 TrackViewList tracks = selection->tracks;
4923 if (!tracks.empty()) {
4924 /* no region selected or entered, but some selected tracks:
4925 * act on all regions on the selected tracks at the edit point
4927 get_regions_at(regions, pos, tracks);
4934 /** Start with regions that are selected, or the entered regionview if none are selected.
4935 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4936 * of the regions that we started with.
4940 Editor::get_regions_from_selection_and_entered ()
4942 RegionSelection regions = selection->regions;
4944 if (regions.empty() && entered_regionview) {
4945 regions.add (entered_regionview);
4952 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4954 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4955 RouteTimeAxisView* rtav;
4957 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4958 boost::shared_ptr<Playlist> pl;
4959 std::vector<boost::shared_ptr<Region> > results;
4960 boost::shared_ptr<Track> tr;
4962 if ((tr = rtav->track()) == 0) {
4967 if ((pl = (tr->playlist())) != 0) {
4968 boost::shared_ptr<Region> r = pl->region_by_id (id);
4970 RegionView* rv = rtav->view()->find_view (r);
4972 regions.push_back (rv);
4981 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4984 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4985 MidiTimeAxisView* mtav;
4987 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4989 mtav->get_per_region_note_selection (selection);
4996 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4998 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5000 RouteTimeAxisView* tatv;
5002 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5004 boost::shared_ptr<Playlist> pl;
5005 vector<boost::shared_ptr<Region> > results;
5007 boost::shared_ptr<Track> tr;
5009 if ((tr = tatv->track()) == 0) {
5014 if ((pl = (tr->playlist())) != 0) {
5015 if (src_comparison) {
5016 pl->get_source_equivalent_regions (region, results);
5018 pl->get_region_list_equivalent_regions (region, results);
5022 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5023 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5024 regions.push_back (marv);
5033 Editor::show_rhythm_ferret ()
5035 if (rhythm_ferret == 0) {
5036 rhythm_ferret = new RhythmFerret(*this);
5039 rhythm_ferret->set_session (_session);
5040 rhythm_ferret->show ();
5041 rhythm_ferret->present ();
5045 Editor::first_idle ()
5047 MessageDialog* dialog = 0;
5049 if (track_views.size() > 1) {
5050 dialog = new MessageDialog (
5052 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5056 ARDOUR_UI::instance()->flush_pending ();
5059 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5063 // first idle adds route children (automation tracks), so we need to redisplay here
5064 _routes->redisplay ();
5068 if (_session->undo_depth() == 0) {
5069 undo_action->set_sensitive(false);
5071 redo_action->set_sensitive(false);
5072 begin_selection_op_history ();
5078 Editor::_idle_resize (gpointer arg)
5080 return ((Editor*)arg)->idle_resize ();
5084 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5086 if (resize_idle_id < 0) {
5087 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5088 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5089 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5091 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5092 _pending_resize_amount = 0;
5095 /* make a note of the smallest resulting height, so that we can clamp the
5096 lower limit at TimeAxisView::hSmall */
5098 int32_t min_resulting = INT32_MAX;
5100 _pending_resize_amount += h;
5101 _pending_resize_view = view;
5103 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5105 if (selection->tracks.contains (_pending_resize_view)) {
5106 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5107 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5111 if (min_resulting < 0) {
5116 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5117 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5121 /** Handle pending resizing of tracks */
5123 Editor::idle_resize ()
5125 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5127 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5128 selection->tracks.contains (_pending_resize_view)) {
5130 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5131 if (*i != _pending_resize_view) {
5132 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5137 _pending_resize_amount = 0;
5138 _group_tabs->set_dirty ();
5139 resize_idle_id = -1;
5147 ENSURE_GUI_THREAD (*this, &Editor::located);
5150 playhead_cursor->set_position (_session->audible_frame ());
5151 if (_follow_playhead && !_pending_initial_locate) {
5152 reset_x_origin_to_follow_playhead ();
5156 _pending_locate_request = false;
5157 _pending_initial_locate = false;
5161 Editor::region_view_added (RegionView * rv)
5163 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5164 if (rv->region ()->id () == (*pr)) {
5165 selection->add (rv);
5166 selection->regions.pending.erase (pr);
5171 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5173 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5174 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5175 if (rv->region()->id () == (*rnote).first) {
5176 mrv->select_notes ((*rnote).second);
5177 selection->pending_midi_note_selection.erase(rnote);
5183 _summary->set_background_dirty ();
5187 Editor::region_view_removed ()
5189 _summary->set_background_dirty ();
5193 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5195 TrackViewList::const_iterator j = track_views.begin ();
5196 while (j != track_views.end()) {
5197 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5198 if (rtv && rtv->route() == r) {
5209 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5213 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5214 TimeAxisView* tv = axis_view_from_route (*i);
5224 Editor::suspend_route_redisplay ()
5227 _routes->suspend_redisplay();
5232 Editor::resume_route_redisplay ()
5235 _routes->resume_redisplay();
5240 Editor::add_routes (RouteList& routes)
5242 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5244 RouteTimeAxisView *rtv;
5245 list<RouteTimeAxisView*> new_views;
5246 TrackViewList new_selection;
5247 bool from_scratch = (track_views.size() == 0);
5249 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5250 boost::shared_ptr<Route> route = (*x);
5252 if (route->is_auditioner() || route->is_monitor()) {
5256 DataType dt = route->input()->default_type();
5258 if (dt == ARDOUR::DataType::AUDIO) {
5259 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5260 rtv->set_route (route);
5261 } else if (dt == ARDOUR::DataType::MIDI) {
5262 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5263 rtv->set_route (route);
5265 throw unknown_type();
5268 new_views.push_back (rtv);
5269 track_views.push_back (rtv);
5270 new_selection.push_back (rtv);
5272 rtv->effective_gain_display ();
5274 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5275 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5278 if (new_views.size() > 0) {
5279 _routes->routes_added (new_views);
5280 _summary->routes_added (new_views);
5283 if (!from_scratch) {
5284 selection->tracks.clear();
5285 selection->add (new_selection);
5286 begin_selection_op_history();
5289 if (show_editor_mixer_when_tracks_arrive) {
5290 show_editor_mixer (true);
5293 editor_list_button.set_sensitive (true);
5297 Editor::timeaxisview_deleted (TimeAxisView *tv)
5299 if (tv == entered_track) {
5303 if (_session && _session->deletion_in_progress()) {
5304 /* the situation is under control */
5308 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5310 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5312 _routes->route_removed (tv);
5314 TimeAxisView::Children c = tv->get_child_list ();
5315 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5316 if (entered_track == i->get()) {
5321 /* remove it from the list of track views */
5323 TrackViewList::iterator i;
5325 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5326 i = track_views.erase (i);
5329 /* update whatever the current mixer strip is displaying, if revelant */
5331 boost::shared_ptr<Route> route;
5334 route = rtav->route ();
5337 if (current_mixer_strip && current_mixer_strip->route() == route) {
5339 TimeAxisView* next_tv;
5341 if (track_views.empty()) {
5343 } else if (i == track_views.end()) {
5344 next_tv = track_views.front();
5351 set_selected_mixer_strip (*next_tv);
5353 /* make the editor mixer strip go away setting the
5354 * button to inactive (which also unticks the menu option)
5357 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5363 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5365 if (apply_to_selection) {
5366 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5368 TrackSelection::iterator j = i;
5371 hide_track_in_display (*i, false);
5376 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5378 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5379 // this will hide the mixer strip
5380 set_selected_mixer_strip (*tv);
5383 _routes->hide_track_in_display (*tv);
5388 Editor::sync_track_view_list_and_routes ()
5390 track_views = TrackViewList (_routes->views ());
5392 _summary->set_dirty ();
5393 _group_tabs->set_dirty ();
5395 return false; // do not call again (until needed)
5399 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5401 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5406 /** Find a RouteTimeAxisView by the ID of its route */
5408 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5410 RouteTimeAxisView* v;
5412 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5413 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5414 if(v->route()->id() == id) {
5424 Editor::fit_route_group (RouteGroup *g)
5426 TrackViewList ts = axis_views_from_routes (g->route_list ());
5431 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5433 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5436 _session->cancel_audition ();
5440 if (_session->is_auditioning()) {
5441 _session->cancel_audition ();
5442 if (r == last_audition_region) {
5447 _session->audition_region (r);
5448 last_audition_region = r;
5453 Editor::hide_a_region (boost::shared_ptr<Region> r)
5455 r->set_hidden (true);
5459 Editor::show_a_region (boost::shared_ptr<Region> r)
5461 r->set_hidden (false);
5465 Editor::audition_region_from_region_list ()
5467 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5471 Editor::hide_region_from_region_list ()
5473 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5477 Editor::show_region_in_region_list ()
5479 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5483 Editor::step_edit_status_change (bool yn)
5486 start_step_editing ();
5488 stop_step_editing ();
5493 Editor::start_step_editing ()
5495 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5499 Editor::stop_step_editing ()
5501 step_edit_connection.disconnect ();
5505 Editor::check_step_edit ()
5507 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5508 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5510 mtv->check_step_edit ();
5514 return true; // do it again, till we stop
5518 Editor::scroll_press (Direction dir)
5520 ++_scroll_callbacks;
5522 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5523 /* delay the first auto-repeat */
5529 scroll_backward (1);
5537 scroll_up_one_track ();
5541 scroll_down_one_track ();
5545 /* do hacky auto-repeat */
5546 if (!_scroll_connection.connected ()) {
5548 _scroll_connection = Glib::signal_timeout().connect (
5549 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5552 _scroll_callbacks = 0;
5559 Editor::scroll_release ()
5561 _scroll_connection.disconnect ();
5564 /** Queue a change for the Editor viewport x origin to follow the playhead */
5566 Editor::reset_x_origin_to_follow_playhead ()
5568 framepos_t const frame = playhead_cursor->current_frame ();
5570 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5572 if (_session->transport_speed() < 0) {
5574 if (frame > (current_page_samples() / 2)) {
5575 center_screen (frame-(current_page_samples()/2));
5577 center_screen (current_page_samples()/2);
5584 if (frame < leftmost_frame) {
5586 if (_session->transport_rolling()) {
5587 /* rolling; end up with the playhead at the right of the page */
5588 l = frame - current_page_samples ();
5590 /* not rolling: end up with the playhead 1/4 of the way along the page */
5591 l = frame - current_page_samples() / 4;
5595 if (_session->transport_rolling()) {
5596 /* rolling: end up with the playhead on the left of the page */
5599 /* not rolling: end up with the playhead 3/4 of the way along the page */
5600 l = frame - 3 * current_page_samples() / 4;
5608 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5614 Editor::super_rapid_screen_update ()
5616 if (!_session || !_session->engine().running()) {
5620 /* METERING / MIXER STRIPS */
5622 /* update track meters, if required */
5623 if (is_mapped() && meters_running) {
5624 RouteTimeAxisView* rtv;
5625 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5626 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5627 rtv->fast_update ();
5632 /* and any current mixer strip */
5633 if (current_mixer_strip) {
5634 current_mixer_strip->fast_update ();
5637 /* PLAYHEAD AND VIEWPORT */
5639 framepos_t const frame = _session->audible_frame();
5641 /* There are a few reasons why we might not update the playhead / viewport stuff:
5643 * 1. we don't update things when there's a pending locate request, otherwise
5644 * when the editor requests a locate there is a chance that this method
5645 * will move the playhead before the locate request is processed, causing
5647 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5648 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5651 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5653 last_update_frame = frame;
5655 if (!_dragging_playhead) {
5656 playhead_cursor->set_position (frame);
5659 if (!_stationary_playhead) {
5661 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5662 /* We only do this if we aren't already
5663 handling a visual change (ie if
5664 pending_visual_change.being_handled is
5665 false) so that these requests don't stack
5666 up there are too many of them to handle in
5669 reset_x_origin_to_follow_playhead ();
5674 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5678 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5679 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5680 if (target <= 0.0) {
5683 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5684 target = (target * 0.15) + (current * 0.85);
5690 set_horizontal_position (current);
5699 Editor::session_going_away ()
5701 _have_idled = false;
5703 _session_connections.drop_connections ();
5705 super_rapid_screen_update_connection.disconnect ();
5707 selection->clear ();
5708 cut_buffer->clear ();
5710 clicked_regionview = 0;
5711 clicked_axisview = 0;
5712 clicked_routeview = 0;
5713 entered_regionview = 0;
5715 last_update_frame = 0;
5718 playhead_cursor->hide ();
5720 /* rip everything out of the list displays */
5724 _route_groups->clear ();
5726 /* do this first so that deleting a track doesn't reset cms to null
5727 and thus cause a leak.
5730 if (current_mixer_strip) {
5731 if (current_mixer_strip->get_parent() != 0) {
5732 global_hpacker.remove (*current_mixer_strip);
5734 delete current_mixer_strip;
5735 current_mixer_strip = 0;
5738 /* delete all trackviews */
5740 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5743 track_views.clear ();
5745 nudge_clock->set_session (0);
5747 editor_list_button.set_active(false);
5748 editor_list_button.set_sensitive(false);
5750 /* clear tempo/meter rulers */
5751 remove_metric_marks ();
5753 clear_marker_display ();
5755 stop_step_editing ();
5757 /* get rid of any existing editor mixer strip */
5759 WindowTitle title(Glib::get_application_name());
5760 title += _("Editor");
5762 set_title (title.get_string());
5764 SessionHandlePtr::session_going_away ();
5769 Editor::show_editor_list (bool yn)
5772 _the_notebook.show ();
5774 _the_notebook.hide ();
5779 Editor::change_region_layering_order (bool from_context_menu)
5781 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5783 if (!clicked_routeview) {
5784 if (layering_order_editor) {
5785 layering_order_editor->hide ();
5790 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5796 boost::shared_ptr<Playlist> pl = track->playlist();
5802 if (layering_order_editor == 0) {
5803 layering_order_editor = new RegionLayeringOrderEditor (*this);
5806 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5807 layering_order_editor->maybe_present ();
5811 Editor::update_region_layering_order_editor ()
5813 if (layering_order_editor && layering_order_editor->is_visible ()) {
5814 change_region_layering_order (true);
5819 Editor::setup_fade_images ()
5821 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5822 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5823 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5824 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5825 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5827 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5828 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5829 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5830 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5831 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5833 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5834 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5835 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5836 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5837 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5839 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5840 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5841 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5842 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5843 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5847 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5849 Editor::action_menu_item (std::string const & name)
5851 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5854 return *manage (a->create_menu_item ());
5858 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5860 EventBox* b = manage (new EventBox);
5861 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5862 Label* l = manage (new Label (name));
5866 _the_notebook.append_page (widget, *b);
5870 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5872 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5873 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5876 if (ev->type == GDK_2BUTTON_PRESS) {
5878 /* double-click on a notebook tab shrinks or expands the notebook */
5880 if (_notebook_shrunk) {
5881 if (pre_notebook_shrink_pane_width) {
5882 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5884 _notebook_shrunk = false;
5886 pre_notebook_shrink_pane_width = edit_pane.get_position();
5888 /* this expands the LHS of the edit pane to cover the notebook
5889 PAGE but leaves the tabs visible.
5891 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5892 _notebook_shrunk = true;
5900 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5902 using namespace Menu_Helpers;
5904 MenuList& items = _control_point_context_menu.items ();
5907 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5908 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5909 if (!can_remove_control_point (item)) {
5910 items.back().set_sensitive (false);
5913 _control_point_context_menu.popup (event->button.button, event->button.time);
5917 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5919 using namespace Menu_Helpers;
5921 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5926 /* We need to get the selection here and pass it to the operations, since
5927 popping up the menu will cause a region leave event which clears
5928 entered_regionview. */
5930 MidiRegionView& mrv = note->region_view();
5931 const RegionSelection rs = get_regions_from_selection_and_entered ();
5933 MenuList& items = _note_context_menu.items();
5936 items.push_back(MenuElem(_("Delete"),
5937 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5938 items.push_back(MenuElem(_("Edit..."),
5939 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5940 items.push_back(MenuElem(_("Legatize"),
5941 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5942 items.push_back(MenuElem(_("Quantize..."),
5943 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5944 items.push_back(MenuElem(_("Remove Overlap"),
5945 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5946 items.push_back(MenuElem(_("Transform..."),
5947 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5949 _note_context_menu.popup (event->button.button, event->button.time);
5953 Editor::zoom_vertical_modifier_released()
5955 _stepping_axis_view = 0;
5959 Editor::ui_parameter_changed (string parameter)
5961 if (parameter == "icon-set") {
5962 while (!_cursor_stack.empty()) {
5963 _cursor_stack.pop_back();
5965 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5966 _cursor_stack.push_back(_cursors->grabber);
5967 } else if (parameter == "draggable-playhead") {
5968 if (_verbose_cursor) {
5969 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());