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 "quantize_dialog.h"
119 #include "region_layering_order_editor.h"
120 #include "rgb_macros.h"
121 #include "rhythm_ferret.h"
122 #include "selection.h"
124 #include "tempo_lines.h"
125 #include "time_axis_view.h"
127 #include "tooltips.h"
128 #include "ui_config.h"
130 #include "verbose_cursor.h"
135 using namespace ARDOUR;
136 using namespace ARDOUR_UI_UTILS;
139 using namespace Glib;
140 using namespace Gtkmm2ext;
141 using namespace Editing;
143 using PBD::internationalize;
145 using Gtkmm2ext::Keyboard;
147 double Editor::timebar_height = 15.0;
149 static const gchar *_snap_type_strings[] = {
183 static const gchar *_snap_mode_strings[] = {
190 static const gchar *_edit_point_strings[] = {
197 static const gchar *_edit_mode_strings[] = {
205 static const gchar *_zoom_focus_strings[] = {
215 #ifdef USE_RUBBERBAND
216 static const gchar *_rb_opt_strings[] = {
219 N_("Balanced multitimbral mixture"),
220 N_("Unpitched percussion with stable notes"),
221 N_("Crisp monophonic instrumental"),
222 N_("Unpitched solo percussion"),
223 N_("Resample without preserving pitch"),
228 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
231 pane_size_watcher (Paned* pane)
233 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
237 Quartz: impossible to access
239 so stop that by preventing it from ever getting too narrow. 35
240 pixels is basically a rough guess at the tab width.
245 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
247 gint pos = pane->get_position ();
249 if (pos > max_width_of_lhs) {
250 pane->set_position (max_width_of_lhs);
255 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
257 , _mouse_changed_selection (false)
258 /* time display buttons */
259 , minsec_label (_("Mins:Secs"))
260 , bbt_label (_("Bars:Beats"))
261 , timecode_label (_("Timecode"))
262 , samples_label (_("Samples"))
263 , tempo_label (_("Tempo"))
264 , meter_label (_("Meter"))
265 , mark_label (_("Location Markers"))
266 , range_mark_label (_("Range Markers"))
267 , transport_mark_label (_("Loop/Punch Ranges"))
268 , cd_mark_label (_("CD Markers"))
269 , videotl_label (_("Video Timeline"))
270 , edit_packer (4, 4, true)
272 /* the values here don't matter: layout widgets
273 reset them as needed.
276 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
277 , horizontal_adjustment (0.0, 0.0, 1e16)
278 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
280 , controls_layout (unused_adjustment, vertical_adjustment)
282 /* tool bar related */
284 , toolbar_selection_clock_table (2,3)
285 , _mouse_mode_tearoff (0)
286 , automation_mode_button (_("mode"))
290 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
291 , selection_op_cmd_depth (0)
292 , selection_op_history_it (0)
296 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
297 , meters_running(false)
298 , _pending_locate_request (false)
299 , _pending_initial_locate (false)
300 , _last_cut_copy_source_track (0)
302 , _region_selection_change_updates_region_list (true)
303 , _following_mixer_selection (false)
304 , _control_point_toggled_on_press (false)
305 , _stepping_axis_view (0)
306 , quantize_dialog (0)
307 , _main_menu_disabler (0)
311 /* we are a singleton */
313 PublicEditor::_instance = this;
317 selection = new Selection (this);
318 cut_buffer = new Selection (this);
319 _selection_memento = new SelectionMemento ();
320 selection_op_history.clear();
323 clicked_regionview = 0;
324 clicked_axisview = 0;
325 clicked_routeview = 0;
326 clicked_control_point = 0;
327 last_update_frame = 0;
330 _drags = new DragManager (this);
333 current_mixer_strip = 0;
336 snap_type_strings = I18N (_snap_type_strings);
337 snap_mode_strings = I18N (_snap_mode_strings);
338 zoom_focus_strings = I18N (_zoom_focus_strings);
339 edit_mode_strings = I18N (_edit_mode_strings);
340 edit_point_strings = I18N (_edit_point_strings);
341 #ifdef USE_RUBBERBAND
342 rb_opt_strings = I18N (_rb_opt_strings);
346 build_edit_mode_menu();
347 build_zoom_focus_menu();
348 build_track_count_menu();
349 build_snap_mode_menu();
350 build_snap_type_menu();
351 build_edit_point_menu();
353 snap_threshold = 5.0;
354 bbt_beat_subdivision = 4;
355 _visible_canvas_width = 0;
356 _visible_canvas_height = 0;
357 autoscroll_horizontal_allowed = false;
358 autoscroll_vertical_allowed = false;
363 current_interthread_info = 0;
364 _show_measures = true;
366 show_gain_after_trim = false;
368 have_pending_keyboard_selection = false;
369 _follow_playhead = true;
370 _stationary_playhead = false;
371 editor_ruler_menu = 0;
372 no_ruler_shown_update = false;
374 range_marker_menu = 0;
375 marker_menu_item = 0;
376 tempo_or_meter_marker_menu = 0;
377 transport_marker_menu = 0;
378 new_transport_marker_menu = 0;
379 editor_mixer_strip_width = Wide;
380 show_editor_mixer_when_tracks_arrive = false;
381 region_edit_menu_split_multichannel_item = 0;
382 region_edit_menu_split_item = 0;
385 mouse_mode = MouseObject;
386 current_stepping_trackview = 0;
388 entered_regionview = 0;
390 clear_entered_track = false;
393 button_release_can_deselect = true;
394 _dragging_playhead = false;
395 _dragging_edit_point = false;
396 select_new_marker = false;
398 layering_order_editor = 0;
399 no_save_visual = false;
401 within_track_canvas = false;
403 scrubbing_direction = 0;
407 location_marker_color = UIConfiguration::instance().color ("location marker");
408 location_range_color = UIConfiguration::instance().color ("location range");
409 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
410 location_loop_color = UIConfiguration::instance().color ("location loop");
411 location_punch_color = UIConfiguration::instance().color ("location punch");
413 zoom_focus = ZoomFocusPlayhead;
414 _edit_point = EditAtMouse;
415 _visible_track_count = -1;
417 samples_per_pixel = 2048; /* too early to use reset_zoom () */
419 timebar_height = std::max(12., ceil (15. * UIConfiguration::instance().get_ui_scale()));
420 TimeAxisView::setup_sizes ();
421 ArdourMarker::setup_sizes (timebar_height);
423 _scroll_callbacks = 0;
425 bbt_label.set_name ("EditorRulerLabel");
426 bbt_label.set_size_request (-1, (int)timebar_height);
427 bbt_label.set_alignment (1.0, 0.5);
428 bbt_label.set_padding (5,0);
430 bbt_label.set_no_show_all();
431 minsec_label.set_name ("EditorRulerLabel");
432 minsec_label.set_size_request (-1, (int)timebar_height);
433 minsec_label.set_alignment (1.0, 0.5);
434 minsec_label.set_padding (5,0);
435 minsec_label.hide ();
436 minsec_label.set_no_show_all();
437 timecode_label.set_name ("EditorRulerLabel");
438 timecode_label.set_size_request (-1, (int)timebar_height);
439 timecode_label.set_alignment (1.0, 0.5);
440 timecode_label.set_padding (5,0);
441 timecode_label.hide ();
442 timecode_label.set_no_show_all();
443 samples_label.set_name ("EditorRulerLabel");
444 samples_label.set_size_request (-1, (int)timebar_height);
445 samples_label.set_alignment (1.0, 0.5);
446 samples_label.set_padding (5,0);
447 samples_label.hide ();
448 samples_label.set_no_show_all();
450 tempo_label.set_name ("EditorRulerLabel");
451 tempo_label.set_size_request (-1, (int)timebar_height);
452 tempo_label.set_alignment (1.0, 0.5);
453 tempo_label.set_padding (5,0);
455 tempo_label.set_no_show_all();
457 meter_label.set_name ("EditorRulerLabel");
458 meter_label.set_size_request (-1, (int)timebar_height);
459 meter_label.set_alignment (1.0, 0.5);
460 meter_label.set_padding (5,0);
462 meter_label.set_no_show_all();
464 if (Profile->get_trx()) {
465 mark_label.set_text (_("Markers"));
467 mark_label.set_name ("EditorRulerLabel");
468 mark_label.set_size_request (-1, (int)timebar_height);
469 mark_label.set_alignment (1.0, 0.5);
470 mark_label.set_padding (5,0);
472 mark_label.set_no_show_all();
474 cd_mark_label.set_name ("EditorRulerLabel");
475 cd_mark_label.set_size_request (-1, (int)timebar_height);
476 cd_mark_label.set_alignment (1.0, 0.5);
477 cd_mark_label.set_padding (5,0);
478 cd_mark_label.hide();
479 cd_mark_label.set_no_show_all();
481 videotl_bar_height = 4;
482 videotl_label.set_name ("EditorRulerLabel");
483 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
484 videotl_label.set_alignment (1.0, 0.5);
485 videotl_label.set_padding (5,0);
486 videotl_label.hide();
487 videotl_label.set_no_show_all();
489 range_mark_label.set_name ("EditorRulerLabel");
490 range_mark_label.set_size_request (-1, (int)timebar_height);
491 range_mark_label.set_alignment (1.0, 0.5);
492 range_mark_label.set_padding (5,0);
493 range_mark_label.hide();
494 range_mark_label.set_no_show_all();
496 transport_mark_label.set_name ("EditorRulerLabel");
497 transport_mark_label.set_size_request (-1, (int)timebar_height);
498 transport_mark_label.set_alignment (1.0, 0.5);
499 transport_mark_label.set_padding (5,0);
500 transport_mark_label.hide();
501 transport_mark_label.set_no_show_all();
503 initialize_canvas ();
505 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
507 _summary = new EditorSummary (this);
509 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
510 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
512 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
514 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
515 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
517 edit_controls_vbox.set_spacing (0);
518 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
519 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
521 HBox* h = manage (new HBox);
522 _group_tabs = new EditorGroupTabs (this);
523 if (!ARDOUR::Profile->get_trx()) {
524 h->pack_start (*_group_tabs, PACK_SHRINK);
526 h->pack_start (edit_controls_vbox);
527 controls_layout.add (*h);
529 controls_layout.set_name ("EditControlsBase");
530 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
531 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
532 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
534 _cursors = new MouseCursors;
535 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
536 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
538 /* Push default cursor to ever-present bottom of cursor stack. */
539 push_canvas_cursor(_cursors->grabber);
541 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
543 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
544 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
545 pad_line_1->set_outline_color (0xFF0000FF);
551 edit_packer.set_col_spacings (0);
552 edit_packer.set_row_spacings (0);
553 edit_packer.set_homogeneous (false);
554 edit_packer.set_border_width (0);
555 edit_packer.set_name ("EditorWindow");
557 time_bars_event_box.add (time_bars_vbox);
558 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
559 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
561 /* labels for the time bars */
562 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
564 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
566 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
568 bottom_hbox.set_border_width (2);
569 bottom_hbox.set_spacing (3);
571 _route_groups = new EditorRouteGroups (this);
572 _routes = new EditorRoutes (this);
573 _regions = new EditorRegions (this);
574 _snapshots = new EditorSnapshots (this);
575 _locations = new EditorLocations (this);
577 /* these are static location signals */
579 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
580 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
581 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
583 add_notebook_page (_("Regions"), _regions->widget ());
584 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
585 add_notebook_page (_("Snapshots"), _snapshots->widget ());
586 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
587 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
589 _the_notebook.set_show_tabs (true);
590 _the_notebook.set_scrollable (true);
591 _the_notebook.popup_disable ();
592 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
593 _the_notebook.show_all ();
595 _notebook_shrunk = false;
597 editor_summary_pane.pack1(edit_packer);
599 Button* summary_arrows_left_left = manage (new Button);
600 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
601 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
602 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
604 Button* summary_arrows_left_right = manage (new Button);
605 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
606 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
607 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
609 VBox* summary_arrows_left = manage (new VBox);
610 summary_arrows_left->pack_start (*summary_arrows_left_left);
611 summary_arrows_left->pack_start (*summary_arrows_left_right);
613 Button* summary_arrows_right_up = manage (new Button);
614 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
615 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
616 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
618 Button* summary_arrows_right_down = manage (new Button);
619 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
620 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
621 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
623 VBox* summary_arrows_right = manage (new VBox);
624 summary_arrows_right->pack_start (*summary_arrows_right_up);
625 summary_arrows_right->pack_start (*summary_arrows_right_down);
627 Frame* summary_frame = manage (new Frame);
628 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
630 summary_frame->add (*_summary);
631 summary_frame->show ();
633 _summary_hbox.pack_start (*summary_arrows_left, false, false);
634 _summary_hbox.pack_start (*summary_frame, true, true);
635 _summary_hbox.pack_start (*summary_arrows_right, false, false);
637 if (!ARDOUR::Profile->get_trx()) {
638 editor_summary_pane.pack2 (_summary_hbox);
641 edit_pane.pack1 (editor_summary_pane, true, true);
642 if (!ARDOUR::Profile->get_trx()) {
643 edit_pane.pack2 (_the_notebook, false, true);
646 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
648 /* XXX: editor_summary_pane might need similar to the edit_pane */
650 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
652 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
653 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
655 top_hbox.pack_start (toolbar_frame);
657 HBox *hbox = manage (new HBox);
658 hbox->pack_start (edit_pane, true, true);
660 global_vpacker.pack_start (top_hbox, false, false);
661 global_vpacker.pack_start (*hbox, true, true);
663 global_hpacker.pack_start (global_vpacker, true, true);
665 set_name ("EditorWindow");
666 add_accel_group (ActionManager::ui_manager->get_accel_group());
668 status_bar_hpacker.show ();
670 vpacker.pack_end (status_bar_hpacker, false, false);
671 vpacker.pack_end (global_hpacker, true, true);
673 /* register actions now so that set_state() can find them and set toggles/checks etc */
676 /* when we start using our own keybinding system for the editor, this
677 * will be uncommented
683 set_zoom_focus (zoom_focus);
684 set_visible_track_count (_visible_track_count);
685 _snap_type = SnapToBeat;
686 set_snap_to (_snap_type);
687 _snap_mode = SnapOff;
688 set_snap_mode (_snap_mode);
689 set_mouse_mode (MouseObject, true);
690 pre_internal_snap_type = _snap_type;
691 pre_internal_snap_mode = _snap_mode;
692 internal_snap_type = _snap_type;
693 internal_snap_mode = _snap_mode;
694 set_edit_point_preference (EditAtMouse, true);
696 _playlist_selector = new PlaylistSelector();
697 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
699 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
703 nudge_forward_button.set_name ("nudge button");
704 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
706 nudge_backward_button.set_name ("nudge button");
707 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
709 fade_context_menu.set_name ("ArdourContextMenu");
711 /* icons, titles, WM stuff */
713 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
714 Glib::RefPtr<Gdk::Pixbuf> icon;
716 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
717 window_icons.push_back (icon);
719 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
720 window_icons.push_back (icon);
722 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
723 window_icons.push_back (icon);
725 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
726 window_icons.push_back (icon);
728 if (!window_icons.empty()) {
729 // set_icon_list (window_icons);
730 set_default_icon_list (window_icons);
733 WindowTitle title(Glib::get_application_name());
734 title += _("Editor");
735 set_title (title.get_string());
736 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
739 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
741 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
742 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
744 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
746 /* allow external control surfaces/protocols to do various things */
748 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
749 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
750 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
751 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
752 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
753 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
754 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
755 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
756 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
757 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
758 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
759 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
760 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
761 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
763 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
764 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
765 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
766 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
767 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
769 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
771 /* problematic: has to return a value and thus cannot be x-thread */
773 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
775 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
776 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
778 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
780 _ignore_region_action = false;
781 _last_region_menu_was_main = false;
782 _popup_region_menu_item = 0;
784 _ignore_follow_edits = false;
786 _show_marker_lines = false;
788 /* Button bindings */
790 button_bindings = new Bindings;
792 XMLNode* node = button_settings();
794 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
795 button_bindings->load (**i);
801 /* grab current parameter state */
802 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
803 UIConfiguration::instance().map_parameters (pc);
805 setup_fade_images ();
812 delete button_bindings;
814 delete _route_groups;
815 delete _track_canvas_viewport;
818 delete quantize_dialog;
824 delete _playlist_selector;
826 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
832 Editor::button_settings () const
834 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
835 XMLNode* node = find_named_node (*settings, X_("Buttons"));
838 node = new XMLNode (X_("Buttons"));
845 Editor::add_toplevel_menu (Container& cont)
847 vpacker.pack_start (cont, false, false);
852 Editor::add_transport_frame (Container& cont)
854 if(ARDOUR::Profile->get_mixbus()) {
855 global_vpacker.pack_start (cont, false, false);
856 global_vpacker.reorder_child (cont, 0);
859 vpacker.pack_start (cont, false, false);
864 Editor::get_smart_mode () const
866 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
870 Editor::catch_vanishing_regionview (RegionView *rv)
872 /* note: the selection will take care of the vanishing
873 audioregionview by itself.
876 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
880 if (clicked_regionview == rv) {
881 clicked_regionview = 0;
884 if (entered_regionview == rv) {
885 set_entered_regionview (0);
888 if (!_all_region_actions_sensitized) {
889 sensitize_all_region_actions (true);
894 Editor::set_entered_regionview (RegionView* rv)
896 if (rv == entered_regionview) {
900 if (entered_regionview) {
901 entered_regionview->exited ();
904 entered_regionview = rv;
906 if (entered_regionview != 0) {
907 entered_regionview->entered ();
910 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
911 /* This RegionView entry might have changed what region actions
912 are allowed, so sensitize them all in case a key is pressed.
914 sensitize_all_region_actions (true);
919 Editor::set_entered_track (TimeAxisView* tav)
922 entered_track->exited ();
928 entered_track->entered ();
933 Editor::show_window ()
935 if (!is_visible ()) {
939 /* XXX: this is a bit unfortunate; it would probably
940 be nicer if we could just call show () above rather
941 than needing the show_all ()
944 /* re-hide stuff if necessary */
945 editor_list_button_toggled ();
946 parameter_changed ("show-summary");
947 parameter_changed ("show-group-tabs");
948 parameter_changed ("show-zoom-tools");
950 /* now reset all audio_time_axis heights, because widgets might need
956 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
957 tv = (static_cast<TimeAxisView*>(*i));
961 if (current_mixer_strip) {
962 current_mixer_strip->hide_things ();
963 current_mixer_strip->parameter_changed ("mixer-element-visibility");
971 Editor::instant_save ()
973 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
978 _session->add_instant_xml(get_state());
980 Config->add_instant_xml(get_state());
985 Editor::control_vertical_zoom_in_all ()
987 tav_zoom_smooth (false, true);
991 Editor::control_vertical_zoom_out_all ()
993 tav_zoom_smooth (true, true);
997 Editor::control_vertical_zoom_in_selected ()
999 tav_zoom_smooth (false, false);
1003 Editor::control_vertical_zoom_out_selected ()
1005 tav_zoom_smooth (true, false);
1009 Editor::control_view (uint32_t view)
1011 goto_visual_state (view);
1015 Editor::control_unselect ()
1017 selection->clear_tracks ();
1021 Editor::control_select (uint32_t rid, Selection::Operation op)
1023 /* handles the (static) signal from the ControlProtocol class that
1024 * requests setting the selected track to a given RID
1031 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1037 TimeAxisView* tav = axis_view_from_route (r);
1041 case Selection::Add:
1042 selection->add (tav);
1044 case Selection::Toggle:
1045 selection->toggle (tav);
1047 case Selection::Extend:
1049 case Selection::Set:
1050 selection->set (tav);
1054 selection->clear_tracks ();
1059 Editor::control_step_tracks_up ()
1061 scroll_tracks_up_line ();
1065 Editor::control_step_tracks_down ()
1067 scroll_tracks_down_line ();
1071 Editor::control_scroll (float fraction)
1073 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1079 double step = fraction * current_page_samples();
1082 _control_scroll_target is an optional<T>
1084 it acts like a pointer to an framepos_t, with
1085 a operator conversion to boolean to check
1086 that it has a value could possibly use
1087 playhead_cursor->current_frame to store the
1088 value and a boolean in the class to know
1089 when it's out of date
1092 if (!_control_scroll_target) {
1093 _control_scroll_target = _session->transport_frame();
1094 _dragging_playhead = true;
1097 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1098 *_control_scroll_target = 0;
1099 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1100 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1102 *_control_scroll_target += (framepos_t) trunc (step);
1105 /* move visuals, we'll catch up with it later */
1107 playhead_cursor->set_position (*_control_scroll_target);
1108 UpdateAllTransportClocks (*_control_scroll_target);
1110 if (*_control_scroll_target > (current_page_samples() / 2)) {
1111 /* try to center PH in window */
1112 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1118 Now we do a timeout to actually bring the session to the right place
1119 according to the playhead. This is to avoid reading disk buffers on every
1120 call to control_scroll, which is driven by ScrollTimeline and therefore
1121 probably by a control surface wheel which can generate lots of events.
1123 /* cancel the existing timeout */
1125 control_scroll_connection.disconnect ();
1127 /* add the next timeout */
1129 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1133 Editor::deferred_control_scroll (framepos_t /*target*/)
1135 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1136 // reset for next stream
1137 _control_scroll_target = boost::none;
1138 _dragging_playhead = false;
1143 Editor::access_action (std::string action_group, std::string action_item)
1149 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1152 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1160 Editor::on_realize ()
1162 Window::on_realize ();
1165 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1166 start_lock_event_timing ();
1169 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1173 Editor::start_lock_event_timing ()
1175 /* check if we should lock the GUI every 30 seconds */
1177 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1181 Editor::generic_event_handler (GdkEvent* ev)
1184 case GDK_BUTTON_PRESS:
1185 case GDK_BUTTON_RELEASE:
1186 case GDK_MOTION_NOTIFY:
1188 case GDK_KEY_RELEASE:
1189 gettimeofday (&last_event_time, 0);
1192 case GDK_LEAVE_NOTIFY:
1193 switch (ev->crossing.detail) {
1194 case GDK_NOTIFY_UNKNOWN:
1195 case GDK_NOTIFY_INFERIOR:
1196 case GDK_NOTIFY_ANCESTOR:
1198 case GDK_NOTIFY_VIRTUAL:
1199 case GDK_NOTIFY_NONLINEAR:
1200 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1201 /* leaving window, so reset focus, thus ending any and
1202 all text entry operations.
1217 Editor::lock_timeout_callback ()
1219 struct timeval now, delta;
1221 gettimeofday (&now, 0);
1223 timersub (&now, &last_event_time, &delta);
1225 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1227 /* don't call again. Returning false will effectively
1228 disconnect us from the timer callback.
1230 unlock() will call start_lock_event_timing() to get things
1240 Editor::map_position_change (framepos_t frame)
1242 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1244 if (_session == 0) {
1248 if (_follow_playhead) {
1249 center_screen (frame);
1252 playhead_cursor->set_position (frame);
1256 Editor::center_screen (framepos_t frame)
1258 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1260 /* if we're off the page, then scroll.
1263 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1264 center_screen_internal (frame, page);
1269 Editor::center_screen_internal (framepos_t frame, float page)
1274 frame -= (framepos_t) page;
1279 reset_x_origin (frame);
1284 Editor::update_title ()
1286 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1289 bool dirty = _session->dirty();
1291 string session_name;
1293 if (_session->snap_name() != _session->name()) {
1294 session_name = _session->snap_name();
1296 session_name = _session->name();
1300 session_name = "*" + session_name;
1303 WindowTitle title(session_name);
1304 title += Glib::get_application_name();
1305 set_title (title.get_string());
1307 /* ::session_going_away() will have taken care of it */
1312 Editor::set_session (Session *t)
1314 SessionHandlePtr::set_session (t);
1320 _playlist_selector->set_session (_session);
1321 nudge_clock->set_session (_session);
1322 _summary->set_session (_session);
1323 _group_tabs->set_session (_session);
1324 _route_groups->set_session (_session);
1325 _regions->set_session (_session);
1326 _snapshots->set_session (_session);
1327 _routes->set_session (_session);
1328 _locations->set_session (_session);
1330 if (rhythm_ferret) {
1331 rhythm_ferret->set_session (_session);
1334 if (analysis_window) {
1335 analysis_window->set_session (_session);
1339 sfbrowser->set_session (_session);
1342 compute_fixed_ruler_scale ();
1344 /* Make sure we have auto loop and auto punch ranges */
1346 Location* loc = _session->locations()->auto_loop_location();
1348 loc->set_name (_("Loop"));
1351 loc = _session->locations()->auto_punch_location();
1354 loc->set_name (_("Punch"));
1357 refresh_location_display ();
1359 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1360 the selected Marker; this needs the LocationMarker list to be available.
1362 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1363 set_state (*node, Stateful::loading_state_version);
1365 /* catch up with the playhead */
1367 _session->request_locate (playhead_cursor->current_frame ());
1368 _pending_initial_locate = true;
1372 /* These signals can all be emitted by a non-GUI thread. Therefore the
1373 handlers for them must not attempt to directly interact with the GUI,
1374 but use PBD::Signal<T>::connect() which accepts an event loop
1375 ("context") where the handler will be asked to run.
1378 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1379 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1380 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1381 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1382 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1383 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1384 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1385 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1386 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1387 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1388 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1389 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1390 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1392 playhead_cursor->show ();
1394 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1395 Config->map_parameters (pc);
1396 _session->config.map_parameters (pc);
1398 restore_ruler_visibility ();
1399 //tempo_map_changed (PropertyChange (0));
1400 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1402 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1403 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1406 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1407 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1410 switch (_snap_type) {
1411 case SnapToRegionStart:
1412 case SnapToRegionEnd:
1413 case SnapToRegionSync:
1414 case SnapToRegionBoundary:
1415 build_region_boundary_cache ();
1422 /* register for undo history */
1423 _session->register_with_memento_command_factory(id(), this);
1424 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1426 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1428 start_updating_meters ();
1432 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1434 if (a->get_name() == "RegionMenu") {
1435 /* When the main menu's region menu is opened, we setup the actions so that they look right
1436 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1437 so we resensitize all region actions when the entered regionview or the region selection
1438 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1439 happens after the region context menu is opened. So we set a flag here, too.
1443 sensitize_the_right_region_actions ();
1444 _last_region_menu_was_main = true;
1449 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1451 using namespace Menu_Helpers;
1453 void (Editor::*emf)(FadeShape);
1454 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1457 images = &_xfade_in_images;
1458 emf = &Editor::set_fade_in_shape;
1460 images = &_xfade_out_images;
1461 emf = &Editor::set_fade_out_shape;
1466 _("Linear (for highly correlated material)"),
1467 *(*images)[FadeLinear],
1468 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1472 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1476 _("Constant power"),
1477 *(*images)[FadeConstantPower],
1478 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1481 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1486 *(*images)[FadeSymmetric],
1487 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1491 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1496 *(*images)[FadeSlow],
1497 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1500 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1505 *(*images)[FadeFast],
1506 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1509 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1512 /** Pop up a context menu for when the user clicks on a start crossfade */
1514 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1516 using namespace Menu_Helpers;
1517 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1522 MenuList& items (xfade_in_context_menu.items());
1525 if (arv->audio_region()->fade_in_active()) {
1526 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1528 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1531 items.push_back (SeparatorElem());
1532 fill_xfade_menu (items, true);
1534 xfade_in_context_menu.popup (button, time);
1537 /** Pop up a context menu for when the user clicks on an end crossfade */
1539 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1541 using namespace Menu_Helpers;
1542 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1547 MenuList& items (xfade_out_context_menu.items());
1550 if (arv->audio_region()->fade_out_active()) {
1551 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1553 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1556 items.push_back (SeparatorElem());
1557 fill_xfade_menu (items, false);
1559 xfade_out_context_menu.popup (button, time);
1563 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1565 using namespace Menu_Helpers;
1566 Menu* (Editor::*build_menu_function)();
1569 switch (item_type) {
1571 case RegionViewName:
1572 case RegionViewNameHighlight:
1573 case LeftFrameHandle:
1574 case RightFrameHandle:
1575 if (with_selection) {
1576 build_menu_function = &Editor::build_track_selection_context_menu;
1578 build_menu_function = &Editor::build_track_region_context_menu;
1583 if (with_selection) {
1584 build_menu_function = &Editor::build_track_selection_context_menu;
1586 build_menu_function = &Editor::build_track_context_menu;
1591 if (clicked_routeview->track()) {
1592 build_menu_function = &Editor::build_track_context_menu;
1594 build_menu_function = &Editor::build_track_bus_context_menu;
1599 /* probably shouldn't happen but if it does, we don't care */
1603 menu = (this->*build_menu_function)();
1604 menu->set_name ("ArdourContextMenu");
1606 /* now handle specific situations */
1608 switch (item_type) {
1610 case RegionViewName:
1611 case RegionViewNameHighlight:
1612 case LeftFrameHandle:
1613 case RightFrameHandle:
1614 if (!with_selection) {
1615 if (region_edit_menu_split_item) {
1616 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1617 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1619 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1622 if (region_edit_menu_split_multichannel_item) {
1623 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1624 region_edit_menu_split_multichannel_item->set_sensitive (true);
1626 region_edit_menu_split_multichannel_item->set_sensitive (false);
1639 /* probably shouldn't happen but if it does, we don't care */
1643 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1645 /* Bounce to disk */
1647 using namespace Menu_Helpers;
1648 MenuList& edit_items = menu->items();
1650 edit_items.push_back (SeparatorElem());
1652 switch (clicked_routeview->audio_track()->freeze_state()) {
1653 case AudioTrack::NoFreeze:
1654 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1657 case AudioTrack::Frozen:
1658 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1661 case AudioTrack::UnFrozen:
1662 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1668 if (item_type == StreamItem && clicked_routeview) {
1669 clicked_routeview->build_underlay_menu(menu);
1672 /* When the region menu is opened, we setup the actions so that they look right
1675 sensitize_the_right_region_actions ();
1676 _last_region_menu_was_main = false;
1678 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1679 menu->popup (button, time);
1683 Editor::build_track_context_menu ()
1685 using namespace Menu_Helpers;
1687 MenuList& edit_items = track_context_menu.items();
1690 add_dstream_context_items (edit_items);
1691 return &track_context_menu;
1695 Editor::build_track_bus_context_menu ()
1697 using namespace Menu_Helpers;
1699 MenuList& edit_items = track_context_menu.items();
1702 add_bus_context_items (edit_items);
1703 return &track_context_menu;
1707 Editor::build_track_region_context_menu ()
1709 using namespace Menu_Helpers;
1710 MenuList& edit_items = track_region_context_menu.items();
1713 /* we've just cleared the track region context menu, so the menu that these
1714 two items were on will have disappeared; stop them dangling.
1716 region_edit_menu_split_item = 0;
1717 region_edit_menu_split_multichannel_item = 0;
1719 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1722 boost::shared_ptr<Track> tr;
1723 boost::shared_ptr<Playlist> pl;
1725 if ((tr = rtv->track())) {
1726 add_region_context_items (edit_items, tr);
1730 add_dstream_context_items (edit_items);
1732 return &track_region_context_menu;
1736 Editor::analyze_region_selection ()
1738 if (analysis_window == 0) {
1739 analysis_window = new AnalysisWindow();
1742 analysis_window->set_session(_session);
1744 analysis_window->show_all();
1747 analysis_window->set_regionmode();
1748 analysis_window->analyze();
1750 analysis_window->present();
1754 Editor::analyze_range_selection()
1756 if (analysis_window == 0) {
1757 analysis_window = new AnalysisWindow();
1760 analysis_window->set_session(_session);
1762 analysis_window->show_all();
1765 analysis_window->set_rangemode();
1766 analysis_window->analyze();
1768 analysis_window->present();
1772 Editor::build_track_selection_context_menu ()
1774 using namespace Menu_Helpers;
1775 MenuList& edit_items = track_selection_context_menu.items();
1776 edit_items.clear ();
1778 add_selection_context_items (edit_items);
1779 // edit_items.push_back (SeparatorElem());
1780 // add_dstream_context_items (edit_items);
1782 return &track_selection_context_menu;
1786 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1788 using namespace Menu_Helpers;
1790 /* OK, stick the region submenu at the top of the list, and then add
1794 RegionSelection rs = get_regions_from_selection_and_entered ();
1796 string::size_type pos = 0;
1797 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1799 /* we have to hack up the region name because "_" has a special
1800 meaning for menu titles.
1803 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1804 menu_item_name.replace (pos, 1, "__");
1808 if (_popup_region_menu_item == 0) {
1809 _popup_region_menu_item = new MenuItem (menu_item_name);
1810 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1811 _popup_region_menu_item->show ();
1813 _popup_region_menu_item->set_label (menu_item_name);
1816 /* No latering allowed in later is higher layering model */
1817 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1818 if (act && Config->get_layer_model() == LaterHigher) {
1819 act->set_sensitive (false);
1821 act->set_sensitive (true);
1824 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1826 edit_items.push_back (*_popup_region_menu_item);
1827 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1828 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1830 edit_items.push_back (SeparatorElem());
1833 /** Add context menu items relevant to selection ranges.
1834 * @param edit_items List to add the items to.
1837 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1839 using namespace Menu_Helpers;
1841 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1842 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1844 edit_items.push_back (SeparatorElem());
1845 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1847 edit_items.push_back (SeparatorElem());
1848 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1850 edit_items.push_back (SeparatorElem());
1852 edit_items.push_back (
1854 _("Move Range Start to Previous Region Boundary"),
1855 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1859 edit_items.push_back (
1861 _("Move Range Start to Next Region Boundary"),
1862 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1866 edit_items.push_back (
1868 _("Move Range End to Previous Region Boundary"),
1869 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1873 edit_items.push_back (
1875 _("Move Range End to Next Region Boundary"),
1876 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1880 edit_items.push_back (SeparatorElem());
1881 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1882 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1884 edit_items.push_back (SeparatorElem());
1885 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1887 edit_items.push_back (SeparatorElem());
1888 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1889 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1890 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1892 edit_items.push_back (SeparatorElem());
1893 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1895 edit_items.push_back (SeparatorElem());
1896 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1897 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1898 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1900 edit_items.push_back (SeparatorElem());
1901 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1902 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1903 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1904 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1905 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1906 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1907 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1913 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1915 using namespace Menu_Helpers;
1919 Menu *play_menu = manage (new Menu);
1920 MenuList& play_items = play_menu->items();
1921 play_menu->set_name ("ArdourContextMenu");
1923 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1924 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1925 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1926 play_items.push_back (SeparatorElem());
1927 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1929 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1933 Menu *select_menu = manage (new Menu);
1934 MenuList& select_items = select_menu->items();
1935 select_menu->set_name ("ArdourContextMenu");
1937 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1938 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1939 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1940 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1941 select_items.push_back (SeparatorElem());
1942 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1943 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1944 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
1945 select_items.push_back (SeparatorElem());
1946 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
1947 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
1948 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1949 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1950 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1951 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1952 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1954 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1958 Menu *cutnpaste_menu = manage (new Menu);
1959 MenuList& cutnpaste_items = cutnpaste_menu->items();
1960 cutnpaste_menu->set_name ("ArdourContextMenu");
1962 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1963 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1964 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1966 cutnpaste_items.push_back (SeparatorElem());
1968 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1969 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1971 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1973 /* Adding new material */
1975 edit_items.push_back (SeparatorElem());
1976 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1977 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1981 Menu *nudge_menu = manage (new Menu());
1982 MenuList& nudge_items = nudge_menu->items();
1983 nudge_menu->set_name ("ArdourContextMenu");
1985 edit_items.push_back (SeparatorElem());
1986 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1987 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1988 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1989 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1991 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1995 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1997 using namespace Menu_Helpers;
2001 Menu *play_menu = manage (new Menu);
2002 MenuList& play_items = play_menu->items();
2003 play_menu->set_name ("ArdourContextMenu");
2005 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2006 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2007 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2011 Menu *select_menu = manage (new Menu);
2012 MenuList& select_items = select_menu->items();
2013 select_menu->set_name ("ArdourContextMenu");
2015 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2016 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2017 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2018 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2019 select_items.push_back (SeparatorElem());
2020 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2021 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2022 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2023 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2025 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2029 Menu *cutnpaste_menu = manage (new Menu);
2030 MenuList& cutnpaste_items = cutnpaste_menu->items();
2031 cutnpaste_menu->set_name ("ArdourContextMenu");
2033 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2034 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2035 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2037 Menu *nudge_menu = manage (new Menu());
2038 MenuList& nudge_items = nudge_menu->items();
2039 nudge_menu->set_name ("ArdourContextMenu");
2041 edit_items.push_back (SeparatorElem());
2042 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2043 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2044 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2045 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2047 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2051 Editor::snap_type() const
2057 Editor::snap_mode() const
2063 Editor::set_snap_to (SnapType st)
2065 unsigned int snap_ind = (unsigned int)st;
2067 if (internal_editing()) {
2068 internal_snap_type = st;
2070 pre_internal_snap_type = st;
2075 if (snap_ind > snap_type_strings.size() - 1) {
2077 _snap_type = (SnapType)snap_ind;
2080 string str = snap_type_strings[snap_ind];
2082 if (str != snap_type_selector.get_text()) {
2083 snap_type_selector.set_text (str);
2088 switch (_snap_type) {
2089 case SnapToBeatDiv128:
2090 case SnapToBeatDiv64:
2091 case SnapToBeatDiv32:
2092 case SnapToBeatDiv28:
2093 case SnapToBeatDiv24:
2094 case SnapToBeatDiv20:
2095 case SnapToBeatDiv16:
2096 case SnapToBeatDiv14:
2097 case SnapToBeatDiv12:
2098 case SnapToBeatDiv10:
2099 case SnapToBeatDiv8:
2100 case SnapToBeatDiv7:
2101 case SnapToBeatDiv6:
2102 case SnapToBeatDiv5:
2103 case SnapToBeatDiv4:
2104 case SnapToBeatDiv3:
2105 case SnapToBeatDiv2: {
2106 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2107 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2109 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2110 current_bbt_points_begin, current_bbt_points_end);
2111 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2112 current_bbt_points_begin, current_bbt_points_end);
2113 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2117 case SnapToRegionStart:
2118 case SnapToRegionEnd:
2119 case SnapToRegionSync:
2120 case SnapToRegionBoundary:
2121 build_region_boundary_cache ();
2129 redisplay_tempo (false);
2131 SnapChanged (); /* EMIT SIGNAL */
2135 Editor::set_snap_mode (SnapMode mode)
2137 string str = snap_mode_strings[(int)mode];
2139 if (internal_editing()) {
2140 internal_snap_mode = mode;
2142 pre_internal_snap_mode = mode;
2147 if (str != snap_mode_selector.get_text ()) {
2148 snap_mode_selector.set_text (str);
2155 Editor::set_edit_point_preference (EditPoint ep, bool force)
2157 bool changed = (_edit_point != ep);
2160 if (Profile->get_mixbus())
2161 if (ep == EditAtSelectedMarker)
2162 ep = EditAtPlayhead;
2164 string str = edit_point_strings[(int)ep];
2165 if (str != edit_point_selector.get_text ()) {
2166 edit_point_selector.set_text (str);
2169 update_all_enter_cursors();
2171 if (!force && !changed) {
2175 const char* action=NULL;
2177 switch (_edit_point) {
2178 case EditAtPlayhead:
2179 action = "edit-at-playhead";
2181 case EditAtSelectedMarker:
2182 action = "edit-at-marker";
2185 action = "edit-at-mouse";
2189 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2191 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2195 bool in_track_canvas;
2197 if (!mouse_frame (foo, in_track_canvas)) {
2198 in_track_canvas = false;
2201 reset_canvas_action_sensitivity (in_track_canvas);
2207 Editor::set_state (const XMLNode& node, int /*version*/)
2209 const XMLProperty* prop;
2216 g.base_width = default_width;
2217 g.base_height = default_height;
2221 if ((geometry = find_named_node (node, "geometry")) != 0) {
2225 if ((prop = geometry->property("x_size")) == 0) {
2226 prop = geometry->property ("x-size");
2229 g.base_width = atoi(prop->value());
2231 if ((prop = geometry->property("y_size")) == 0) {
2232 prop = geometry->property ("y-size");
2235 g.base_height = atoi(prop->value());
2238 if ((prop = geometry->property ("x_pos")) == 0) {
2239 prop = geometry->property ("x-pos");
2242 x = atoi (prop->value());
2245 if ((prop = geometry->property ("y_pos")) == 0) {
2246 prop = geometry->property ("y-pos");
2249 y = atoi (prop->value());
2253 set_default_size (g.base_width, g.base_height);
2256 if (_session && (prop = node.property ("playhead"))) {
2258 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2260 playhead_cursor->set_position (pos);
2262 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2263 playhead_cursor->set_position (0);
2266 playhead_cursor->set_position (0);
2269 if ((prop = node.property ("mixer-width"))) {
2270 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2273 if ((prop = node.property ("zoom-focus"))) {
2274 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2277 if ((prop = node.property ("zoom"))) {
2278 /* older versions of ardour used floating point samples_per_pixel */
2279 double f = PBD::atof (prop->value());
2280 reset_zoom (llrintf (f));
2282 reset_zoom (samples_per_pixel);
2285 if ((prop = node.property ("visible-track-count"))) {
2286 set_visible_track_count (PBD::atoi (prop->value()));
2289 if ((prop = node.property ("snap-to"))) {
2290 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2293 if ((prop = node.property ("snap-mode"))) {
2294 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2297 if ((prop = node.property ("internal-snap-to"))) {
2298 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2301 if ((prop = node.property ("internal-snap-mode"))) {
2302 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2305 if ((prop = node.property ("pre-internal-snap-to"))) {
2306 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2309 if ((prop = node.property ("pre-internal-snap-mode"))) {
2310 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2313 if ((prop = node.property ("mouse-mode"))) {
2314 MouseMode m = str2mousemode(prop->value());
2315 set_mouse_mode (m, true);
2317 set_mouse_mode (MouseObject, true);
2320 if ((prop = node.property ("left-frame")) != 0) {
2322 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2326 reset_x_origin (pos);
2330 if ((prop = node.property ("y-origin")) != 0) {
2331 reset_y_origin (atof (prop->value ()));
2334 if ((prop = node.property ("join-object-range"))) {
2335 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2336 bool yn = string_is_affirmative (prop->value());
2338 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2339 tact->set_active (!yn);
2340 tact->set_active (yn);
2342 set_mouse_mode(mouse_mode, true);
2345 if ((prop = node.property ("edit-point"))) {
2346 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2349 if ((prop = node.property ("show-measures"))) {
2350 bool yn = string_is_affirmative (prop->value());
2351 _show_measures = yn;
2354 if ((prop = node.property ("follow-playhead"))) {
2355 bool yn = string_is_affirmative (prop->value());
2356 set_follow_playhead (yn);
2359 if ((prop = node.property ("stationary-playhead"))) {
2360 bool yn = string_is_affirmative (prop->value());
2361 set_stationary_playhead (yn);
2364 if ((prop = node.property ("region-list-sort-type"))) {
2365 RegionListSortType st;
2366 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2369 if ((prop = node.property ("show-editor-mixer"))) {
2371 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2374 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2375 bool yn = string_is_affirmative (prop->value());
2377 /* do it twice to force the change */
2379 tact->set_active (!yn);
2380 tact->set_active (yn);
2383 if ((prop = node.property ("show-editor-list"))) {
2385 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2388 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2389 bool yn = string_is_affirmative (prop->value());
2391 /* do it twice to force the change */
2393 tact->set_active (!yn);
2394 tact->set_active (yn);
2397 if ((prop = node.property (X_("editor-list-page")))) {
2398 _the_notebook.set_current_page (atoi (prop->value ()));
2401 if ((prop = node.property (X_("show-marker-lines")))) {
2402 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2404 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2405 bool yn = string_is_affirmative (prop->value ());
2407 tact->set_active (!yn);
2408 tact->set_active (yn);
2411 XMLNodeList children = node.children ();
2412 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2413 selection->set_state (**i, Stateful::current_state_version);
2414 _regions->set_state (**i);
2417 if ((prop = node.property ("maximised"))) {
2418 bool yn = string_is_affirmative (prop->value());
2419 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2421 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2422 bool fs = tact && tact->get_active();
2424 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2428 if ((prop = node.property ("nudge-clock-value"))) {
2430 sscanf (prop->value().c_str(), "%" PRId64, &f);
2431 nudge_clock->set (f);
2433 nudge_clock->set_mode (AudioClock::Timecode);
2434 nudge_clock->set (_session->frame_rate() * 5, true);
2439 * Not all properties may have been in XML, but
2440 * those that are linked to a private variable may need changing
2445 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2447 yn = _show_measures;
2448 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2449 /* do it twice to force the change */
2450 tact->set_active (!yn);
2451 tact->set_active (yn);
2454 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2455 yn = _follow_playhead;
2457 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2458 if (tact->get_active() != yn) {
2459 tact->set_active (yn);
2463 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2464 yn = _stationary_playhead;
2466 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2467 if (tact->get_active() != yn) {
2468 tact->set_active (yn);
2477 Editor::get_state ()
2479 XMLNode* node = new XMLNode ("Editor");
2482 id().print (buf, sizeof (buf));
2483 node->add_property ("id", buf);
2485 if (is_realized()) {
2486 Glib::RefPtr<Gdk::Window> win = get_window();
2488 int x, y, width, height;
2489 win->get_root_origin(x, y);
2490 win->get_size(width, height);
2492 XMLNode* geometry = new XMLNode ("geometry");
2494 snprintf(buf, sizeof(buf), "%d", width);
2495 geometry->add_property("x-size", string(buf));
2496 snprintf(buf, sizeof(buf), "%d", height);
2497 geometry->add_property("y-size", string(buf));
2498 snprintf(buf, sizeof(buf), "%d", x);
2499 geometry->add_property("x-pos", string(buf));
2500 snprintf(buf, sizeof(buf), "%d", y);
2501 geometry->add_property("y-pos", string(buf));
2502 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2503 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2504 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2505 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2506 geometry->add_property("edit-vertical-pane-pos", string(buf));
2508 node->add_child_nocopy (*geometry);
2511 maybe_add_mixer_strip_width (*node);
2513 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2515 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2516 node->add_property ("zoom", buf);
2517 node->add_property ("snap-to", enum_2_string (_snap_type));
2518 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2519 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2520 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2521 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2522 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2523 node->add_property ("edit-point", enum_2_string (_edit_point));
2524 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2525 node->add_property ("visible-track-count", buf);
2527 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2528 node->add_property ("playhead", buf);
2529 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2530 node->add_property ("left-frame", buf);
2531 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2532 node->add_property ("y-origin", buf);
2534 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2535 node->add_property ("maximised", _maximised ? "yes" : "no");
2536 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2537 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2538 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2539 node->add_property ("mouse-mode", enum2str(mouse_mode));
2540 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2542 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2544 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2545 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2548 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2550 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2551 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2554 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2555 node->add_property (X_("editor-list-page"), buf);
2557 if (button_bindings) {
2558 XMLNode* bb = new XMLNode (X_("Buttons"));
2559 button_bindings->save (*bb);
2560 node->add_child_nocopy (*bb);
2563 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2565 node->add_child_nocopy (selection->get_state ());
2566 node->add_child_nocopy (_regions->get_state ());
2568 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2569 node->add_property ("nudge-clock-value", buf);
2574 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2575 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2577 * @return pair: TimeAxisView that y is over, layer index.
2579 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2580 * in stacked or expanded region display mode, otherwise 0.
2582 std::pair<TimeAxisView *, double>
2583 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2585 if (!trackview_relative_offset) {
2586 y -= _trackview_group->canvas_origin().y;
2590 return std::make_pair ( (TimeAxisView *) 0, 0);
2593 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2595 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2602 return std::make_pair ( (TimeAxisView *) 0, 0);
2605 /** Snap a position to the grid, if appropriate, taking into account current
2606 * grid settings and also the state of any snap modifier keys that may be pressed.
2607 * @param start Position to snap.
2608 * @param event Event to get current key modifier information from, or 0.
2611 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2613 if (!_session || !event) {
2617 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2618 if (_snap_mode == SnapOff) {
2619 snap_to_internal (start, direction, for_mark);
2622 if (_snap_mode != SnapOff) {
2623 snap_to_internal (start, direction, for_mark);
2624 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2625 /* SnapOff, but we pressed the snap_delta modifier */
2626 snap_to_internal (start, direction, for_mark);
2632 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2634 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2638 snap_to_internal (start, direction, for_mark, ensure_snap);
2642 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2644 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2645 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2647 switch (_snap_type) {
2648 case SnapToTimecodeFrame:
2649 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2650 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2651 /* start is already on a whole timecode frame, do nothing */
2652 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2653 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2655 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2659 case SnapToTimecodeSeconds:
2660 if (_session->config.get_timecode_offset_negative()) {
2661 start += _session->config.get_timecode_offset ();
2663 start -= _session->config.get_timecode_offset ();
2665 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2666 (start % one_timecode_second == 0)) {
2667 /* start is already on a whole second, do nothing */
2668 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2669 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2671 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2674 if (_session->config.get_timecode_offset_negative()) {
2675 start -= _session->config.get_timecode_offset ();
2677 start += _session->config.get_timecode_offset ();
2681 case SnapToTimecodeMinutes:
2682 if (_session->config.get_timecode_offset_negative()) {
2683 start += _session->config.get_timecode_offset ();
2685 start -= _session->config.get_timecode_offset ();
2687 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2688 (start % one_timecode_minute == 0)) {
2689 /* start is already on a whole minute, do nothing */
2690 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2691 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2693 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2695 if (_session->config.get_timecode_offset_negative()) {
2696 start -= _session->config.get_timecode_offset ();
2698 start += _session->config.get_timecode_offset ();
2702 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2703 abort(); /*NOTREACHED*/
2708 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2710 const framepos_t one_second = _session->frame_rate();
2711 const framepos_t one_minute = _session->frame_rate() * 60;
2712 framepos_t presnap = start;
2716 switch (_snap_type) {
2717 case SnapToTimecodeFrame:
2718 case SnapToTimecodeSeconds:
2719 case SnapToTimecodeMinutes:
2720 return timecode_snap_to_internal (start, direction, for_mark);
2723 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2724 start % (one_second/75) == 0) {
2725 /* start is already on a whole CD frame, do nothing */
2726 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2727 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2729 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2734 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2735 start % one_second == 0) {
2736 /* start is already on a whole second, do nothing */
2737 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2738 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2740 start = (framepos_t) floor ((double) start / one_second) * one_second;
2745 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2746 start % one_minute == 0) {
2747 /* start is already on a whole minute, do nothing */
2748 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2749 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2751 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2756 start = _session->tempo_map().round_to_bar (start, direction);
2760 start = _session->tempo_map().round_to_beat (start, direction);
2763 case SnapToBeatDiv128:
2764 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2766 case SnapToBeatDiv64:
2767 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2769 case SnapToBeatDiv32:
2770 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2772 case SnapToBeatDiv28:
2773 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2775 case SnapToBeatDiv24:
2776 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2778 case SnapToBeatDiv20:
2779 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2781 case SnapToBeatDiv16:
2782 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2784 case SnapToBeatDiv14:
2785 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2787 case SnapToBeatDiv12:
2788 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2790 case SnapToBeatDiv10:
2791 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2793 case SnapToBeatDiv8:
2794 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2796 case SnapToBeatDiv7:
2797 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2799 case SnapToBeatDiv6:
2800 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2802 case SnapToBeatDiv5:
2803 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2805 case SnapToBeatDiv4:
2806 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2808 case SnapToBeatDiv3:
2809 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2811 case SnapToBeatDiv2:
2812 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2820 _session->locations()->marks_either_side (start, before, after);
2822 if (before == max_framepos && after == max_framepos) {
2823 /* No marks to snap to, so just don't snap */
2825 } else if (before == max_framepos) {
2827 } else if (after == max_framepos) {
2829 } else if (before != max_framepos && after != max_framepos) {
2830 /* have before and after */
2831 if ((start - before) < (after - start)) {
2840 case SnapToRegionStart:
2841 case SnapToRegionEnd:
2842 case SnapToRegionSync:
2843 case SnapToRegionBoundary:
2844 if (!region_boundary_cache.empty()) {
2846 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2847 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2849 if (direction > 0) {
2850 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2852 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2855 if (next != region_boundary_cache.begin ()) {
2860 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2861 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2863 if (start > (p + n) / 2) {
2872 switch (_snap_mode) {
2882 if (presnap > start) {
2883 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2887 } else if (presnap < start) {
2888 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2894 /* handled at entry */
2902 Editor::setup_toolbar ()
2904 HBox* mode_box = manage(new HBox);
2905 mode_box->set_border_width (2);
2906 mode_box->set_spacing(2);
2908 HBox* mouse_mode_box = manage (new HBox);
2909 HBox* mouse_mode_hbox = manage (new HBox);
2910 VBox* mouse_mode_vbox = manage (new VBox);
2911 Alignment* mouse_mode_align = manage (new Alignment);
2913 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2914 mouse_mode_size_group->add_widget (smart_mode_button);
2915 mouse_mode_size_group->add_widget (mouse_move_button);
2916 mouse_mode_size_group->add_widget (mouse_cut_button);
2917 mouse_mode_size_group->add_widget (mouse_select_button);
2918 mouse_mode_size_group->add_widget (mouse_timefx_button);
2919 mouse_mode_size_group->add_widget (mouse_audition_button);
2920 mouse_mode_size_group->add_widget (mouse_draw_button);
2921 mouse_mode_size_group->add_widget (mouse_content_button);
2923 mouse_mode_size_group->add_widget (zoom_in_button);
2924 mouse_mode_size_group->add_widget (zoom_out_button);
2925 mouse_mode_size_group->add_widget (zoom_preset_selector);
2926 mouse_mode_size_group->add_widget (zoom_out_full_button);
2927 mouse_mode_size_group->add_widget (zoom_focus_selector);
2929 mouse_mode_size_group->add_widget (tav_shrink_button);
2930 mouse_mode_size_group->add_widget (tav_expand_button);
2931 mouse_mode_size_group->add_widget (visible_tracks_selector);
2933 mouse_mode_size_group->add_widget (snap_type_selector);
2934 mouse_mode_size_group->add_widget (snap_mode_selector);
2936 mouse_mode_size_group->add_widget (edit_point_selector);
2937 mouse_mode_size_group->add_widget (edit_mode_selector);
2939 mouse_mode_size_group->add_widget (*nudge_clock);
2940 mouse_mode_size_group->add_widget (nudge_forward_button);
2941 mouse_mode_size_group->add_widget (nudge_backward_button);
2943 mouse_mode_hbox->set_spacing (2);
2945 if (!ARDOUR::Profile->get_trx()) {
2946 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2949 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2950 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2952 if (!ARDOUR::Profile->get_mixbus()) {
2953 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2956 if (!ARDOUR::Profile->get_trx()) {
2957 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2958 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2959 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2960 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2963 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2965 mouse_mode_align->add (*mouse_mode_vbox);
2966 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2968 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2970 edit_mode_selector.set_name ("mouse mode button");
2972 if (!ARDOUR::Profile->get_trx()) {
2973 mode_box->pack_start (edit_mode_selector, false, false);
2975 mode_box->pack_start (*mouse_mode_box, false, false);
2977 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2978 _mouse_mode_tearoff->set_name ("MouseModeBase");
2979 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2981 if (Profile->get_sae() || Profile->get_mixbus() ) {
2982 _mouse_mode_tearoff->set_can_be_torn_off (false);
2985 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2986 &_mouse_mode_tearoff->tearoff_window()));
2987 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2988 &_mouse_mode_tearoff->tearoff_window(), 1));
2989 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2990 &_mouse_mode_tearoff->tearoff_window()));
2991 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2992 &_mouse_mode_tearoff->tearoff_window(), 1));
2996 _zoom_box.set_spacing (2);
2997 _zoom_box.set_border_width (2);
3001 zoom_preset_selector.set_name ("zoom button");
3002 zoom_preset_selector.set_image(::get_icon ("time_exp"));
3003 zoom_preset_selector.set_size_request (42, -1);
3005 zoom_in_button.set_name ("zoom button");
3006 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3007 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3008 zoom_in_button.set_related_action (act);
3010 zoom_out_button.set_name ("zoom button");
3011 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3012 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3013 zoom_out_button.set_related_action (act);
3015 zoom_out_full_button.set_name ("zoom button");
3016 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3017 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3018 zoom_out_full_button.set_related_action (act);
3020 zoom_focus_selector.set_name ("zoom button");
3022 if (ARDOUR::Profile->get_mixbus()) {
3023 _zoom_box.pack_start (zoom_preset_selector, false, false);
3024 } else if (ARDOUR::Profile->get_trx()) {
3025 mode_box->pack_start (zoom_out_button, false, false);
3026 mode_box->pack_start (zoom_in_button, false, false);
3028 _zoom_box.pack_start (zoom_out_button, false, false);
3029 _zoom_box.pack_start (zoom_in_button, false, false);
3030 _zoom_box.pack_start (zoom_out_full_button, false, false);
3031 _zoom_box.pack_start (zoom_focus_selector, false, false);
3034 /* Track zoom buttons */
3035 visible_tracks_selector.set_name ("zoom button");
3036 if (Profile->get_mixbus()) {
3037 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3038 visible_tracks_selector.set_size_request (42, -1);
3040 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3043 tav_expand_button.set_name ("zoom button");
3044 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3045 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3046 tav_expand_button.set_related_action (act);
3048 tav_shrink_button.set_name ("zoom button");
3049 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3050 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3051 tav_shrink_button.set_related_action (act);
3053 if (ARDOUR::Profile->get_mixbus()) {
3054 _zoom_box.pack_start (visible_tracks_selector);
3055 } else if (ARDOUR::Profile->get_trx()) {
3056 _zoom_box.pack_start (tav_shrink_button);
3057 _zoom_box.pack_start (tav_expand_button);
3059 _zoom_box.pack_start (visible_tracks_selector);
3060 _zoom_box.pack_start (tav_shrink_button);
3061 _zoom_box.pack_start (tav_expand_button);
3064 if (!ARDOUR::Profile->get_trx()) {
3065 _zoom_tearoff = manage (new TearOff (_zoom_box));
3067 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3068 &_zoom_tearoff->tearoff_window()));
3069 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3070 &_zoom_tearoff->tearoff_window(), 0));
3071 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3072 &_zoom_tearoff->tearoff_window()));
3073 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3074 &_zoom_tearoff->tearoff_window(), 0));
3077 if (Profile->get_sae() || Profile->get_mixbus() ) {
3078 _zoom_tearoff->set_can_be_torn_off (false);
3081 snap_box.set_spacing (2);
3082 snap_box.set_border_width (2);
3084 snap_type_selector.set_name ("mouse mode button");
3086 snap_mode_selector.set_name ("mouse mode button");
3088 edit_point_selector.set_name ("mouse mode button");
3090 snap_box.pack_start (snap_mode_selector, false, false);
3091 snap_box.pack_start (snap_type_selector, false, false);
3092 snap_box.pack_start (edit_point_selector, false, false);
3096 HBox *nudge_box = manage (new HBox);
3097 nudge_box->set_spacing (2);
3098 nudge_box->set_border_width (2);
3100 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3101 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3103 nudge_box->pack_start (nudge_backward_button, false, false);
3104 nudge_box->pack_start (nudge_forward_button, false, false);
3105 nudge_box->pack_start (*nudge_clock, false, false);
3108 /* Pack everything in... */
3110 HBox* hbox = manage (new HBox);
3111 hbox->set_spacing(2);
3113 _tools_tearoff = manage (new TearOff (*hbox));
3114 _tools_tearoff->set_name ("MouseModeBase");
3115 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3117 if (Profile->get_sae() || Profile->get_mixbus()) {
3118 _tools_tearoff->set_can_be_torn_off (false);
3121 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3122 &_tools_tearoff->tearoff_window()));
3123 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3124 &_tools_tearoff->tearoff_window(), 0));
3125 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3126 &_tools_tearoff->tearoff_window()));
3127 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3128 &_tools_tearoff->tearoff_window(), 0));
3130 toolbar_hbox.set_spacing (2);
3131 toolbar_hbox.set_border_width (1);
3133 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3134 if (!ARDOUR::Profile->get_trx()) {
3135 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3136 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3139 if (!ARDOUR::Profile->get_trx()) {
3140 hbox->pack_start (snap_box, false, false);
3141 hbox->pack_start (*nudge_box, false, false);
3143 hbox->pack_start (panic_box, false, false);
3147 toolbar_base.set_name ("ToolBarBase");
3148 toolbar_base.add (toolbar_hbox);
3150 _toolbar_viewport.add (toolbar_base);
3151 /* stick to the required height but allow width to vary if there's not enough room */
3152 _toolbar_viewport.set_size_request (1, -1);
3154 toolbar_frame.set_shadow_type (SHADOW_OUT);
3155 toolbar_frame.set_name ("BaseFrame");
3156 toolbar_frame.add (_toolbar_viewport);
3160 Editor::build_edit_point_menu ()
3162 using namespace Menu_Helpers;
3164 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3165 if(!Profile->get_mixbus())
3166 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3167 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3169 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3173 Editor::build_edit_mode_menu ()
3175 using namespace Menu_Helpers;
3177 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3178 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3179 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3180 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3182 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3186 Editor::build_snap_mode_menu ()
3188 using namespace Menu_Helpers;
3190 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3191 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3192 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3194 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3198 Editor::build_snap_type_menu ()
3200 using namespace Menu_Helpers;
3202 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3203 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3204 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3205 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3206 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3207 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3208 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3209 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3210 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3211 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3212 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3213 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3214 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3215 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3216 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3217 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3218 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3219 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3220 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3221 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3222 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3223 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3224 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3225 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3226 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3227 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3228 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3229 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3230 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3231 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3233 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3238 Editor::setup_tooltips ()
3240 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3241 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3242 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3243 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3244 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3245 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3246 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3247 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3248 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3249 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3250 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3251 set_tooltip (zoom_in_button, _("Zoom In"));
3252 set_tooltip (zoom_out_button, _("Zoom Out"));
3253 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3254 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3255 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3256 set_tooltip (tav_expand_button, _("Expand Tracks"));
3257 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3258 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3259 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3260 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3261 set_tooltip (edit_point_selector, _("Edit Point"));
3262 set_tooltip (edit_mode_selector, _("Edit Mode"));
3263 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3267 Editor::convert_drop_to_paths (
3268 vector<string>& paths,
3269 const RefPtr<Gdk::DragContext>& /*context*/,
3272 const SelectionData& data,
3276 if (_session == 0) {
3280 vector<string> uris = data.get_uris();
3284 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3285 are actually URI lists. So do it by hand.
3288 if (data.get_target() != "text/plain") {
3292 /* Parse the "uri-list" format that Nautilus provides,
3293 where each pathname is delimited by \r\n.
3295 THERE MAY BE NO NULL TERMINATING CHAR!!!
3298 string txt = data.get_text();
3302 p = (char *) malloc (txt.length() + 1);
3303 txt.copy (p, txt.length(), 0);
3304 p[txt.length()] = '\0';
3310 while (g_ascii_isspace (*p))
3314 while (*q && (*q != '\n') && (*q != '\r')) {
3321 while (q > p && g_ascii_isspace (*q))
3326 uris.push_back (string (p, q - p + 1));
3330 p = strchr (p, '\n');
3342 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3343 if ((*i).substr (0,7) == "file://") {
3344 paths.push_back (Glib::filename_from_uri (*i));
3352 Editor::new_tempo_section ()
3357 Editor::map_transport_state ()
3359 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3361 if (_session && _session->transport_stopped()) {
3362 have_pending_keyboard_selection = false;
3365 update_loop_range_view ();
3371 Editor::begin_selection_op_history ()
3373 selection_op_cmd_depth = 0;
3374 selection_op_history_it = 0;
3376 while(!selection_op_history.empty()) {
3377 delete selection_op_history.front();
3378 selection_op_history.pop_front();
3381 selection_undo_action->set_sensitive (false);
3382 selection_redo_action->set_sensitive (false);
3383 selection_op_history.push_front (&_selection_memento->get_state ());
3387 Editor::begin_reversible_selection_op (string name)
3390 //cerr << name << endl;
3391 /* begin/commit pairs can be nested */
3392 selection_op_cmd_depth++;
3397 Editor::commit_reversible_selection_op ()
3400 if (selection_op_cmd_depth == 1) {
3402 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3404 The user has undone some selection ops and then made a new one,
3405 making anything earlier in the list invalid.
3408 list<XMLNode *>::iterator it = selection_op_history.begin();
3409 list<XMLNode *>::iterator e_it = it;
3410 advance (e_it, selection_op_history_it);
3412 for ( ; it != e_it; ++it) {
3415 selection_op_history.erase (selection_op_history.begin(), e_it);
3418 selection_op_history.push_front (&_selection_memento->get_state ());
3419 selection_op_history_it = 0;
3421 selection_undo_action->set_sensitive (true);
3422 selection_redo_action->set_sensitive (false);
3425 if (selection_op_cmd_depth > 0) {
3426 selection_op_cmd_depth--;
3432 Editor::undo_selection_op ()
3435 selection_op_history_it++;
3437 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3438 if (n == selection_op_history_it) {
3439 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3440 selection_redo_action->set_sensitive (true);
3444 /* is there an earlier entry? */
3445 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3446 selection_undo_action->set_sensitive (false);
3452 Editor::redo_selection_op ()
3455 if (selection_op_history_it > 0) {
3456 selection_op_history_it--;
3459 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3460 if (n == selection_op_history_it) {
3461 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3462 selection_undo_action->set_sensitive (true);
3467 if (selection_op_history_it == 0) {
3468 selection_redo_action->set_sensitive (false);
3474 Editor::begin_reversible_command (string name)
3477 before.push_back (&_selection_memento->get_state ());
3478 _session->begin_reversible_command (name);
3483 Editor::begin_reversible_command (GQuark q)
3486 before.push_back (&_selection_memento->get_state ());
3487 _session->begin_reversible_command (q);
3492 Editor::abort_reversible_command ()
3495 while(!before.empty()) {
3496 delete before.front();
3499 _session->abort_reversible_command ();
3504 Editor::commit_reversible_command ()
3507 if (before.size() == 1) {
3508 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3509 redo_action->set_sensitive(false);
3510 undo_action->set_sensitive(true);
3511 begin_selection_op_history ();
3514 if (before.empty()) {
3515 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3520 _session->commit_reversible_command ();
3525 Editor::history_changed ()
3529 if (undo_action && _session) {
3530 if (_session->undo_depth() == 0) {
3531 label = S_("Command|Undo");
3533 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3535 undo_action->property_label() = label;
3538 if (redo_action && _session) {
3539 if (_session->redo_depth() == 0) {
3541 redo_action->set_sensitive (false);
3543 label = string_compose(_("Redo (%1)"), _session->next_redo());
3544 redo_action->set_sensitive (true);
3546 redo_action->property_label() = label;
3551 Editor::duplicate_range (bool with_dialog)
3555 RegionSelection rs = get_regions_from_selection_and_entered ();
3557 if ( selection->time.length() == 0 && rs.empty()) {
3563 ArdourDialog win (_("Duplicate"));
3564 Label label (_("Number of duplications:"));
3565 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3566 SpinButton spinner (adjustment, 0.0, 1);
3569 win.get_vbox()->set_spacing (12);
3570 win.get_vbox()->pack_start (hbox);
3571 hbox.set_border_width (6);
3572 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3574 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3575 place, visually. so do this by hand.
3578 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3579 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3580 spinner.grab_focus();
3586 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3587 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3588 win.set_default_response (RESPONSE_ACCEPT);
3590 spinner.grab_focus ();
3592 switch (win.run ()) {
3593 case RESPONSE_ACCEPT:
3599 times = adjustment.get_value();
3602 if ((current_mouse_mode() == Editing::MouseRange)) {
3603 if (selection->time.length()) {
3604 duplicate_selection (times);
3606 } else if (get_smart_mode()) {
3607 if (selection->time.length()) {
3608 duplicate_selection (times);
3610 duplicate_some_regions (rs, times);
3612 duplicate_some_regions (rs, times);
3617 Editor::set_edit_mode (EditMode m)
3619 Config->set_edit_mode (m);
3623 Editor::cycle_edit_mode ()
3625 switch (Config->get_edit_mode()) {
3627 if (Profile->get_sae()) {
3628 Config->set_edit_mode (Lock);
3630 Config->set_edit_mode (Ripple);
3635 Config->set_edit_mode (Lock);
3638 Config->set_edit_mode (Slide);
3644 Editor::edit_mode_selection_done ( EditMode m )
3646 Config->set_edit_mode ( m );
3650 Editor::snap_type_selection_done (SnapType snaptype)
3652 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3654 ract->set_active ();
3659 Editor::snap_mode_selection_done (SnapMode mode)
3661 RefPtr<RadioAction> ract = snap_mode_action (mode);
3664 ract->set_active (true);
3669 Editor::cycle_edit_point (bool with_marker)
3671 if(Profile->get_mixbus())
3672 with_marker = false;
3674 switch (_edit_point) {
3676 set_edit_point_preference (EditAtPlayhead);
3678 case EditAtPlayhead:
3680 set_edit_point_preference (EditAtSelectedMarker);
3682 set_edit_point_preference (EditAtMouse);
3685 case EditAtSelectedMarker:
3686 set_edit_point_preference (EditAtMouse);
3692 Editor::edit_point_selection_done (EditPoint ep)
3694 set_edit_point_preference ( ep );
3698 Editor::build_zoom_focus_menu ()
3700 using namespace Menu_Helpers;
3702 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3703 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3704 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3705 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3706 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3707 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3709 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3713 Editor::zoom_focus_selection_done ( ZoomFocus f )
3715 RefPtr<RadioAction> ract = zoom_focus_action (f);
3717 ract->set_active ();
3722 Editor::build_track_count_menu ()
3724 using namespace Menu_Helpers;
3726 if (!Profile->get_mixbus()) {
3727 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3728 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3729 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3730 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3731 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3732 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3733 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3734 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3735 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3736 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3737 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3738 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3739 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3741 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3742 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3743 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3744 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3745 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3746 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3747 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3748 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3749 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3750 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3752 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3753 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3754 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3755 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3756 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3757 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3758 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3759 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3760 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3761 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3762 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3767 Editor::set_zoom_preset (int64_t ms)
3770 temporal_zoom_session();
3774 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3775 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3779 Editor::set_visible_track_count (int32_t n)
3781 _visible_track_count = n;
3783 /* if the canvas hasn't really been allocated any size yet, just
3784 record the desired number of visible tracks and return. when canvas
3785 allocation happens, we will get called again and then we can do the
3789 if (_visible_canvas_height <= 1) {
3795 DisplaySuspender ds;
3797 if (_visible_track_count > 0) {
3798 h = trackviews_height() / _visible_track_count;
3799 std::ostringstream s;
3800 s << _visible_track_count;
3802 } else if (_visible_track_count == 0) {
3804 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3805 if ((*i)->marked_for_display()) {
3809 h = trackviews_height() / n;
3812 /* negative value means that the visible track count has
3813 been overridden by explicit track height changes.
3815 visible_tracks_selector.set_text (X_("*"));
3819 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3820 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3823 if (str != visible_tracks_selector.get_text()) {
3824 visible_tracks_selector.set_text (str);
3829 Editor::override_visible_track_count ()
3831 _visible_track_count = -1;
3832 visible_tracks_selector.set_text ( _("*") );
3836 Editor::edit_controls_button_release (GdkEventButton* ev)
3838 if (Keyboard::is_context_menu_event (ev)) {
3839 ARDOUR_UI::instance()->add_route (this);
3840 } else if (ev->button == 1) {
3841 selection->clear_tracks ();
3848 Editor::mouse_select_button_release (GdkEventButton* ev)
3850 /* this handles just right-clicks */
3852 if (ev->button != 3) {
3860 Editor::set_zoom_focus (ZoomFocus f)
3862 string str = zoom_focus_strings[(int)f];
3864 if (str != zoom_focus_selector.get_text()) {
3865 zoom_focus_selector.set_text (str);
3868 if (zoom_focus != f) {
3875 Editor::cycle_zoom_focus ()
3877 switch (zoom_focus) {
3879 set_zoom_focus (ZoomFocusRight);
3881 case ZoomFocusRight:
3882 set_zoom_focus (ZoomFocusCenter);
3884 case ZoomFocusCenter:
3885 set_zoom_focus (ZoomFocusPlayhead);
3887 case ZoomFocusPlayhead:
3888 set_zoom_focus (ZoomFocusMouse);
3890 case ZoomFocusMouse:
3891 set_zoom_focus (ZoomFocusEdit);
3894 set_zoom_focus (ZoomFocusLeft);
3900 Editor::ensure_float (Window& win)
3902 win.set_transient_for (*this);
3906 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3908 /* recover or initialize pane positions. do this here rather than earlier because
3909 we don't want the positions to change the child allocations, which they seem to do.
3915 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3924 XMLNode* geometry = find_named_node (*node, "geometry");
3926 if (which == static_cast<Paned*> (&edit_pane)) {
3928 if (done & Horizontal) {
3932 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3933 _notebook_shrunk = string_is_affirmative (prop->value ());
3936 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3937 /* initial allocation is 90% to canvas, 10% to notebook */
3938 pos = (int) floor (alloc.get_width() * 0.90f);
3939 snprintf (buf, sizeof(buf), "%d", pos);
3941 pos = atoi (prop->value());
3944 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3945 edit_pane.set_position (pos);
3948 done = (Pane) (done | Horizontal);
3950 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3952 if (done & Vertical) {
3956 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3957 /* initial allocation is 90% to canvas, 10% to summary */
3958 pos = (int) floor (alloc.get_height() * 0.90f);
3959 snprintf (buf, sizeof(buf), "%d", pos);
3962 pos = atoi (prop->value());
3965 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3966 editor_summary_pane.set_position (pos);
3969 done = (Pane) (done | Vertical);
3974 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3976 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3977 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3978 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3979 top_hbox.remove (toolbar_frame);
3984 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3986 if (toolbar_frame.get_parent() == 0) {
3987 top_hbox.pack_end (toolbar_frame);
3992 Editor::set_show_measures (bool yn)
3994 if (_show_measures != yn) {
3997 if ((_show_measures = yn) == true) {
3999 tempo_lines->show();
4002 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
4003 ARDOUR::TempoMap::BBTPointList::const_iterator end;
4005 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
4006 draw_measures (begin, end);
4014 Editor::toggle_follow_playhead ()
4016 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
4018 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4019 set_follow_playhead (tact->get_active());
4023 /** @param yn true to follow playhead, otherwise false.
4024 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4027 Editor::set_follow_playhead (bool yn, bool catch_up)
4029 if (_follow_playhead != yn) {
4030 if ((_follow_playhead = yn) == true && catch_up) {
4032 reset_x_origin_to_follow_playhead ();
4039 Editor::toggle_stationary_playhead ()
4041 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4043 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4044 set_stationary_playhead (tact->get_active());
4049 Editor::set_stationary_playhead (bool yn)
4051 if (_stationary_playhead != yn) {
4052 if ((_stationary_playhead = yn) == true) {
4054 // FIXME need a 3.0 equivalent of this 2.X call
4055 // update_current_screen ();
4062 Editor::playlist_selector () const
4064 return *_playlist_selector;
4068 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4070 if (paste_count == 0) {
4071 /* don't bother calculating an offset that will be zero anyway */
4075 /* calculate basic unsnapped multi-paste offset */
4076 framecnt_t offset = paste_count * duration;
4078 /* snap offset so pos + offset is aligned to the grid */
4079 framepos_t offset_pos = pos + offset;
4080 snap_to(offset_pos, RoundUpMaybe);
4081 offset = offset_pos - pos;
4087 Editor::get_grid_beat_divisions(framepos_t position)
4089 switch (_snap_type) {
4090 case SnapToBeatDiv128: return 128;
4091 case SnapToBeatDiv64: return 64;
4092 case SnapToBeatDiv32: return 32;
4093 case SnapToBeatDiv28: return 28;
4094 case SnapToBeatDiv24: return 24;
4095 case SnapToBeatDiv20: return 20;
4096 case SnapToBeatDiv16: return 16;
4097 case SnapToBeatDiv14: return 14;
4098 case SnapToBeatDiv12: return 12;
4099 case SnapToBeatDiv10: return 10;
4100 case SnapToBeatDiv8: return 8;
4101 case SnapToBeatDiv7: return 7;
4102 case SnapToBeatDiv6: return 6;
4103 case SnapToBeatDiv5: return 5;
4104 case SnapToBeatDiv4: return 4;
4105 case SnapToBeatDiv3: return 3;
4106 case SnapToBeatDiv2: return 2;
4113 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4117 const unsigned divisions = get_grid_beat_divisions(position);
4119 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4122 switch (_snap_type) {
4124 return Evoral::Beats(1.0);
4127 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
4135 return Evoral::Beats();
4139 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4143 ret = nudge_clock->current_duration (pos);
4144 next = ret + 1; /* XXXX fix me */
4150 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4152 ArdourDialog dialog (_("Playlist Deletion"));
4153 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4154 "If it is kept, its audio files will not be cleaned.\n"
4155 "If it is deleted, audio files used by it alone will be cleaned."),
4158 dialog.set_position (WIN_POS_CENTER);
4159 dialog.get_vbox()->pack_start (label);
4163 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4164 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4165 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4166 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4167 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4169 switch (dialog.run ()) {
4171 /* keep this and all remaining ones */
4176 /* delete this and all others */
4180 case RESPONSE_ACCEPT:
4181 /* delete the playlist */
4185 case RESPONSE_REJECT:
4186 /* keep the playlist */
4198 Editor::audio_region_selection_covers (framepos_t where)
4200 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4201 if ((*a)->region()->covers (where)) {
4210 Editor::prepare_for_cleanup ()
4212 cut_buffer->clear_regions ();
4213 cut_buffer->clear_playlists ();
4215 selection->clear_regions ();
4216 selection->clear_playlists ();
4218 _regions->suspend_redisplay ();
4222 Editor::finish_cleanup ()
4224 _regions->resume_redisplay ();
4228 Editor::transport_loop_location()
4231 return _session->locations()->auto_loop_location();
4238 Editor::transport_punch_location()
4241 return _session->locations()->auto_punch_location();
4248 Editor::control_layout_scroll (GdkEventScroll* ev)
4250 /* Just forward to the normal canvas scroll method. The coordinate
4251 systems are different but since the canvas is always larger than the
4252 track headers, and aligned with the trackview area, this will work.
4254 In the not too distant future this layout is going away anyway and
4255 headers will be on the canvas.
4257 return canvas_scroll_event (ev, false);
4261 Editor::session_state_saved (string)
4264 _snapshots->redisplay ();
4268 Editor::update_tearoff_visibility()
4270 bool visible = UIConfiguration::instance().get_keep_tearoffs();
4271 _mouse_mode_tearoff->set_visible (visible);
4272 _tools_tearoff->set_visible (visible);
4273 if (_zoom_tearoff) {
4274 _zoom_tearoff->set_visible (visible);
4279 Editor::reattach_all_tearoffs ()
4281 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4282 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4283 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4287 Editor::maximise_editing_space ()
4299 Editor::restore_editing_space ()
4311 * Make new playlists for a given track and also any others that belong
4312 * to the same active route group with the `select' property.
4317 Editor::new_playlists (TimeAxisView* v)
4319 begin_reversible_command (_("new playlists"));
4320 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4321 _session->playlists->get (playlists);
4322 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4323 commit_reversible_command ();
4327 * Use a copy of the current playlist for a given track and also any others that belong
4328 * to the same active route group with the `select' property.
4333 Editor::copy_playlists (TimeAxisView* v)
4335 begin_reversible_command (_("copy playlists"));
4336 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4337 _session->playlists->get (playlists);
4338 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4339 commit_reversible_command ();
4342 /** Clear the current playlist for a given track and also any others that belong
4343 * to the same active route group with the `select' property.
4348 Editor::clear_playlists (TimeAxisView* v)
4350 begin_reversible_command (_("clear playlists"));
4351 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4352 _session->playlists->get (playlists);
4353 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4354 commit_reversible_command ();
4358 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4360 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4364 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4366 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4370 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4372 atv.clear_playlist ();
4376 Editor::on_key_press_event (GdkEventKey* ev)
4378 return key_press_focus_accelerator_handler (*this, ev);
4382 Editor::on_key_release_event (GdkEventKey* ev)
4384 return Gtk::Window::on_key_release_event (ev);
4385 // return key_press_focus_accelerator_handler (*this, ev);
4389 Editor::get_y_origin () const
4391 return vertical_adjustment.get_value ();
4394 /** Queue up a change to the viewport x origin.
4395 * @param frame New x origin.
4398 Editor::reset_x_origin (framepos_t frame)
4400 pending_visual_change.add (VisualChange::TimeOrigin);
4401 pending_visual_change.time_origin = frame;
4402 ensure_visual_change_idle_handler ();
4406 Editor::reset_y_origin (double y)
4408 pending_visual_change.add (VisualChange::YOrigin);
4409 pending_visual_change.y_origin = y;
4410 ensure_visual_change_idle_handler ();
4414 Editor::reset_zoom (framecnt_t spp)
4416 if (spp == samples_per_pixel) {
4420 pending_visual_change.add (VisualChange::ZoomLevel);
4421 pending_visual_change.samples_per_pixel = spp;
4422 ensure_visual_change_idle_handler ();
4426 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4428 reset_x_origin (frame);
4431 if (!no_save_visual) {
4432 undo_visual_stack.push_back (current_visual_state(false));
4436 Editor::VisualState::VisualState (bool with_tracks)
4437 : gui_state (with_tracks ? new GUIObjectState : 0)
4441 Editor::VisualState::~VisualState ()
4446 Editor::VisualState*
4447 Editor::current_visual_state (bool with_tracks)
4449 VisualState* vs = new VisualState (with_tracks);
4450 vs->y_position = vertical_adjustment.get_value();
4451 vs->samples_per_pixel = samples_per_pixel;
4452 vs->leftmost_frame = leftmost_frame;
4453 vs->zoom_focus = zoom_focus;
4456 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4463 Editor::undo_visual_state ()
4465 if (undo_visual_stack.empty()) {
4469 VisualState* vs = undo_visual_stack.back();
4470 undo_visual_stack.pop_back();
4473 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4476 use_visual_state (*vs);
4481 Editor::redo_visual_state ()
4483 if (redo_visual_stack.empty()) {
4487 VisualState* vs = redo_visual_stack.back();
4488 redo_visual_stack.pop_back();
4490 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4491 // why do we check here?
4492 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4495 use_visual_state (*vs);
4500 Editor::swap_visual_state ()
4502 if (undo_visual_stack.empty()) {
4503 redo_visual_state ();
4505 undo_visual_state ();
4510 Editor::use_visual_state (VisualState& vs)
4512 PBD::Unwinder<bool> nsv (no_save_visual, true);
4513 DisplaySuspender ds;
4515 vertical_adjustment.set_value (vs.y_position);
4517 set_zoom_focus (vs.zoom_focus);
4518 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4521 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4523 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4524 (*i)->clear_property_cache();
4525 (*i)->reset_visual_state ();
4529 _routes->update_visibility ();
4532 /** This is the core function that controls the zoom level of the canvas. It is called
4533 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4534 * @param spp new number of samples per pixel
4537 Editor::set_samples_per_pixel (framecnt_t spp)
4543 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4544 const framecnt_t lots_of_pixels = 4000;
4546 /* if the zoom level is greater than what you'd get trying to display 3
4547 * days of audio on a really big screen, then it's too big.
4550 if (spp * lots_of_pixels > three_days) {
4554 samples_per_pixel = spp;
4557 tempo_lines->tempo_map_changed();
4560 bool const showing_time_selection = selection->time.length() > 0;
4562 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4563 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4564 (*i)->reshow_selection (selection->time);
4568 ZoomChanged (); /* EMIT_SIGNAL */
4570 ArdourCanvas::GtkCanvasViewport* c;
4572 c = get_track_canvas();
4574 c->canvas()->zoomed ();
4577 if (playhead_cursor) {
4578 playhead_cursor->set_position (playhead_cursor->current_frame ());
4581 refresh_location_display();
4582 _summary->set_overlays_dirty ();
4584 update_marker_labels ();
4590 Editor::queue_visual_videotimeline_update ()
4593 * pending_visual_change.add (VisualChange::VideoTimeline);
4594 * or maybe even more specific: which videotimeline-image
4595 * currently it calls update_video_timeline() to update
4596 * _all outdated_ images on the video-timeline.
4597 * see 'exposeimg()' in video_image_frame.cc
4599 ensure_visual_change_idle_handler ();
4603 Editor::ensure_visual_change_idle_handler ()
4605 if (pending_visual_change.idle_handler_id < 0) {
4606 // see comment in add_to_idle_resize above.
4607 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4608 pending_visual_change.being_handled = false;
4613 Editor::_idle_visual_changer (void* arg)
4615 return static_cast<Editor*>(arg)->idle_visual_changer ();
4619 Editor::idle_visual_changer ()
4621 /* set_horizontal_position() below (and maybe other calls) call
4622 gtk_main_iteration(), so it's possible that a signal will be handled
4623 half-way through this method. If this signal wants an
4624 idle_visual_changer we must schedule another one after this one, so
4625 mark the idle_handler_id as -1 here to allow that. Also make a note
4626 that we are doing the visual change, so that changes in response to
4627 super-rapid-screen-update can be dropped if we are still processing
4631 pending_visual_change.idle_handler_id = -1;
4632 pending_visual_change.being_handled = true;
4634 VisualChange vc = pending_visual_change;
4636 pending_visual_change.pending = (VisualChange::Type) 0;
4638 visual_changer (vc);
4640 pending_visual_change.being_handled = false;
4642 return 0; /* this is always a one-shot call */
4646 Editor::visual_changer (const VisualChange& vc)
4648 double const last_time_origin = horizontal_position ();
4650 if (vc.pending & VisualChange::ZoomLevel) {
4651 set_samples_per_pixel (vc.samples_per_pixel);
4653 compute_fixed_ruler_scale ();
4655 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4656 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4658 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4659 current_bbt_points_begin, current_bbt_points_end);
4660 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4661 current_bbt_points_begin, current_bbt_points_end);
4662 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4664 update_video_timeline();
4667 if (vc.pending & VisualChange::TimeOrigin) {
4668 set_horizontal_position (vc.time_origin / samples_per_pixel);
4671 if (vc.pending & VisualChange::YOrigin) {
4672 vertical_adjustment.set_value (vc.y_origin);
4675 if (last_time_origin == horizontal_position ()) {
4676 /* changed signal not emitted */
4677 update_fixed_rulers ();
4678 redisplay_tempo (true);
4681 if (!(vc.pending & VisualChange::ZoomLevel)) {
4682 update_video_timeline();
4685 _summary->set_overlays_dirty ();
4688 struct EditorOrderTimeAxisSorter {
4689 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4690 return a->order () < b->order ();
4695 Editor::sort_track_selection (TrackViewList& sel)
4697 EditorOrderTimeAxisSorter cmp;
4702 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4705 framepos_t where = 0;
4706 EditPoint ep = _edit_point;
4708 if (Profile->get_mixbus())
4709 if (ep == EditAtSelectedMarker)
4710 ep = EditAtPlayhead;
4712 if (from_outside_canvas && (ep == EditAtMouse)) {
4713 ep = EditAtPlayhead;
4714 } else if (from_context_menu && (ep == EditAtMouse)) {
4715 return canvas_event_sample (&context_click_event, 0, 0);
4718 if (entered_marker) {
4719 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4720 return entered_marker->position();
4723 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4724 ep = EditAtSelectedMarker;
4727 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4728 ep = EditAtPlayhead;
4732 case EditAtPlayhead:
4733 if (_dragging_playhead) {
4734 if (!mouse_frame (where, ignored)) {
4735 /* XXX not right but what can we do ? */
4739 where = _session->audible_frame();
4741 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4744 case EditAtSelectedMarker:
4745 if (!selection->markers.empty()) {
4747 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4750 where = loc->start();
4754 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4762 if (!mouse_frame (where, ignored)) {
4763 /* XXX not right but what can we do ? */
4767 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4775 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4777 if (!_session) return;
4779 begin_reversible_command (cmd);
4783 if ((tll = transport_loop_location()) == 0) {
4784 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4785 XMLNode &before = _session->locations()->get_state();
4786 _session->locations()->add (loc, true);
4787 _session->set_auto_loop_location (loc);
4788 XMLNode &after = _session->locations()->get_state();
4789 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4791 XMLNode &before = tll->get_state();
4792 tll->set_hidden (false, this);
4793 tll->set (start, end);
4794 XMLNode &after = tll->get_state();
4795 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4798 commit_reversible_command ();
4802 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4804 if (!_session) return;
4806 begin_reversible_command (cmd);
4810 if ((tpl = transport_punch_location()) == 0) {
4811 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4812 XMLNode &before = _session->locations()->get_state();
4813 _session->locations()->add (loc, true);
4814 _session->set_auto_punch_location (loc);
4815 XMLNode &after = _session->locations()->get_state();
4816 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4818 XMLNode &before = tpl->get_state();
4819 tpl->set_hidden (false, this);
4820 tpl->set (start, end);
4821 XMLNode &after = tpl->get_state();
4822 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4825 commit_reversible_command ();
4828 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4829 * @param rs List to which found regions are added.
4830 * @param where Time to look at.
4831 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4834 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4836 const TrackViewList* tracks;
4839 tracks = &track_views;
4844 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4846 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4849 boost::shared_ptr<Track> tr;
4850 boost::shared_ptr<Playlist> pl;
4852 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4854 boost::shared_ptr<RegionList> regions = pl->regions_at (
4855 (framepos_t) floor ( (double) where * tr->speed()));
4857 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4858 RegionView* rv = rtv->view()->find_view (*i);
4869 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4871 const TrackViewList* tracks;
4874 tracks = &track_views;
4879 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4880 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4882 boost::shared_ptr<Track> tr;
4883 boost::shared_ptr<Playlist> pl;
4885 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4887 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4888 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4890 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4892 RegionView* rv = rtv->view()->find_view (*i);
4903 /** Get regions using the following method:
4905 * Make a region list using:
4906 * (a) any selected regions
4907 * (b) the intersection of any selected tracks and the edit point(*)
4908 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4910 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4912 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4916 Editor::get_regions_from_selection_and_edit_point ()
4918 RegionSelection regions;
4920 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4921 regions.add (entered_regionview);
4923 regions = selection->regions;
4926 if ( regions.empty() ) {
4927 TrackViewList tracks = selection->tracks;
4929 if (!tracks.empty()) {
4930 /* no region selected or entered, but some selected tracks:
4931 * act on all regions on the selected tracks at the edit point
4933 framepos_t const where = get_preferred_edit_position ();
4934 get_regions_at(regions, where, tracks);
4941 /** Get regions using the following method:
4943 * Make a region list using:
4944 * (a) any selected regions
4945 * (b) the intersection of any selected tracks and the edit point(*)
4946 * (c) if neither exists, then whatever region is under the mouse
4948 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4950 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4953 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4955 RegionSelection regions;
4957 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4958 regions.add (entered_regionview);
4960 regions = selection->regions;
4963 if ( regions.empty() ) {
4964 TrackViewList tracks = selection->tracks;
4966 if (!tracks.empty()) {
4967 /* no region selected or entered, but some selected tracks:
4968 * act on all regions on the selected tracks at the edit point
4970 get_regions_at(regions, pos, tracks);
4977 /** Start with regions that are selected, or the entered regionview if none are selected.
4978 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4979 * of the regions that we started with.
4983 Editor::get_regions_from_selection_and_entered ()
4985 RegionSelection regions = selection->regions;
4987 if (regions.empty() && entered_regionview) {
4988 regions.add (entered_regionview);
4995 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4997 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4998 RouteTimeAxisView* rtav;
5000 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5001 boost::shared_ptr<Playlist> pl;
5002 std::vector<boost::shared_ptr<Region> > results;
5003 boost::shared_ptr<Track> tr;
5005 if ((tr = rtav->track()) == 0) {
5010 if ((pl = (tr->playlist())) != 0) {
5011 boost::shared_ptr<Region> r = pl->region_by_id (id);
5013 RegionView* rv = rtav->view()->find_view (r);
5015 regions.push_back (rv);
5024 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5027 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5028 MidiTimeAxisView* mtav;
5030 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5032 mtav->get_per_region_note_selection (selection);
5039 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5041 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5043 RouteTimeAxisView* tatv;
5045 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5047 boost::shared_ptr<Playlist> pl;
5048 vector<boost::shared_ptr<Region> > results;
5050 boost::shared_ptr<Track> tr;
5052 if ((tr = tatv->track()) == 0) {
5057 if ((pl = (tr->playlist())) != 0) {
5058 if (src_comparison) {
5059 pl->get_source_equivalent_regions (region, results);
5061 pl->get_region_list_equivalent_regions (region, results);
5065 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5066 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5067 regions.push_back (marv);
5076 Editor::show_rhythm_ferret ()
5078 if (rhythm_ferret == 0) {
5079 rhythm_ferret = new RhythmFerret(*this);
5082 rhythm_ferret->set_session (_session);
5083 rhythm_ferret->show ();
5084 rhythm_ferret->present ();
5088 Editor::first_idle ()
5090 MessageDialog* dialog = 0;
5092 if (track_views.size() > 1) {
5093 Timers::TimerSuspender t;
5094 dialog = new MessageDialog (
5096 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5100 ARDOUR_UI::instance()->flush_pending ();
5103 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5107 // first idle adds route children (automation tracks), so we need to redisplay here
5108 _routes->redisplay ();
5112 if (_session->undo_depth() == 0) {
5113 undo_action->set_sensitive(false);
5115 redo_action->set_sensitive(false);
5116 begin_selection_op_history ();
5122 Editor::_idle_resize (gpointer arg)
5124 return ((Editor*)arg)->idle_resize ();
5128 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5130 if (resize_idle_id < 0) {
5131 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5132 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5133 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5135 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5136 _pending_resize_amount = 0;
5139 /* make a note of the smallest resulting height, so that we can clamp the
5140 lower limit at TimeAxisView::hSmall */
5142 int32_t min_resulting = INT32_MAX;
5144 _pending_resize_amount += h;
5145 _pending_resize_view = view;
5147 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5149 if (selection->tracks.contains (_pending_resize_view)) {
5150 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5151 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5155 if (min_resulting < 0) {
5160 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5161 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5165 /** Handle pending resizing of tracks */
5167 Editor::idle_resize ()
5169 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5171 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5172 selection->tracks.contains (_pending_resize_view)) {
5174 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5175 if (*i != _pending_resize_view) {
5176 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5181 _pending_resize_amount = 0;
5182 _group_tabs->set_dirty ();
5183 resize_idle_id = -1;
5191 ENSURE_GUI_THREAD (*this, &Editor::located);
5194 playhead_cursor->set_position (_session->audible_frame ());
5195 if (_follow_playhead && !_pending_initial_locate) {
5196 reset_x_origin_to_follow_playhead ();
5200 _pending_locate_request = false;
5201 _pending_initial_locate = false;
5205 Editor::region_view_added (RegionView * rv)
5207 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5208 if (rv->region ()->id () == (*pr)) {
5209 selection->add (rv);
5210 selection->regions.pending.erase (pr);
5215 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5217 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5218 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5219 if (rv->region()->id () == (*rnote).first) {
5220 mrv->select_notes ((*rnote).second);
5221 selection->pending_midi_note_selection.erase(rnote);
5227 _summary->set_background_dirty ();
5231 Editor::region_view_removed ()
5233 _summary->set_background_dirty ();
5237 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5239 TrackViewList::const_iterator j = track_views.begin ();
5240 while (j != track_views.end()) {
5241 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5242 if (rtv && rtv->route() == r) {
5253 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5257 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5258 TimeAxisView* tv = axis_view_from_route (*i);
5268 Editor::suspend_route_redisplay ()
5271 _routes->suspend_redisplay();
5276 Editor::resume_route_redisplay ()
5279 _routes->redisplay(); // queue redisplay
5280 _routes->resume_redisplay();
5285 Editor::add_routes (RouteList& routes)
5287 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5289 RouteTimeAxisView *rtv;
5290 list<RouteTimeAxisView*> new_views;
5291 TrackViewList new_selection;
5292 bool from_scratch = (track_views.size() == 0);
5294 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5295 boost::shared_ptr<Route> route = (*x);
5297 if (route->is_auditioner() || route->is_monitor()) {
5301 DataType dt = route->input()->default_type();
5303 if (dt == ARDOUR::DataType::AUDIO) {
5304 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5305 rtv->set_route (route);
5306 } else if (dt == ARDOUR::DataType::MIDI) {
5307 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5308 rtv->set_route (route);
5310 throw unknown_type();
5313 new_views.push_back (rtv);
5314 track_views.push_back (rtv);
5315 new_selection.push_back (rtv);
5317 rtv->effective_gain_display ();
5319 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5320 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5323 if (new_views.size() > 0) {
5324 _routes->routes_added (new_views);
5325 _summary->routes_added (new_views);
5328 if (!from_scratch) {
5329 selection->tracks.clear();
5330 selection->add (new_selection);
5331 begin_selection_op_history();
5334 if (show_editor_mixer_when_tracks_arrive) {
5335 show_editor_mixer (true);
5338 editor_list_button.set_sensitive (true);
5342 Editor::timeaxisview_deleted (TimeAxisView *tv)
5344 if (tv == entered_track) {
5348 if (_session && _session->deletion_in_progress()) {
5349 /* the situation is under control */
5353 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5355 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5357 _routes->route_removed (tv);
5359 TimeAxisView::Children c = tv->get_child_list ();
5360 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5361 if (entered_track == i->get()) {
5366 /* remove it from the list of track views */
5368 TrackViewList::iterator i;
5370 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5371 i = track_views.erase (i);
5374 /* update whatever the current mixer strip is displaying, if revelant */
5376 boost::shared_ptr<Route> route;
5379 route = rtav->route ();
5382 if (current_mixer_strip && current_mixer_strip->route() == route) {
5384 TimeAxisView* next_tv;
5386 if (track_views.empty()) {
5388 } else if (i == track_views.end()) {
5389 next_tv = track_views.front();
5396 set_selected_mixer_strip (*next_tv);
5398 /* make the editor mixer strip go away setting the
5399 * button to inactive (which also unticks the menu option)
5402 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5408 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5410 if (apply_to_selection) {
5411 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5413 TrackSelection::iterator j = i;
5416 hide_track_in_display (*i, false);
5421 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5423 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5424 // this will hide the mixer strip
5425 set_selected_mixer_strip (*tv);
5428 _routes->hide_track_in_display (*tv);
5433 Editor::sync_track_view_list_and_routes ()
5435 track_views = TrackViewList (_routes->views ());
5437 _summary->set_background_dirty();
5438 _group_tabs->set_dirty ();
5440 return false; // do not call again (until needed)
5444 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5446 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5451 /** Find a RouteTimeAxisView by the ID of its route */
5453 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5455 RouteTimeAxisView* v;
5457 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5458 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5459 if(v->route()->id() == id) {
5469 Editor::fit_route_group (RouteGroup *g)
5471 TrackViewList ts = axis_views_from_routes (g->route_list ());
5476 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5478 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5481 _session->cancel_audition ();
5485 if (_session->is_auditioning()) {
5486 _session->cancel_audition ();
5487 if (r == last_audition_region) {
5492 _session->audition_region (r);
5493 last_audition_region = r;
5498 Editor::hide_a_region (boost::shared_ptr<Region> r)
5500 r->set_hidden (true);
5504 Editor::show_a_region (boost::shared_ptr<Region> r)
5506 r->set_hidden (false);
5510 Editor::audition_region_from_region_list ()
5512 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5516 Editor::hide_region_from_region_list ()
5518 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5522 Editor::show_region_in_region_list ()
5524 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5528 Editor::step_edit_status_change (bool yn)
5531 start_step_editing ();
5533 stop_step_editing ();
5538 Editor::start_step_editing ()
5540 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5544 Editor::stop_step_editing ()
5546 step_edit_connection.disconnect ();
5550 Editor::check_step_edit ()
5552 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5553 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5555 mtv->check_step_edit ();
5559 return true; // do it again, till we stop
5563 Editor::scroll_press (Direction dir)
5565 ++_scroll_callbacks;
5567 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5568 /* delay the first auto-repeat */
5574 scroll_backward (1);
5582 scroll_up_one_track ();
5586 scroll_down_one_track ();
5590 /* do hacky auto-repeat */
5591 if (!_scroll_connection.connected ()) {
5593 _scroll_connection = Glib::signal_timeout().connect (
5594 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5597 _scroll_callbacks = 0;
5604 Editor::scroll_release ()
5606 _scroll_connection.disconnect ();
5609 /** Queue a change for the Editor viewport x origin to follow the playhead */
5611 Editor::reset_x_origin_to_follow_playhead ()
5613 framepos_t const frame = playhead_cursor->current_frame ();
5615 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5617 if (_session->transport_speed() < 0) {
5619 if (frame > (current_page_samples() / 2)) {
5620 center_screen (frame-(current_page_samples()/2));
5622 center_screen (current_page_samples()/2);
5629 if (frame < leftmost_frame) {
5631 if (_session->transport_rolling()) {
5632 /* rolling; end up with the playhead at the right of the page */
5633 l = frame - current_page_samples ();
5635 /* not rolling: end up with the playhead 1/4 of the way along the page */
5636 l = frame - current_page_samples() / 4;
5640 if (_session->transport_rolling()) {
5641 /* rolling: end up with the playhead on the left of the page */
5644 /* not rolling: end up with the playhead 3/4 of the way along the page */
5645 l = frame - 3 * current_page_samples() / 4;
5653 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5659 Editor::super_rapid_screen_update ()
5661 if (!_session || !_session->engine().running()) {
5665 /* METERING / MIXER STRIPS */
5667 /* update track meters, if required */
5668 if (is_mapped() && meters_running) {
5669 RouteTimeAxisView* rtv;
5670 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5671 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5672 rtv->fast_update ();
5677 /* and any current mixer strip */
5678 if (current_mixer_strip) {
5679 current_mixer_strip->fast_update ();
5682 /* PLAYHEAD AND VIEWPORT */
5684 framepos_t const frame = _session->audible_frame();
5686 /* There are a few reasons why we might not update the playhead / viewport stuff:
5688 * 1. we don't update things when there's a pending locate request, otherwise
5689 * when the editor requests a locate there is a chance that this method
5690 * will move the playhead before the locate request is processed, causing
5692 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5693 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5696 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5698 last_update_frame = frame;
5700 if (!_dragging_playhead) {
5701 playhead_cursor->set_position (frame);
5704 if (!_stationary_playhead) {
5706 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5707 /* We only do this if we aren't already
5708 handling a visual change (ie if
5709 pending_visual_change.being_handled is
5710 false) so that these requests don't stack
5711 up there are too many of them to handle in
5714 reset_x_origin_to_follow_playhead ();
5719 if (!_dragging_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5720 framepos_t const frame = playhead_cursor->current_frame ();
5721 double target = ((double)frame - (double)current_page_samples()/3.0);
5722 if (target <= 0.0) {
5725 // compare to EditorCursor::set_position()
5726 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5727 double const new_pos = sample_to_pixel_unrounded (target);
5728 if (rint (new_pos) != rint (old_pos)) {
5729 reset_x_origin (pixel_to_sample (floor (new_pos)));
5740 Editor::session_going_away ()
5742 _have_idled = false;
5744 _session_connections.drop_connections ();
5746 super_rapid_screen_update_connection.disconnect ();
5748 selection->clear ();
5749 cut_buffer->clear ();
5751 clicked_regionview = 0;
5752 clicked_axisview = 0;
5753 clicked_routeview = 0;
5754 entered_regionview = 0;
5756 last_update_frame = 0;
5759 playhead_cursor->hide ();
5761 /* rip everything out of the list displays */
5765 _route_groups->clear ();
5767 /* do this first so that deleting a track doesn't reset cms to null
5768 and thus cause a leak.
5771 if (current_mixer_strip) {
5772 if (current_mixer_strip->get_parent() != 0) {
5773 global_hpacker.remove (*current_mixer_strip);
5775 delete current_mixer_strip;
5776 current_mixer_strip = 0;
5779 /* delete all trackviews */
5781 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5784 track_views.clear ();
5786 nudge_clock->set_session (0);
5788 editor_list_button.set_active(false);
5789 editor_list_button.set_sensitive(false);
5791 /* clear tempo/meter rulers */
5792 remove_metric_marks ();
5794 clear_marker_display ();
5796 stop_step_editing ();
5798 /* get rid of any existing editor mixer strip */
5800 WindowTitle title(Glib::get_application_name());
5801 title += _("Editor");
5803 set_title (title.get_string());
5805 SessionHandlePtr::session_going_away ();
5810 Editor::show_editor_list (bool yn)
5813 _the_notebook.show ();
5815 _the_notebook.hide ();
5820 Editor::change_region_layering_order (bool from_context_menu)
5822 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5824 if (!clicked_routeview) {
5825 if (layering_order_editor) {
5826 layering_order_editor->hide ();
5831 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5837 boost::shared_ptr<Playlist> pl = track->playlist();
5843 if (layering_order_editor == 0) {
5844 layering_order_editor = new RegionLayeringOrderEditor (*this);
5847 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5848 layering_order_editor->maybe_present ();
5852 Editor::update_region_layering_order_editor ()
5854 if (layering_order_editor && layering_order_editor->is_visible ()) {
5855 change_region_layering_order (true);
5860 Editor::setup_fade_images ()
5862 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5863 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5864 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5865 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5866 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5868 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5869 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5870 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5871 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5872 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5874 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5875 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5876 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5877 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5878 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5880 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5881 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5882 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5883 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5884 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5888 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5890 Editor::action_menu_item (std::string const & name)
5892 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5895 return *manage (a->create_menu_item ());
5899 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5901 EventBox* b = manage (new EventBox);
5902 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5903 Label* l = manage (new Label (name));
5907 _the_notebook.append_page (widget, *b);
5911 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5913 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5914 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5917 if (ev->type == GDK_2BUTTON_PRESS) {
5919 /* double-click on a notebook tab shrinks or expands the notebook */
5921 if (_notebook_shrunk) {
5922 if (pre_notebook_shrink_pane_width) {
5923 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5925 _notebook_shrunk = false;
5927 pre_notebook_shrink_pane_width = edit_pane.get_position();
5929 /* this expands the LHS of the edit pane to cover the notebook
5930 PAGE but leaves the tabs visible.
5932 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5933 _notebook_shrunk = true;
5941 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5943 using namespace Menu_Helpers;
5945 MenuList& items = _control_point_context_menu.items ();
5948 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5949 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5950 if (!can_remove_control_point (item)) {
5951 items.back().set_sensitive (false);
5954 _control_point_context_menu.popup (event->button.button, event->button.time);
5958 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5960 using namespace Menu_Helpers;
5962 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5967 /* We need to get the selection here and pass it to the operations, since
5968 popping up the menu will cause a region leave event which clears
5969 entered_regionview. */
5971 MidiRegionView& mrv = note->region_view();
5972 const RegionSelection rs = get_regions_from_selection_and_entered ();
5973 const uint32_t sel_size = mrv.selection_size ();
5975 MenuList& items = _note_context_menu.items();
5979 items.push_back(MenuElem(_("Delete"),
5980 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5983 items.push_back(MenuElem(_("Edit..."),
5984 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5985 if (sel_size != 1) {
5986 items.back().set_sensitive (false);
5989 items.push_back(MenuElem(_("Transpose..."),
5990 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
5993 items.push_back(MenuElem(_("Legatize"),
5994 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5996 items.back().set_sensitive (false);
5999 items.push_back(MenuElem(_("Quantize..."),
6000 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6002 items.push_back(MenuElem(_("Remove Overlap"),
6003 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6005 items.back().set_sensitive (false);
6008 items.push_back(MenuElem(_("Transform..."),
6009 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6011 _note_context_menu.popup (event->button.button, event->button.time);
6015 Editor::zoom_vertical_modifier_released()
6017 _stepping_axis_view = 0;
6021 Editor::ui_parameter_changed (string parameter)
6023 if (parameter == "icon-set") {
6024 while (!_cursor_stack.empty()) {
6025 _cursor_stack.pop_back();
6027 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6028 _cursor_stack.push_back(_cursors->grabber);
6029 } else if (parameter == "draggable-playhead") {
6030 if (_verbose_cursor) {
6031 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());