2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include "gtkmm2ext/tearoff.h"
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/audio_track.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/audioregion.h"
71 #include "ardour/lmath.h"
72 #include "ardour/location.h"
73 #include "ardour/profile.h"
74 #include "ardour/route_group.h"
75 #include "ardour/session_playlists.h"
76 #include "ardour/tempo.h"
77 #include "ardour/utils.h"
79 #include "canvas/debug.h"
80 #include "canvas/text.h"
82 #include "control_protocol/control_protocol.h"
85 #include "analysis_window.h"
86 #include "audio_clock.h"
87 #include "audio_region_view.h"
88 #include "audio_streamview.h"
89 #include "audio_time_axis.h"
90 #include "automation_time_axis.h"
91 #include "bundle_manager.h"
92 #include "crossfade_edit.h"
96 #include "editor_cursors.h"
97 #include "editor_drag.h"
98 #include "editor_group_tabs.h"
99 #include "editor_locations.h"
100 #include "editor_regions.h"
101 #include "editor_route_groups.h"
102 #include "editor_routes.h"
103 #include "editor_snapshots.h"
104 #include "editor_summary.h"
105 #include "global_port_matrix.h"
106 #include "gui_object.h"
107 #include "gui_thread.h"
108 #include "keyboard.h"
110 #include "midi_region_view.h"
111 #include "midi_time_axis.h"
112 #include "mixer_strip.h"
113 #include "mixer_ui.h"
114 #include "mouse_cursors.h"
115 #include "note_base.h"
116 #include "playlist_selector.h"
117 #include "public_editor.h"
118 #include "region_layering_order_editor.h"
119 #include "rgb_macros.h"
120 #include "rhythm_ferret.h"
121 #include "selection.h"
123 #include "tempo_lines.h"
124 #include "time_axis_view.h"
127 #include "verbose_cursor.h"
132 using namespace ARDOUR;
133 using namespace ARDOUR_UI_UTILS;
136 using namespace Glib;
137 using namespace Gtkmm2ext;
138 using namespace Editing;
140 using PBD::internationalize;
142 using Gtkmm2ext::Keyboard;
144 double Editor::timebar_height = 15.0;
146 static const gchar *_snap_type_strings[] = {
180 static const gchar *_snap_mode_strings[] = {
187 static const gchar *_edit_point_strings[] = {
194 static const gchar *_edit_mode_strings[] = {
202 static const gchar *_zoom_focus_strings[] = {
212 #ifdef USE_RUBBERBAND
213 static const gchar *_rb_opt_strings[] = {
216 N_("Balanced multitimbral mixture"),
217 N_("Unpitched percussion with stable notes"),
218 N_("Crisp monophonic instrumental"),
219 N_("Unpitched solo percussion"),
220 N_("Resample without preserving pitch"),
225 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
228 pane_size_watcher (Paned* pane)
230 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
234 Quartz: impossible to access
236 so stop that by preventing it from ever getting too narrow. 35
237 pixels is basically a rough guess at the tab width.
242 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
244 gint pos = pane->get_position ();
246 if (pos > max_width_of_lhs) {
247 pane->set_position (max_width_of_lhs);
252 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
254 , _mouse_changed_selection (false)
255 /* time display buttons */
256 , minsec_label (_("Mins:Secs"))
257 , bbt_label (_("Bars:Beats"))
258 , timecode_label (_("Timecode"))
259 , samples_label (_("Samples"))
260 , tempo_label (_("Tempo"))
261 , meter_label (_("Meter"))
262 , mark_label (_("Location Markers"))
263 , range_mark_label (_("Range Markers"))
264 , transport_mark_label (_("Loop/Punch Ranges"))
265 , cd_mark_label (_("CD Markers"))
266 , videotl_label (_("Video Timeline"))
267 , edit_packer (4, 4, true)
269 /* the values here don't matter: layout widgets
270 reset them as needed.
273 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
274 , horizontal_adjustment (0.0, 0.0, 1e16)
275 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
277 , controls_layout (unused_adjustment, vertical_adjustment)
279 /* tool bar related */
281 , toolbar_selection_clock_table (2,3)
282 , _mouse_mode_tearoff (0)
283 , automation_mode_button (_("mode"))
287 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
288 , selection_op_cmd_depth (0)
289 , selection_op_history_it (0)
293 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
294 , meters_running(false)
295 , _pending_locate_request (false)
296 , _pending_initial_locate (false)
297 , _last_cut_copy_source_track (0)
299 , _region_selection_change_updates_region_list (true)
300 , _following_mixer_selection (false)
301 , _control_point_toggled_on_press (false)
302 , _stepping_axis_view (0)
306 /* we are a singleton */
308 PublicEditor::_instance = this;
312 selection = new Selection (this);
313 cut_buffer = new Selection (this);
314 _selection_memento = new SelectionMemento ();
315 selection_op_history.clear();
318 clicked_regionview = 0;
319 clicked_axisview = 0;
320 clicked_routeview = 0;
321 clicked_control_point = 0;
322 last_update_frame = 0;
325 _drags = new DragManager (this);
328 current_mixer_strip = 0;
331 snap_type_strings = I18N (_snap_type_strings);
332 snap_mode_strings = I18N (_snap_mode_strings);
333 zoom_focus_strings = I18N (_zoom_focus_strings);
334 edit_mode_strings = I18N (_edit_mode_strings);
335 edit_point_strings = I18N (_edit_point_strings);
336 #ifdef USE_RUBBERBAND
337 rb_opt_strings = I18N (_rb_opt_strings);
341 build_edit_mode_menu();
342 build_zoom_focus_menu();
343 build_track_count_menu();
344 build_snap_mode_menu();
345 build_snap_type_menu();
346 build_edit_point_menu();
348 snap_threshold = 5.0;
349 bbt_beat_subdivision = 4;
350 _visible_canvas_width = 0;
351 _visible_canvas_height = 0;
352 autoscroll_horizontal_allowed = false;
353 autoscroll_vertical_allowed = false;
358 current_interthread_info = 0;
359 _show_measures = true;
361 show_gain_after_trim = false;
363 have_pending_keyboard_selection = false;
364 _follow_playhead = true;
365 _stationary_playhead = false;
366 editor_ruler_menu = 0;
367 no_ruler_shown_update = false;
369 range_marker_menu = 0;
370 marker_menu_item = 0;
371 tempo_or_meter_marker_menu = 0;
372 transport_marker_menu = 0;
373 new_transport_marker_menu = 0;
374 editor_mixer_strip_width = Wide;
375 show_editor_mixer_when_tracks_arrive = false;
376 region_edit_menu_split_multichannel_item = 0;
377 region_edit_menu_split_item = 0;
380 current_stepping_trackview = 0;
382 entered_regionview = 0;
384 clear_entered_track = false;
387 button_release_can_deselect = true;
388 _dragging_playhead = false;
389 _dragging_edit_point = false;
390 select_new_marker = false;
392 layering_order_editor = 0;
393 no_save_visual = false;
395 within_track_canvas = false;
397 scrubbing_direction = 0;
401 location_marker_color = ARDOUR_UI::config()->color ("location marker");
402 location_range_color = ARDOUR_UI::config()->color ("location range");
403 location_cd_marker_color = ARDOUR_UI::config()->color ("location cd marker");
404 location_loop_color = ARDOUR_UI::config()->color ("location loop");
405 location_punch_color = ARDOUR_UI::config()->color ("location punch");
407 zoom_focus = ZoomFocusPlayhead;
408 _edit_point = EditAtMouse;
409 _visible_track_count = -1;
411 samples_per_pixel = 2048; /* too early to use reset_zoom () */
413 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
414 TimeAxisView::setup_sizes ();
415 Marker::setup_sizes (timebar_height);
417 _scroll_callbacks = 0;
419 bbt_label.set_name ("EditorRulerLabel");
420 bbt_label.set_size_request (-1, (int)timebar_height);
421 bbt_label.set_alignment (1.0, 0.5);
422 bbt_label.set_padding (5,0);
424 bbt_label.set_no_show_all();
425 minsec_label.set_name ("EditorRulerLabel");
426 minsec_label.set_size_request (-1, (int)timebar_height);
427 minsec_label.set_alignment (1.0, 0.5);
428 minsec_label.set_padding (5,0);
429 minsec_label.hide ();
430 minsec_label.set_no_show_all();
431 timecode_label.set_name ("EditorRulerLabel");
432 timecode_label.set_size_request (-1, (int)timebar_height);
433 timecode_label.set_alignment (1.0, 0.5);
434 timecode_label.set_padding (5,0);
435 timecode_label.hide ();
436 timecode_label.set_no_show_all();
437 samples_label.set_name ("EditorRulerLabel");
438 samples_label.set_size_request (-1, (int)timebar_height);
439 samples_label.set_alignment (1.0, 0.5);
440 samples_label.set_padding (5,0);
441 samples_label.hide ();
442 samples_label.set_no_show_all();
444 tempo_label.set_name ("EditorRulerLabel");
445 tempo_label.set_size_request (-1, (int)timebar_height);
446 tempo_label.set_alignment (1.0, 0.5);
447 tempo_label.set_padding (5,0);
449 tempo_label.set_no_show_all();
451 meter_label.set_name ("EditorRulerLabel");
452 meter_label.set_size_request (-1, (int)timebar_height);
453 meter_label.set_alignment (1.0, 0.5);
454 meter_label.set_padding (5,0);
456 meter_label.set_no_show_all();
458 if (Profile->get_trx()) {
459 mark_label.set_text (_("Markers"));
461 mark_label.set_name ("EditorRulerLabel");
462 mark_label.set_size_request (-1, (int)timebar_height);
463 mark_label.set_alignment (1.0, 0.5);
464 mark_label.set_padding (5,0);
466 mark_label.set_no_show_all();
468 cd_mark_label.set_name ("EditorRulerLabel");
469 cd_mark_label.set_size_request (-1, (int)timebar_height);
470 cd_mark_label.set_alignment (1.0, 0.5);
471 cd_mark_label.set_padding (5,0);
472 cd_mark_label.hide();
473 cd_mark_label.set_no_show_all();
475 videotl_bar_height = 4;
476 videotl_label.set_name ("EditorRulerLabel");
477 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
478 videotl_label.set_alignment (1.0, 0.5);
479 videotl_label.set_padding (5,0);
480 videotl_label.hide();
481 videotl_label.set_no_show_all();
483 range_mark_label.set_name ("EditorRulerLabel");
484 range_mark_label.set_size_request (-1, (int)timebar_height);
485 range_mark_label.set_alignment (1.0, 0.5);
486 range_mark_label.set_padding (5,0);
487 range_mark_label.hide();
488 range_mark_label.set_no_show_all();
490 transport_mark_label.set_name ("EditorRulerLabel");
491 transport_mark_label.set_size_request (-1, (int)timebar_height);
492 transport_mark_label.set_alignment (1.0, 0.5);
493 transport_mark_label.set_padding (5,0);
494 transport_mark_label.hide();
495 transport_mark_label.set_no_show_all();
497 initialize_canvas ();
499 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
501 _summary = new EditorSummary (this);
503 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
504 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
506 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
508 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
509 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
511 edit_controls_vbox.set_spacing (0);
512 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
513 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
515 HBox* h = manage (new HBox);
516 _group_tabs = new EditorGroupTabs (this);
517 if (!ARDOUR::Profile->get_trx()) {
518 h->pack_start (*_group_tabs, PACK_SHRINK);
520 h->pack_start (edit_controls_vbox);
521 controls_layout.add (*h);
523 controls_layout.set_name ("EditControlsBase");
524 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
525 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
526 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
528 _cursors = new MouseCursors;
529 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
530 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
532 /* Push default cursor to ever-present bottom of cursor stack. */
533 push_canvas_cursor(_cursors->grabber);
535 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
537 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
538 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
539 pad_line_1->set_outline_color (0xFF0000FF);
545 edit_packer.set_col_spacings (0);
546 edit_packer.set_row_spacings (0);
547 edit_packer.set_homogeneous (false);
548 edit_packer.set_border_width (0);
549 edit_packer.set_name ("EditorWindow");
551 time_bars_event_box.add (time_bars_vbox);
552 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
553 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
555 /* labels for the time bars */
556 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
558 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
560 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
562 bottom_hbox.set_border_width (2);
563 bottom_hbox.set_spacing (3);
565 _route_groups = new EditorRouteGroups (this);
566 _routes = new EditorRoutes (this);
567 _regions = new EditorRegions (this);
568 _snapshots = new EditorSnapshots (this);
569 _locations = new EditorLocations (this);
571 /* these are static location signals */
573 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
574 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
575 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
577 add_notebook_page (_("Regions"), _regions->widget ());
578 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
579 add_notebook_page (_("Snapshots"), _snapshots->widget ());
580 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
581 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
583 _the_notebook.set_show_tabs (true);
584 _the_notebook.set_scrollable (true);
585 _the_notebook.popup_disable ();
586 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
587 _the_notebook.show_all ();
589 _notebook_shrunk = false;
591 editor_summary_pane.pack1(edit_packer);
593 Button* summary_arrows_left_left = manage (new Button);
594 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
595 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
596 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
598 Button* summary_arrows_left_right = manage (new Button);
599 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
600 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
601 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
603 VBox* summary_arrows_left = manage (new VBox);
604 summary_arrows_left->pack_start (*summary_arrows_left_left);
605 summary_arrows_left->pack_start (*summary_arrows_left_right);
607 Button* summary_arrows_right_up = manage (new Button);
608 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
609 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
610 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
612 Button* summary_arrows_right_down = manage (new Button);
613 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
614 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
615 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
617 VBox* summary_arrows_right = manage (new VBox);
618 summary_arrows_right->pack_start (*summary_arrows_right_up);
619 summary_arrows_right->pack_start (*summary_arrows_right_down);
621 Frame* summary_frame = manage (new Frame);
622 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
624 summary_frame->add (*_summary);
625 summary_frame->show ();
627 _summary_hbox.pack_start (*summary_arrows_left, false, false);
628 _summary_hbox.pack_start (*summary_frame, true, true);
629 _summary_hbox.pack_start (*summary_arrows_right, false, false);
631 if (!ARDOUR::Profile->get_trx()) {
632 editor_summary_pane.pack2 (_summary_hbox);
635 edit_pane.pack1 (editor_summary_pane, true, true);
636 if (!ARDOUR::Profile->get_trx()) {
637 edit_pane.pack2 (_the_notebook, false, true);
640 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
642 /* XXX: editor_summary_pane might need similar to the edit_pane */
644 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
646 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
647 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
649 top_hbox.pack_start (toolbar_frame);
651 HBox *hbox = manage (new HBox);
652 hbox->pack_start (edit_pane, true, true);
654 global_vpacker.pack_start (top_hbox, false, false);
655 global_vpacker.pack_start (*hbox, true, true);
657 global_hpacker.pack_start (global_vpacker, true, true);
659 set_name ("EditorWindow");
660 add_accel_group (ActionManager::ui_manager->get_accel_group());
662 status_bar_hpacker.show ();
664 vpacker.pack_end (status_bar_hpacker, false, false);
665 vpacker.pack_end (global_hpacker, true, true);
667 /* register actions now so that set_state() can find them and set toggles/checks etc */
670 /* when we start using our own keybinding system for the editor, this
671 * will be uncommented
677 set_zoom_focus (zoom_focus);
678 set_visible_track_count (_visible_track_count);
679 _snap_type = SnapToBeat;
680 set_snap_to (_snap_type);
681 _snap_mode = SnapOff;
682 set_snap_mode (_snap_mode);
683 set_mouse_mode (MouseObject, true);
684 pre_internal_snap_type = _snap_type;
685 pre_internal_snap_mode = _snap_mode;
686 internal_snap_type = _snap_type;
687 internal_snap_mode = _snap_mode;
688 set_edit_point_preference (EditAtMouse, true);
690 _playlist_selector = new PlaylistSelector();
691 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
693 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
697 nudge_forward_button.set_name ("nudge button");
698 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
700 nudge_backward_button.set_name ("nudge button");
701 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
703 fade_context_menu.set_name ("ArdourContextMenu");
705 /* icons, titles, WM stuff */
707 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
708 Glib::RefPtr<Gdk::Pixbuf> icon;
710 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
711 window_icons.push_back (icon);
713 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
714 window_icons.push_back (icon);
716 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
717 window_icons.push_back (icon);
719 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
720 window_icons.push_back (icon);
722 if (!window_icons.empty()) {
723 // set_icon_list (window_icons);
724 set_default_icon_list (window_icons);
727 WindowTitle title(Glib::get_application_name());
728 title += _("Editor");
729 set_title (title.get_string());
730 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
733 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
735 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
736 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
738 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
740 /* allow external control surfaces/protocols to do various things */
742 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
743 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
744 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
745 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
746 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
747 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
748 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
749 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
750 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
751 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
752 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
753 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
754 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
755 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
757 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
758 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
759 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
760 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
761 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
763 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
765 /* problematic: has to return a value and thus cannot be x-thread */
767 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
769 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
770 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
772 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
774 _ignore_region_action = false;
775 _last_region_menu_was_main = false;
776 _popup_region_menu_item = 0;
778 _ignore_follow_edits = false;
780 _show_marker_lines = false;
782 /* Button bindings */
784 button_bindings = new Bindings;
786 XMLNode* node = button_settings();
788 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
789 button_bindings->load (**i);
795 /* grab current parameter state */
796 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
797 ARDOUR_UI::config()->map_parameters (pc);
799 setup_fade_images ();
806 delete button_bindings;
808 delete _route_groups;
809 delete _track_canvas_viewport;
815 Editor::button_settings () const
817 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
818 XMLNode* node = find_named_node (*settings, X_("Buttons"));
821 node = new XMLNode (X_("Buttons"));
828 Editor::add_toplevel_menu (Container& cont)
830 vpacker.pack_start (cont, false, false);
835 Editor::add_transport_frame (Container& cont)
837 if(ARDOUR::Profile->get_mixbus()) {
838 global_vpacker.pack_start (cont, false, false);
839 global_vpacker.reorder_child (cont, 0);
842 vpacker.pack_start (cont, false, false);
847 Editor::get_smart_mode () const
849 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
853 Editor::catch_vanishing_regionview (RegionView *rv)
855 /* note: the selection will take care of the vanishing
856 audioregionview by itself.
859 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
863 if (clicked_regionview == rv) {
864 clicked_regionview = 0;
867 if (entered_regionview == rv) {
868 set_entered_regionview (0);
871 if (!_all_region_actions_sensitized) {
872 sensitize_all_region_actions (true);
877 Editor::set_entered_regionview (RegionView* rv)
879 if (rv == entered_regionview) {
883 if (entered_regionview) {
884 entered_regionview->exited ();
887 entered_regionview = rv;
889 if (entered_regionview != 0) {
890 entered_regionview->entered ();
893 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
894 /* This RegionView entry might have changed what region actions
895 are allowed, so sensitize them all in case a key is pressed.
897 sensitize_all_region_actions (true);
902 Editor::set_entered_track (TimeAxisView* tav)
905 entered_track->exited ();
911 entered_track->entered ();
916 Editor::show_window ()
918 if (!is_visible ()) {
922 /* XXX: this is a bit unfortunate; it would probably
923 be nicer if we could just call show () above rather
924 than needing the show_all ()
927 /* re-hide stuff if necessary */
928 editor_list_button_toggled ();
929 parameter_changed ("show-summary");
930 parameter_changed ("show-group-tabs");
931 parameter_changed ("show-zoom-tools");
933 /* now reset all audio_time_axis heights, because widgets might need
939 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
940 tv = (static_cast<TimeAxisView*>(*i));
944 if (current_mixer_strip) {
945 current_mixer_strip->hide_things ();
946 current_mixer_strip->parameter_changed ("mixer-element-visibility");
954 Editor::instant_save ()
956 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
961 _session->add_instant_xml(get_state());
963 Config->add_instant_xml(get_state());
968 Editor::control_vertical_zoom_in_all ()
970 tav_zoom_smooth (false, true);
974 Editor::control_vertical_zoom_out_all ()
976 tav_zoom_smooth (true, true);
980 Editor::control_vertical_zoom_in_selected ()
982 tav_zoom_smooth (false, false);
986 Editor::control_vertical_zoom_out_selected ()
988 tav_zoom_smooth (true, false);
992 Editor::control_view (uint32_t view)
994 goto_visual_state (view);
998 Editor::control_unselect ()
1000 selection->clear_tracks ();
1004 Editor::control_select (uint32_t rid, Selection::Operation op)
1006 /* handles the (static) signal from the ControlProtocol class that
1007 * requests setting the selected track to a given RID
1014 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1020 TimeAxisView* tav = axis_view_from_route (r);
1024 case Selection::Add:
1025 selection->add (tav);
1027 case Selection::Toggle:
1028 selection->toggle (tav);
1030 case Selection::Extend:
1032 case Selection::Set:
1033 selection->set (tav);
1037 selection->clear_tracks ();
1042 Editor::control_step_tracks_up ()
1044 scroll_tracks_up_line ();
1048 Editor::control_step_tracks_down ()
1050 scroll_tracks_down_line ();
1054 Editor::control_scroll (float fraction)
1056 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1062 double step = fraction * current_page_samples();
1065 _control_scroll_target is an optional<T>
1067 it acts like a pointer to an framepos_t, with
1068 a operator conversion to boolean to check
1069 that it has a value could possibly use
1070 playhead_cursor->current_frame to store the
1071 value and a boolean in the class to know
1072 when it's out of date
1075 if (!_control_scroll_target) {
1076 _control_scroll_target = _session->transport_frame();
1077 _dragging_playhead = true;
1080 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1081 *_control_scroll_target = 0;
1082 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1083 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1085 *_control_scroll_target += (framepos_t) trunc (step);
1088 /* move visuals, we'll catch up with it later */
1090 playhead_cursor->set_position (*_control_scroll_target);
1091 UpdateAllTransportClocks (*_control_scroll_target);
1093 if (*_control_scroll_target > (current_page_samples() / 2)) {
1094 /* try to center PH in window */
1095 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1101 Now we do a timeout to actually bring the session to the right place
1102 according to the playhead. This is to avoid reading disk buffers on every
1103 call to control_scroll, which is driven by ScrollTimeline and therefore
1104 probably by a control surface wheel which can generate lots of events.
1106 /* cancel the existing timeout */
1108 control_scroll_connection.disconnect ();
1110 /* add the next timeout */
1112 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1116 Editor::deferred_control_scroll (framepos_t /*target*/)
1118 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1119 // reset for next stream
1120 _control_scroll_target = boost::none;
1121 _dragging_playhead = false;
1126 Editor::access_action (std::string action_group, std::string action_item)
1132 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1135 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1143 Editor::on_realize ()
1145 Window::on_realize ();
1148 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1149 start_lock_event_timing ();
1152 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1156 Editor::start_lock_event_timing ()
1158 /* check if we should lock the GUI every 30 seconds */
1160 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1164 Editor::generic_event_handler (GdkEvent* ev)
1167 case GDK_BUTTON_PRESS:
1168 case GDK_BUTTON_RELEASE:
1169 case GDK_MOTION_NOTIFY:
1171 case GDK_KEY_RELEASE:
1172 gettimeofday (&last_event_time, 0);
1175 case GDK_LEAVE_NOTIFY:
1176 switch (ev->crossing.detail) {
1177 case GDK_NOTIFY_UNKNOWN:
1178 case GDK_NOTIFY_INFERIOR:
1179 case GDK_NOTIFY_ANCESTOR:
1181 case GDK_NOTIFY_VIRTUAL:
1182 case GDK_NOTIFY_NONLINEAR:
1183 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1184 /* leaving window, so reset focus, thus ending any and
1185 all text entry operations.
1200 Editor::lock_timeout_callback ()
1202 struct timeval now, delta;
1204 gettimeofday (&now, 0);
1206 timersub (&now, &last_event_time, &delta);
1208 if (delta.tv_sec > (time_t) ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1210 /* don't call again. Returning false will effectively
1211 disconnect us from the timer callback.
1213 unlock() will call start_lock_event_timing() to get things
1223 Editor::map_position_change (framepos_t frame)
1225 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1227 if (_session == 0) {
1231 if (_follow_playhead) {
1232 center_screen (frame);
1235 playhead_cursor->set_position (frame);
1239 Editor::center_screen (framepos_t frame)
1241 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1243 /* if we're off the page, then scroll.
1246 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1247 center_screen_internal (frame, page);
1252 Editor::center_screen_internal (framepos_t frame, float page)
1257 frame -= (framepos_t) page;
1262 reset_x_origin (frame);
1267 Editor::update_title ()
1269 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1272 bool dirty = _session->dirty();
1274 string session_name;
1276 if (_session->snap_name() != _session->name()) {
1277 session_name = _session->snap_name();
1279 session_name = _session->name();
1283 session_name = "*" + session_name;
1286 WindowTitle title(session_name);
1287 title += Glib::get_application_name();
1288 set_title (title.get_string());
1290 /* ::session_going_away() will have taken care of it */
1295 Editor::set_session (Session *t)
1297 SessionHandlePtr::set_session (t);
1303 _playlist_selector->set_session (_session);
1304 nudge_clock->set_session (_session);
1305 _summary->set_session (_session);
1306 _group_tabs->set_session (_session);
1307 _route_groups->set_session (_session);
1308 _regions->set_session (_session);
1309 _snapshots->set_session (_session);
1310 _routes->set_session (_session);
1311 _locations->set_session (_session);
1313 if (rhythm_ferret) {
1314 rhythm_ferret->set_session (_session);
1317 if (analysis_window) {
1318 analysis_window->set_session (_session);
1322 sfbrowser->set_session (_session);
1325 compute_fixed_ruler_scale ();
1327 /* Make sure we have auto loop and auto punch ranges */
1329 Location* loc = _session->locations()->auto_loop_location();
1331 loc->set_name (_("Loop"));
1334 loc = _session->locations()->auto_punch_location();
1337 loc->set_name (_("Punch"));
1340 refresh_location_display ();
1342 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1343 the selected Marker; this needs the LocationMarker list to be available.
1345 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1346 set_state (*node, Stateful::loading_state_version);
1348 /* catch up with the playhead */
1350 _session->request_locate (playhead_cursor->current_frame ());
1351 _pending_initial_locate = true;
1355 /* These signals can all be emitted by a non-GUI thread. Therefore the
1356 handlers for them must not attempt to directly interact with the GUI,
1357 but use PBD::Signal<T>::connect() which accepts an event loop
1358 ("context") where the handler will be asked to run.
1361 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1362 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1363 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1364 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1365 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1366 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1367 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1368 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1369 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1370 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1371 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1372 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1373 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1375 playhead_cursor->show ();
1377 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1378 Config->map_parameters (pc);
1379 _session->config.map_parameters (pc);
1381 restore_ruler_visibility ();
1382 //tempo_map_changed (PropertyChange (0));
1383 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1385 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1386 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1389 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1390 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1393 switch (_snap_type) {
1394 case SnapToRegionStart:
1395 case SnapToRegionEnd:
1396 case SnapToRegionSync:
1397 case SnapToRegionBoundary:
1398 build_region_boundary_cache ();
1405 /* register for undo history */
1406 _session->register_with_memento_command_factory(id(), this);
1407 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1409 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1411 start_updating_meters ();
1415 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1417 if (a->get_name() == "RegionMenu") {
1418 /* When the main menu's region menu is opened, we setup the actions so that they look right
1419 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1420 so we resensitize all region actions when the entered regionview or the region selection
1421 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1422 happens after the region context menu is opened. So we set a flag here, too.
1426 sensitize_the_right_region_actions ();
1427 _last_region_menu_was_main = true;
1432 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1434 using namespace Menu_Helpers;
1436 void (Editor::*emf)(FadeShape);
1437 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1440 images = &_xfade_in_images;
1441 emf = &Editor::set_fade_in_shape;
1443 images = &_xfade_out_images;
1444 emf = &Editor::set_fade_out_shape;
1449 _("Linear (for highly correlated material)"),
1450 *(*images)[FadeLinear],
1451 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1455 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1459 _("Constant power"),
1460 *(*images)[FadeConstantPower],
1461 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1464 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1469 *(*images)[FadeSymmetric],
1470 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1474 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1479 *(*images)[FadeSlow],
1480 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1483 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1488 *(*images)[FadeFast],
1489 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1492 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1495 /** Pop up a context menu for when the user clicks on a start crossfade */
1497 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1499 using namespace Menu_Helpers;
1500 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1505 MenuList& items (xfade_in_context_menu.items());
1508 if (arv->audio_region()->fade_in_active()) {
1509 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1511 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1514 items.push_back (SeparatorElem());
1515 fill_xfade_menu (items, true);
1517 xfade_in_context_menu.popup (button, time);
1520 /** Pop up a context menu for when the user clicks on an end crossfade */
1522 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1524 using namespace Menu_Helpers;
1525 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1530 MenuList& items (xfade_out_context_menu.items());
1533 if (arv->audio_region()->fade_out_active()) {
1534 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1536 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1539 items.push_back (SeparatorElem());
1540 fill_xfade_menu (items, false);
1542 xfade_out_context_menu.popup (button, time);
1546 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1548 using namespace Menu_Helpers;
1549 Menu* (Editor::*build_menu_function)();
1552 switch (item_type) {
1554 case RegionViewName:
1555 case RegionViewNameHighlight:
1556 case LeftFrameHandle:
1557 case RightFrameHandle:
1558 if (with_selection) {
1559 build_menu_function = &Editor::build_track_selection_context_menu;
1561 build_menu_function = &Editor::build_track_region_context_menu;
1566 if (with_selection) {
1567 build_menu_function = &Editor::build_track_selection_context_menu;
1569 build_menu_function = &Editor::build_track_context_menu;
1574 if (clicked_routeview->track()) {
1575 build_menu_function = &Editor::build_track_context_menu;
1577 build_menu_function = &Editor::build_track_bus_context_menu;
1582 /* probably shouldn't happen but if it does, we don't care */
1586 menu = (this->*build_menu_function)();
1587 menu->set_name ("ArdourContextMenu");
1589 /* now handle specific situations */
1591 switch (item_type) {
1593 case RegionViewName:
1594 case RegionViewNameHighlight:
1595 case LeftFrameHandle:
1596 case RightFrameHandle:
1597 if (!with_selection) {
1598 if (region_edit_menu_split_item) {
1599 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1600 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1602 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1605 if (region_edit_menu_split_multichannel_item) {
1606 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1607 region_edit_menu_split_multichannel_item->set_sensitive (true);
1609 region_edit_menu_split_multichannel_item->set_sensitive (false);
1622 /* probably shouldn't happen but if it does, we don't care */
1626 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1628 /* Bounce to disk */
1630 using namespace Menu_Helpers;
1631 MenuList& edit_items = menu->items();
1633 edit_items.push_back (SeparatorElem());
1635 switch (clicked_routeview->audio_track()->freeze_state()) {
1636 case AudioTrack::NoFreeze:
1637 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1640 case AudioTrack::Frozen:
1641 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1644 case AudioTrack::UnFrozen:
1645 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1651 if (item_type == StreamItem && clicked_routeview) {
1652 clicked_routeview->build_underlay_menu(menu);
1655 /* When the region menu is opened, we setup the actions so that they look right
1658 sensitize_the_right_region_actions ();
1659 _last_region_menu_was_main = false;
1661 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1662 menu->popup (button, time);
1666 Editor::build_track_context_menu ()
1668 using namespace Menu_Helpers;
1670 MenuList& edit_items = track_context_menu.items();
1673 add_dstream_context_items (edit_items);
1674 return &track_context_menu;
1678 Editor::build_track_bus_context_menu ()
1680 using namespace Menu_Helpers;
1682 MenuList& edit_items = track_context_menu.items();
1685 add_bus_context_items (edit_items);
1686 return &track_context_menu;
1690 Editor::build_track_region_context_menu ()
1692 using namespace Menu_Helpers;
1693 MenuList& edit_items = track_region_context_menu.items();
1696 /* we've just cleared the track region context menu, so the menu that these
1697 two items were on will have disappeared; stop them dangling.
1699 region_edit_menu_split_item = 0;
1700 region_edit_menu_split_multichannel_item = 0;
1702 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1705 boost::shared_ptr<Track> tr;
1706 boost::shared_ptr<Playlist> pl;
1708 if ((tr = rtv->track())) {
1709 add_region_context_items (edit_items, tr);
1713 add_dstream_context_items (edit_items);
1715 return &track_region_context_menu;
1719 Editor::analyze_region_selection ()
1721 if (analysis_window == 0) {
1722 analysis_window = new AnalysisWindow();
1725 analysis_window->set_session(_session);
1727 analysis_window->show_all();
1730 analysis_window->set_regionmode();
1731 analysis_window->analyze();
1733 analysis_window->present();
1737 Editor::analyze_range_selection()
1739 if (analysis_window == 0) {
1740 analysis_window = new AnalysisWindow();
1743 analysis_window->set_session(_session);
1745 analysis_window->show_all();
1748 analysis_window->set_rangemode();
1749 analysis_window->analyze();
1751 analysis_window->present();
1755 Editor::build_track_selection_context_menu ()
1757 using namespace Menu_Helpers;
1758 MenuList& edit_items = track_selection_context_menu.items();
1759 edit_items.clear ();
1761 add_selection_context_items (edit_items);
1762 // edit_items.push_back (SeparatorElem());
1763 // add_dstream_context_items (edit_items);
1765 return &track_selection_context_menu;
1769 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1771 using namespace Menu_Helpers;
1773 /* OK, stick the region submenu at the top of the list, and then add
1777 RegionSelection rs = get_regions_from_selection_and_entered ();
1779 string::size_type pos = 0;
1780 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1782 /* we have to hack up the region name because "_" has a special
1783 meaning for menu titles.
1786 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1787 menu_item_name.replace (pos, 1, "__");
1791 if (_popup_region_menu_item == 0) {
1792 _popup_region_menu_item = new MenuItem (menu_item_name);
1793 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1794 _popup_region_menu_item->show ();
1796 _popup_region_menu_item->set_label (menu_item_name);
1799 /* No latering allowed in later is higher layering model */
1800 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1801 if (act && Config->get_layer_model() == LaterHigher) {
1802 act->set_sensitive (false);
1804 act->set_sensitive (true);
1807 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1809 edit_items.push_back (*_popup_region_menu_item);
1810 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1811 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1813 edit_items.push_back (SeparatorElem());
1816 /** Add context menu items relevant to selection ranges.
1817 * @param edit_items List to add the items to.
1820 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1822 using namespace Menu_Helpers;
1824 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1825 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1827 edit_items.push_back (SeparatorElem());
1828 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1830 edit_items.push_back (SeparatorElem());
1831 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1833 edit_items.push_back (SeparatorElem());
1835 edit_items.push_back (
1837 _("Move Range Start to Previous Region Boundary"),
1838 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1842 edit_items.push_back (
1844 _("Move Range Start to Next Region Boundary"),
1845 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1849 edit_items.push_back (
1851 _("Move Range End to Previous Region Boundary"),
1852 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1856 edit_items.push_back (
1858 _("Move Range End to Next Region Boundary"),
1859 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1863 edit_items.push_back (SeparatorElem());
1864 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1865 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1867 edit_items.push_back (SeparatorElem());
1868 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1870 edit_items.push_back (SeparatorElem());
1871 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1872 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1873 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1875 edit_items.push_back (SeparatorElem());
1876 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1878 edit_items.push_back (SeparatorElem());
1879 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1880 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1881 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1883 edit_items.push_back (SeparatorElem());
1884 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1885 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1886 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1887 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1888 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1889 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1890 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1896 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1898 using namespace Menu_Helpers;
1902 Menu *play_menu = manage (new Menu);
1903 MenuList& play_items = play_menu->items();
1904 play_menu->set_name ("ArdourContextMenu");
1906 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1907 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1908 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1909 play_items.push_back (SeparatorElem());
1910 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1912 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1916 Menu *select_menu = manage (new Menu);
1917 MenuList& select_items = select_menu->items();
1918 select_menu->set_name ("ArdourContextMenu");
1920 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1921 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1922 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1923 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1924 select_items.push_back (SeparatorElem());
1925 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1926 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1927 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
1928 select_items.push_back (SeparatorElem());
1929 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1930 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1931 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1932 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1933 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1934 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1935 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1937 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1941 Menu *cutnpaste_menu = manage (new Menu);
1942 MenuList& cutnpaste_items = cutnpaste_menu->items();
1943 cutnpaste_menu->set_name ("ArdourContextMenu");
1945 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1946 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1947 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1949 cutnpaste_items.push_back (SeparatorElem());
1951 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1952 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1954 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1956 /* Adding new material */
1958 edit_items.push_back (SeparatorElem());
1959 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1960 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1964 Menu *nudge_menu = manage (new Menu());
1965 MenuList& nudge_items = nudge_menu->items();
1966 nudge_menu->set_name ("ArdourContextMenu");
1968 edit_items.push_back (SeparatorElem());
1969 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1970 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1971 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1972 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1974 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1978 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1980 using namespace Menu_Helpers;
1984 Menu *play_menu = manage (new Menu);
1985 MenuList& play_items = play_menu->items();
1986 play_menu->set_name ("ArdourContextMenu");
1988 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1989 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1990 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1994 Menu *select_menu = manage (new Menu);
1995 MenuList& select_items = select_menu->items();
1996 select_menu->set_name ("ArdourContextMenu");
1998 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1999 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2000 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2001 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2002 select_items.push_back (SeparatorElem());
2003 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2004 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2005 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2006 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2008 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2012 Menu *cutnpaste_menu = manage (new Menu);
2013 MenuList& cutnpaste_items = cutnpaste_menu->items();
2014 cutnpaste_menu->set_name ("ArdourContextMenu");
2016 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2017 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2018 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2020 Menu *nudge_menu = manage (new Menu());
2021 MenuList& nudge_items = nudge_menu->items();
2022 nudge_menu->set_name ("ArdourContextMenu");
2024 edit_items.push_back (SeparatorElem());
2025 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2026 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2027 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2028 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2030 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2034 Editor::snap_type() const
2040 Editor::snap_mode() const
2046 Editor::set_snap_to (SnapType st)
2048 unsigned int snap_ind = (unsigned int)st;
2050 if (internal_editing()) {
2051 internal_snap_type = st;
2053 pre_internal_snap_type = st;
2058 if (snap_ind > snap_type_strings.size() - 1) {
2060 _snap_type = (SnapType)snap_ind;
2063 string str = snap_type_strings[snap_ind];
2065 if (str != snap_type_selector.get_text()) {
2066 snap_type_selector.set_text (str);
2071 switch (_snap_type) {
2072 case SnapToBeatDiv128:
2073 case SnapToBeatDiv64:
2074 case SnapToBeatDiv32:
2075 case SnapToBeatDiv28:
2076 case SnapToBeatDiv24:
2077 case SnapToBeatDiv20:
2078 case SnapToBeatDiv16:
2079 case SnapToBeatDiv14:
2080 case SnapToBeatDiv12:
2081 case SnapToBeatDiv10:
2082 case SnapToBeatDiv8:
2083 case SnapToBeatDiv7:
2084 case SnapToBeatDiv6:
2085 case SnapToBeatDiv5:
2086 case SnapToBeatDiv4:
2087 case SnapToBeatDiv3:
2088 case SnapToBeatDiv2: {
2089 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2090 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2092 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2093 current_bbt_points_begin, current_bbt_points_end);
2094 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2095 current_bbt_points_begin, current_bbt_points_end);
2096 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2100 case SnapToRegionStart:
2101 case SnapToRegionEnd:
2102 case SnapToRegionSync:
2103 case SnapToRegionBoundary:
2104 build_region_boundary_cache ();
2112 redisplay_tempo (false);
2114 SnapChanged (); /* EMIT SIGNAL */
2118 Editor::set_snap_mode (SnapMode mode)
2120 string str = snap_mode_strings[(int)mode];
2122 if (internal_editing()) {
2123 internal_snap_mode = mode;
2125 pre_internal_snap_mode = mode;
2130 if (str != snap_mode_selector.get_text ()) {
2131 snap_mode_selector.set_text (str);
2138 Editor::set_edit_point_preference (EditPoint ep, bool force)
2140 bool changed = (_edit_point != ep);
2143 if (Profile->get_mixbus())
2144 if (ep == EditAtSelectedMarker)
2145 ep = EditAtPlayhead;
2147 string str = edit_point_strings[(int)ep];
2148 if (str != edit_point_selector.get_text ()) {
2149 edit_point_selector.set_text (str);
2152 update_all_enter_cursors();
2154 if (!force && !changed) {
2158 const char* action=NULL;
2160 switch (_edit_point) {
2161 case EditAtPlayhead:
2162 action = "edit-at-playhead";
2164 case EditAtSelectedMarker:
2165 action = "edit-at-marker";
2168 action = "edit-at-mouse";
2172 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2174 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2178 bool in_track_canvas;
2180 if (!mouse_frame (foo, in_track_canvas)) {
2181 in_track_canvas = false;
2184 reset_canvas_action_sensitivity (in_track_canvas);
2190 Editor::set_state (const XMLNode& node, int /*version*/)
2192 const XMLProperty* prop;
2199 g.base_width = default_width;
2200 g.base_height = default_height;
2204 if ((geometry = find_named_node (node, "geometry")) != 0) {
2208 if ((prop = geometry->property("x_size")) == 0) {
2209 prop = geometry->property ("x-size");
2212 g.base_width = atoi(prop->value());
2214 if ((prop = geometry->property("y_size")) == 0) {
2215 prop = geometry->property ("y-size");
2218 g.base_height = atoi(prop->value());
2221 if ((prop = geometry->property ("x_pos")) == 0) {
2222 prop = geometry->property ("x-pos");
2225 x = atoi (prop->value());
2228 if ((prop = geometry->property ("y_pos")) == 0) {
2229 prop = geometry->property ("y-pos");
2232 y = atoi (prop->value());
2236 set_default_size (g.base_width, g.base_height);
2239 if (_session && (prop = node.property ("playhead"))) {
2241 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2243 playhead_cursor->set_position (pos);
2245 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2246 playhead_cursor->set_position (0);
2249 playhead_cursor->set_position (0);
2252 if ((prop = node.property ("mixer-width"))) {
2253 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2256 if ((prop = node.property ("zoom-focus"))) {
2257 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2260 if ((prop = node.property ("zoom"))) {
2261 /* older versions of ardour used floating point samples_per_pixel */
2262 double f = PBD::atof (prop->value());
2263 reset_zoom (llrintf (f));
2265 reset_zoom (samples_per_pixel);
2268 if ((prop = node.property ("visible-track-count"))) {
2269 set_visible_track_count (PBD::atoi (prop->value()));
2272 if ((prop = node.property ("snap-to"))) {
2273 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2276 if ((prop = node.property ("snap-mode"))) {
2277 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2280 if ((prop = node.property ("internal-snap-to"))) {
2281 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2284 if ((prop = node.property ("internal-snap-mode"))) {
2285 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2288 if ((prop = node.property ("pre-internal-snap-to"))) {
2289 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2292 if ((prop = node.property ("pre-internal-snap-mode"))) {
2293 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2296 if ((prop = node.property ("mouse-mode"))) {
2297 MouseMode m = str2mousemode(prop->value());
2298 set_mouse_mode (m, true);
2300 set_mouse_mode (MouseObject, true);
2303 if ((prop = node.property ("left-frame")) != 0) {
2305 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2309 reset_x_origin (pos);
2313 if ((prop = node.property ("y-origin")) != 0) {
2314 reset_y_origin (atof (prop->value ()));
2317 if ((prop = node.property ("join-object-range"))) {
2318 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2319 bool yn = string_is_affirmative (prop->value());
2321 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2322 tact->set_active (!yn);
2323 tact->set_active (yn);
2325 set_mouse_mode(mouse_mode, true);
2328 if ((prop = node.property ("edit-point"))) {
2329 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2332 if ((prop = node.property ("show-measures"))) {
2333 bool yn = string_is_affirmative (prop->value());
2334 _show_measures = yn;
2337 if ((prop = node.property ("follow-playhead"))) {
2338 bool yn = string_is_affirmative (prop->value());
2339 set_follow_playhead (yn);
2342 if ((prop = node.property ("stationary-playhead"))) {
2343 bool yn = string_is_affirmative (prop->value());
2344 set_stationary_playhead (yn);
2347 if ((prop = node.property ("region-list-sort-type"))) {
2348 RegionListSortType st;
2349 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2352 if ((prop = node.property ("show-editor-mixer"))) {
2354 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2357 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2358 bool yn = string_is_affirmative (prop->value());
2360 /* do it twice to force the change */
2362 tact->set_active (!yn);
2363 tact->set_active (yn);
2366 if ((prop = node.property ("show-editor-list"))) {
2368 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2371 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2372 bool yn = string_is_affirmative (prop->value());
2374 /* do it twice to force the change */
2376 tact->set_active (!yn);
2377 tact->set_active (yn);
2380 if ((prop = node.property (X_("editor-list-page")))) {
2381 _the_notebook.set_current_page (atoi (prop->value ()));
2384 if ((prop = node.property (X_("show-marker-lines")))) {
2385 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2387 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2388 bool yn = string_is_affirmative (prop->value ());
2390 tact->set_active (!yn);
2391 tact->set_active (yn);
2394 XMLNodeList children = node.children ();
2395 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2396 selection->set_state (**i, Stateful::current_state_version);
2397 _regions->set_state (**i);
2400 if ((prop = node.property ("maximised"))) {
2401 bool yn = string_is_affirmative (prop->value());
2402 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2404 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2405 bool fs = tact && tact->get_active();
2407 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2411 if ((prop = node.property ("nudge-clock-value"))) {
2413 sscanf (prop->value().c_str(), "%" PRId64, &f);
2414 nudge_clock->set (f);
2416 nudge_clock->set_mode (AudioClock::Timecode);
2417 nudge_clock->set (_session->frame_rate() * 5, true);
2422 * Not all properties may have been in XML, but
2423 * those that are linked to a private variable may need changing
2428 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2430 yn = _show_measures;
2431 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2432 /* do it twice to force the change */
2433 tact->set_active (!yn);
2434 tact->set_active (yn);
2437 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2438 yn = _follow_playhead;
2440 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2441 if (tact->get_active() != yn) {
2442 tact->set_active (yn);
2446 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2447 yn = _stationary_playhead;
2449 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2450 if (tact->get_active() != yn) {
2451 tact->set_active (yn);
2460 Editor::get_state ()
2462 XMLNode* node = new XMLNode ("Editor");
2465 id().print (buf, sizeof (buf));
2466 node->add_property ("id", buf);
2468 if (is_realized()) {
2469 Glib::RefPtr<Gdk::Window> win = get_window();
2471 int x, y, width, height;
2472 win->get_root_origin(x, y);
2473 win->get_size(width, height);
2475 XMLNode* geometry = new XMLNode ("geometry");
2477 snprintf(buf, sizeof(buf), "%d", width);
2478 geometry->add_property("x-size", string(buf));
2479 snprintf(buf, sizeof(buf), "%d", height);
2480 geometry->add_property("y-size", string(buf));
2481 snprintf(buf, sizeof(buf), "%d", x);
2482 geometry->add_property("x-pos", string(buf));
2483 snprintf(buf, sizeof(buf), "%d", y);
2484 geometry->add_property("y-pos", string(buf));
2485 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2486 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2487 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2488 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2489 geometry->add_property("edit-vertical-pane-pos", string(buf));
2491 node->add_child_nocopy (*geometry);
2494 maybe_add_mixer_strip_width (*node);
2496 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2498 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2499 node->add_property ("zoom", buf);
2500 node->add_property ("snap-to", enum_2_string (_snap_type));
2501 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2502 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2503 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2504 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2505 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2506 node->add_property ("edit-point", enum_2_string (_edit_point));
2507 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2508 node->add_property ("visible-track-count", buf);
2510 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2511 node->add_property ("playhead", buf);
2512 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2513 node->add_property ("left-frame", buf);
2514 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2515 node->add_property ("y-origin", buf);
2517 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2518 node->add_property ("maximised", _maximised ? "yes" : "no");
2519 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2520 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2521 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2522 node->add_property ("mouse-mode", enum2str(mouse_mode));
2523 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2525 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2527 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2528 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2531 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2533 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2534 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2537 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2538 node->add_property (X_("editor-list-page"), buf);
2540 if (button_bindings) {
2541 XMLNode* bb = new XMLNode (X_("Buttons"));
2542 button_bindings->save (*bb);
2543 node->add_child_nocopy (*bb);
2546 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2548 node->add_child_nocopy (selection->get_state ());
2549 node->add_child_nocopy (_regions->get_state ());
2551 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2552 node->add_property ("nudge-clock-value", buf);
2557 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2558 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2560 * @return pair: TimeAxisView that y is over, layer index.
2562 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2563 * in stacked or expanded region display mode, otherwise 0.
2565 std::pair<TimeAxisView *, double>
2566 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2568 if (!trackview_relative_offset) {
2569 y -= _trackview_group->canvas_origin().y;
2573 return std::make_pair ( (TimeAxisView *) 0, 0);
2576 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2578 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2585 return std::make_pair ( (TimeAxisView *) 0, 0);
2588 /** Snap a position to the grid, if appropriate, taking into account current
2589 * grid settings and also the state of any snap modifier keys that may be pressed.
2590 * @param start Position to snap.
2591 * @param event Event to get current key modifier information from, or 0.
2594 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2596 if (!_session || !event) {
2600 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2601 if (_snap_mode == SnapOff) {
2602 snap_to_internal (start, direction, for_mark);
2605 if (_snap_mode != SnapOff) {
2606 snap_to_internal (start, direction, for_mark);
2607 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2608 /* SnapOff, but we pressed the snap_delta modifier */
2609 snap_to_internal (start, direction, for_mark);
2615 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2617 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2621 snap_to_internal (start, direction, for_mark, ensure_snap);
2625 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2627 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2628 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2630 switch (_snap_type) {
2631 case SnapToTimecodeFrame:
2632 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2633 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2634 /* start is already on a whole timecode frame, do nothing */
2635 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2636 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2638 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2642 case SnapToTimecodeSeconds:
2643 if (_session->config.get_timecode_offset_negative()) {
2644 start += _session->config.get_timecode_offset ();
2646 start -= _session->config.get_timecode_offset ();
2648 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2649 (start % one_timecode_second == 0)) {
2650 /* start is already on a whole second, do nothing */
2651 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2652 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2654 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2657 if (_session->config.get_timecode_offset_negative()) {
2658 start -= _session->config.get_timecode_offset ();
2660 start += _session->config.get_timecode_offset ();
2664 case SnapToTimecodeMinutes:
2665 if (_session->config.get_timecode_offset_negative()) {
2666 start += _session->config.get_timecode_offset ();
2668 start -= _session->config.get_timecode_offset ();
2670 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2671 (start % one_timecode_minute == 0)) {
2672 /* start is already on a whole minute, do nothing */
2673 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2674 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2676 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2678 if (_session->config.get_timecode_offset_negative()) {
2679 start -= _session->config.get_timecode_offset ();
2681 start += _session->config.get_timecode_offset ();
2685 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2686 abort(); /*NOTREACHED*/
2691 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2693 const framepos_t one_second = _session->frame_rate();
2694 const framepos_t one_minute = _session->frame_rate() * 60;
2695 framepos_t presnap = start;
2699 switch (_snap_type) {
2700 case SnapToTimecodeFrame:
2701 case SnapToTimecodeSeconds:
2702 case SnapToTimecodeMinutes:
2703 return timecode_snap_to_internal (start, direction, for_mark);
2706 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2707 start % (one_second/75) == 0) {
2708 /* start is already on a whole CD frame, do nothing */
2709 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2710 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2712 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2717 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2718 start % one_second == 0) {
2719 /* start is already on a whole second, do nothing */
2720 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2721 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2723 start = (framepos_t) floor ((double) start / one_second) * one_second;
2728 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2729 start % one_minute == 0) {
2730 /* start is already on a whole minute, do nothing */
2731 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2732 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2734 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2739 start = _session->tempo_map().round_to_bar (start, direction);
2743 start = _session->tempo_map().round_to_beat (start, direction);
2746 case SnapToBeatDiv128:
2747 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2749 case SnapToBeatDiv64:
2750 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2752 case SnapToBeatDiv32:
2753 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2755 case SnapToBeatDiv28:
2756 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2758 case SnapToBeatDiv24:
2759 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2761 case SnapToBeatDiv20:
2762 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2764 case SnapToBeatDiv16:
2765 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2767 case SnapToBeatDiv14:
2768 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2770 case SnapToBeatDiv12:
2771 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2773 case SnapToBeatDiv10:
2774 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2776 case SnapToBeatDiv8:
2777 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2779 case SnapToBeatDiv7:
2780 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2782 case SnapToBeatDiv6:
2783 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2785 case SnapToBeatDiv5:
2786 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2788 case SnapToBeatDiv4:
2789 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2791 case SnapToBeatDiv3:
2792 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2794 case SnapToBeatDiv2:
2795 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2803 _session->locations()->marks_either_side (start, before, after);
2805 if (before == max_framepos && after == max_framepos) {
2806 /* No marks to snap to, so just don't snap */
2808 } else if (before == max_framepos) {
2810 } else if (after == max_framepos) {
2812 } else if (before != max_framepos && after != max_framepos) {
2813 /* have before and after */
2814 if ((start - before) < (after - start)) {
2823 case SnapToRegionStart:
2824 case SnapToRegionEnd:
2825 case SnapToRegionSync:
2826 case SnapToRegionBoundary:
2827 if (!region_boundary_cache.empty()) {
2829 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2830 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2832 if (direction > 0) {
2833 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2835 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2838 if (next != region_boundary_cache.begin ()) {
2843 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2844 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2846 if (start > (p + n) / 2) {
2855 switch (_snap_mode) {
2865 if (presnap > start) {
2866 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2870 } else if (presnap < start) {
2871 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2877 /* handled at entry */
2885 Editor::setup_toolbar ()
2887 HBox* mode_box = manage(new HBox);
2888 mode_box->set_border_width (2);
2889 mode_box->set_spacing(2);
2891 HBox* mouse_mode_box = manage (new HBox);
2892 HBox* mouse_mode_hbox = manage (new HBox);
2893 VBox* mouse_mode_vbox = manage (new VBox);
2894 Alignment* mouse_mode_align = manage (new Alignment);
2896 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2897 mouse_mode_size_group->add_widget (smart_mode_button);
2898 mouse_mode_size_group->add_widget (mouse_move_button);
2899 mouse_mode_size_group->add_widget (mouse_cut_button);
2900 mouse_mode_size_group->add_widget (mouse_select_button);
2901 mouse_mode_size_group->add_widget (mouse_timefx_button);
2902 mouse_mode_size_group->add_widget (mouse_audition_button);
2903 mouse_mode_size_group->add_widget (mouse_draw_button);
2904 mouse_mode_size_group->add_widget (mouse_content_button);
2906 mouse_mode_size_group->add_widget (zoom_in_button);
2907 mouse_mode_size_group->add_widget (zoom_out_button);
2908 mouse_mode_size_group->add_widget (zoom_preset_selector);
2909 mouse_mode_size_group->add_widget (zoom_out_full_button);
2910 mouse_mode_size_group->add_widget (zoom_focus_selector);
2912 mouse_mode_size_group->add_widget (tav_shrink_button);
2913 mouse_mode_size_group->add_widget (tav_expand_button);
2914 mouse_mode_size_group->add_widget (visible_tracks_selector);
2916 mouse_mode_size_group->add_widget (snap_type_selector);
2917 mouse_mode_size_group->add_widget (snap_mode_selector);
2919 mouse_mode_size_group->add_widget (edit_point_selector);
2920 mouse_mode_size_group->add_widget (edit_mode_selector);
2922 mouse_mode_size_group->add_widget (*nudge_clock);
2923 mouse_mode_size_group->add_widget (nudge_forward_button);
2924 mouse_mode_size_group->add_widget (nudge_backward_button);
2926 mouse_mode_hbox->set_spacing (2);
2928 if (!ARDOUR::Profile->get_trx()) {
2929 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2932 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2933 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2935 if (!ARDOUR::Profile->get_mixbus()) {
2936 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2939 if (!ARDOUR::Profile->get_trx()) {
2940 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2941 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2942 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2943 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2946 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2948 mouse_mode_align->add (*mouse_mode_vbox);
2949 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2951 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2953 edit_mode_selector.set_name ("mouse mode button");
2955 if (!ARDOUR::Profile->get_trx()) {
2956 mode_box->pack_start (edit_mode_selector, false, false);
2958 mode_box->pack_start (*mouse_mode_box, false, false);
2960 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2961 _mouse_mode_tearoff->set_name ("MouseModeBase");
2962 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2964 if (Profile->get_sae() || Profile->get_mixbus() ) {
2965 _mouse_mode_tearoff->set_can_be_torn_off (false);
2968 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2969 &_mouse_mode_tearoff->tearoff_window()));
2970 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2971 &_mouse_mode_tearoff->tearoff_window(), 1));
2972 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2973 &_mouse_mode_tearoff->tearoff_window()));
2974 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2975 &_mouse_mode_tearoff->tearoff_window(), 1));
2979 _zoom_box.set_spacing (2);
2980 _zoom_box.set_border_width (2);
2984 zoom_preset_selector.set_name ("zoom button");
2985 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2986 zoom_preset_selector.set_size_request (42, -1);
2988 zoom_in_button.set_name ("zoom button");
2989 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
2990 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2991 zoom_in_button.set_related_action (act);
2993 zoom_out_button.set_name ("zoom button");
2994 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
2995 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2996 zoom_out_button.set_related_action (act);
2998 zoom_out_full_button.set_name ("zoom button");
2999 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3000 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3001 zoom_out_full_button.set_related_action (act);
3003 zoom_focus_selector.set_name ("zoom button");
3005 if (ARDOUR::Profile->get_mixbus()) {
3006 _zoom_box.pack_start (zoom_preset_selector, false, false);
3007 } else if (ARDOUR::Profile->get_trx()) {
3008 mode_box->pack_start (zoom_out_button, false, false);
3009 mode_box->pack_start (zoom_in_button, false, false);
3011 _zoom_box.pack_start (zoom_out_button, false, false);
3012 _zoom_box.pack_start (zoom_in_button, false, false);
3013 _zoom_box.pack_start (zoom_out_full_button, false, false);
3014 _zoom_box.pack_start (zoom_focus_selector, false, false);
3017 /* Track zoom buttons */
3018 visible_tracks_selector.set_name ("zoom button");
3019 if (Profile->get_mixbus()) {
3020 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3021 visible_tracks_selector.set_size_request (42, -1);
3023 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3026 tav_expand_button.set_name ("zoom button");
3027 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3028 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3029 tav_expand_button.set_related_action (act);
3031 tav_shrink_button.set_name ("zoom button");
3032 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3033 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3034 tav_shrink_button.set_related_action (act);
3036 if (ARDOUR::Profile->get_mixbus()) {
3037 _zoom_box.pack_start (visible_tracks_selector);
3038 } else if (ARDOUR::Profile->get_trx()) {
3039 _zoom_box.pack_start (tav_shrink_button);
3040 _zoom_box.pack_start (tav_expand_button);
3042 _zoom_box.pack_start (visible_tracks_selector);
3043 _zoom_box.pack_start (tav_shrink_button);
3044 _zoom_box.pack_start (tav_expand_button);
3047 if (!ARDOUR::Profile->get_trx()) {
3048 _zoom_tearoff = manage (new TearOff (_zoom_box));
3050 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3051 &_zoom_tearoff->tearoff_window()));
3052 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3053 &_zoom_tearoff->tearoff_window(), 0));
3054 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3055 &_zoom_tearoff->tearoff_window()));
3056 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3057 &_zoom_tearoff->tearoff_window(), 0));
3060 if (Profile->get_sae() || Profile->get_mixbus() ) {
3061 _zoom_tearoff->set_can_be_torn_off (false);
3064 snap_box.set_spacing (2);
3065 snap_box.set_border_width (2);
3067 snap_type_selector.set_name ("mouse mode button");
3069 snap_mode_selector.set_name ("mouse mode button");
3071 edit_point_selector.set_name ("mouse mode button");
3073 snap_box.pack_start (snap_mode_selector, false, false);
3074 snap_box.pack_start (snap_type_selector, false, false);
3075 snap_box.pack_start (edit_point_selector, false, false);
3079 HBox *nudge_box = manage (new HBox);
3080 nudge_box->set_spacing (2);
3081 nudge_box->set_border_width (2);
3083 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3084 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3086 nudge_box->pack_start (nudge_backward_button, false, false);
3087 nudge_box->pack_start (nudge_forward_button, false, false);
3088 nudge_box->pack_start (*nudge_clock, false, false);
3091 /* Pack everything in... */
3093 HBox* hbox = manage (new HBox);
3094 hbox->set_spacing(2);
3096 _tools_tearoff = manage (new TearOff (*hbox));
3097 _tools_tearoff->set_name ("MouseModeBase");
3098 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3100 if (Profile->get_sae() || Profile->get_mixbus()) {
3101 _tools_tearoff->set_can_be_torn_off (false);
3104 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3105 &_tools_tearoff->tearoff_window()));
3106 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3107 &_tools_tearoff->tearoff_window(), 0));
3108 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3109 &_tools_tearoff->tearoff_window()));
3110 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3111 &_tools_tearoff->tearoff_window(), 0));
3113 toolbar_hbox.set_spacing (2);
3114 toolbar_hbox.set_border_width (1);
3116 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3117 if (!ARDOUR::Profile->get_trx()) {
3118 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3119 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3122 if (!ARDOUR::Profile->get_trx()) {
3123 hbox->pack_start (snap_box, false, false);
3124 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3125 hbox->pack_start (*nudge_box, false, false);
3127 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3130 hbox->pack_start (panic_box, false, false);
3134 toolbar_base.set_name ("ToolBarBase");
3135 toolbar_base.add (toolbar_hbox);
3137 _toolbar_viewport.add (toolbar_base);
3138 /* stick to the required height but allow width to vary if there's not enough room */
3139 _toolbar_viewport.set_size_request (1, -1);
3141 toolbar_frame.set_shadow_type (SHADOW_OUT);
3142 toolbar_frame.set_name ("BaseFrame");
3143 toolbar_frame.add (_toolbar_viewport);
3147 Editor::build_edit_point_menu ()
3149 using namespace Menu_Helpers;
3151 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3152 if(!Profile->get_mixbus())
3153 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3154 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3156 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3160 Editor::build_edit_mode_menu ()
3162 using namespace Menu_Helpers;
3164 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3165 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3166 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3167 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3169 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3173 Editor::build_snap_mode_menu ()
3175 using namespace Menu_Helpers;
3177 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3178 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3179 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3181 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3185 Editor::build_snap_type_menu ()
3187 using namespace Menu_Helpers;
3189 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3190 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3191 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3192 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3193 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3194 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3195 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3196 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3197 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3198 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3199 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3200 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3201 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3202 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3203 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3204 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3205 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3206 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3207 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3208 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3209 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3210 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3211 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3212 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3213 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3214 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3215 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3216 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3217 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3218 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3220 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3225 Editor::setup_tooltips ()
3227 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Grab mode)"));
3228 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Grab Mode (select/move objects)"));
3229 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split regions)"));
3230 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select time ranges)"));
3231 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3232 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3233 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3234 ARDOUR_UI::instance()->set_tip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3235 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3236 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3237 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3238 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3239 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3240 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3241 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3242 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3243 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3244 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3245 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3246 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3247 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3248 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3249 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3250 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3254 Editor::convert_drop_to_paths (
3255 vector<string>& paths,
3256 const RefPtr<Gdk::DragContext>& /*context*/,
3259 const SelectionData& data,
3263 if (_session == 0) {
3267 vector<string> uris = data.get_uris();
3271 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3272 are actually URI lists. So do it by hand.
3275 if (data.get_target() != "text/plain") {
3279 /* Parse the "uri-list" format that Nautilus provides,
3280 where each pathname is delimited by \r\n.
3282 THERE MAY BE NO NULL TERMINATING CHAR!!!
3285 string txt = data.get_text();
3289 p = (char *) malloc (txt.length() + 1);
3290 txt.copy (p, txt.length(), 0);
3291 p[txt.length()] = '\0';
3297 while (g_ascii_isspace (*p))
3301 while (*q && (*q != '\n') && (*q != '\r')) {
3308 while (q > p && g_ascii_isspace (*q))
3313 uris.push_back (string (p, q - p + 1));
3317 p = strchr (p, '\n');
3329 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3330 if ((*i).substr (0,7) == "file://") {
3331 paths.push_back (Glib::filename_from_uri (*i));
3339 Editor::new_tempo_section ()
3344 Editor::map_transport_state ()
3346 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3348 if (_session && _session->transport_stopped()) {
3349 have_pending_keyboard_selection = false;
3352 update_loop_range_view ();
3358 Editor::begin_selection_op_history ()
3360 selection_op_cmd_depth = 0;
3361 selection_op_history_it = 0;
3363 while(!selection_op_history.empty()) {
3364 delete selection_op_history.front();
3365 selection_op_history.pop_front();
3368 selection_undo_action->set_sensitive (false);
3369 selection_redo_action->set_sensitive (false);
3370 selection_op_history.push_front (&_selection_memento->get_state ());
3374 Editor::begin_reversible_selection_op (string name)
3377 //cerr << name << endl;
3378 /* begin/commit pairs can be nested */
3379 selection_op_cmd_depth++;
3384 Editor::commit_reversible_selection_op ()
3387 if (selection_op_cmd_depth == 1) {
3389 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3391 The user has undone some selection ops and then made a new one,
3392 making anything earlier in the list invalid.
3395 list<XMLNode *>::iterator it = selection_op_history.begin();
3396 list<XMLNode *>::iterator e_it = it;
3397 advance (e_it, selection_op_history_it);
3399 for ( ; it != e_it; ++it) {
3402 selection_op_history.erase (selection_op_history.begin(), e_it);
3405 selection_op_history.push_front (&_selection_memento->get_state ());
3406 selection_op_history_it = 0;
3408 selection_undo_action->set_sensitive (true);
3409 selection_redo_action->set_sensitive (false);
3412 if (selection_op_cmd_depth > 0) {
3413 selection_op_cmd_depth--;
3419 Editor::undo_selection_op ()
3422 selection_op_history_it++;
3424 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3425 if (n == selection_op_history_it) {
3426 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3427 selection_redo_action->set_sensitive (true);
3431 /* is there an earlier entry? */
3432 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3433 selection_undo_action->set_sensitive (false);
3439 Editor::redo_selection_op ()
3442 if (selection_op_history_it > 0) {
3443 selection_op_history_it--;
3446 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3447 if (n == selection_op_history_it) {
3448 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3449 selection_undo_action->set_sensitive (true);
3454 if (selection_op_history_it == 0) {
3455 selection_redo_action->set_sensitive (false);
3461 Editor::begin_reversible_command (string name)
3464 before.push_back (&_selection_memento->get_state ());
3465 _session->begin_reversible_command (name);
3470 Editor::begin_reversible_command (GQuark q)
3473 before.push_back (&_selection_memento->get_state ());
3474 _session->begin_reversible_command (q);
3479 Editor::abort_reversible_command ()
3482 while(!before.empty()) {
3483 delete before.front();
3486 _session->abort_reversible_command ();
3491 Editor::commit_reversible_command ()
3494 if (before.size() == 1) {
3495 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3496 redo_action->set_sensitive(false);
3497 undo_action->set_sensitive(true);
3498 begin_selection_op_history ();
3501 if (before.empty()) {
3502 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3507 _session->commit_reversible_command ();
3512 Editor::history_changed ()
3516 if (undo_action && _session) {
3517 if (_session->undo_depth() == 0) {
3518 label = S_("Command|Undo");
3520 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3522 undo_action->property_label() = label;
3525 if (redo_action && _session) {
3526 if (_session->redo_depth() == 0) {
3529 label = string_compose(_("Redo (%1)"), _session->next_redo());
3531 redo_action->property_label() = label;
3536 Editor::duplicate_range (bool with_dialog)
3540 RegionSelection rs = get_regions_from_selection_and_entered ();
3542 if ( selection->time.length() == 0 && rs.empty()) {
3548 ArdourDialog win (_("Duplicate"));
3549 Label label (_("Number of duplications:"));
3550 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3551 SpinButton spinner (adjustment, 0.0, 1);
3554 win.get_vbox()->set_spacing (12);
3555 win.get_vbox()->pack_start (hbox);
3556 hbox.set_border_width (6);
3557 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3559 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3560 place, visually. so do this by hand.
3563 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3564 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3565 spinner.grab_focus();
3571 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3572 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3573 win.set_default_response (RESPONSE_ACCEPT);
3575 spinner.grab_focus ();
3577 switch (win.run ()) {
3578 case RESPONSE_ACCEPT:
3584 times = adjustment.get_value();
3587 if ((current_mouse_mode() == Editing::MouseRange)) {
3588 if (selection->time.length()) {
3589 duplicate_selection (times);
3591 } else if (get_smart_mode()) {
3592 if (selection->time.length()) {
3593 duplicate_selection (times);
3595 duplicate_some_regions (rs, times);
3597 duplicate_some_regions (rs, times);
3602 Editor::set_edit_mode (EditMode m)
3604 Config->set_edit_mode (m);
3608 Editor::cycle_edit_mode ()
3610 switch (Config->get_edit_mode()) {
3612 if (Profile->get_sae()) {
3613 Config->set_edit_mode (Lock);
3615 Config->set_edit_mode (Ripple);
3620 Config->set_edit_mode (Lock);
3623 Config->set_edit_mode (Slide);
3629 Editor::edit_mode_selection_done ( EditMode m )
3631 Config->set_edit_mode ( m );
3635 Editor::snap_type_selection_done (SnapType snaptype)
3637 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3639 ract->set_active ();
3644 Editor::snap_mode_selection_done (SnapMode mode)
3646 RefPtr<RadioAction> ract = snap_mode_action (mode);
3649 ract->set_active (true);
3654 Editor::cycle_edit_point (bool with_marker)
3656 if(Profile->get_mixbus())
3657 with_marker = false;
3659 switch (_edit_point) {
3661 set_edit_point_preference (EditAtPlayhead);
3663 case EditAtPlayhead:
3665 set_edit_point_preference (EditAtSelectedMarker);
3667 set_edit_point_preference (EditAtMouse);
3670 case EditAtSelectedMarker:
3671 set_edit_point_preference (EditAtMouse);
3677 Editor::edit_point_selection_done (EditPoint ep)
3679 set_edit_point_preference ( ep );
3683 Editor::build_zoom_focus_menu ()
3685 using namespace Menu_Helpers;
3687 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3688 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3689 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3690 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3691 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3692 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3694 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3698 Editor::zoom_focus_selection_done ( ZoomFocus f )
3700 RefPtr<RadioAction> ract = zoom_focus_action (f);
3702 ract->set_active ();
3707 Editor::build_track_count_menu ()
3709 using namespace Menu_Helpers;
3711 if (!Profile->get_mixbus()) {
3712 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3713 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3714 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3715 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3716 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3717 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3718 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3719 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3720 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3721 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3722 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3723 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3724 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3726 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3727 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3728 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3729 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3730 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3731 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3732 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3733 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3734 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3735 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3737 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3738 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3739 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3740 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3741 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3742 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3743 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3744 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3745 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3746 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3747 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3752 Editor::set_zoom_preset (int64_t ms)
3755 temporal_zoom_session();
3759 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3760 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3764 Editor::set_visible_track_count (int32_t n)
3766 _visible_track_count = n;
3768 /* if the canvas hasn't really been allocated any size yet, just
3769 record the desired number of visible tracks and return. when canvas
3770 allocation happens, we will get called again and then we can do the
3774 if (_visible_canvas_height <= 1) {
3780 DisplaySuspender ds;
3782 if (_visible_track_count > 0) {
3783 h = trackviews_height() / _visible_track_count;
3784 std::ostringstream s;
3785 s << _visible_track_count;
3787 } else if (_visible_track_count == 0) {
3789 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3790 if ((*i)->marked_for_display()) {
3794 h = trackviews_height() / n;
3797 /* negative value means that the visible track count has
3798 been overridden by explicit track height changes.
3800 visible_tracks_selector.set_text (X_("*"));
3804 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3805 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3808 if (str != visible_tracks_selector.get_text()) {
3809 visible_tracks_selector.set_text (str);
3814 Editor::override_visible_track_count ()
3816 _visible_track_count = -1;
3817 visible_tracks_selector.set_text ( _("*") );
3821 Editor::edit_controls_button_release (GdkEventButton* ev)
3823 if (Keyboard::is_context_menu_event (ev)) {
3824 ARDOUR_UI::instance()->add_route (this);
3825 } else if (ev->button == 1) {
3826 selection->clear_tracks ();
3833 Editor::mouse_select_button_release (GdkEventButton* ev)
3835 /* this handles just right-clicks */
3837 if (ev->button != 3) {
3845 Editor::set_zoom_focus (ZoomFocus f)
3847 string str = zoom_focus_strings[(int)f];
3849 if (str != zoom_focus_selector.get_text()) {
3850 zoom_focus_selector.set_text (str);
3853 if (zoom_focus != f) {
3860 Editor::cycle_zoom_focus ()
3862 switch (zoom_focus) {
3864 set_zoom_focus (ZoomFocusRight);
3866 case ZoomFocusRight:
3867 set_zoom_focus (ZoomFocusCenter);
3869 case ZoomFocusCenter:
3870 set_zoom_focus (ZoomFocusPlayhead);
3872 case ZoomFocusPlayhead:
3873 set_zoom_focus (ZoomFocusMouse);
3875 case ZoomFocusMouse:
3876 set_zoom_focus (ZoomFocusEdit);
3879 set_zoom_focus (ZoomFocusLeft);
3885 Editor::ensure_float (Window& win)
3887 win.set_transient_for (*this);
3891 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3893 /* recover or initialize pane positions. do this here rather than earlier because
3894 we don't want the positions to change the child allocations, which they seem to do.
3900 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3909 XMLNode* geometry = find_named_node (*node, "geometry");
3911 if (which == static_cast<Paned*> (&edit_pane)) {
3913 if (done & Horizontal) {
3917 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3918 _notebook_shrunk = string_is_affirmative (prop->value ());
3921 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3922 /* initial allocation is 90% to canvas, 10% to notebook */
3923 pos = (int) floor (alloc.get_width() * 0.90f);
3924 snprintf (buf, sizeof(buf), "%d", pos);
3926 pos = atoi (prop->value());
3929 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3930 edit_pane.set_position (pos);
3933 done = (Pane) (done | Horizontal);
3935 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3937 if (done & Vertical) {
3941 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3942 /* initial allocation is 90% to canvas, 10% to summary */
3943 pos = (int) floor (alloc.get_height() * 0.90f);
3944 snprintf (buf, sizeof(buf), "%d", pos);
3947 pos = atoi (prop->value());
3950 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3951 editor_summary_pane.set_position (pos);
3954 done = (Pane) (done | Vertical);
3959 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3961 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3962 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3963 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3964 top_hbox.remove (toolbar_frame);
3969 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3971 if (toolbar_frame.get_parent() == 0) {
3972 top_hbox.pack_end (toolbar_frame);
3977 Editor::set_show_measures (bool yn)
3979 if (_show_measures != yn) {
3982 if ((_show_measures = yn) == true) {
3984 tempo_lines->show();
3987 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3988 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3990 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3991 draw_measures (begin, end);
3999 Editor::toggle_follow_playhead ()
4001 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
4003 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4004 set_follow_playhead (tact->get_active());
4008 /** @param yn true to follow playhead, otherwise false.
4009 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4012 Editor::set_follow_playhead (bool yn, bool catch_up)
4014 if (_follow_playhead != yn) {
4015 if ((_follow_playhead = yn) == true && catch_up) {
4017 reset_x_origin_to_follow_playhead ();
4024 Editor::toggle_stationary_playhead ()
4026 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4028 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4029 set_stationary_playhead (tact->get_active());
4034 Editor::set_stationary_playhead (bool yn)
4036 if (_stationary_playhead != yn) {
4037 if ((_stationary_playhead = yn) == true) {
4039 // FIXME need a 3.0 equivalent of this 2.X call
4040 // update_current_screen ();
4047 Editor::playlist_selector () const
4049 return *_playlist_selector;
4053 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4055 if (paste_count == 0) {
4056 /* don't bother calculating an offset that will be zero anyway */
4060 /* calculate basic unsnapped multi-paste offset */
4061 framecnt_t offset = paste_count * duration;
4063 /* snap offset so pos + offset is aligned to the grid */
4064 framepos_t offset_pos = pos + offset;
4065 snap_to(offset_pos, RoundUpMaybe);
4066 offset = offset_pos - pos;
4072 Editor::get_grid_beat_divisions(framepos_t position)
4074 switch (_snap_type) {
4075 case SnapToBeatDiv128: return 128;
4076 case SnapToBeatDiv64: return 64;
4077 case SnapToBeatDiv32: return 32;
4078 case SnapToBeatDiv28: return 28;
4079 case SnapToBeatDiv24: return 24;
4080 case SnapToBeatDiv20: return 20;
4081 case SnapToBeatDiv16: return 16;
4082 case SnapToBeatDiv14: return 14;
4083 case SnapToBeatDiv12: return 12;
4084 case SnapToBeatDiv10: return 10;
4085 case SnapToBeatDiv8: return 8;
4086 case SnapToBeatDiv7: return 7;
4087 case SnapToBeatDiv6: return 6;
4088 case SnapToBeatDiv5: return 5;
4089 case SnapToBeatDiv4: return 4;
4090 case SnapToBeatDiv3: return 3;
4091 case SnapToBeatDiv2: return 2;
4098 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4102 const unsigned divisions = get_grid_beat_divisions(position);
4104 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4107 switch (_snap_type) {
4109 return Evoral::Beats(1.0);
4112 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
4120 return Evoral::Beats();
4124 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4128 ret = nudge_clock->current_duration (pos);
4129 next = ret + 1; /* XXXX fix me */
4135 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4137 ArdourDialog dialog (_("Playlist Deletion"));
4138 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4139 "If it is kept, its audio files will not be cleaned.\n"
4140 "If it is deleted, audio files used by it alone will be cleaned."),
4143 dialog.set_position (WIN_POS_CENTER);
4144 dialog.get_vbox()->pack_start (label);
4148 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4149 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4150 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4152 switch (dialog.run ()) {
4153 case RESPONSE_ACCEPT:
4154 /* delete the playlist */
4158 case RESPONSE_REJECT:
4159 /* keep the playlist */
4171 Editor::audio_region_selection_covers (framepos_t where)
4173 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4174 if ((*a)->region()->covers (where)) {
4183 Editor::prepare_for_cleanup ()
4185 cut_buffer->clear_regions ();
4186 cut_buffer->clear_playlists ();
4188 selection->clear_regions ();
4189 selection->clear_playlists ();
4191 _regions->suspend_redisplay ();
4195 Editor::finish_cleanup ()
4197 _regions->resume_redisplay ();
4201 Editor::transport_loop_location()
4204 return _session->locations()->auto_loop_location();
4211 Editor::transport_punch_location()
4214 return _session->locations()->auto_punch_location();
4221 Editor::control_layout_scroll (GdkEventScroll* ev)
4223 /* Just forward to the normal canvas scroll method. The coordinate
4224 systems are different but since the canvas is always larger than the
4225 track headers, and aligned with the trackview area, this will work.
4227 In the not too distant future this layout is going away anyway and
4228 headers will be on the canvas.
4230 return canvas_scroll_event (ev, false);
4234 Editor::session_state_saved (string)
4237 _snapshots->redisplay ();
4241 Editor::update_tearoff_visibility()
4243 bool visible = ARDOUR_UI::config()->get_keep_tearoffs();
4244 _mouse_mode_tearoff->set_visible (visible);
4245 _tools_tearoff->set_visible (visible);
4246 if (_zoom_tearoff) {
4247 _zoom_tearoff->set_visible (visible);
4252 Editor::reattach_all_tearoffs ()
4254 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4255 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4256 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4260 Editor::maximise_editing_space ()
4272 Editor::restore_editing_space ()
4284 * Make new playlists for a given track and also any others that belong
4285 * to the same active route group with the `select' property.
4290 Editor::new_playlists (TimeAxisView* v)
4292 begin_reversible_command (_("new playlists"));
4293 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4294 _session->playlists->get (playlists);
4295 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4296 commit_reversible_command ();
4300 * Use a copy of the current playlist for a given track and also any others that belong
4301 * to the same active route group with the `select' property.
4306 Editor::copy_playlists (TimeAxisView* v)
4308 begin_reversible_command (_("copy playlists"));
4309 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4310 _session->playlists->get (playlists);
4311 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4312 commit_reversible_command ();
4315 /** Clear the current playlist for a given track and also any others that belong
4316 * to the same active route group with the `select' property.
4321 Editor::clear_playlists (TimeAxisView* v)
4323 begin_reversible_command (_("clear playlists"));
4324 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4325 _session->playlists->get (playlists);
4326 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4327 commit_reversible_command ();
4331 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4333 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4337 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4339 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4343 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4345 atv.clear_playlist ();
4349 Editor::on_key_press_event (GdkEventKey* ev)
4351 return key_press_focus_accelerator_handler (*this, ev);
4355 Editor::on_key_release_event (GdkEventKey* ev)
4357 return Gtk::Window::on_key_release_event (ev);
4358 // return key_press_focus_accelerator_handler (*this, ev);
4362 Editor::get_y_origin () const
4364 return vertical_adjustment.get_value ();
4367 /** Queue up a change to the viewport x origin.
4368 * @param frame New x origin.
4371 Editor::reset_x_origin (framepos_t frame)
4373 pending_visual_change.add (VisualChange::TimeOrigin);
4374 pending_visual_change.time_origin = frame;
4375 ensure_visual_change_idle_handler ();
4379 Editor::reset_y_origin (double y)
4381 pending_visual_change.add (VisualChange::YOrigin);
4382 pending_visual_change.y_origin = y;
4383 ensure_visual_change_idle_handler ();
4387 Editor::reset_zoom (framecnt_t spp)
4389 if (spp == samples_per_pixel) {
4393 pending_visual_change.add (VisualChange::ZoomLevel);
4394 pending_visual_change.samples_per_pixel = spp;
4395 ensure_visual_change_idle_handler ();
4399 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4401 reset_x_origin (frame);
4404 if (!no_save_visual) {
4405 undo_visual_stack.push_back (current_visual_state(false));
4409 Editor::VisualState::VisualState (bool with_tracks)
4410 : gui_state (with_tracks ? new GUIObjectState : 0)
4414 Editor::VisualState::~VisualState ()
4419 Editor::VisualState*
4420 Editor::current_visual_state (bool with_tracks)
4422 VisualState* vs = new VisualState (with_tracks);
4423 vs->y_position = vertical_adjustment.get_value();
4424 vs->samples_per_pixel = samples_per_pixel;
4425 vs->leftmost_frame = leftmost_frame;
4426 vs->zoom_focus = zoom_focus;
4429 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4436 Editor::undo_visual_state ()
4438 if (undo_visual_stack.empty()) {
4442 VisualState* vs = undo_visual_stack.back();
4443 undo_visual_stack.pop_back();
4446 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4449 use_visual_state (*vs);
4454 Editor::redo_visual_state ()
4456 if (redo_visual_stack.empty()) {
4460 VisualState* vs = redo_visual_stack.back();
4461 redo_visual_stack.pop_back();
4463 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4464 // why do we check here?
4465 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4468 use_visual_state (*vs);
4473 Editor::swap_visual_state ()
4475 if (undo_visual_stack.empty()) {
4476 redo_visual_state ();
4478 undo_visual_state ();
4483 Editor::use_visual_state (VisualState& vs)
4485 PBD::Unwinder<bool> nsv (no_save_visual, true);
4486 DisplaySuspender ds;
4488 vertical_adjustment.set_value (vs.y_position);
4490 set_zoom_focus (vs.zoom_focus);
4491 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4494 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4496 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4497 (*i)->clear_property_cache();
4498 (*i)->reset_visual_state ();
4502 _routes->update_visibility ();
4505 /** This is the core function that controls the zoom level of the canvas. It is called
4506 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4507 * @param spp new number of samples per pixel
4510 Editor::set_samples_per_pixel (framecnt_t spp)
4516 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4517 const framecnt_t lots_of_pixels = 4000;
4519 /* if the zoom level is greater than what you'd get trying to display 3
4520 * days of audio on a really big screen, then it's too big.
4523 if (spp * lots_of_pixels > three_days) {
4527 samples_per_pixel = spp;
4530 tempo_lines->tempo_map_changed();
4533 bool const showing_time_selection = selection->time.length() > 0;
4535 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4536 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4537 (*i)->reshow_selection (selection->time);
4541 ZoomChanged (); /* EMIT_SIGNAL */
4543 ArdourCanvas::GtkCanvasViewport* c;
4545 c = get_track_canvas();
4547 c->canvas()->zoomed ();
4550 if (playhead_cursor) {
4551 playhead_cursor->set_position (playhead_cursor->current_frame ());
4554 refresh_location_display();
4555 _summary->set_overlays_dirty ();
4557 update_marker_labels ();
4563 Editor::queue_visual_videotimeline_update ()
4566 * pending_visual_change.add (VisualChange::VideoTimeline);
4567 * or maybe even more specific: which videotimeline-image
4568 * currently it calls update_video_timeline() to update
4569 * _all outdated_ images on the video-timeline.
4570 * see 'exposeimg()' in video_image_frame.cc
4572 ensure_visual_change_idle_handler ();
4576 Editor::ensure_visual_change_idle_handler ()
4578 if (pending_visual_change.idle_handler_id < 0) {
4579 // see comment in add_to_idle_resize above.
4580 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4581 pending_visual_change.being_handled = false;
4586 Editor::_idle_visual_changer (void* arg)
4588 return static_cast<Editor*>(arg)->idle_visual_changer ();
4592 Editor::idle_visual_changer ()
4594 /* set_horizontal_position() below (and maybe other calls) call
4595 gtk_main_iteration(), so it's possible that a signal will be handled
4596 half-way through this method. If this signal wants an
4597 idle_visual_changer we must schedule another one after this one, so
4598 mark the idle_handler_id as -1 here to allow that. Also make a note
4599 that we are doing the visual change, so that changes in response to
4600 super-rapid-screen-update can be dropped if we are still processing
4604 pending_visual_change.idle_handler_id = -1;
4605 pending_visual_change.being_handled = true;
4607 VisualChange vc = pending_visual_change;
4609 pending_visual_change.pending = (VisualChange::Type) 0;
4611 visual_changer (vc);
4613 pending_visual_change.being_handled = false;
4615 return 0; /* this is always a one-shot call */
4619 Editor::visual_changer (const VisualChange& vc)
4621 double const last_time_origin = horizontal_position ();
4623 if (vc.pending & VisualChange::ZoomLevel) {
4624 set_samples_per_pixel (vc.samples_per_pixel);
4626 compute_fixed_ruler_scale ();
4628 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4629 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4631 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4632 current_bbt_points_begin, current_bbt_points_end);
4633 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4634 current_bbt_points_begin, current_bbt_points_end);
4635 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4637 update_video_timeline();
4640 if (vc.pending & VisualChange::TimeOrigin) {
4641 set_horizontal_position (vc.time_origin / samples_per_pixel);
4644 if (vc.pending & VisualChange::YOrigin) {
4645 vertical_adjustment.set_value (vc.y_origin);
4648 if (last_time_origin == horizontal_position ()) {
4649 /* changed signal not emitted */
4650 update_fixed_rulers ();
4651 redisplay_tempo (true);
4654 if (!(vc.pending & VisualChange::ZoomLevel)) {
4655 update_video_timeline();
4658 _summary->set_overlays_dirty ();
4661 struct EditorOrderTimeAxisSorter {
4662 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4663 return a->order () < b->order ();
4668 Editor::sort_track_selection (TrackViewList& sel)
4670 EditorOrderTimeAxisSorter cmp;
4675 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4678 framepos_t where = 0;
4679 EditPoint ep = _edit_point;
4681 if (Profile->get_mixbus())
4682 if (ep == EditAtSelectedMarker)
4683 ep = EditAtPlayhead;
4685 if (from_outside_canvas && (ep == EditAtMouse)) {
4686 ep = EditAtPlayhead;
4687 } else if (from_context_menu && (ep == EditAtMouse)) {
4688 return canvas_event_sample (&context_click_event, 0, 0);
4691 if (entered_marker) {
4692 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4693 return entered_marker->position();
4696 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4697 ep = EditAtSelectedMarker;
4700 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4701 ep = EditAtPlayhead;
4705 case EditAtPlayhead:
4706 if (_dragging_playhead) {
4707 if (!mouse_frame (where, ignored)) {
4708 /* XXX not right but what can we do ? */
4712 where = _session->audible_frame();
4714 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4717 case EditAtSelectedMarker:
4718 if (!selection->markers.empty()) {
4720 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4723 where = loc->start();
4727 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4735 if (!mouse_frame (where, ignored)) {
4736 /* XXX not right but what can we do ? */
4740 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4748 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4750 if (!_session) return;
4752 begin_reversible_command (cmd);
4756 if ((tll = transport_loop_location()) == 0) {
4757 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4758 XMLNode &before = _session->locations()->get_state();
4759 _session->locations()->add (loc, true);
4760 _session->set_auto_loop_location (loc);
4761 XMLNode &after = _session->locations()->get_state();
4762 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4764 XMLNode &before = tll->get_state();
4765 tll->set_hidden (false, this);
4766 tll->set (start, end);
4767 XMLNode &after = tll->get_state();
4768 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4771 commit_reversible_command ();
4775 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4777 if (!_session) return;
4779 begin_reversible_command (cmd);
4783 if ((tpl = transport_punch_location()) == 0) {
4784 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4785 XMLNode &before = _session->locations()->get_state();
4786 _session->locations()->add (loc, true);
4787 _session->set_auto_punch_location (loc);
4788 XMLNode &after = _session->locations()->get_state();
4789 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4791 XMLNode &before = tpl->get_state();
4792 tpl->set_hidden (false, this);
4793 tpl->set (start, end);
4794 XMLNode &after = tpl->get_state();
4795 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4798 commit_reversible_command ();
4801 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4802 * @param rs List to which found regions are added.
4803 * @param where Time to look at.
4804 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4807 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4809 const TrackViewList* tracks;
4812 tracks = &track_views;
4817 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4819 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4822 boost::shared_ptr<Track> tr;
4823 boost::shared_ptr<Playlist> pl;
4825 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4827 boost::shared_ptr<RegionList> regions = pl->regions_at (
4828 (framepos_t) floor ( (double) where * tr->speed()));
4830 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4831 RegionView* rv = rtv->view()->find_view (*i);
4842 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4844 const TrackViewList* tracks;
4847 tracks = &track_views;
4852 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4853 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4855 boost::shared_ptr<Track> tr;
4856 boost::shared_ptr<Playlist> pl;
4858 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4860 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4861 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4863 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4865 RegionView* rv = rtv->view()->find_view (*i);
4876 /** Get regions using the following method:
4878 * Make a region list using:
4879 * (a) any selected regions
4880 * (b) the intersection of any selected tracks and the edit point(*)
4881 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4883 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4885 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4889 Editor::get_regions_from_selection_and_edit_point ()
4891 RegionSelection regions;
4893 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4894 regions.add (entered_regionview);
4896 regions = selection->regions;
4899 if ( regions.empty() ) {
4900 TrackViewList tracks = selection->tracks;
4902 if (!tracks.empty()) {
4903 /* no region selected or entered, but some selected tracks:
4904 * act on all regions on the selected tracks at the edit point
4906 framepos_t const where = get_preferred_edit_position ();
4907 get_regions_at(regions, where, tracks);
4914 /** Get regions using the following method:
4916 * Make a region list using:
4917 * (a) any selected regions
4918 * (b) the intersection of any selected tracks and the edit point(*)
4919 * (c) if neither exists, then whatever region is under the mouse
4921 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4923 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4926 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4928 RegionSelection regions;
4930 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4931 regions.add (entered_regionview);
4933 regions = selection->regions;
4936 if ( regions.empty() ) {
4937 TrackViewList tracks = selection->tracks;
4939 if (!tracks.empty()) {
4940 /* no region selected or entered, but some selected tracks:
4941 * act on all regions on the selected tracks at the edit point
4943 get_regions_at(regions, pos, tracks);
4950 /** Start with regions that are selected, or the entered regionview if none are selected.
4951 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4952 * of the regions that we started with.
4956 Editor::get_regions_from_selection_and_entered ()
4958 RegionSelection regions = selection->regions;
4960 if (regions.empty() && entered_regionview) {
4961 regions.add (entered_regionview);
4968 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4970 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4971 RouteTimeAxisView* rtav;
4973 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4974 boost::shared_ptr<Playlist> pl;
4975 std::vector<boost::shared_ptr<Region> > results;
4976 boost::shared_ptr<Track> tr;
4978 if ((tr = rtav->track()) == 0) {
4983 if ((pl = (tr->playlist())) != 0) {
4984 boost::shared_ptr<Region> r = pl->region_by_id (id);
4986 RegionView* rv = rtav->view()->find_view (r);
4988 regions.push_back (rv);
4997 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5000 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5001 MidiTimeAxisView* mtav;
5003 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5005 mtav->get_per_region_note_selection (selection);
5012 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5014 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5016 RouteTimeAxisView* tatv;
5018 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5020 boost::shared_ptr<Playlist> pl;
5021 vector<boost::shared_ptr<Region> > results;
5023 boost::shared_ptr<Track> tr;
5025 if ((tr = tatv->track()) == 0) {
5030 if ((pl = (tr->playlist())) != 0) {
5031 if (src_comparison) {
5032 pl->get_source_equivalent_regions (region, results);
5034 pl->get_region_list_equivalent_regions (region, results);
5038 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5039 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5040 regions.push_back (marv);
5049 Editor::show_rhythm_ferret ()
5051 if (rhythm_ferret == 0) {
5052 rhythm_ferret = new RhythmFerret(*this);
5055 rhythm_ferret->set_session (_session);
5056 rhythm_ferret->show ();
5057 rhythm_ferret->present ();
5061 Editor::first_idle ()
5063 MessageDialog* dialog = 0;
5065 if (track_views.size() > 1) {
5066 dialog = new MessageDialog (
5068 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5072 ARDOUR_UI::instance()->flush_pending ();
5075 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5079 // first idle adds route children (automation tracks), so we need to redisplay here
5080 _routes->redisplay ();
5084 if (_session->undo_depth() == 0) {
5085 undo_action->set_sensitive(false);
5087 redo_action->set_sensitive(false);
5088 begin_selection_op_history ();
5094 Editor::_idle_resize (gpointer arg)
5096 return ((Editor*)arg)->idle_resize ();
5100 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5102 if (resize_idle_id < 0) {
5103 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5104 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5105 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5107 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5108 _pending_resize_amount = 0;
5111 /* make a note of the smallest resulting height, so that we can clamp the
5112 lower limit at TimeAxisView::hSmall */
5114 int32_t min_resulting = INT32_MAX;
5116 _pending_resize_amount += h;
5117 _pending_resize_view = view;
5119 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5121 if (selection->tracks.contains (_pending_resize_view)) {
5122 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5123 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5127 if (min_resulting < 0) {
5132 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5133 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5137 /** Handle pending resizing of tracks */
5139 Editor::idle_resize ()
5141 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5143 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5144 selection->tracks.contains (_pending_resize_view)) {
5146 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5147 if (*i != _pending_resize_view) {
5148 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5153 _pending_resize_amount = 0;
5154 _group_tabs->set_dirty ();
5155 resize_idle_id = -1;
5163 ENSURE_GUI_THREAD (*this, &Editor::located);
5166 playhead_cursor->set_position (_session->audible_frame ());
5167 if (_follow_playhead && !_pending_initial_locate) {
5168 reset_x_origin_to_follow_playhead ();
5172 _pending_locate_request = false;
5173 _pending_initial_locate = false;
5177 Editor::region_view_added (RegionView * rv)
5179 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5180 if (rv->region ()->id () == (*pr)) {
5181 selection->add (rv);
5182 selection->regions.pending.erase (pr);
5187 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5189 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5190 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5191 if (rv->region()->id () == (*rnote).first) {
5192 mrv->select_notes ((*rnote).second);
5193 selection->pending_midi_note_selection.erase(rnote);
5199 _summary->set_background_dirty ();
5203 Editor::region_view_removed ()
5205 _summary->set_background_dirty ();
5209 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5211 TrackViewList::const_iterator j = track_views.begin ();
5212 while (j != track_views.end()) {
5213 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5214 if (rtv && rtv->route() == r) {
5225 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5229 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5230 TimeAxisView* tv = axis_view_from_route (*i);
5240 Editor::suspend_route_redisplay ()
5243 _routes->suspend_redisplay();
5248 Editor::resume_route_redisplay ()
5251 _routes->redisplay(); // queue redisplay
5252 _routes->resume_redisplay();
5257 Editor::add_routes (RouteList& routes)
5259 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5261 RouteTimeAxisView *rtv;
5262 list<RouteTimeAxisView*> new_views;
5263 TrackViewList new_selection;
5264 bool from_scratch = (track_views.size() == 0);
5266 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5267 boost::shared_ptr<Route> route = (*x);
5269 if (route->is_auditioner() || route->is_monitor()) {
5273 DataType dt = route->input()->default_type();
5275 if (dt == ARDOUR::DataType::AUDIO) {
5276 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5277 rtv->set_route (route);
5278 } else if (dt == ARDOUR::DataType::MIDI) {
5279 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5280 rtv->set_route (route);
5282 throw unknown_type();
5285 new_views.push_back (rtv);
5286 track_views.push_back (rtv);
5287 new_selection.push_back (rtv);
5289 rtv->effective_gain_display ();
5291 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5292 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5295 if (new_views.size() > 0) {
5296 _routes->routes_added (new_views);
5297 _summary->routes_added (new_views);
5300 if (!from_scratch) {
5301 selection->tracks.clear();
5302 selection->add (new_selection);
5303 begin_selection_op_history();
5306 if (show_editor_mixer_when_tracks_arrive) {
5307 show_editor_mixer (true);
5310 editor_list_button.set_sensitive (true);
5314 Editor::timeaxisview_deleted (TimeAxisView *tv)
5316 if (tv == entered_track) {
5320 if (_session && _session->deletion_in_progress()) {
5321 /* the situation is under control */
5325 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5327 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5329 _routes->route_removed (tv);
5331 TimeAxisView::Children c = tv->get_child_list ();
5332 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5333 if (entered_track == i->get()) {
5338 /* remove it from the list of track views */
5340 TrackViewList::iterator i;
5342 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5343 i = track_views.erase (i);
5346 /* update whatever the current mixer strip is displaying, if revelant */
5348 boost::shared_ptr<Route> route;
5351 route = rtav->route ();
5354 if (current_mixer_strip && current_mixer_strip->route() == route) {
5356 TimeAxisView* next_tv;
5358 if (track_views.empty()) {
5360 } else if (i == track_views.end()) {
5361 next_tv = track_views.front();
5368 set_selected_mixer_strip (*next_tv);
5370 /* make the editor mixer strip go away setting the
5371 * button to inactive (which also unticks the menu option)
5374 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5380 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5382 if (apply_to_selection) {
5383 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5385 TrackSelection::iterator j = i;
5388 hide_track_in_display (*i, false);
5393 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5395 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5396 // this will hide the mixer strip
5397 set_selected_mixer_strip (*tv);
5400 _routes->hide_track_in_display (*tv);
5405 Editor::sync_track_view_list_and_routes ()
5407 track_views = TrackViewList (_routes->views ());
5409 _summary->set_dirty ();
5410 _group_tabs->set_dirty ();
5412 return false; // do not call again (until needed)
5416 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5418 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5423 /** Find a RouteTimeAxisView by the ID of its route */
5425 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5427 RouteTimeAxisView* v;
5429 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5430 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5431 if(v->route()->id() == id) {
5441 Editor::fit_route_group (RouteGroup *g)
5443 TrackViewList ts = axis_views_from_routes (g->route_list ());
5448 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5450 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5453 _session->cancel_audition ();
5457 if (_session->is_auditioning()) {
5458 _session->cancel_audition ();
5459 if (r == last_audition_region) {
5464 _session->audition_region (r);
5465 last_audition_region = r;
5470 Editor::hide_a_region (boost::shared_ptr<Region> r)
5472 r->set_hidden (true);
5476 Editor::show_a_region (boost::shared_ptr<Region> r)
5478 r->set_hidden (false);
5482 Editor::audition_region_from_region_list ()
5484 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5488 Editor::hide_region_from_region_list ()
5490 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5494 Editor::show_region_in_region_list ()
5496 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5500 Editor::step_edit_status_change (bool yn)
5503 start_step_editing ();
5505 stop_step_editing ();
5510 Editor::start_step_editing ()
5512 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5516 Editor::stop_step_editing ()
5518 step_edit_connection.disconnect ();
5522 Editor::check_step_edit ()
5524 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5525 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5527 mtv->check_step_edit ();
5531 return true; // do it again, till we stop
5535 Editor::scroll_press (Direction dir)
5537 ++_scroll_callbacks;
5539 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5540 /* delay the first auto-repeat */
5546 scroll_backward (1);
5554 scroll_up_one_track ();
5558 scroll_down_one_track ();
5562 /* do hacky auto-repeat */
5563 if (!_scroll_connection.connected ()) {
5565 _scroll_connection = Glib::signal_timeout().connect (
5566 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5569 _scroll_callbacks = 0;
5576 Editor::scroll_release ()
5578 _scroll_connection.disconnect ();
5581 /** Queue a change for the Editor viewport x origin to follow the playhead */
5583 Editor::reset_x_origin_to_follow_playhead ()
5585 framepos_t const frame = playhead_cursor->current_frame ();
5587 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5589 if (_session->transport_speed() < 0) {
5591 if (frame > (current_page_samples() / 2)) {
5592 center_screen (frame-(current_page_samples()/2));
5594 center_screen (current_page_samples()/2);
5601 if (frame < leftmost_frame) {
5603 if (_session->transport_rolling()) {
5604 /* rolling; end up with the playhead at the right of the page */
5605 l = frame - current_page_samples ();
5607 /* not rolling: end up with the playhead 1/4 of the way along the page */
5608 l = frame - current_page_samples() / 4;
5612 if (_session->transport_rolling()) {
5613 /* rolling: end up with the playhead on the left of the page */
5616 /* not rolling: end up with the playhead 3/4 of the way along the page */
5617 l = frame - 3 * current_page_samples() / 4;
5625 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5631 Editor::super_rapid_screen_update ()
5633 if (!_session || !_session->engine().running()) {
5637 /* METERING / MIXER STRIPS */
5639 /* update track meters, if required */
5640 if (is_mapped() && meters_running) {
5641 RouteTimeAxisView* rtv;
5642 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5643 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5644 rtv->fast_update ();
5649 /* and any current mixer strip */
5650 if (current_mixer_strip) {
5651 current_mixer_strip->fast_update ();
5654 /* PLAYHEAD AND VIEWPORT */
5656 framepos_t const frame = _session->audible_frame();
5658 /* There are a few reasons why we might not update the playhead / viewport stuff:
5660 * 1. we don't update things when there's a pending locate request, otherwise
5661 * when the editor requests a locate there is a chance that this method
5662 * will move the playhead before the locate request is processed, causing
5664 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5665 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5668 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5670 last_update_frame = frame;
5672 if (!_dragging_playhead) {
5673 playhead_cursor->set_position (frame);
5676 if (!_stationary_playhead) {
5678 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5679 /* We only do this if we aren't already
5680 handling a visual change (ie if
5681 pending_visual_change.being_handled is
5682 false) so that these requests don't stack
5683 up there are too many of them to handle in
5686 reset_x_origin_to_follow_playhead ();
5691 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5692 framepos_t const frame = playhead_cursor->current_frame ();
5693 double target = ((double)frame - (double)current_page_samples()/3.0);
5694 if (target <= 0.0) {
5697 reset_x_origin (target);
5707 Editor::session_going_away ()
5709 _have_idled = false;
5711 _session_connections.drop_connections ();
5713 super_rapid_screen_update_connection.disconnect ();
5715 selection->clear ();
5716 cut_buffer->clear ();
5718 clicked_regionview = 0;
5719 clicked_axisview = 0;
5720 clicked_routeview = 0;
5721 entered_regionview = 0;
5723 last_update_frame = 0;
5726 playhead_cursor->hide ();
5728 /* rip everything out of the list displays */
5732 _route_groups->clear ();
5734 /* do this first so that deleting a track doesn't reset cms to null
5735 and thus cause a leak.
5738 if (current_mixer_strip) {
5739 if (current_mixer_strip->get_parent() != 0) {
5740 global_hpacker.remove (*current_mixer_strip);
5742 delete current_mixer_strip;
5743 current_mixer_strip = 0;
5746 /* delete all trackviews */
5748 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5751 track_views.clear ();
5753 nudge_clock->set_session (0);
5755 editor_list_button.set_active(false);
5756 editor_list_button.set_sensitive(false);
5758 /* clear tempo/meter rulers */
5759 remove_metric_marks ();
5761 clear_marker_display ();
5763 stop_step_editing ();
5765 /* get rid of any existing editor mixer strip */
5767 WindowTitle title(Glib::get_application_name());
5768 title += _("Editor");
5770 set_title (title.get_string());
5772 SessionHandlePtr::session_going_away ();
5777 Editor::show_editor_list (bool yn)
5780 _the_notebook.show ();
5782 _the_notebook.hide ();
5787 Editor::change_region_layering_order (bool from_context_menu)
5789 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5791 if (!clicked_routeview) {
5792 if (layering_order_editor) {
5793 layering_order_editor->hide ();
5798 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5804 boost::shared_ptr<Playlist> pl = track->playlist();
5810 if (layering_order_editor == 0) {
5811 layering_order_editor = new RegionLayeringOrderEditor (*this);
5814 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5815 layering_order_editor->maybe_present ();
5819 Editor::update_region_layering_order_editor ()
5821 if (layering_order_editor && layering_order_editor->is_visible ()) {
5822 change_region_layering_order (true);
5827 Editor::setup_fade_images ()
5829 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5830 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5831 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5832 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5833 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5835 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5836 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5837 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5838 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5839 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5841 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5842 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5843 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5844 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5845 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5847 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5848 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5849 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5850 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5851 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5855 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5857 Editor::action_menu_item (std::string const & name)
5859 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5862 return *manage (a->create_menu_item ());
5866 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5868 EventBox* b = manage (new EventBox);
5869 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5870 Label* l = manage (new Label (name));
5874 _the_notebook.append_page (widget, *b);
5878 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5880 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5881 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5884 if (ev->type == GDK_2BUTTON_PRESS) {
5886 /* double-click on a notebook tab shrinks or expands the notebook */
5888 if (_notebook_shrunk) {
5889 if (pre_notebook_shrink_pane_width) {
5890 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5892 _notebook_shrunk = false;
5894 pre_notebook_shrink_pane_width = edit_pane.get_position();
5896 /* this expands the LHS of the edit pane to cover the notebook
5897 PAGE but leaves the tabs visible.
5899 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5900 _notebook_shrunk = true;
5908 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5910 using namespace Menu_Helpers;
5912 MenuList& items = _control_point_context_menu.items ();
5915 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5916 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5917 if (!can_remove_control_point (item)) {
5918 items.back().set_sensitive (false);
5921 _control_point_context_menu.popup (event->button.button, event->button.time);
5925 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5927 using namespace Menu_Helpers;
5929 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5934 /* We need to get the selection here and pass it to the operations, since
5935 popping up the menu will cause a region leave event which clears
5936 entered_regionview. */
5938 MidiRegionView& mrv = note->region_view();
5939 const RegionSelection rs = get_regions_from_selection_and_entered ();
5941 MenuList& items = _note_context_menu.items();
5944 items.push_back(MenuElem(_("Delete"),
5945 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5946 items.push_back(MenuElem(_("Edit..."),
5947 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5948 items.push_back(MenuElem(_("Legatize"),
5949 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5950 items.push_back(MenuElem(_("Quantize..."),
5951 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5952 items.push_back(MenuElem(_("Remove Overlap"),
5953 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5954 items.push_back(MenuElem(_("Transform..."),
5955 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5957 _note_context_menu.popup (event->button.button, event->button.time);
5961 Editor::zoom_vertical_modifier_released()
5963 _stepping_axis_view = 0;
5967 Editor::ui_parameter_changed (string parameter)
5969 if (parameter == "icon-set") {
5970 while (!_cursor_stack.empty()) {
5971 _cursor_stack.pop_back();
5973 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5974 _cursor_stack.push_back(_cursors->grabber);
5975 } else if (parameter == "draggable-playhead") {
5976 if (_verbose_cursor) {
5977 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());