2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include "gtkmm2ext/tearoff.h"
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/audio_track.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/audioregion.h"
71 #include "ardour/location.h"
72 #include "ardour/profile.h"
73 #include "ardour/route_group.h"
74 #include "ardour/session_playlists.h"
75 #include "ardour/tempo.h"
76 #include "ardour/utils.h"
78 #include "canvas/debug.h"
79 #include "canvas/text.h"
81 #include "control_protocol/control_protocol.h"
84 #include "analysis_window.h"
85 #include "audio_clock.h"
86 #include "audio_region_view.h"
87 #include "audio_streamview.h"
88 #include "audio_time_axis.h"
89 #include "automation_time_axis.h"
90 #include "bundle_manager.h"
91 #include "crossfade_edit.h"
95 #include "editor_cursors.h"
96 #include "editor_drag.h"
97 #include "editor_group_tabs.h"
98 #include "editor_locations.h"
99 #include "editor_regions.h"
100 #include "editor_route_groups.h"
101 #include "editor_routes.h"
102 #include "editor_snapshots.h"
103 #include "editor_summary.h"
104 #include "global_port_matrix.h"
105 #include "gui_object.h"
106 #include "gui_thread.h"
107 #include "keyboard.h"
109 #include "midi_region_view.h"
110 #include "midi_time_axis.h"
111 #include "mixer_strip.h"
112 #include "mixer_ui.h"
113 #include "mouse_cursors.h"
114 #include "note_base.h"
115 #include "playlist_selector.h"
116 #include "public_editor.h"
117 #include "region_layering_order_editor.h"
118 #include "rgb_macros.h"
119 #include "rhythm_ferret.h"
120 #include "selection.h"
122 #include "tempo_lines.h"
123 #include "time_axis_view.h"
126 #include "verbose_cursor.h"
131 using namespace ARDOUR;
132 using namespace ARDOUR_UI_UTILS;
135 using namespace Glib;
136 using namespace Gtkmm2ext;
137 using namespace Editing;
139 using PBD::internationalize;
141 using Gtkmm2ext::Keyboard;
143 double Editor::timebar_height = 15.0;
145 static const gchar *_snap_type_strings[] = {
179 static const gchar *_snap_mode_strings[] = {
186 static const gchar *_edit_point_strings[] = {
193 static const gchar *_edit_mode_strings[] = {
201 static const gchar *_zoom_focus_strings[] = {
211 #ifdef USE_RUBBERBAND
212 static const gchar *_rb_opt_strings[] = {
215 N_("Balanced multitimbral mixture"),
216 N_("Unpitched percussion with stable notes"),
217 N_("Crisp monophonic instrumental"),
218 N_("Unpitched solo percussion"),
219 N_("Resample without preserving pitch"),
224 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
227 pane_size_watcher (Paned* pane)
229 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
233 Quartz: impossible to access
235 so stop that by preventing it from ever getting too narrow. 35
236 pixels is basically a rough guess at the tab width.
241 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
243 gint pos = pane->get_position ();
245 if (pos > max_width_of_lhs) {
246 pane->set_position (max_width_of_lhs);
251 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
253 , _mouse_changed_selection (false)
254 /* time display buttons */
255 , minsec_label (_("Mins:Secs"))
256 , bbt_label (_("Bars:Beats"))
257 , timecode_label (_("Timecode"))
258 , samples_label (_("Samples"))
259 , tempo_label (_("Tempo"))
260 , meter_label (_("Meter"))
261 , mark_label (_("Location Markers"))
262 , range_mark_label (_("Range Markers"))
263 , transport_mark_label (_("Loop/Punch Ranges"))
264 , cd_mark_label (_("CD Markers"))
265 , videotl_label (_("Video Timeline"))
266 , edit_packer (4, 4, true)
268 /* the values here don't matter: layout widgets
269 reset them as needed.
272 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
273 , horizontal_adjustment (0.0, 0.0, 1e16)
274 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
276 , controls_layout (unused_adjustment, vertical_adjustment)
278 /* tool bar related */
280 , toolbar_selection_clock_table (2,3)
281 , _mouse_mode_tearoff (0)
282 , automation_mode_button (_("mode"))
286 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
287 , selection_op_cmd_depth (0)
288 , selection_op_history_it (0)
292 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
293 , meters_running(false)
294 , _pending_locate_request (false)
295 , _pending_initial_locate (false)
296 , _last_cut_copy_source_track (0)
298 , _region_selection_change_updates_region_list (true)
299 , _following_mixer_selection (false)
300 , _control_point_toggled_on_press (false)
301 , _stepping_axis_view (0)
305 /* we are a singleton */
307 PublicEditor::_instance = this;
311 selection = new Selection (this);
312 cut_buffer = new Selection (this);
313 _selection_memento = new SelectionMemento ();
314 selection_op_history.clear();
317 clicked_regionview = 0;
318 clicked_axisview = 0;
319 clicked_routeview = 0;
320 clicked_control_point = 0;
321 last_update_frame = 0;
324 _drags = new DragManager (this);
327 current_mixer_strip = 0;
330 snap_type_strings = I18N (_snap_type_strings);
331 snap_mode_strings = I18N (_snap_mode_strings);
332 zoom_focus_strings = I18N (_zoom_focus_strings);
333 edit_mode_strings = I18N (_edit_mode_strings);
334 edit_point_strings = I18N (_edit_point_strings);
335 #ifdef USE_RUBBERBAND
336 rb_opt_strings = I18N (_rb_opt_strings);
340 build_edit_mode_menu();
341 build_zoom_focus_menu();
342 build_track_count_menu();
343 build_snap_mode_menu();
344 build_snap_type_menu();
345 build_edit_point_menu();
347 snap_threshold = 5.0;
348 bbt_beat_subdivision = 4;
349 _visible_canvas_width = 0;
350 _visible_canvas_height = 0;
351 autoscroll_horizontal_allowed = false;
352 autoscroll_vertical_allowed = false;
357 current_interthread_info = 0;
358 _show_measures = true;
360 show_gain_after_trim = false;
362 have_pending_keyboard_selection = false;
363 _follow_playhead = true;
364 _stationary_playhead = false;
365 editor_ruler_menu = 0;
366 no_ruler_shown_update = false;
368 range_marker_menu = 0;
369 marker_menu_item = 0;
370 tempo_or_meter_marker_menu = 0;
371 transport_marker_menu = 0;
372 new_transport_marker_menu = 0;
373 editor_mixer_strip_width = Wide;
374 show_editor_mixer_when_tracks_arrive = false;
375 region_edit_menu_split_multichannel_item = 0;
376 region_edit_menu_split_item = 0;
379 current_stepping_trackview = 0;
381 entered_regionview = 0;
383 clear_entered_track = false;
386 button_release_can_deselect = true;
387 _dragging_playhead = false;
388 _dragging_edit_point = false;
389 select_new_marker = false;
391 layering_order_editor = 0;
392 no_save_visual = false;
394 within_track_canvas = false;
396 scrubbing_direction = 0;
400 location_marker_color = ARDOUR_UI::config()->color ("location marker");
401 location_range_color = ARDOUR_UI::config()->color ("location range");
402 location_cd_marker_color = ARDOUR_UI::config()->color ("location cd marker");
403 location_loop_color = ARDOUR_UI::config()->color ("location loop");
404 location_punch_color = ARDOUR_UI::config()->color ("location punch");
406 zoom_focus = ZoomFocusPlayhead;
407 _edit_point = EditAtMouse;
408 _visible_track_count = -1;
410 samples_per_pixel = 2048; /* too early to use reset_zoom () */
412 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::config()->get_font_scale() / 102400.));
413 TimeAxisView::setup_sizes ();
414 Marker::setup_sizes (timebar_height);
416 _scroll_callbacks = 0;
418 bbt_label.set_name ("EditorRulerLabel");
419 bbt_label.set_size_request (-1, (int)timebar_height);
420 bbt_label.set_alignment (1.0, 0.5);
421 bbt_label.set_padding (5,0);
423 bbt_label.set_no_show_all();
424 minsec_label.set_name ("EditorRulerLabel");
425 minsec_label.set_size_request (-1, (int)timebar_height);
426 minsec_label.set_alignment (1.0, 0.5);
427 minsec_label.set_padding (5,0);
428 minsec_label.hide ();
429 minsec_label.set_no_show_all();
430 timecode_label.set_name ("EditorRulerLabel");
431 timecode_label.set_size_request (-1, (int)timebar_height);
432 timecode_label.set_alignment (1.0, 0.5);
433 timecode_label.set_padding (5,0);
434 timecode_label.hide ();
435 timecode_label.set_no_show_all();
436 samples_label.set_name ("EditorRulerLabel");
437 samples_label.set_size_request (-1, (int)timebar_height);
438 samples_label.set_alignment (1.0, 0.5);
439 samples_label.set_padding (5,0);
440 samples_label.hide ();
441 samples_label.set_no_show_all();
443 tempo_label.set_name ("EditorRulerLabel");
444 tempo_label.set_size_request (-1, (int)timebar_height);
445 tempo_label.set_alignment (1.0, 0.5);
446 tempo_label.set_padding (5,0);
448 tempo_label.set_no_show_all();
450 meter_label.set_name ("EditorRulerLabel");
451 meter_label.set_size_request (-1, (int)timebar_height);
452 meter_label.set_alignment (1.0, 0.5);
453 meter_label.set_padding (5,0);
455 meter_label.set_no_show_all();
457 if (Profile->get_trx()) {
458 mark_label.set_text (_("Markers"));
460 mark_label.set_name ("EditorRulerLabel");
461 mark_label.set_size_request (-1, (int)timebar_height);
462 mark_label.set_alignment (1.0, 0.5);
463 mark_label.set_padding (5,0);
465 mark_label.set_no_show_all();
467 cd_mark_label.set_name ("EditorRulerLabel");
468 cd_mark_label.set_size_request (-1, (int)timebar_height);
469 cd_mark_label.set_alignment (1.0, 0.5);
470 cd_mark_label.set_padding (5,0);
471 cd_mark_label.hide();
472 cd_mark_label.set_no_show_all();
474 videotl_bar_height = 4;
475 videotl_label.set_name ("EditorRulerLabel");
476 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
477 videotl_label.set_alignment (1.0, 0.5);
478 videotl_label.set_padding (5,0);
479 videotl_label.hide();
480 videotl_label.set_no_show_all();
482 range_mark_label.set_name ("EditorRulerLabel");
483 range_mark_label.set_size_request (-1, (int)timebar_height);
484 range_mark_label.set_alignment (1.0, 0.5);
485 range_mark_label.set_padding (5,0);
486 range_mark_label.hide();
487 range_mark_label.set_no_show_all();
489 transport_mark_label.set_name ("EditorRulerLabel");
490 transport_mark_label.set_size_request (-1, (int)timebar_height);
491 transport_mark_label.set_alignment (1.0, 0.5);
492 transport_mark_label.set_padding (5,0);
493 transport_mark_label.hide();
494 transport_mark_label.set_no_show_all();
496 initialize_canvas ();
498 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
500 _summary = new EditorSummary (this);
502 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
503 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
505 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
507 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
508 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
510 edit_controls_vbox.set_spacing (0);
511 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
512 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
514 HBox* h = manage (new HBox);
515 _group_tabs = new EditorGroupTabs (this);
516 if (!ARDOUR::Profile->get_trx()) {
517 h->pack_start (*_group_tabs, PACK_SHRINK);
519 h->pack_start (edit_controls_vbox);
520 controls_layout.add (*h);
522 controls_layout.set_name ("EditControlsBase");
523 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
524 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
525 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
527 _cursors = new MouseCursors;
528 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
529 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
531 /* Push default cursor to ever-present bottom of cursor stack. */
532 push_canvas_cursor(_cursors->grabber);
534 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
536 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
537 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
538 pad_line_1->set_outline_color (0xFF0000FF);
544 edit_packer.set_col_spacings (0);
545 edit_packer.set_row_spacings (0);
546 edit_packer.set_homogeneous (false);
547 edit_packer.set_border_width (0);
548 edit_packer.set_name ("EditorWindow");
550 time_bars_event_box.add (time_bars_vbox);
551 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
552 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
554 /* labels for the time bars */
555 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
557 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
559 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
561 bottom_hbox.set_border_width (2);
562 bottom_hbox.set_spacing (3);
564 _route_groups = new EditorRouteGroups (this);
565 _routes = new EditorRoutes (this);
566 _regions = new EditorRegions (this);
567 _snapshots = new EditorSnapshots (this);
568 _locations = new EditorLocations (this);
570 /* these are static location signals */
572 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
573 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
574 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
576 add_notebook_page (_("Regions"), _regions->widget ());
577 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
578 add_notebook_page (_("Snapshots"), _snapshots->widget ());
579 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
580 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
582 _the_notebook.set_show_tabs (true);
583 _the_notebook.set_scrollable (true);
584 _the_notebook.popup_disable ();
585 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
586 _the_notebook.show_all ();
588 _notebook_shrunk = false;
590 editor_summary_pane.pack1(edit_packer);
592 Button* summary_arrows_left_left = manage (new Button);
593 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
594 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
595 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
597 Button* summary_arrows_left_right = manage (new Button);
598 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
599 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
600 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
602 VBox* summary_arrows_left = manage (new VBox);
603 summary_arrows_left->pack_start (*summary_arrows_left_left);
604 summary_arrows_left->pack_start (*summary_arrows_left_right);
606 Button* summary_arrows_right_up = manage (new Button);
607 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
608 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
609 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
611 Button* summary_arrows_right_down = manage (new Button);
612 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
613 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
614 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
616 VBox* summary_arrows_right = manage (new VBox);
617 summary_arrows_right->pack_start (*summary_arrows_right_up);
618 summary_arrows_right->pack_start (*summary_arrows_right_down);
620 Frame* summary_frame = manage (new Frame);
621 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
623 summary_frame->add (*_summary);
624 summary_frame->show ();
626 _summary_hbox.pack_start (*summary_arrows_left, false, false);
627 _summary_hbox.pack_start (*summary_frame, true, true);
628 _summary_hbox.pack_start (*summary_arrows_right, false, false);
630 if (!ARDOUR::Profile->get_trx()) {
631 editor_summary_pane.pack2 (_summary_hbox);
634 edit_pane.pack1 (editor_summary_pane, true, true);
635 if (!ARDOUR::Profile->get_trx()) {
636 edit_pane.pack2 (_the_notebook, false, true);
639 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
641 /* XXX: editor_summary_pane might need similar to the edit_pane */
643 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
645 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
646 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
648 top_hbox.pack_start (toolbar_frame);
650 HBox *hbox = manage (new HBox);
651 hbox->pack_start (edit_pane, true, true);
653 global_vpacker.pack_start (top_hbox, false, false);
654 global_vpacker.pack_start (*hbox, true, true);
656 global_hpacker.pack_start (global_vpacker, true, true);
658 set_name ("EditorWindow");
659 add_accel_group (ActionManager::ui_manager->get_accel_group());
661 status_bar_hpacker.show ();
663 vpacker.pack_end (status_bar_hpacker, false, false);
664 vpacker.pack_end (global_hpacker, true, true);
666 /* register actions now so that set_state() can find them and set toggles/checks etc */
669 /* when we start using our own keybinding system for the editor, this
670 * will be uncommented
676 set_zoom_focus (zoom_focus);
677 set_visible_track_count (_visible_track_count);
678 _snap_type = SnapToBeat;
679 set_snap_to (_snap_type);
680 _snap_mode = SnapOff;
681 set_snap_mode (_snap_mode);
682 set_mouse_mode (MouseObject, true);
683 pre_internal_snap_type = _snap_type;
684 pre_internal_snap_mode = _snap_mode;
685 internal_snap_type = _snap_type;
686 internal_snap_mode = _snap_mode;
687 set_edit_point_preference (EditAtMouse, true);
689 _playlist_selector = new PlaylistSelector();
690 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
692 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
696 nudge_forward_button.set_name ("nudge button");
697 nudge_forward_button.set_image(::get_icon("nudge_right"));
699 nudge_backward_button.set_name ("nudge button");
700 nudge_backward_button.set_image(::get_icon("nudge_left"));
702 fade_context_menu.set_name ("ArdourContextMenu");
704 /* icons, titles, WM stuff */
706 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
707 Glib::RefPtr<Gdk::Pixbuf> icon;
709 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
710 window_icons.push_back (icon);
712 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
713 window_icons.push_back (icon);
715 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
716 window_icons.push_back (icon);
718 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
719 window_icons.push_back (icon);
721 if (!window_icons.empty()) {
722 // set_icon_list (window_icons);
723 set_default_icon_list (window_icons);
726 WindowTitle title(Glib::get_application_name());
727 title += _("Editor");
728 set_title (title.get_string());
729 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
732 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
734 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
735 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
737 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
739 /* allow external control surfaces/protocols to do various things */
741 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
742 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
743 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
744 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
745 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
746 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
747 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
748 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
749 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
750 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
751 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
752 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
753 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
754 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
756 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
757 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
758 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
759 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
760 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
762 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
764 /* problematic: has to return a value and thus cannot be x-thread */
766 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
768 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
769 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
771 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
773 _ignore_region_action = false;
774 _last_region_menu_was_main = false;
775 _popup_region_menu_item = 0;
777 _ignore_follow_edits = false;
779 _show_marker_lines = false;
781 /* Button bindings */
783 button_bindings = new Bindings;
785 XMLNode* node = button_settings();
787 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
788 button_bindings->load (**i);
794 /* grab current parameter state */
795 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
796 ARDOUR_UI::config()->map_parameters (pc);
798 setup_fade_images ();
805 delete button_bindings;
807 delete _route_groups;
808 delete _track_canvas_viewport;
814 Editor::button_settings () const
816 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
817 XMLNode* node = find_named_node (*settings, X_("Buttons"));
820 node = new XMLNode (X_("Buttons"));
827 Editor::add_toplevel_menu (Container& cont)
829 vpacker.pack_start (cont, false, false);
834 Editor::add_transport_frame (Container& cont)
836 if(ARDOUR::Profile->get_mixbus()) {
837 global_vpacker.pack_start (cont, false, false);
838 global_vpacker.reorder_child (cont, 0);
841 vpacker.pack_start (cont, false, false);
846 Editor::get_smart_mode () const
848 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
852 Editor::catch_vanishing_regionview (RegionView *rv)
854 /* note: the selection will take care of the vanishing
855 audioregionview by itself.
858 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
862 if (clicked_regionview == rv) {
863 clicked_regionview = 0;
866 if (entered_regionview == rv) {
867 set_entered_regionview (0);
870 if (!_all_region_actions_sensitized) {
871 sensitize_all_region_actions (true);
876 Editor::set_entered_regionview (RegionView* rv)
878 if (rv == entered_regionview) {
882 if (entered_regionview) {
883 entered_regionview->exited ();
886 entered_regionview = rv;
888 if (entered_regionview != 0) {
889 entered_regionview->entered ();
892 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
893 /* This RegionView entry might have changed what region actions
894 are allowed, so sensitize them all in case a key is pressed.
896 sensitize_all_region_actions (true);
901 Editor::set_entered_track (TimeAxisView* tav)
904 entered_track->exited ();
910 entered_track->entered ();
915 Editor::show_window ()
917 if (!is_visible ()) {
921 /* XXX: this is a bit unfortunate; it would probably
922 be nicer if we could just call show () above rather
923 than needing the show_all ()
926 /* re-hide stuff if necessary */
927 editor_list_button_toggled ();
928 parameter_changed ("show-summary");
929 parameter_changed ("show-group-tabs");
930 parameter_changed ("show-zoom-tools");
932 /* now reset all audio_time_axis heights, because widgets might need
938 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
939 tv = (static_cast<TimeAxisView*>(*i));
943 if (current_mixer_strip) {
944 current_mixer_strip->hide_things ();
945 current_mixer_strip->parameter_changed ("mixer-element-visibility");
953 Editor::instant_save ()
955 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
960 _session->add_instant_xml(get_state());
962 Config->add_instant_xml(get_state());
967 Editor::control_vertical_zoom_in_all ()
969 tav_zoom_smooth (false, true);
973 Editor::control_vertical_zoom_out_all ()
975 tav_zoom_smooth (true, true);
979 Editor::control_vertical_zoom_in_selected ()
981 tav_zoom_smooth (false, false);
985 Editor::control_vertical_zoom_out_selected ()
987 tav_zoom_smooth (true, false);
991 Editor::control_view (uint32_t view)
993 goto_visual_state (view);
997 Editor::control_unselect ()
999 selection->clear_tracks ();
1003 Editor::control_select (uint32_t rid, Selection::Operation op)
1005 /* handles the (static) signal from the ControlProtocol class that
1006 * requests setting the selected track to a given RID
1013 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1019 TimeAxisView* tav = axis_view_from_route (r);
1023 case Selection::Add:
1024 selection->add (tav);
1026 case Selection::Toggle:
1027 selection->toggle (tav);
1029 case Selection::Extend:
1031 case Selection::Set:
1032 selection->set (tav);
1036 selection->clear_tracks ();
1041 Editor::control_step_tracks_up ()
1043 scroll_tracks_up_line ();
1047 Editor::control_step_tracks_down ()
1049 scroll_tracks_down_line ();
1053 Editor::control_scroll (float fraction)
1055 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1061 double step = fraction * current_page_samples();
1064 _control_scroll_target is an optional<T>
1066 it acts like a pointer to an framepos_t, with
1067 a operator conversion to boolean to check
1068 that it has a value could possibly use
1069 playhead_cursor->current_frame to store the
1070 value and a boolean in the class to know
1071 when it's out of date
1074 if (!_control_scroll_target) {
1075 _control_scroll_target = _session->transport_frame();
1076 _dragging_playhead = true;
1079 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1080 *_control_scroll_target = 0;
1081 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1082 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1084 *_control_scroll_target += (framepos_t) trunc (step);
1087 /* move visuals, we'll catch up with it later */
1089 playhead_cursor->set_position (*_control_scroll_target);
1090 UpdateAllTransportClocks (*_control_scroll_target);
1092 if (*_control_scroll_target > (current_page_samples() / 2)) {
1093 /* try to center PH in window */
1094 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1100 Now we do a timeout to actually bring the session to the right place
1101 according to the playhead. This is to avoid reading disk buffers on every
1102 call to control_scroll, which is driven by ScrollTimeline and therefore
1103 probably by a control surface wheel which can generate lots of events.
1105 /* cancel the existing timeout */
1107 control_scroll_connection.disconnect ();
1109 /* add the next timeout */
1111 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1115 Editor::deferred_control_scroll (framepos_t /*target*/)
1117 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1118 // reset for next stream
1119 _control_scroll_target = boost::none;
1120 _dragging_playhead = false;
1125 Editor::access_action (std::string action_group, std::string action_item)
1131 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1134 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1142 Editor::on_realize ()
1144 Window::on_realize ();
1147 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1148 start_lock_event_timing ();
1151 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1155 Editor::start_lock_event_timing ()
1157 /* check if we should lock the GUI every 30 seconds */
1159 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1163 Editor::generic_event_handler (GdkEvent* ev)
1166 case GDK_BUTTON_PRESS:
1167 case GDK_BUTTON_RELEASE:
1168 case GDK_MOTION_NOTIFY:
1170 case GDK_KEY_RELEASE:
1171 gettimeofday (&last_event_time, 0);
1174 case GDK_LEAVE_NOTIFY:
1175 switch (ev->crossing.detail) {
1176 case GDK_NOTIFY_UNKNOWN:
1177 case GDK_NOTIFY_INFERIOR:
1178 case GDK_NOTIFY_ANCESTOR:
1180 case GDK_NOTIFY_VIRTUAL:
1181 case GDK_NOTIFY_NONLINEAR:
1182 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1183 /* leaving window, so reset focus, thus ending any and
1184 all text entry operations.
1199 Editor::lock_timeout_callback ()
1201 struct timeval now, delta;
1203 gettimeofday (&now, 0);
1205 timersub (&now, &last_event_time, &delta);
1207 if (delta.tv_sec > (time_t) ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1209 /* don't call again. Returning false will effectively
1210 disconnect us from the timer callback.
1212 unlock() will call start_lock_event_timing() to get things
1222 Editor::map_position_change (framepos_t frame)
1224 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1226 if (_session == 0) {
1230 if (_follow_playhead) {
1231 center_screen (frame);
1234 playhead_cursor->set_position (frame);
1238 Editor::center_screen (framepos_t frame)
1240 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1242 /* if we're off the page, then scroll.
1245 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1246 center_screen_internal (frame, page);
1251 Editor::center_screen_internal (framepos_t frame, float page)
1256 frame -= (framepos_t) page;
1261 reset_x_origin (frame);
1266 Editor::update_title ()
1268 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1271 bool dirty = _session->dirty();
1273 string session_name;
1275 if (_session->snap_name() != _session->name()) {
1276 session_name = _session->snap_name();
1278 session_name = _session->name();
1282 session_name = "*" + session_name;
1285 WindowTitle title(session_name);
1286 title += Glib::get_application_name();
1287 set_title (title.get_string());
1289 /* ::session_going_away() will have taken care of it */
1294 Editor::set_session (Session *t)
1296 SessionHandlePtr::set_session (t);
1302 _playlist_selector->set_session (_session);
1303 nudge_clock->set_session (_session);
1304 _summary->set_session (_session);
1305 _group_tabs->set_session (_session);
1306 _route_groups->set_session (_session);
1307 _regions->set_session (_session);
1308 _snapshots->set_session (_session);
1309 _routes->set_session (_session);
1310 _locations->set_session (_session);
1312 if (rhythm_ferret) {
1313 rhythm_ferret->set_session (_session);
1316 if (analysis_window) {
1317 analysis_window->set_session (_session);
1321 sfbrowser->set_session (_session);
1324 compute_fixed_ruler_scale ();
1326 /* Make sure we have auto loop and auto punch ranges */
1328 Location* loc = _session->locations()->auto_loop_location();
1330 loc->set_name (_("Loop"));
1333 loc = _session->locations()->auto_punch_location();
1336 loc->set_name (_("Punch"));
1339 refresh_location_display ();
1341 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1342 the selected Marker; this needs the LocationMarker list to be available.
1344 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1345 set_state (*node, Stateful::loading_state_version);
1347 /* catch up with the playhead */
1349 _session->request_locate (playhead_cursor->current_frame ());
1350 _pending_initial_locate = true;
1354 /* These signals can all be emitted by a non-GUI thread. Therefore the
1355 handlers for them must not attempt to directly interact with the GUI,
1356 but use PBD::Signal<T>::connect() which accepts an event loop
1357 ("context") where the handler will be asked to run.
1360 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1361 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1362 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1363 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1364 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1365 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1366 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1367 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1368 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1369 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1370 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1371 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1372 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1374 playhead_cursor->show ();
1376 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1377 Config->map_parameters (pc);
1378 _session->config.map_parameters (pc);
1380 restore_ruler_visibility ();
1381 //tempo_map_changed (PropertyChange (0));
1382 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1384 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1385 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1388 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1389 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1392 switch (_snap_type) {
1393 case SnapToRegionStart:
1394 case SnapToRegionEnd:
1395 case SnapToRegionSync:
1396 case SnapToRegionBoundary:
1397 build_region_boundary_cache ();
1404 /* register for undo history */
1405 _session->register_with_memento_command_factory(id(), this);
1406 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1408 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1410 start_updating_meters ();
1414 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1416 if (a->get_name() == "RegionMenu") {
1417 /* When the main menu's region menu is opened, we setup the actions so that they look right
1418 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1419 so we resensitize all region actions when the entered regionview or the region selection
1420 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1421 happens after the region context menu is opened. So we set a flag here, too.
1425 sensitize_the_right_region_actions ();
1426 _last_region_menu_was_main = true;
1431 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1433 using namespace Menu_Helpers;
1435 void (Editor::*emf)(FadeShape);
1436 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1439 images = &_xfade_in_images;
1440 emf = &Editor::set_fade_in_shape;
1442 images = &_xfade_out_images;
1443 emf = &Editor::set_fade_out_shape;
1448 _("Linear (for highly correlated material)"),
1449 *(*images)[FadeLinear],
1450 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1454 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1458 _("Constant power"),
1459 *(*images)[FadeConstantPower],
1460 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1463 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1468 *(*images)[FadeSymmetric],
1469 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1473 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1478 *(*images)[FadeSlow],
1479 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1482 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1487 *(*images)[FadeFast],
1488 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1491 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1494 /** Pop up a context menu for when the user clicks on a start crossfade */
1496 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1498 using namespace Menu_Helpers;
1499 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1504 MenuList& items (xfade_in_context_menu.items());
1507 if (arv->audio_region()->fade_in_active()) {
1508 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1510 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1513 items.push_back (SeparatorElem());
1514 fill_xfade_menu (items, true);
1516 xfade_in_context_menu.popup (button, time);
1519 /** Pop up a context menu for when the user clicks on an end crossfade */
1521 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1523 using namespace Menu_Helpers;
1524 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1529 MenuList& items (xfade_out_context_menu.items());
1532 if (arv->audio_region()->fade_out_active()) {
1533 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1535 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1538 items.push_back (SeparatorElem());
1539 fill_xfade_menu (items, false);
1541 xfade_out_context_menu.popup (button, time);
1545 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1547 using namespace Menu_Helpers;
1548 Menu* (Editor::*build_menu_function)();
1551 switch (item_type) {
1553 case RegionViewName:
1554 case RegionViewNameHighlight:
1555 case LeftFrameHandle:
1556 case RightFrameHandle:
1557 if (with_selection) {
1558 build_menu_function = &Editor::build_track_selection_context_menu;
1560 build_menu_function = &Editor::build_track_region_context_menu;
1565 if (with_selection) {
1566 build_menu_function = &Editor::build_track_selection_context_menu;
1568 build_menu_function = &Editor::build_track_context_menu;
1573 if (clicked_routeview->track()) {
1574 build_menu_function = &Editor::build_track_context_menu;
1576 build_menu_function = &Editor::build_track_bus_context_menu;
1581 /* probably shouldn't happen but if it does, we don't care */
1585 menu = (this->*build_menu_function)();
1586 menu->set_name ("ArdourContextMenu");
1588 /* now handle specific situations */
1590 switch (item_type) {
1592 case RegionViewName:
1593 case RegionViewNameHighlight:
1594 case LeftFrameHandle:
1595 case RightFrameHandle:
1596 if (!with_selection) {
1597 if (region_edit_menu_split_item) {
1598 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1599 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1601 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1604 if (region_edit_menu_split_multichannel_item) {
1605 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1606 region_edit_menu_split_multichannel_item->set_sensitive (true);
1608 region_edit_menu_split_multichannel_item->set_sensitive (false);
1621 /* probably shouldn't happen but if it does, we don't care */
1625 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1627 /* Bounce to disk */
1629 using namespace Menu_Helpers;
1630 MenuList& edit_items = menu->items();
1632 edit_items.push_back (SeparatorElem());
1634 switch (clicked_routeview->audio_track()->freeze_state()) {
1635 case AudioTrack::NoFreeze:
1636 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1639 case AudioTrack::Frozen:
1640 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1643 case AudioTrack::UnFrozen:
1644 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1650 if (item_type == StreamItem && clicked_routeview) {
1651 clicked_routeview->build_underlay_menu(menu);
1654 /* When the region menu is opened, we setup the actions so that they look right
1657 sensitize_the_right_region_actions ();
1658 _last_region_menu_was_main = false;
1660 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1661 menu->popup (button, time);
1665 Editor::build_track_context_menu ()
1667 using namespace Menu_Helpers;
1669 MenuList& edit_items = track_context_menu.items();
1672 add_dstream_context_items (edit_items);
1673 return &track_context_menu;
1677 Editor::build_track_bus_context_menu ()
1679 using namespace Menu_Helpers;
1681 MenuList& edit_items = track_context_menu.items();
1684 add_bus_context_items (edit_items);
1685 return &track_context_menu;
1689 Editor::build_track_region_context_menu ()
1691 using namespace Menu_Helpers;
1692 MenuList& edit_items = track_region_context_menu.items();
1695 /* we've just cleared the track region context menu, so the menu that these
1696 two items were on will have disappeared; stop them dangling.
1698 region_edit_menu_split_item = 0;
1699 region_edit_menu_split_multichannel_item = 0;
1701 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1704 boost::shared_ptr<Track> tr;
1705 boost::shared_ptr<Playlist> pl;
1707 if ((tr = rtv->track())) {
1708 add_region_context_items (edit_items, tr);
1712 add_dstream_context_items (edit_items);
1714 return &track_region_context_menu;
1718 Editor::analyze_region_selection ()
1720 if (analysis_window == 0) {
1721 analysis_window = new AnalysisWindow();
1724 analysis_window->set_session(_session);
1726 analysis_window->show_all();
1729 analysis_window->set_regionmode();
1730 analysis_window->analyze();
1732 analysis_window->present();
1736 Editor::analyze_range_selection()
1738 if (analysis_window == 0) {
1739 analysis_window = new AnalysisWindow();
1742 analysis_window->set_session(_session);
1744 analysis_window->show_all();
1747 analysis_window->set_rangemode();
1748 analysis_window->analyze();
1750 analysis_window->present();
1754 Editor::build_track_selection_context_menu ()
1756 using namespace Menu_Helpers;
1757 MenuList& edit_items = track_selection_context_menu.items();
1758 edit_items.clear ();
1760 add_selection_context_items (edit_items);
1761 // edit_items.push_back (SeparatorElem());
1762 // add_dstream_context_items (edit_items);
1764 return &track_selection_context_menu;
1768 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1770 using namespace Menu_Helpers;
1772 /* OK, stick the region submenu at the top of the list, and then add
1776 RegionSelection rs = get_regions_from_selection_and_entered ();
1778 string::size_type pos = 0;
1779 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1781 /* we have to hack up the region name because "_" has a special
1782 meaning for menu titles.
1785 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1786 menu_item_name.replace (pos, 1, "__");
1790 if (_popup_region_menu_item == 0) {
1791 _popup_region_menu_item = new MenuItem (menu_item_name);
1792 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1793 _popup_region_menu_item->show ();
1795 _popup_region_menu_item->set_label (menu_item_name);
1798 const framepos_t position = get_preferred_edit_position (false, true);
1800 edit_items.push_back (*_popup_region_menu_item);
1801 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1802 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1804 edit_items.push_back (SeparatorElem());
1807 /** Add context menu items relevant to selection ranges.
1808 * @param edit_items List to add the items to.
1811 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1813 using namespace Menu_Helpers;
1815 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1816 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1818 edit_items.push_back (SeparatorElem());
1819 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1821 edit_items.push_back (SeparatorElem());
1822 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1824 edit_items.push_back (SeparatorElem());
1826 edit_items.push_back (
1828 _("Move Range Start to Previous Region Boundary"),
1829 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1833 edit_items.push_back (
1835 _("Move Range Start to Next Region Boundary"),
1836 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1840 edit_items.push_back (
1842 _("Move Range End to Previous Region Boundary"),
1843 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1847 edit_items.push_back (
1849 _("Move Range End to Next Region Boundary"),
1850 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1854 edit_items.push_back (SeparatorElem());
1855 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1856 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1858 edit_items.push_back (SeparatorElem());
1859 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1861 edit_items.push_back (SeparatorElem());
1862 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1863 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1864 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1866 edit_items.push_back (SeparatorElem());
1867 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1869 edit_items.push_back (SeparatorElem());
1870 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1871 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1872 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1874 edit_items.push_back (SeparatorElem());
1875 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1876 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1877 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1878 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1879 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1880 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1881 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1887 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1889 using namespace Menu_Helpers;
1893 Menu *play_menu = manage (new Menu);
1894 MenuList& play_items = play_menu->items();
1895 play_menu->set_name ("ArdourContextMenu");
1897 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1898 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1899 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1900 play_items.push_back (SeparatorElem());
1901 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1903 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1907 Menu *select_menu = manage (new Menu);
1908 MenuList& select_items = select_menu->items();
1909 select_menu->set_name ("ArdourContextMenu");
1911 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1912 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1913 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1914 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1915 select_items.push_back (SeparatorElem());
1916 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1917 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1918 select_items.push_back (SeparatorElem());
1919 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1920 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1921 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1922 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1923 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1924 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1925 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1927 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1931 Menu *cutnpaste_menu = manage (new Menu);
1932 MenuList& cutnpaste_items = cutnpaste_menu->items();
1933 cutnpaste_menu->set_name ("ArdourContextMenu");
1935 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1936 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1937 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1939 cutnpaste_items.push_back (SeparatorElem());
1941 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1942 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1944 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1946 /* Adding new material */
1948 edit_items.push_back (SeparatorElem());
1949 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1950 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1954 Menu *nudge_menu = manage (new Menu());
1955 MenuList& nudge_items = nudge_menu->items();
1956 nudge_menu->set_name ("ArdourContextMenu");
1958 edit_items.push_back (SeparatorElem());
1959 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1960 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1961 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1962 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1964 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1968 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1970 using namespace Menu_Helpers;
1974 Menu *play_menu = manage (new Menu);
1975 MenuList& play_items = play_menu->items();
1976 play_menu->set_name ("ArdourContextMenu");
1978 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1979 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1980 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1984 Menu *select_menu = manage (new Menu);
1985 MenuList& select_items = select_menu->items();
1986 select_menu->set_name ("ArdourContextMenu");
1988 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1989 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1990 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1991 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1992 select_items.push_back (SeparatorElem());
1993 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1994 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1995 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1996 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1998 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2002 Menu *cutnpaste_menu = manage (new Menu);
2003 MenuList& cutnpaste_items = cutnpaste_menu->items();
2004 cutnpaste_menu->set_name ("ArdourContextMenu");
2006 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2007 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2008 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2010 Menu *nudge_menu = manage (new Menu());
2011 MenuList& nudge_items = nudge_menu->items();
2012 nudge_menu->set_name ("ArdourContextMenu");
2014 edit_items.push_back (SeparatorElem());
2015 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2016 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2017 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2018 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2020 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2024 Editor::snap_type() const
2030 Editor::snap_mode() const
2036 Editor::set_snap_to (SnapType st)
2038 unsigned int snap_ind = (unsigned int)st;
2040 if (internal_editing()) {
2041 internal_snap_type = st;
2043 pre_internal_snap_type = st;
2048 if (snap_ind > snap_type_strings.size() - 1) {
2050 _snap_type = (SnapType)snap_ind;
2053 string str = snap_type_strings[snap_ind];
2055 if (str != snap_type_selector.get_text()) {
2056 snap_type_selector.set_text (str);
2061 switch (_snap_type) {
2062 case SnapToBeatDiv128:
2063 case SnapToBeatDiv64:
2064 case SnapToBeatDiv32:
2065 case SnapToBeatDiv28:
2066 case SnapToBeatDiv24:
2067 case SnapToBeatDiv20:
2068 case SnapToBeatDiv16:
2069 case SnapToBeatDiv14:
2070 case SnapToBeatDiv12:
2071 case SnapToBeatDiv10:
2072 case SnapToBeatDiv8:
2073 case SnapToBeatDiv7:
2074 case SnapToBeatDiv6:
2075 case SnapToBeatDiv5:
2076 case SnapToBeatDiv4:
2077 case SnapToBeatDiv3:
2078 case SnapToBeatDiv2: {
2079 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2080 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2082 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2083 current_bbt_points_begin, current_bbt_points_end);
2084 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2085 current_bbt_points_begin, current_bbt_points_end);
2086 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2090 case SnapToRegionStart:
2091 case SnapToRegionEnd:
2092 case SnapToRegionSync:
2093 case SnapToRegionBoundary:
2094 build_region_boundary_cache ();
2102 redisplay_tempo (false);
2104 SnapChanged (); /* EMIT SIGNAL */
2108 Editor::set_snap_mode (SnapMode mode)
2110 string str = snap_mode_strings[(int)mode];
2112 if (internal_editing()) {
2113 internal_snap_mode = mode;
2115 pre_internal_snap_mode = mode;
2120 if (str != snap_mode_selector.get_text ()) {
2121 snap_mode_selector.set_text (str);
2127 Editor::set_edit_point_preference (EditPoint ep, bool force)
2129 bool changed = (_edit_point != ep);
2132 if (Profile->get_mixbus())
2133 if (ep == EditAtSelectedMarker)
2134 ep = EditAtPlayhead;
2136 string str = edit_point_strings[(int)ep];
2137 if (str != edit_point_selector.get_text ()) {
2138 edit_point_selector.set_text (str);
2141 update_all_enter_cursors();
2143 if (!force && !changed) {
2147 const char* action=NULL;
2149 switch (_edit_point) {
2150 case EditAtPlayhead:
2151 action = "edit-at-playhead";
2153 case EditAtSelectedMarker:
2154 action = "edit-at-marker";
2157 action = "edit-at-mouse";
2161 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2163 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2167 bool in_track_canvas;
2169 if (!mouse_frame (foo, in_track_canvas)) {
2170 in_track_canvas = false;
2173 reset_canvas_action_sensitivity (in_track_canvas);
2179 Editor::set_state (const XMLNode& node, int /*version*/)
2181 const XMLProperty* prop;
2188 g.base_width = default_width;
2189 g.base_height = default_height;
2193 if ((geometry = find_named_node (node, "geometry")) != 0) {
2197 if ((prop = geometry->property("x_size")) == 0) {
2198 prop = geometry->property ("x-size");
2201 g.base_width = atoi(prop->value());
2203 if ((prop = geometry->property("y_size")) == 0) {
2204 prop = geometry->property ("y-size");
2207 g.base_height = atoi(prop->value());
2210 if ((prop = geometry->property ("x_pos")) == 0) {
2211 prop = geometry->property ("x-pos");
2214 x = atoi (prop->value());
2217 if ((prop = geometry->property ("y_pos")) == 0) {
2218 prop = geometry->property ("y-pos");
2221 y = atoi (prop->value());
2225 set_default_size (g.base_width, g.base_height);
2228 if (_session && (prop = node.property ("playhead"))) {
2230 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2232 playhead_cursor->set_position (pos);
2234 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2235 playhead_cursor->set_position (0);
2238 playhead_cursor->set_position (0);
2241 if ((prop = node.property ("mixer-width"))) {
2242 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2245 if ((prop = node.property ("zoom-focus"))) {
2246 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2249 if ((prop = node.property ("zoom"))) {
2250 /* older versions of ardour used floating point samples_per_pixel */
2251 double f = PBD::atof (prop->value());
2252 reset_zoom (llrintf (f));
2254 reset_zoom (samples_per_pixel);
2257 if ((prop = node.property ("visible-track-count"))) {
2258 set_visible_track_count (PBD::atoi (prop->value()));
2261 if ((prop = node.property ("snap-to"))) {
2262 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2265 if ((prop = node.property ("snap-mode"))) {
2266 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2269 if ((prop = node.property ("internal-snap-to"))) {
2270 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2273 if ((prop = node.property ("internal-snap-mode"))) {
2274 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2277 if ((prop = node.property ("pre-internal-snap-to"))) {
2278 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2281 if ((prop = node.property ("pre-internal-snap-mode"))) {
2282 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2285 if ((prop = node.property ("mouse-mode"))) {
2286 MouseMode m = str2mousemode(prop->value());
2287 set_mouse_mode (m, true);
2289 set_mouse_mode (MouseObject, true);
2292 if ((prop = node.property ("left-frame")) != 0) {
2294 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2298 reset_x_origin (pos);
2302 if ((prop = node.property ("y-origin")) != 0) {
2303 reset_y_origin (atof (prop->value ()));
2306 if ((prop = node.property ("join-object-range"))) {
2307 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2308 bool yn = string_is_affirmative (prop->value());
2310 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2311 tact->set_active (!yn);
2312 tact->set_active (yn);
2314 set_mouse_mode(mouse_mode, true);
2317 if ((prop = node.property ("edit-point"))) {
2318 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2321 if ((prop = node.property ("show-measures"))) {
2322 bool yn = string_is_affirmative (prop->value());
2323 _show_measures = yn;
2326 if ((prop = node.property ("follow-playhead"))) {
2327 bool yn = string_is_affirmative (prop->value());
2328 set_follow_playhead (yn);
2331 if ((prop = node.property ("stationary-playhead"))) {
2332 bool yn = string_is_affirmative (prop->value());
2333 set_stationary_playhead (yn);
2336 if ((prop = node.property ("region-list-sort-type"))) {
2337 RegionListSortType st;
2338 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2341 if ((prop = node.property ("show-editor-mixer"))) {
2343 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2346 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2347 bool yn = string_is_affirmative (prop->value());
2349 /* do it twice to force the change */
2351 tact->set_active (!yn);
2352 tact->set_active (yn);
2355 if ((prop = node.property ("show-editor-list"))) {
2357 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2360 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2361 bool yn = string_is_affirmative (prop->value());
2363 /* do it twice to force the change */
2365 tact->set_active (!yn);
2366 tact->set_active (yn);
2369 if ((prop = node.property (X_("editor-list-page")))) {
2370 _the_notebook.set_current_page (atoi (prop->value ()));
2373 if ((prop = node.property (X_("show-marker-lines")))) {
2374 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2376 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2377 bool yn = string_is_affirmative (prop->value ());
2379 tact->set_active (!yn);
2380 tact->set_active (yn);
2383 XMLNodeList children = node.children ();
2384 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2385 selection->set_state (**i, Stateful::current_state_version);
2386 _regions->set_state (**i);
2389 if ((prop = node.property ("maximised"))) {
2390 bool yn = string_is_affirmative (prop->value());
2391 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2393 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2394 bool fs = tact && tact->get_active();
2396 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2400 if ((prop = node.property ("nudge-clock-value"))) {
2402 sscanf (prop->value().c_str(), "%" PRId64, &f);
2403 nudge_clock->set (f);
2405 nudge_clock->set_mode (AudioClock::Timecode);
2406 nudge_clock->set (_session->frame_rate() * 5, true);
2411 * Not all properties may have been in XML, but
2412 * those that are linked to a private variable may need changing
2417 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2419 yn = _show_measures;
2420 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2421 /* do it twice to force the change */
2422 tact->set_active (!yn);
2423 tact->set_active (yn);
2426 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2427 yn = _follow_playhead;
2429 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2430 if (tact->get_active() != yn) {
2431 tact->set_active (yn);
2435 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2436 yn = _stationary_playhead;
2438 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2439 if (tact->get_active() != yn) {
2440 tact->set_active (yn);
2449 Editor::get_state ()
2451 XMLNode* node = new XMLNode ("Editor");
2454 id().print (buf, sizeof (buf));
2455 node->add_property ("id", buf);
2457 if (is_realized()) {
2458 Glib::RefPtr<Gdk::Window> win = get_window();
2460 int x, y, width, height;
2461 win->get_root_origin(x, y);
2462 win->get_size(width, height);
2464 XMLNode* geometry = new XMLNode ("geometry");
2466 snprintf(buf, sizeof(buf), "%d", width);
2467 geometry->add_property("x-size", string(buf));
2468 snprintf(buf, sizeof(buf), "%d", height);
2469 geometry->add_property("y-size", string(buf));
2470 snprintf(buf, sizeof(buf), "%d", x);
2471 geometry->add_property("x-pos", string(buf));
2472 snprintf(buf, sizeof(buf), "%d", y);
2473 geometry->add_property("y-pos", string(buf));
2474 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2475 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2476 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2477 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2478 geometry->add_property("edit-vertical-pane-pos", string(buf));
2480 node->add_child_nocopy (*geometry);
2483 maybe_add_mixer_strip_width (*node);
2485 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2487 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2488 node->add_property ("zoom", buf);
2489 node->add_property ("snap-to", enum_2_string (_snap_type));
2490 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2491 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2492 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2493 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2494 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2495 node->add_property ("edit-point", enum_2_string (_edit_point));
2496 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2497 node->add_property ("visible-track-count", buf);
2499 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2500 node->add_property ("playhead", buf);
2501 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2502 node->add_property ("left-frame", buf);
2503 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2504 node->add_property ("y-origin", buf);
2506 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2507 node->add_property ("maximised", _maximised ? "yes" : "no");
2508 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2509 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2510 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2511 node->add_property ("mouse-mode", enum2str(mouse_mode));
2512 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2514 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2516 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2517 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2520 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2522 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2523 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2526 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2527 node->add_property (X_("editor-list-page"), buf);
2529 if (button_bindings) {
2530 XMLNode* bb = new XMLNode (X_("Buttons"));
2531 button_bindings->save (*bb);
2532 node->add_child_nocopy (*bb);
2535 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2537 node->add_child_nocopy (selection->get_state ());
2538 node->add_child_nocopy (_regions->get_state ());
2540 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2541 node->add_property ("nudge-clock-value", buf);
2546 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2547 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2549 * @return pair: TimeAxisView that y is over, layer index.
2551 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2552 * in stacked or expanded region display mode, otherwise 0.
2554 std::pair<TimeAxisView *, double>
2555 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2557 if (!trackview_relative_offset) {
2558 y -= _trackview_group->canvas_origin().y;
2562 return std::make_pair ( (TimeAxisView *) 0, 0);
2565 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2567 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2574 return std::make_pair ( (TimeAxisView *) 0, 0);
2577 /** Snap a position to the grid, if appropriate, taking into account current
2578 * grid settings and also the state of any snap modifier keys that may be pressed.
2579 * @param start Position to snap.
2580 * @param event Event to get current key modifier information from, or 0.
2583 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2585 if (!_session || !event) {
2589 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2590 if (_snap_mode == SnapOff) {
2591 snap_to_internal (start, direction, for_mark);
2594 if (_snap_mode != SnapOff) {
2595 snap_to_internal (start, direction, for_mark);
2601 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark)
2603 if (!_session || _snap_mode == SnapOff) {
2607 snap_to_internal (start, direction, for_mark);
2611 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2613 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2614 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2616 switch (_snap_type) {
2617 case SnapToTimecodeFrame:
2618 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2619 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2620 /* start is already on a whole timecode frame, do nothing */
2621 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2622 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2624 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2628 case SnapToTimecodeSeconds:
2629 if (_session->config.get_timecode_offset_negative()) {
2630 start += _session->config.get_timecode_offset ();
2632 start -= _session->config.get_timecode_offset ();
2634 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2635 (start % one_timecode_second == 0)) {
2636 /* start is already on a whole second, do nothing */
2637 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2638 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2640 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2643 if (_session->config.get_timecode_offset_negative()) {
2644 start -= _session->config.get_timecode_offset ();
2646 start += _session->config.get_timecode_offset ();
2650 case SnapToTimecodeMinutes:
2651 if (_session->config.get_timecode_offset_negative()) {
2652 start += _session->config.get_timecode_offset ();
2654 start -= _session->config.get_timecode_offset ();
2656 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2657 (start % one_timecode_minute == 0)) {
2658 /* start is already on a whole minute, do nothing */
2659 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2660 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2662 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2664 if (_session->config.get_timecode_offset_negative()) {
2665 start -= _session->config.get_timecode_offset ();
2667 start += _session->config.get_timecode_offset ();
2671 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2672 abort(); /*NOTREACHED*/
2677 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark)
2679 const framepos_t one_second = _session->frame_rate();
2680 const framepos_t one_minute = _session->frame_rate() * 60;
2681 framepos_t presnap = start;
2685 switch (_snap_type) {
2686 case SnapToTimecodeFrame:
2687 case SnapToTimecodeSeconds:
2688 case SnapToTimecodeMinutes:
2689 return timecode_snap_to_internal (start, direction, for_mark);
2692 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2693 start % (one_second/75) == 0) {
2694 /* start is already on a whole CD frame, do nothing */
2695 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2696 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2698 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2703 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2704 start % one_second == 0) {
2705 /* start is already on a whole second, do nothing */
2706 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2707 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2709 start = (framepos_t) floor ((double) start / one_second) * one_second;
2714 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2715 start % one_minute == 0) {
2716 /* start is already on a whole minute, do nothing */
2717 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2718 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2720 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2725 start = _session->tempo_map().round_to_bar (start, direction);
2729 start = _session->tempo_map().round_to_beat (start, direction);
2732 case SnapToBeatDiv128:
2733 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2735 case SnapToBeatDiv64:
2736 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2738 case SnapToBeatDiv32:
2739 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2741 case SnapToBeatDiv28:
2742 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2744 case SnapToBeatDiv24:
2745 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2747 case SnapToBeatDiv20:
2748 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2750 case SnapToBeatDiv16:
2751 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2753 case SnapToBeatDiv14:
2754 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2756 case SnapToBeatDiv12:
2757 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2759 case SnapToBeatDiv10:
2760 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2762 case SnapToBeatDiv8:
2763 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2765 case SnapToBeatDiv7:
2766 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2768 case SnapToBeatDiv6:
2769 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2771 case SnapToBeatDiv5:
2772 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2774 case SnapToBeatDiv4:
2775 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2777 case SnapToBeatDiv3:
2778 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2780 case SnapToBeatDiv2:
2781 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2789 _session->locations()->marks_either_side (start, before, after);
2791 if (before == max_framepos && after == max_framepos) {
2792 /* No marks to snap to, so just don't snap */
2794 } else if (before == max_framepos) {
2796 } else if (after == max_framepos) {
2798 } else if (before != max_framepos && after != max_framepos) {
2799 /* have before and after */
2800 if ((start - before) < (after - start)) {
2809 case SnapToRegionStart:
2810 case SnapToRegionEnd:
2811 case SnapToRegionSync:
2812 case SnapToRegionBoundary:
2813 if (!region_boundary_cache.empty()) {
2815 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2816 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2818 if (direction > 0) {
2819 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2821 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2824 if (next != region_boundary_cache.begin ()) {
2829 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2830 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2832 if (start > (p + n) / 2) {
2841 switch (_snap_mode) {
2847 if (presnap > start) {
2848 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2852 } else if (presnap < start) {
2853 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2859 /* handled at entry */
2867 Editor::setup_toolbar ()
2869 HBox* mode_box = manage(new HBox);
2870 mode_box->set_border_width (2);
2871 mode_box->set_spacing(2);
2873 HBox* mouse_mode_box = manage (new HBox);
2874 HBox* mouse_mode_hbox = manage (new HBox);
2875 VBox* mouse_mode_vbox = manage (new VBox);
2876 Alignment* mouse_mode_align = manage (new Alignment);
2878 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2879 mouse_mode_size_group->add_widget (smart_mode_button);
2880 mouse_mode_size_group->add_widget (mouse_move_button);
2881 mouse_mode_size_group->add_widget (mouse_cut_button);
2882 mouse_mode_size_group->add_widget (mouse_select_button);
2883 mouse_mode_size_group->add_widget (mouse_timefx_button);
2884 mouse_mode_size_group->add_widget (mouse_audition_button);
2885 mouse_mode_size_group->add_widget (mouse_draw_button);
2886 mouse_mode_size_group->add_widget (mouse_content_button);
2888 mouse_mode_size_group->add_widget (zoom_in_button);
2889 mouse_mode_size_group->add_widget (zoom_out_button);
2890 mouse_mode_size_group->add_widget (zoom_preset_selector);
2891 mouse_mode_size_group->add_widget (zoom_out_full_button);
2892 mouse_mode_size_group->add_widget (zoom_focus_selector);
2894 mouse_mode_size_group->add_widget (tav_shrink_button);
2895 mouse_mode_size_group->add_widget (tav_expand_button);
2896 mouse_mode_size_group->add_widget (visible_tracks_selector);
2898 mouse_mode_size_group->add_widget (snap_type_selector);
2899 mouse_mode_size_group->add_widget (snap_mode_selector);
2901 mouse_mode_size_group->add_widget (edit_point_selector);
2902 mouse_mode_size_group->add_widget (edit_mode_selector);
2904 mouse_mode_size_group->add_widget (*nudge_clock);
2905 mouse_mode_size_group->add_widget (nudge_forward_button);
2906 mouse_mode_size_group->add_widget (nudge_backward_button);
2908 mouse_mode_hbox->set_spacing (2);
2910 if (!ARDOUR::Profile->get_trx()) {
2911 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2914 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2915 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2917 if (!ARDOUR::Profile->get_mixbus()) {
2918 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2921 if (!ARDOUR::Profile->get_trx()) {
2922 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2923 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2924 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2925 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2928 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2930 mouse_mode_align->add (*mouse_mode_vbox);
2931 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2933 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2935 edit_mode_selector.set_name ("mouse mode button");
2937 if (!ARDOUR::Profile->get_trx()) {
2938 mode_box->pack_start (edit_mode_selector, false, false);
2940 mode_box->pack_start (*mouse_mode_box, false, false);
2942 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2943 _mouse_mode_tearoff->set_name ("MouseModeBase");
2944 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2946 if (Profile->get_sae() || Profile->get_mixbus() ) {
2947 _mouse_mode_tearoff->set_can_be_torn_off (false);
2950 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2951 &_mouse_mode_tearoff->tearoff_window()));
2952 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2953 &_mouse_mode_tearoff->tearoff_window(), 1));
2954 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2955 &_mouse_mode_tearoff->tearoff_window()));
2956 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2957 &_mouse_mode_tearoff->tearoff_window(), 1));
2961 _zoom_box.set_spacing (2);
2962 _zoom_box.set_border_width (2);
2966 zoom_preset_selector.set_name ("zoom button");
2967 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2968 zoom_preset_selector.set_size_request (42, -1);
2970 zoom_in_button.set_name ("zoom button");
2971 zoom_in_button.set_image(::get_icon ("zoom_in"));
2972 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2973 zoom_in_button.set_related_action (act);
2975 zoom_out_button.set_name ("zoom button");
2976 zoom_out_button.set_image(::get_icon ("zoom_out"));
2977 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2978 zoom_out_button.set_related_action (act);
2980 zoom_out_full_button.set_name ("zoom button");
2981 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2982 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2983 zoom_out_full_button.set_related_action (act);
2985 zoom_focus_selector.set_name ("zoom button");
2987 if (ARDOUR::Profile->get_mixbus()) {
2988 _zoom_box.pack_start (zoom_preset_selector, false, false);
2989 } else if (ARDOUR::Profile->get_trx()) {
2990 mode_box->pack_start (zoom_out_button, false, false);
2991 mode_box->pack_start (zoom_in_button, false, false);
2993 _zoom_box.pack_start (zoom_out_button, false, false);
2994 _zoom_box.pack_start (zoom_in_button, false, false);
2995 _zoom_box.pack_start (zoom_out_full_button, false, false);
2996 _zoom_box.pack_start (zoom_focus_selector, false, false);
2999 /* Track zoom buttons */
3000 visible_tracks_selector.set_name ("zoom button");
3001 if (Profile->get_mixbus()) {
3002 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3003 visible_tracks_selector.set_size_request (42, -1);
3005 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3008 tav_expand_button.set_name ("zoom button");
3009 tav_expand_button.set_image(::get_icon ("tav_exp"));
3010 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3011 tav_expand_button.set_related_action (act);
3013 tav_shrink_button.set_name ("zoom button");
3014 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
3015 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3016 tav_shrink_button.set_related_action (act);
3018 if (ARDOUR::Profile->get_mixbus()) {
3019 _zoom_box.pack_start (visible_tracks_selector);
3020 } else if (ARDOUR::Profile->get_trx()) {
3021 _zoom_box.pack_start (tav_shrink_button);
3022 _zoom_box.pack_start (tav_expand_button);
3024 _zoom_box.pack_start (visible_tracks_selector);
3025 _zoom_box.pack_start (tav_shrink_button);
3026 _zoom_box.pack_start (tav_expand_button);
3029 if (!ARDOUR::Profile->get_trx()) {
3030 _zoom_tearoff = manage (new TearOff (_zoom_box));
3032 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3033 &_zoom_tearoff->tearoff_window()));
3034 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3035 &_zoom_tearoff->tearoff_window(), 0));
3036 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3037 &_zoom_tearoff->tearoff_window()));
3038 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3039 &_zoom_tearoff->tearoff_window(), 0));
3042 if (Profile->get_sae() || Profile->get_mixbus() ) {
3043 _zoom_tearoff->set_can_be_torn_off (false);
3046 snap_box.set_spacing (2);
3047 snap_box.set_border_width (2);
3049 snap_type_selector.set_name ("mouse mode button");
3051 snap_mode_selector.set_name ("mouse mode button");
3053 edit_point_selector.set_name ("mouse mode button");
3055 snap_box.pack_start (snap_mode_selector, false, false);
3056 snap_box.pack_start (snap_type_selector, false, false);
3057 snap_box.pack_start (edit_point_selector, false, false);
3061 HBox *nudge_box = manage (new HBox);
3062 nudge_box->set_spacing (2);
3063 nudge_box->set_border_width (2);
3065 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3066 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3068 nudge_box->pack_start (nudge_backward_button, false, false);
3069 nudge_box->pack_start (nudge_forward_button, false, false);
3070 nudge_box->pack_start (*nudge_clock, false, false);
3073 /* Pack everything in... */
3075 HBox* hbox = manage (new HBox);
3076 hbox->set_spacing(2);
3078 _tools_tearoff = manage (new TearOff (*hbox));
3079 _tools_tearoff->set_name ("MouseModeBase");
3080 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3082 if (Profile->get_sae() || Profile->get_mixbus()) {
3083 _tools_tearoff->set_can_be_torn_off (false);
3086 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3087 &_tools_tearoff->tearoff_window()));
3088 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3089 &_tools_tearoff->tearoff_window(), 0));
3090 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3091 &_tools_tearoff->tearoff_window()));
3092 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3093 &_tools_tearoff->tearoff_window(), 0));
3095 toolbar_hbox.set_spacing (2);
3096 toolbar_hbox.set_border_width (1);
3098 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3099 if (!ARDOUR::Profile->get_trx()) {
3100 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3101 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3104 if (!ARDOUR::Profile->get_trx()) {
3105 hbox->pack_start (snap_box, false, false);
3106 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3107 hbox->pack_start (*nudge_box, false, false);
3109 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3112 hbox->pack_start (panic_box, false, false);
3116 toolbar_base.set_name ("ToolBarBase");
3117 toolbar_base.add (toolbar_hbox);
3119 _toolbar_viewport.add (toolbar_base);
3120 /* stick to the required height but allow width to vary if there's not enough room */
3121 _toolbar_viewport.set_size_request (1, -1);
3123 toolbar_frame.set_shadow_type (SHADOW_OUT);
3124 toolbar_frame.set_name ("BaseFrame");
3125 toolbar_frame.add (_toolbar_viewport);
3129 Editor::build_edit_point_menu ()
3131 using namespace Menu_Helpers;
3133 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3134 if(!Profile->get_mixbus())
3135 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3136 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3138 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3142 Editor::build_edit_mode_menu ()
3144 using namespace Menu_Helpers;
3146 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3147 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3148 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3149 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3151 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3155 Editor::build_snap_mode_menu ()
3157 using namespace Menu_Helpers;
3159 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3160 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3161 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3163 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3167 Editor::build_snap_type_menu ()
3169 using namespace Menu_Helpers;
3171 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3172 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3173 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3174 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3175 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3176 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3177 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3178 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3179 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3180 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3181 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3182 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3183 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3184 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3185 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3186 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3187 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3188 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3189 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3190 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3191 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3192 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3193 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3194 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3195 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3196 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3197 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3198 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3199 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3200 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3202 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3207 Editor::setup_tooltips ()
3209 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Grab mode)"));
3210 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Grab Mode (select/move objects)"));
3211 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split regions)"));
3212 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select time ranges)"));
3213 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3214 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3215 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3216 ARDOUR_UI::instance()->set_tip (mouse_content_button, _("Internal Edit Mode (edit notes and gain curves inside regions)"));
3217 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3218 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3219 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3220 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3221 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3222 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3223 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3224 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3225 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3226 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3227 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3228 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3229 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3230 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3231 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3232 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3236 Editor::convert_drop_to_paths (
3237 vector<string>& paths,
3238 const RefPtr<Gdk::DragContext>& /*context*/,
3241 const SelectionData& data,
3245 if (_session == 0) {
3249 vector<string> uris = data.get_uris();
3253 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3254 are actually URI lists. So do it by hand.
3257 if (data.get_target() != "text/plain") {
3261 /* Parse the "uri-list" format that Nautilus provides,
3262 where each pathname is delimited by \r\n.
3264 THERE MAY BE NO NULL TERMINATING CHAR!!!
3267 string txt = data.get_text();
3271 p = (char *) malloc (txt.length() + 1);
3272 txt.copy (p, txt.length(), 0);
3273 p[txt.length()] = '\0';
3279 while (g_ascii_isspace (*p))
3283 while (*q && (*q != '\n') && (*q != '\r')) {
3290 while (q > p && g_ascii_isspace (*q))
3295 uris.push_back (string (p, q - p + 1));
3299 p = strchr (p, '\n');
3311 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3312 if ((*i).substr (0,7) == "file://") {
3313 paths.push_back (Glib::filename_from_uri (*i));
3321 Editor::new_tempo_section ()
3326 Editor::map_transport_state ()
3328 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3330 if (_session && _session->transport_stopped()) {
3331 have_pending_keyboard_selection = false;
3334 update_loop_range_view ();
3340 Editor::begin_selection_op_history ()
3342 selection_op_cmd_depth = 0;
3343 selection_op_history_it = 0;
3345 while(!selection_op_history.empty()) {
3346 delete selection_op_history.front();
3347 selection_op_history.pop_front();
3350 selection_undo_action->set_sensitive (false);
3351 selection_redo_action->set_sensitive (false);
3352 selection_op_history.push_front (&_selection_memento->get_state ());
3356 Editor::begin_reversible_selection_op (string name)
3359 //cerr << name << endl;
3360 /* begin/commit pairs can be nested */
3361 selection_op_cmd_depth++;
3366 Editor::commit_reversible_selection_op ()
3369 if (selection_op_cmd_depth == 1) {
3371 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3373 The user has undone some selection ops and then made a new one,
3374 making anything earlier in the list invalid.
3377 list<XMLNode *>::iterator it = selection_op_history.begin();
3378 list<XMLNode *>::iterator e_it = it;
3379 advance (e_it, selection_op_history_it);
3381 for ( ; it != e_it; ++it) {
3384 selection_op_history.erase (selection_op_history.begin(), e_it);
3387 selection_op_history.push_front (&_selection_memento->get_state ());
3388 selection_op_history_it = 0;
3390 selection_undo_action->set_sensitive (true);
3391 selection_redo_action->set_sensitive (false);
3394 if (selection_op_cmd_depth > 0) {
3395 selection_op_cmd_depth--;
3401 Editor::undo_selection_op ()
3404 selection_op_history_it++;
3406 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3407 if (n == selection_op_history_it) {
3408 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3409 selection_redo_action->set_sensitive (true);
3413 /* is there an earlier entry? */
3414 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3415 selection_undo_action->set_sensitive (false);
3421 Editor::redo_selection_op ()
3424 if (selection_op_history_it > 0) {
3425 selection_op_history_it--;
3428 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3429 if (n == selection_op_history_it) {
3430 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3431 selection_undo_action->set_sensitive (true);
3436 if (selection_op_history_it == 0) {
3437 selection_redo_action->set_sensitive (false);
3443 Editor::begin_reversible_command (string name)
3446 before.push_back (&_selection_memento->get_state ());
3447 _session->begin_reversible_command (name);
3452 Editor::begin_reversible_command (GQuark q)
3455 before.push_back (&_selection_memento->get_state ());
3456 _session->begin_reversible_command (q);
3461 Editor::abort_reversible_command ()
3464 while(!before.empty()) {
3465 delete before.front();
3468 _session->abort_reversible_command ();
3473 Editor::commit_reversible_command ()
3476 if (before.size() == 1) {
3477 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3478 redo_action->set_sensitive(false);
3479 undo_action->set_sensitive(true);
3480 begin_selection_op_history ();
3483 if (before.empty()) {
3484 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3489 _session->commit_reversible_command ();
3494 Editor::history_changed ()
3498 if (undo_action && _session) {
3499 if (_session->undo_depth() == 0) {
3500 label = S_("Command|Undo");
3502 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3504 undo_action->property_label() = label;
3507 if (redo_action && _session) {
3508 if (_session->redo_depth() == 0) {
3511 label = string_compose(_("Redo (%1)"), _session->next_redo());
3513 redo_action->property_label() = label;
3518 Editor::duplicate_range (bool with_dialog)
3522 RegionSelection rs = get_regions_from_selection_and_entered ();
3524 if ( selection->time.length() == 0 && rs.empty()) {
3530 ArdourDialog win (_("Duplicate"));
3531 Label label (_("Number of duplications:"));
3532 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3533 SpinButton spinner (adjustment, 0.0, 1);
3536 win.get_vbox()->set_spacing (12);
3537 win.get_vbox()->pack_start (hbox);
3538 hbox.set_border_width (6);
3539 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3541 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3542 place, visually. so do this by hand.
3545 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3546 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3547 spinner.grab_focus();
3553 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3554 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3555 win.set_default_response (RESPONSE_ACCEPT);
3557 spinner.grab_focus ();
3559 switch (win.run ()) {
3560 case RESPONSE_ACCEPT:
3566 times = adjustment.get_value();
3569 if ((current_mouse_mode() == Editing::MouseRange)) {
3570 if (selection->time.length()) {
3571 duplicate_selection (times);
3573 } else if (get_smart_mode()) {
3574 if (selection->time.length()) {
3575 duplicate_selection (times);
3577 duplicate_some_regions (rs, times);
3579 duplicate_some_regions (rs, times);
3584 Editor::set_edit_mode (EditMode m)
3586 Config->set_edit_mode (m);
3590 Editor::cycle_edit_mode ()
3592 switch (Config->get_edit_mode()) {
3594 if (Profile->get_sae()) {
3595 Config->set_edit_mode (Lock);
3597 Config->set_edit_mode (Ripple);
3602 Config->set_edit_mode (Lock);
3605 Config->set_edit_mode (Slide);
3611 Editor::edit_mode_selection_done ( EditMode m )
3613 Config->set_edit_mode ( m );
3617 Editor::snap_type_selection_done (SnapType snaptype)
3619 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3621 ract->set_active ();
3626 Editor::snap_mode_selection_done (SnapMode mode)
3628 RefPtr<RadioAction> ract = snap_mode_action (mode);
3631 ract->set_active (true);
3636 Editor::cycle_edit_point (bool with_marker)
3638 if(Profile->get_mixbus())
3639 with_marker = false;
3641 switch (_edit_point) {
3643 set_edit_point_preference (EditAtPlayhead);
3645 case EditAtPlayhead:
3647 set_edit_point_preference (EditAtSelectedMarker);
3649 set_edit_point_preference (EditAtMouse);
3652 case EditAtSelectedMarker:
3653 set_edit_point_preference (EditAtMouse);
3659 Editor::edit_point_selection_done (EditPoint ep)
3661 set_edit_point_preference ( ep );
3665 Editor::build_zoom_focus_menu ()
3667 using namespace Menu_Helpers;
3669 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3670 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3671 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3672 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3673 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3674 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3676 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3680 Editor::zoom_focus_selection_done ( ZoomFocus f )
3682 RefPtr<RadioAction> ract = zoom_focus_action (f);
3684 ract->set_active ();
3689 Editor::build_track_count_menu ()
3691 using namespace Menu_Helpers;
3693 if (!Profile->get_mixbus()) {
3694 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3695 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3696 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3697 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3698 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3699 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3700 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3701 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3702 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3703 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3704 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3705 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3706 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3708 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3709 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3710 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3711 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3712 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3713 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3714 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3715 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3716 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3717 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3719 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3720 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3721 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3722 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3723 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3724 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3725 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3726 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3727 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3728 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3729 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3734 Editor::set_zoom_preset (int64_t ms)
3737 temporal_zoom_session();
3741 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3742 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3746 Editor::set_visible_track_count (int32_t n)
3748 _visible_track_count = n;
3750 /* if the canvas hasn't really been allocated any size yet, just
3751 record the desired number of visible tracks and return. when canvas
3752 allocation happens, we will get called again and then we can do the
3756 if (_visible_canvas_height <= 1) {
3762 DisplaySuspender ds;
3764 if (_visible_track_count > 0) {
3765 h = trackviews_height() / _visible_track_count;
3766 std::ostringstream s;
3767 s << _visible_track_count;
3769 } else if (_visible_track_count == 0) {
3771 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3772 if ((*i)->marked_for_display()) {
3776 h = trackviews_height() / n;
3779 /* negative value means that the visible track count has
3780 been overridden by explicit track height changes.
3782 visible_tracks_selector.set_text (X_("*"));
3786 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3787 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3790 if (str != visible_tracks_selector.get_text()) {
3791 visible_tracks_selector.set_text (str);
3796 Editor::override_visible_track_count ()
3798 _visible_track_count = -1;
3799 visible_tracks_selector.set_text ( _("*") );
3803 Editor::edit_controls_button_release (GdkEventButton* ev)
3805 if (Keyboard::is_context_menu_event (ev)) {
3806 ARDOUR_UI::instance()->add_route (this);
3807 } else if (ev->button == 1) {
3808 selection->clear_tracks ();
3815 Editor::mouse_select_button_release (GdkEventButton* ev)
3817 /* this handles just right-clicks */
3819 if (ev->button != 3) {
3827 Editor::set_zoom_focus (ZoomFocus f)
3829 string str = zoom_focus_strings[(int)f];
3831 if (str != zoom_focus_selector.get_text()) {
3832 zoom_focus_selector.set_text (str);
3835 if (zoom_focus != f) {
3842 Editor::cycle_zoom_focus ()
3844 switch (zoom_focus) {
3846 set_zoom_focus (ZoomFocusRight);
3848 case ZoomFocusRight:
3849 set_zoom_focus (ZoomFocusCenter);
3851 case ZoomFocusCenter:
3852 set_zoom_focus (ZoomFocusPlayhead);
3854 case ZoomFocusPlayhead:
3855 set_zoom_focus (ZoomFocusMouse);
3857 case ZoomFocusMouse:
3858 set_zoom_focus (ZoomFocusEdit);
3861 set_zoom_focus (ZoomFocusLeft);
3867 Editor::ensure_float (Window& win)
3869 win.set_transient_for (*this);
3873 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3875 /* recover or initialize pane positions. do this here rather than earlier because
3876 we don't want the positions to change the child allocations, which they seem to do.
3882 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3891 XMLNode* geometry = find_named_node (*node, "geometry");
3893 if (which == static_cast<Paned*> (&edit_pane)) {
3895 if (done & Horizontal) {
3899 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3900 _notebook_shrunk = string_is_affirmative (prop->value ());
3903 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3904 /* initial allocation is 90% to canvas, 10% to notebook */
3905 pos = (int) floor (alloc.get_width() * 0.90f);
3906 snprintf (buf, sizeof(buf), "%d", pos);
3908 pos = atoi (prop->value());
3911 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3912 edit_pane.set_position (pos);
3915 done = (Pane) (done | Horizontal);
3917 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3919 if (done & Vertical) {
3923 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3924 /* initial allocation is 90% to canvas, 10% to summary */
3925 pos = (int) floor (alloc.get_height() * 0.90f);
3926 snprintf (buf, sizeof(buf), "%d", pos);
3929 pos = atoi (prop->value());
3932 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3933 editor_summary_pane.set_position (pos);
3936 done = (Pane) (done | Vertical);
3941 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3943 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3944 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3945 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3946 top_hbox.remove (toolbar_frame);
3951 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3953 if (toolbar_frame.get_parent() == 0) {
3954 top_hbox.pack_end (toolbar_frame);
3959 Editor::set_show_measures (bool yn)
3961 if (_show_measures != yn) {
3964 if ((_show_measures = yn) == true) {
3966 tempo_lines->show();
3969 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3970 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3972 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3973 draw_measures (begin, end);
3981 Editor::toggle_follow_playhead ()
3983 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3985 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3986 set_follow_playhead (tact->get_active());
3990 /** @param yn true to follow playhead, otherwise false.
3991 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3994 Editor::set_follow_playhead (bool yn, bool catch_up)
3996 if (_follow_playhead != yn) {
3997 if ((_follow_playhead = yn) == true && catch_up) {
3999 reset_x_origin_to_follow_playhead ();
4006 Editor::toggle_stationary_playhead ()
4008 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4010 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4011 set_stationary_playhead (tact->get_active());
4016 Editor::set_stationary_playhead (bool yn)
4018 if (_stationary_playhead != yn) {
4019 if ((_stationary_playhead = yn) == true) {
4021 // FIXME need a 3.0 equivalent of this 2.X call
4022 // update_current_screen ();
4029 Editor::playlist_selector () const
4031 return *_playlist_selector;
4035 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4037 if (paste_count == 0) {
4038 /* don't bother calculating an offset that will be zero anyway */
4042 /* calculate basic unsnapped multi-paste offset */
4043 framecnt_t offset = paste_count * duration;
4045 /* snap offset so pos + offset is aligned to the grid */
4046 framepos_t offset_pos = pos + offset;
4047 snap_to(offset_pos, RoundUpMaybe);
4048 offset = offset_pos - pos;
4054 Editor::get_grid_beat_divisions(framepos_t position)
4056 switch (_snap_type) {
4057 case SnapToBeatDiv128: return 128;
4058 case SnapToBeatDiv64: return 64;
4059 case SnapToBeatDiv32: return 32;
4060 case SnapToBeatDiv28: return 28;
4061 case SnapToBeatDiv24: return 24;
4062 case SnapToBeatDiv20: return 20;
4063 case SnapToBeatDiv16: return 16;
4064 case SnapToBeatDiv14: return 14;
4065 case SnapToBeatDiv12: return 12;
4066 case SnapToBeatDiv10: return 10;
4067 case SnapToBeatDiv8: return 8;
4068 case SnapToBeatDiv7: return 7;
4069 case SnapToBeatDiv6: return 6;
4070 case SnapToBeatDiv5: return 5;
4071 case SnapToBeatDiv4: return 4;
4072 case SnapToBeatDiv3: return 3;
4073 case SnapToBeatDiv2: return 2;
4080 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4084 const unsigned divisions = get_grid_beat_divisions(position);
4086 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4089 switch (_snap_type) {
4091 return Evoral::Beats(1.0);
4094 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
4102 return Evoral::Beats();
4106 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4110 ret = nudge_clock->current_duration (pos);
4111 next = ret + 1; /* XXXX fix me */
4117 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4119 ArdourDialog dialog (_("Playlist Deletion"));
4120 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4121 "If it is kept, its audio files will not be cleaned.\n"
4122 "If it is deleted, audio files used by it alone will be cleaned."),
4125 dialog.set_position (WIN_POS_CENTER);
4126 dialog.get_vbox()->pack_start (label);
4130 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4131 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4132 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4134 switch (dialog.run ()) {
4135 case RESPONSE_ACCEPT:
4136 /* delete the playlist */
4140 case RESPONSE_REJECT:
4141 /* keep the playlist */
4153 Editor::audio_region_selection_covers (framepos_t where)
4155 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4156 if ((*a)->region()->covers (where)) {
4165 Editor::prepare_for_cleanup ()
4167 cut_buffer->clear_regions ();
4168 cut_buffer->clear_playlists ();
4170 selection->clear_regions ();
4171 selection->clear_playlists ();
4173 _regions->suspend_redisplay ();
4177 Editor::finish_cleanup ()
4179 _regions->resume_redisplay ();
4183 Editor::transport_loop_location()
4186 return _session->locations()->auto_loop_location();
4193 Editor::transport_punch_location()
4196 return _session->locations()->auto_punch_location();
4203 Editor::control_layout_scroll (GdkEventScroll* ev)
4205 /* Just forward to the normal canvas scroll method. The coordinate
4206 systems are different but since the canvas is always larger than the
4207 track headers, and aligned with the trackview area, this will work.
4209 In the not too distant future this layout is going away anyway and
4210 headers will be on the canvas.
4212 return canvas_scroll_event (ev, false);
4216 Editor::session_state_saved (string)
4219 _snapshots->redisplay ();
4223 Editor::update_tearoff_visibility()
4225 bool visible = ARDOUR_UI::config()->get_keep_tearoffs();
4226 _mouse_mode_tearoff->set_visible (visible);
4227 _tools_tearoff->set_visible (visible);
4228 if (_zoom_tearoff) {
4229 _zoom_tearoff->set_visible (visible);
4234 Editor::reattach_all_tearoffs ()
4236 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4237 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4238 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4242 Editor::maximise_editing_space ()
4254 Editor::restore_editing_space ()
4266 * Make new playlists for a given track and also any others that belong
4267 * to the same active route group with the `select' property.
4272 Editor::new_playlists (TimeAxisView* v)
4274 begin_reversible_command (_("new playlists"));
4275 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4276 _session->playlists->get (playlists);
4277 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4278 commit_reversible_command ();
4282 * Use a copy of the current playlist for a given track and also any others that belong
4283 * to the same active route group with the `select' property.
4288 Editor::copy_playlists (TimeAxisView* v)
4290 begin_reversible_command (_("copy playlists"));
4291 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4292 _session->playlists->get (playlists);
4293 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4294 commit_reversible_command ();
4297 /** Clear the current playlist for a given track and also any others that belong
4298 * to the same active route group with the `select' property.
4303 Editor::clear_playlists (TimeAxisView* v)
4305 begin_reversible_command (_("clear playlists"));
4306 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4307 _session->playlists->get (playlists);
4308 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4309 commit_reversible_command ();
4313 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4315 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4319 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4321 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4325 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4327 atv.clear_playlist ();
4331 Editor::on_key_press_event (GdkEventKey* ev)
4333 return key_press_focus_accelerator_handler (*this, ev);
4337 Editor::on_key_release_event (GdkEventKey* ev)
4339 return Gtk::Window::on_key_release_event (ev);
4340 // return key_press_focus_accelerator_handler (*this, ev);
4344 Editor::get_y_origin () const
4346 return vertical_adjustment.get_value ();
4349 /** Queue up a change to the viewport x origin.
4350 * @param frame New x origin.
4353 Editor::reset_x_origin (framepos_t frame)
4355 pending_visual_change.add (VisualChange::TimeOrigin);
4356 pending_visual_change.time_origin = frame;
4357 ensure_visual_change_idle_handler ();
4361 Editor::reset_y_origin (double y)
4363 pending_visual_change.add (VisualChange::YOrigin);
4364 pending_visual_change.y_origin = y;
4365 ensure_visual_change_idle_handler ();
4369 Editor::reset_zoom (framecnt_t spp)
4371 if (spp == samples_per_pixel) {
4375 pending_visual_change.add (VisualChange::ZoomLevel);
4376 pending_visual_change.samples_per_pixel = spp;
4377 ensure_visual_change_idle_handler ();
4381 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4383 reset_x_origin (frame);
4386 if (!no_save_visual) {
4387 undo_visual_stack.push_back (current_visual_state(false));
4391 Editor::VisualState::VisualState (bool with_tracks)
4392 : gui_state (with_tracks ? new GUIObjectState : 0)
4396 Editor::VisualState::~VisualState ()
4401 Editor::VisualState*
4402 Editor::current_visual_state (bool with_tracks)
4404 VisualState* vs = new VisualState (with_tracks);
4405 vs->y_position = vertical_adjustment.get_value();
4406 vs->samples_per_pixel = samples_per_pixel;
4407 vs->leftmost_frame = leftmost_frame;
4408 vs->zoom_focus = zoom_focus;
4411 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4418 Editor::undo_visual_state ()
4420 if (undo_visual_stack.empty()) {
4424 VisualState* vs = undo_visual_stack.back();
4425 undo_visual_stack.pop_back();
4428 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4431 use_visual_state (*vs);
4436 Editor::redo_visual_state ()
4438 if (redo_visual_stack.empty()) {
4442 VisualState* vs = redo_visual_stack.back();
4443 redo_visual_stack.pop_back();
4445 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4446 // why do we check here?
4447 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4450 use_visual_state (*vs);
4455 Editor::swap_visual_state ()
4457 if (undo_visual_stack.empty()) {
4458 redo_visual_state ();
4460 undo_visual_state ();
4465 Editor::use_visual_state (VisualState& vs)
4467 PBD::Unwinder<bool> nsv (no_save_visual, true);
4468 DisplaySuspender ds;
4470 vertical_adjustment.set_value (vs.y_position);
4472 set_zoom_focus (vs.zoom_focus);
4473 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4476 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4478 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4479 (*i)->clear_property_cache();
4480 (*i)->reset_visual_state ();
4484 _routes->update_visibility ();
4487 /** This is the core function that controls the zoom level of the canvas. It is called
4488 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4489 * @param spp new number of samples per pixel
4492 Editor::set_samples_per_pixel (framecnt_t spp)
4498 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4499 const framecnt_t lots_of_pixels = 4000;
4501 /* if the zoom level is greater than what you'd get trying to display 3
4502 * days of audio on a really big screen, then it's too big.
4505 if (spp * lots_of_pixels > three_days) {
4509 samples_per_pixel = spp;
4512 tempo_lines->tempo_map_changed();
4515 bool const showing_time_selection = selection->time.length() > 0;
4517 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4518 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4519 (*i)->reshow_selection (selection->time);
4523 ZoomChanged (); /* EMIT_SIGNAL */
4525 ArdourCanvas::GtkCanvasViewport* c;
4527 c = get_track_canvas();
4529 c->canvas()->zoomed ();
4532 if (playhead_cursor) {
4533 playhead_cursor->set_position (playhead_cursor->current_frame ());
4536 refresh_location_display();
4537 _summary->set_overlays_dirty ();
4539 update_marker_labels ();
4545 Editor::queue_visual_videotimeline_update ()
4548 * pending_visual_change.add (VisualChange::VideoTimeline);
4549 * or maybe even more specific: which videotimeline-image
4550 * currently it calls update_video_timeline() to update
4551 * _all outdated_ images on the video-timeline.
4552 * see 'exposeimg()' in video_image_frame.cc
4554 ensure_visual_change_idle_handler ();
4558 Editor::ensure_visual_change_idle_handler ()
4560 if (pending_visual_change.idle_handler_id < 0) {
4561 // see comment in add_to_idle_resize above.
4562 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4563 pending_visual_change.being_handled = false;
4568 Editor::_idle_visual_changer (void* arg)
4570 return static_cast<Editor*>(arg)->idle_visual_changer ();
4574 Editor::idle_visual_changer ()
4576 /* set_horizontal_position() below (and maybe other calls) call
4577 gtk_main_iteration(), so it's possible that a signal will be handled
4578 half-way through this method. If this signal wants an
4579 idle_visual_changer we must schedule another one after this one, so
4580 mark the idle_handler_id as -1 here to allow that. Also make a note
4581 that we are doing the visual change, so that changes in response to
4582 super-rapid-screen-update can be dropped if we are still processing
4586 pending_visual_change.idle_handler_id = -1;
4587 pending_visual_change.being_handled = true;
4589 VisualChange vc = pending_visual_change;
4591 pending_visual_change.pending = (VisualChange::Type) 0;
4593 visual_changer (vc);
4595 pending_visual_change.being_handled = false;
4597 return 0; /* this is always a one-shot call */
4601 Editor::visual_changer (const VisualChange& vc)
4603 double const last_time_origin = horizontal_position ();
4605 if (vc.pending & VisualChange::ZoomLevel) {
4606 set_samples_per_pixel (vc.samples_per_pixel);
4608 compute_fixed_ruler_scale ();
4610 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4611 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4613 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4614 current_bbt_points_begin, current_bbt_points_end);
4615 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4616 current_bbt_points_begin, current_bbt_points_end);
4617 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4619 update_video_timeline();
4622 if (vc.pending & VisualChange::TimeOrigin) {
4623 set_horizontal_position (vc.time_origin / samples_per_pixel);
4626 if (vc.pending & VisualChange::YOrigin) {
4627 vertical_adjustment.set_value (vc.y_origin);
4630 if (last_time_origin == horizontal_position ()) {
4631 /* changed signal not emitted */
4632 update_fixed_rulers ();
4633 redisplay_tempo (true);
4636 if (!(vc.pending & VisualChange::ZoomLevel)) {
4637 update_video_timeline();
4640 _summary->set_overlays_dirty ();
4643 struct EditorOrderTimeAxisSorter {
4644 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4645 return a->order () < b->order ();
4650 Editor::sort_track_selection (TrackViewList& sel)
4652 EditorOrderTimeAxisSorter cmp;
4657 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu, bool from_outside_canvas)
4660 framepos_t where = 0;
4661 EditPoint ep = _edit_point;
4663 if(Profile->get_mixbus())
4664 if (ep == EditAtSelectedMarker)
4667 if (from_outside_canvas && (ep == EditAtMouse)) {
4668 ep = EditAtPlayhead;
4669 } else if (from_context_menu && (ep == EditAtMouse)) {
4670 return canvas_event_sample (&context_click_event, 0, 0);
4673 if (entered_marker) {
4674 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4675 return entered_marker->position();
4678 if (ignore_playhead && ep == EditAtPlayhead) {
4679 ep = EditAtSelectedMarker;
4683 case EditAtPlayhead:
4684 if (_dragging_playhead) {
4685 if (!mouse_frame (where, ignored)) {
4686 /* XXX not right but what can we do ? */
4690 where = _session->audible_frame();
4691 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4694 case EditAtSelectedMarker:
4695 if (!selection->markers.empty()) {
4697 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4700 where = loc->start();
4704 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4712 if (!mouse_frame (where, ignored)) {
4713 /* XXX not right but what can we do ? */
4717 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4725 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4727 if (!_session) return;
4729 begin_reversible_command (cmd);
4733 if ((tll = transport_loop_location()) == 0) {
4734 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4735 XMLNode &before = _session->locations()->get_state();
4736 _session->locations()->add (loc, true);
4737 _session->set_auto_loop_location (loc);
4738 XMLNode &after = _session->locations()->get_state();
4739 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4741 XMLNode &before = tll->get_state();
4742 tll->set_hidden (false, this);
4743 tll->set (start, end);
4744 XMLNode &after = tll->get_state();
4745 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4748 commit_reversible_command ();
4752 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4754 if (!_session) return;
4756 begin_reversible_command (cmd);
4760 if ((tpl = transport_punch_location()) == 0) {
4761 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4762 XMLNode &before = _session->locations()->get_state();
4763 _session->locations()->add (loc, true);
4764 _session->set_auto_punch_location (loc);
4765 XMLNode &after = _session->locations()->get_state();
4766 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4768 XMLNode &before = tpl->get_state();
4769 tpl->set_hidden (false, this);
4770 tpl->set (start, end);
4771 XMLNode &after = tpl->get_state();
4772 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4775 commit_reversible_command ();
4778 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4779 * @param rs List to which found regions are added.
4780 * @param where Time to look at.
4781 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4784 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4786 const TrackViewList* tracks;
4789 tracks = &track_views;
4794 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4796 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4799 boost::shared_ptr<Track> tr;
4800 boost::shared_ptr<Playlist> pl;
4802 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4804 boost::shared_ptr<RegionList> regions = pl->regions_at (
4805 (framepos_t) floor ( (double) where * tr->speed()));
4807 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4808 RegionView* rv = rtv->view()->find_view (*i);
4819 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4821 const TrackViewList* tracks;
4824 tracks = &track_views;
4829 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4830 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4832 boost::shared_ptr<Track> tr;
4833 boost::shared_ptr<Playlist> pl;
4835 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4837 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4838 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4840 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4842 RegionView* rv = rtv->view()->find_view (*i);
4853 /** Get regions using the following method:
4855 * Make a region list using:
4856 * (a) any selected regions
4857 * (b) the intersection of any selected tracks and the edit point(*)
4858 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4860 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4862 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4866 Editor::get_regions_from_selection_and_edit_point ()
4868 RegionSelection regions;
4870 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4871 regions.add (entered_regionview);
4873 regions = selection->regions;
4876 if ( regions.empty() ) {
4877 TrackViewList tracks = selection->tracks;
4879 if (!tracks.empty()) {
4880 /* no region selected or entered, but some selected tracks:
4881 * act on all regions on the selected tracks at the edit point
4883 framepos_t const where = get_preferred_edit_position ();
4884 get_regions_at(regions, where, tracks);
4891 /** Get regions using the following method:
4893 * Make a region list using:
4894 * (a) any selected regions
4895 * (b) the intersection of any selected tracks and the edit point(*)
4896 * (c) if neither exists, then whatever region is under the mouse
4898 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4900 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4903 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4905 RegionSelection regions;
4907 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4908 regions.add (entered_regionview);
4910 regions = selection->regions;
4913 if ( regions.empty() ) {
4914 TrackViewList tracks = selection->tracks;
4916 if (!tracks.empty()) {
4917 /* no region selected or entered, but some selected tracks:
4918 * act on all regions on the selected tracks at the edit point
4920 get_regions_at(regions, pos, tracks);
4927 /** Start with regions that are selected, or the entered regionview if none are selected.
4928 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4929 * of the regions that we started with.
4933 Editor::get_regions_from_selection_and_entered ()
4935 RegionSelection regions = selection->regions;
4937 if (regions.empty() && entered_regionview) {
4938 regions.add (entered_regionview);
4945 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4947 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4948 RouteTimeAxisView* rtav;
4950 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4951 boost::shared_ptr<Playlist> pl;
4952 std::vector<boost::shared_ptr<Region> > results;
4953 boost::shared_ptr<Track> tr;
4955 if ((tr = rtav->track()) == 0) {
4960 if ((pl = (tr->playlist())) != 0) {
4961 boost::shared_ptr<Region> r = pl->region_by_id (id);
4963 RegionView* rv = rtav->view()->find_view (r);
4965 regions.push_back (rv);
4974 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4977 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4978 MidiTimeAxisView* mtav;
4980 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4982 mtav->get_per_region_note_selection (selection);
4989 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4991 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4993 RouteTimeAxisView* tatv;
4995 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4997 boost::shared_ptr<Playlist> pl;
4998 vector<boost::shared_ptr<Region> > results;
5000 boost::shared_ptr<Track> tr;
5002 if ((tr = tatv->track()) == 0) {
5007 if ((pl = (tr->playlist())) != 0) {
5008 if (src_comparison) {
5009 pl->get_source_equivalent_regions (region, results);
5011 pl->get_region_list_equivalent_regions (region, results);
5015 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5016 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5017 regions.push_back (marv);
5026 Editor::show_rhythm_ferret ()
5028 if (rhythm_ferret == 0) {
5029 rhythm_ferret = new RhythmFerret(*this);
5032 rhythm_ferret->set_session (_session);
5033 rhythm_ferret->show ();
5034 rhythm_ferret->present ();
5038 Editor::first_idle ()
5040 MessageDialog* dialog = 0;
5042 if (track_views.size() > 1) {
5043 dialog = new MessageDialog (
5045 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5049 ARDOUR_UI::instance()->flush_pending ();
5052 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5056 // first idle adds route children (automation tracks), so we need to redisplay here
5057 _routes->redisplay ();
5061 if (_session->undo_depth() == 0) {
5062 undo_action->set_sensitive(false);
5064 redo_action->set_sensitive(false);
5065 begin_selection_op_history ();
5071 Editor::_idle_resize (gpointer arg)
5073 return ((Editor*)arg)->idle_resize ();
5077 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5079 if (resize_idle_id < 0) {
5080 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5081 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5082 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5084 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5085 _pending_resize_amount = 0;
5088 /* make a note of the smallest resulting height, so that we can clamp the
5089 lower limit at TimeAxisView::hSmall */
5091 int32_t min_resulting = INT32_MAX;
5093 _pending_resize_amount += h;
5094 _pending_resize_view = view;
5096 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5098 if (selection->tracks.contains (_pending_resize_view)) {
5099 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5100 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5104 if (min_resulting < 0) {
5109 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5110 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5114 /** Handle pending resizing of tracks */
5116 Editor::idle_resize ()
5118 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5120 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5121 selection->tracks.contains (_pending_resize_view)) {
5123 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5124 if (*i != _pending_resize_view) {
5125 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5130 _pending_resize_amount = 0;
5131 _group_tabs->set_dirty ();
5132 resize_idle_id = -1;
5140 ENSURE_GUI_THREAD (*this, &Editor::located);
5143 playhead_cursor->set_position (_session->audible_frame ());
5144 if (_follow_playhead && !_pending_initial_locate) {
5145 reset_x_origin_to_follow_playhead ();
5149 _pending_locate_request = false;
5150 _pending_initial_locate = false;
5154 Editor::region_view_added (RegionView * rv)
5156 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5157 if (rv->region ()->id () == (*pr)) {
5158 selection->add (rv);
5159 selection->regions.pending.erase (pr);
5164 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5166 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5167 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5168 if (rv->region()->id () == (*rnote).first) {
5169 mrv->select_notes ((*rnote).second);
5170 selection->pending_midi_note_selection.erase(rnote);
5176 _summary->set_background_dirty ();
5180 Editor::region_view_removed ()
5182 _summary->set_background_dirty ();
5186 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5188 TrackViewList::const_iterator j = track_views.begin ();
5189 while (j != track_views.end()) {
5190 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5191 if (rtv && rtv->route() == r) {
5202 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5206 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5207 TimeAxisView* tv = axis_view_from_route (*i);
5217 Editor::suspend_route_redisplay ()
5220 _routes->suspend_redisplay();
5225 Editor::resume_route_redisplay ()
5228 _routes->resume_redisplay();
5233 Editor::add_routes (RouteList& routes)
5235 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5237 RouteTimeAxisView *rtv;
5238 list<RouteTimeAxisView*> new_views;
5239 TrackViewList new_selection;
5240 bool from_scratch = (track_views.size() == 0);
5242 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5243 boost::shared_ptr<Route> route = (*x);
5245 if (route->is_auditioner() || route->is_monitor()) {
5249 DataType dt = route->input()->default_type();
5251 if (dt == ARDOUR::DataType::AUDIO) {
5252 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5253 rtv->set_route (route);
5254 } else if (dt == ARDOUR::DataType::MIDI) {
5255 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5256 rtv->set_route (route);
5258 throw unknown_type();
5261 new_views.push_back (rtv);
5262 track_views.push_back (rtv);
5263 new_selection.push_back (rtv);
5265 rtv->effective_gain_display ();
5267 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5268 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5271 if (new_views.size() > 0) {
5272 _routes->routes_added (new_views);
5273 _summary->routes_added (new_views);
5276 if (!from_scratch) {
5277 selection->tracks.clear();
5278 selection->add (new_selection);
5279 begin_selection_op_history();
5282 if (show_editor_mixer_when_tracks_arrive) {
5283 show_editor_mixer (true);
5286 editor_list_button.set_sensitive (true);
5290 Editor::timeaxisview_deleted (TimeAxisView *tv)
5292 if (tv == entered_track) {
5296 if (_session && _session->deletion_in_progress()) {
5297 /* the situation is under control */
5301 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5303 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5305 _routes->route_removed (tv);
5307 TimeAxisView::Children c = tv->get_child_list ();
5308 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5309 if (entered_track == i->get()) {
5314 /* remove it from the list of track views */
5316 TrackViewList::iterator i;
5318 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5319 i = track_views.erase (i);
5322 /* update whatever the current mixer strip is displaying, if revelant */
5324 boost::shared_ptr<Route> route;
5327 route = rtav->route ();
5330 if (current_mixer_strip && current_mixer_strip->route() == route) {
5332 TimeAxisView* next_tv;
5334 if (track_views.empty()) {
5336 } else if (i == track_views.end()) {
5337 next_tv = track_views.front();
5344 set_selected_mixer_strip (*next_tv);
5346 /* make the editor mixer strip go away setting the
5347 * button to inactive (which also unticks the menu option)
5350 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5356 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5358 if (apply_to_selection) {
5359 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5361 TrackSelection::iterator j = i;
5364 hide_track_in_display (*i, false);
5369 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5371 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5372 // this will hide the mixer strip
5373 set_selected_mixer_strip (*tv);
5376 _routes->hide_track_in_display (*tv);
5381 Editor::sync_track_view_list_and_routes ()
5383 track_views = TrackViewList (_routes->views ());
5385 _summary->set_dirty ();
5386 _group_tabs->set_dirty ();
5388 return false; // do not call again (until needed)
5392 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5394 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5399 /** Find a RouteTimeAxisView by the ID of its route */
5401 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5403 RouteTimeAxisView* v;
5405 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5406 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5407 if(v->route()->id() == id) {
5417 Editor::fit_route_group (RouteGroup *g)
5419 TrackViewList ts = axis_views_from_routes (g->route_list ());
5424 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5426 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5429 _session->cancel_audition ();
5433 if (_session->is_auditioning()) {
5434 _session->cancel_audition ();
5435 if (r == last_audition_region) {
5440 _session->audition_region (r);
5441 last_audition_region = r;
5446 Editor::hide_a_region (boost::shared_ptr<Region> r)
5448 r->set_hidden (true);
5452 Editor::show_a_region (boost::shared_ptr<Region> r)
5454 r->set_hidden (false);
5458 Editor::audition_region_from_region_list ()
5460 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5464 Editor::hide_region_from_region_list ()
5466 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5470 Editor::show_region_in_region_list ()
5472 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5476 Editor::step_edit_status_change (bool yn)
5479 start_step_editing ();
5481 stop_step_editing ();
5486 Editor::start_step_editing ()
5488 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5492 Editor::stop_step_editing ()
5494 step_edit_connection.disconnect ();
5498 Editor::check_step_edit ()
5500 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5501 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5503 mtv->check_step_edit ();
5507 return true; // do it again, till we stop
5511 Editor::scroll_press (Direction dir)
5513 ++_scroll_callbacks;
5515 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5516 /* delay the first auto-repeat */
5522 scroll_backward (1);
5530 scroll_up_one_track ();
5534 scroll_down_one_track ();
5538 /* do hacky auto-repeat */
5539 if (!_scroll_connection.connected ()) {
5541 _scroll_connection = Glib::signal_timeout().connect (
5542 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5545 _scroll_callbacks = 0;
5552 Editor::scroll_release ()
5554 _scroll_connection.disconnect ();
5557 /** Queue a change for the Editor viewport x origin to follow the playhead */
5559 Editor::reset_x_origin_to_follow_playhead ()
5561 framepos_t const frame = playhead_cursor->current_frame ();
5563 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5565 if (_session->transport_speed() < 0) {
5567 if (frame > (current_page_samples() / 2)) {
5568 center_screen (frame-(current_page_samples()/2));
5570 center_screen (current_page_samples()/2);
5577 if (frame < leftmost_frame) {
5579 if (_session->transport_rolling()) {
5580 /* rolling; end up with the playhead at the right of the page */
5581 l = frame - current_page_samples ();
5583 /* not rolling: end up with the playhead 1/4 of the way along the page */
5584 l = frame - current_page_samples() / 4;
5588 if (_session->transport_rolling()) {
5589 /* rolling: end up with the playhead on the left of the page */
5592 /* not rolling: end up with the playhead 3/4 of the way along the page */
5593 l = frame - 3 * current_page_samples() / 4;
5601 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5607 Editor::super_rapid_screen_update ()
5609 if (!_session || !_session->engine().running()) {
5613 /* METERING / MIXER STRIPS */
5615 /* update track meters, if required */
5616 if (is_mapped() && meters_running) {
5617 RouteTimeAxisView* rtv;
5618 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5619 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5620 rtv->fast_update ();
5625 /* and any current mixer strip */
5626 if (current_mixer_strip) {
5627 current_mixer_strip->fast_update ();
5630 /* PLAYHEAD AND VIEWPORT */
5632 framepos_t const frame = _session->audible_frame();
5634 /* There are a few reasons why we might not update the playhead / viewport stuff:
5636 * 1. we don't update things when there's a pending locate request, otherwise
5637 * when the editor requests a locate there is a chance that this method
5638 * will move the playhead before the locate request is processed, causing
5640 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5641 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5644 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5646 last_update_frame = frame;
5648 if (!_dragging_playhead) {
5649 playhead_cursor->set_position (frame);
5652 if (!_stationary_playhead) {
5654 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5655 /* We only do this if we aren't already
5656 handling a visual change (ie if
5657 pending_visual_change.being_handled is
5658 false) so that these requests don't stack
5659 up there are too many of them to handle in
5662 reset_x_origin_to_follow_playhead ();
5667 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5671 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5672 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5673 if (target <= 0.0) {
5676 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5677 target = (target * 0.15) + (current * 0.85);
5683 set_horizontal_position (current);
5692 Editor::session_going_away ()
5694 _have_idled = false;
5696 _session_connections.drop_connections ();
5698 super_rapid_screen_update_connection.disconnect ();
5700 selection->clear ();
5701 cut_buffer->clear ();
5703 clicked_regionview = 0;
5704 clicked_axisview = 0;
5705 clicked_routeview = 0;
5706 entered_regionview = 0;
5708 last_update_frame = 0;
5711 playhead_cursor->hide ();
5713 /* rip everything out of the list displays */
5717 _route_groups->clear ();
5719 /* do this first so that deleting a track doesn't reset cms to null
5720 and thus cause a leak.
5723 if (current_mixer_strip) {
5724 if (current_mixer_strip->get_parent() != 0) {
5725 global_hpacker.remove (*current_mixer_strip);
5727 delete current_mixer_strip;
5728 current_mixer_strip = 0;
5731 /* delete all trackviews */
5733 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5736 track_views.clear ();
5738 nudge_clock->set_session (0);
5740 editor_list_button.set_active(false);
5741 editor_list_button.set_sensitive(false);
5743 /* clear tempo/meter rulers */
5744 remove_metric_marks ();
5746 clear_marker_display ();
5748 stop_step_editing ();
5750 /* get rid of any existing editor mixer strip */
5752 WindowTitle title(Glib::get_application_name());
5753 title += _("Editor");
5755 set_title (title.get_string());
5757 SessionHandlePtr::session_going_away ();
5762 Editor::show_editor_list (bool yn)
5765 _the_notebook.show ();
5767 _the_notebook.hide ();
5772 Editor::change_region_layering_order (bool from_context_menu)
5774 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5776 if (!clicked_routeview) {
5777 if (layering_order_editor) {
5778 layering_order_editor->hide ();
5783 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5789 boost::shared_ptr<Playlist> pl = track->playlist();
5795 if (layering_order_editor == 0) {
5796 layering_order_editor = new RegionLayeringOrderEditor (*this);
5799 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5800 layering_order_editor->maybe_present ();
5804 Editor::update_region_layering_order_editor ()
5806 if (layering_order_editor && layering_order_editor->is_visible ()) {
5807 change_region_layering_order (true);
5812 Editor::setup_fade_images ()
5814 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5815 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5816 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5817 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5818 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5820 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5821 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5822 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5823 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5824 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5826 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5827 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5828 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5829 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5830 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5832 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5833 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5834 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5835 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5836 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5840 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5842 Editor::action_menu_item (std::string const & name)
5844 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5847 return *manage (a->create_menu_item ());
5851 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5853 EventBox* b = manage (new EventBox);
5854 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5855 Label* l = manage (new Label (name));
5859 _the_notebook.append_page (widget, *b);
5863 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5865 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5866 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5869 if (ev->type == GDK_2BUTTON_PRESS) {
5871 /* double-click on a notebook tab shrinks or expands the notebook */
5873 if (_notebook_shrunk) {
5874 if (pre_notebook_shrink_pane_width) {
5875 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5877 _notebook_shrunk = false;
5879 pre_notebook_shrink_pane_width = edit_pane.get_position();
5881 /* this expands the LHS of the edit pane to cover the notebook
5882 PAGE but leaves the tabs visible.
5884 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5885 _notebook_shrunk = true;
5893 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5895 using namespace Menu_Helpers;
5897 MenuList& items = _control_point_context_menu.items ();
5900 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5901 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5902 if (!can_remove_control_point (item)) {
5903 items.back().set_sensitive (false);
5906 _control_point_context_menu.popup (event->button.button, event->button.time);
5910 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5912 using namespace Menu_Helpers;
5914 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5919 /* We need to get the selection here and pass it to the operations, since
5920 popping up the menu will cause a region leave event which clears
5921 entered_regionview. */
5923 MidiRegionView& mrv = note->region_view();
5924 const RegionSelection rs = get_regions_from_selection_and_entered ();
5926 MenuList& items = _note_context_menu.items();
5929 items.push_back(MenuElem(_("Delete"),
5930 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5931 items.push_back(MenuElem(_("Edit..."),
5932 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5933 items.push_back(MenuElem(_("Legatize"),
5934 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5935 items.push_back(MenuElem(_("Quantize..."),
5936 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5937 items.push_back(MenuElem(_("Remove Overlap"),
5938 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5939 items.push_back(MenuElem(_("Transform..."),
5940 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5942 _note_context_menu.popup (event->button.button, event->button.time);
5946 Editor::zoom_vertical_modifier_released()
5948 _stepping_axis_view = 0;
5952 Editor::ui_parameter_changed (string parameter)
5954 if (parameter == "icon-set") {
5955 while (!_cursor_stack.empty()) {
5956 _cursor_stack.pop_back();
5958 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5959 _cursor_stack.push_back(_cursors->grabber);
5960 } else if (parameter == "draggable-playhead") {
5961 if (_verbose_cursor) {
5962 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());