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 (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1899 edit_items.push_back (SeparatorElem());
1900 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1901 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1902 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1903 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1904 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1905 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1906 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1912 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1914 using namespace Menu_Helpers;
1918 Menu *play_menu = manage (new Menu);
1919 MenuList& play_items = play_menu->items();
1920 play_menu->set_name ("ArdourContextMenu");
1922 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1923 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1924 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1925 play_items.push_back (SeparatorElem());
1926 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1928 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1932 Menu *select_menu = manage (new Menu);
1933 MenuList& select_items = select_menu->items();
1934 select_menu->set_name ("ArdourContextMenu");
1936 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1937 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1938 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1939 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1940 select_items.push_back (SeparatorElem());
1941 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1942 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1943 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
1944 select_items.push_back (SeparatorElem());
1945 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
1946 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
1947 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1948 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1949 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1950 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1951 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1953 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1957 Menu *cutnpaste_menu = manage (new Menu);
1958 MenuList& cutnpaste_items = cutnpaste_menu->items();
1959 cutnpaste_menu->set_name ("ArdourContextMenu");
1961 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1962 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1963 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1965 cutnpaste_items.push_back (SeparatorElem());
1967 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1968 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1970 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1972 /* Adding new material */
1974 edit_items.push_back (SeparatorElem());
1975 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1976 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1980 Menu *nudge_menu = manage (new Menu());
1981 MenuList& nudge_items = nudge_menu->items();
1982 nudge_menu->set_name ("ArdourContextMenu");
1984 edit_items.push_back (SeparatorElem());
1985 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1986 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1987 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1988 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1990 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1994 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1996 using namespace Menu_Helpers;
2000 Menu *play_menu = manage (new Menu);
2001 MenuList& play_items = play_menu->items();
2002 play_menu->set_name ("ArdourContextMenu");
2004 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2005 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2006 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2010 Menu *select_menu = manage (new Menu);
2011 MenuList& select_items = select_menu->items();
2012 select_menu->set_name ("ArdourContextMenu");
2014 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2015 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2016 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2017 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2018 select_items.push_back (SeparatorElem());
2019 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2020 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2021 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2022 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2024 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2028 Menu *cutnpaste_menu = manage (new Menu);
2029 MenuList& cutnpaste_items = cutnpaste_menu->items();
2030 cutnpaste_menu->set_name ("ArdourContextMenu");
2032 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2033 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2034 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2036 Menu *nudge_menu = manage (new Menu());
2037 MenuList& nudge_items = nudge_menu->items();
2038 nudge_menu->set_name ("ArdourContextMenu");
2040 edit_items.push_back (SeparatorElem());
2041 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2042 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2043 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2044 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2046 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2050 Editor::snap_type() const
2056 Editor::snap_mode() const
2062 Editor::set_snap_to (SnapType st)
2064 unsigned int snap_ind = (unsigned int)st;
2066 if (internal_editing()) {
2067 internal_snap_type = st;
2069 pre_internal_snap_type = st;
2074 if (snap_ind > snap_type_strings.size() - 1) {
2076 _snap_type = (SnapType)snap_ind;
2079 string str = snap_type_strings[snap_ind];
2081 if (str != snap_type_selector.get_text()) {
2082 snap_type_selector.set_text (str);
2087 switch (_snap_type) {
2088 case SnapToBeatDiv128:
2089 case SnapToBeatDiv64:
2090 case SnapToBeatDiv32:
2091 case SnapToBeatDiv28:
2092 case SnapToBeatDiv24:
2093 case SnapToBeatDiv20:
2094 case SnapToBeatDiv16:
2095 case SnapToBeatDiv14:
2096 case SnapToBeatDiv12:
2097 case SnapToBeatDiv10:
2098 case SnapToBeatDiv8:
2099 case SnapToBeatDiv7:
2100 case SnapToBeatDiv6:
2101 case SnapToBeatDiv5:
2102 case SnapToBeatDiv4:
2103 case SnapToBeatDiv3:
2104 case SnapToBeatDiv2: {
2105 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2106 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2108 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2109 current_bbt_points_begin, current_bbt_points_end);
2110 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2111 current_bbt_points_begin, current_bbt_points_end);
2112 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2116 case SnapToRegionStart:
2117 case SnapToRegionEnd:
2118 case SnapToRegionSync:
2119 case SnapToRegionBoundary:
2120 build_region_boundary_cache ();
2128 redisplay_tempo (false);
2130 SnapChanged (); /* EMIT SIGNAL */
2134 Editor::set_snap_mode (SnapMode mode)
2136 string str = snap_mode_strings[(int)mode];
2138 if (internal_editing()) {
2139 internal_snap_mode = mode;
2141 pre_internal_snap_mode = mode;
2146 if (str != snap_mode_selector.get_text ()) {
2147 snap_mode_selector.set_text (str);
2154 Editor::set_edit_point_preference (EditPoint ep, bool force)
2156 bool changed = (_edit_point != ep);
2159 if (Profile->get_mixbus())
2160 if (ep == EditAtSelectedMarker)
2161 ep = EditAtPlayhead;
2163 string str = edit_point_strings[(int)ep];
2164 if (str != edit_point_selector.get_text ()) {
2165 edit_point_selector.set_text (str);
2168 update_all_enter_cursors();
2170 if (!force && !changed) {
2174 const char* action=NULL;
2176 switch (_edit_point) {
2177 case EditAtPlayhead:
2178 action = "edit-at-playhead";
2180 case EditAtSelectedMarker:
2181 action = "edit-at-marker";
2184 action = "edit-at-mouse";
2188 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2190 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2194 bool in_track_canvas;
2196 if (!mouse_frame (foo, in_track_canvas)) {
2197 in_track_canvas = false;
2200 reset_canvas_action_sensitivity (in_track_canvas);
2206 Editor::set_state (const XMLNode& node, int /*version*/)
2208 const XMLProperty* prop;
2215 g.base_width = default_width;
2216 g.base_height = default_height;
2220 if ((geometry = find_named_node (node, "geometry")) != 0) {
2224 if ((prop = geometry->property("x_size")) == 0) {
2225 prop = geometry->property ("x-size");
2228 g.base_width = atoi(prop->value());
2230 if ((prop = geometry->property("y_size")) == 0) {
2231 prop = geometry->property ("y-size");
2234 g.base_height = atoi(prop->value());
2237 if ((prop = geometry->property ("x_pos")) == 0) {
2238 prop = geometry->property ("x-pos");
2241 x = atoi (prop->value());
2244 if ((prop = geometry->property ("y_pos")) == 0) {
2245 prop = geometry->property ("y-pos");
2248 y = atoi (prop->value());
2252 set_default_size (g.base_width, g.base_height);
2255 if (_session && (prop = node.property ("playhead"))) {
2257 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2259 playhead_cursor->set_position (pos);
2261 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2262 playhead_cursor->set_position (0);
2265 playhead_cursor->set_position (0);
2268 if ((prop = node.property ("mixer-width"))) {
2269 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2272 if ((prop = node.property ("zoom-focus"))) {
2273 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2276 if ((prop = node.property ("zoom"))) {
2277 /* older versions of ardour used floating point samples_per_pixel */
2278 double f = PBD::atof (prop->value());
2279 reset_zoom (llrintf (f));
2281 reset_zoom (samples_per_pixel);
2284 if ((prop = node.property ("visible-track-count"))) {
2285 set_visible_track_count (PBD::atoi (prop->value()));
2288 if ((prop = node.property ("snap-to"))) {
2289 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2292 if ((prop = node.property ("snap-mode"))) {
2293 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2296 if ((prop = node.property ("internal-snap-to"))) {
2297 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2300 if ((prop = node.property ("internal-snap-mode"))) {
2301 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2304 if ((prop = node.property ("pre-internal-snap-to"))) {
2305 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2308 if ((prop = node.property ("pre-internal-snap-mode"))) {
2309 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2312 if ((prop = node.property ("mouse-mode"))) {
2313 MouseMode m = str2mousemode(prop->value());
2314 set_mouse_mode (m, true);
2316 set_mouse_mode (MouseObject, true);
2319 if ((prop = node.property ("left-frame")) != 0) {
2321 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2325 reset_x_origin (pos);
2329 if ((prop = node.property ("y-origin")) != 0) {
2330 reset_y_origin (atof (prop->value ()));
2333 if ((prop = node.property ("join-object-range"))) {
2334 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2335 bool yn = string_is_affirmative (prop->value());
2337 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2338 tact->set_active (!yn);
2339 tact->set_active (yn);
2341 set_mouse_mode(mouse_mode, true);
2344 if ((prop = node.property ("edit-point"))) {
2345 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2348 if ((prop = node.property ("show-measures"))) {
2349 bool yn = string_is_affirmative (prop->value());
2350 _show_measures = yn;
2353 if ((prop = node.property ("follow-playhead"))) {
2354 bool yn = string_is_affirmative (prop->value());
2355 set_follow_playhead (yn);
2358 if ((prop = node.property ("stationary-playhead"))) {
2359 bool yn = string_is_affirmative (prop->value());
2360 set_stationary_playhead (yn);
2363 if ((prop = node.property ("region-list-sort-type"))) {
2364 RegionListSortType st;
2365 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2368 if ((prop = node.property ("show-editor-mixer"))) {
2370 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2373 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2374 bool yn = string_is_affirmative (prop->value());
2376 /* do it twice to force the change */
2378 tact->set_active (!yn);
2379 tact->set_active (yn);
2382 if ((prop = node.property ("show-editor-list"))) {
2384 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2387 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2388 bool yn = string_is_affirmative (prop->value());
2390 /* do it twice to force the change */
2392 tact->set_active (!yn);
2393 tact->set_active (yn);
2396 if ((prop = node.property (X_("editor-list-page")))) {
2397 _the_notebook.set_current_page (atoi (prop->value ()));
2400 if ((prop = node.property (X_("show-marker-lines")))) {
2401 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2403 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2404 bool yn = string_is_affirmative (prop->value ());
2406 tact->set_active (!yn);
2407 tact->set_active (yn);
2410 XMLNodeList children = node.children ();
2411 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2412 selection->set_state (**i, Stateful::current_state_version);
2413 _regions->set_state (**i);
2416 if ((prop = node.property ("maximised"))) {
2417 bool yn = string_is_affirmative (prop->value());
2418 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2420 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2421 bool fs = tact && tact->get_active();
2423 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2427 if ((prop = node.property ("nudge-clock-value"))) {
2429 sscanf (prop->value().c_str(), "%" PRId64, &f);
2430 nudge_clock->set (f);
2432 nudge_clock->set_mode (AudioClock::Timecode);
2433 nudge_clock->set (_session->frame_rate() * 5, true);
2438 * Not all properties may have been in XML, but
2439 * those that are linked to a private variable may need changing
2444 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2446 yn = _show_measures;
2447 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2448 /* do it twice to force the change */
2449 tact->set_active (!yn);
2450 tact->set_active (yn);
2453 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2454 yn = _follow_playhead;
2456 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2457 if (tact->get_active() != yn) {
2458 tact->set_active (yn);
2462 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2463 yn = _stationary_playhead;
2465 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2466 if (tact->get_active() != yn) {
2467 tact->set_active (yn);
2476 Editor::get_state ()
2478 XMLNode* node = new XMLNode ("Editor");
2481 id().print (buf, sizeof (buf));
2482 node->add_property ("id", buf);
2484 if (is_realized()) {
2485 Glib::RefPtr<Gdk::Window> win = get_window();
2487 int x, y, width, height;
2488 win->get_root_origin(x, y);
2489 win->get_size(width, height);
2491 XMLNode* geometry = new XMLNode ("geometry");
2493 snprintf(buf, sizeof(buf), "%d", width);
2494 geometry->add_property("x-size", string(buf));
2495 snprintf(buf, sizeof(buf), "%d", height);
2496 geometry->add_property("y-size", string(buf));
2497 snprintf(buf, sizeof(buf), "%d", x);
2498 geometry->add_property("x-pos", string(buf));
2499 snprintf(buf, sizeof(buf), "%d", y);
2500 geometry->add_property("y-pos", string(buf));
2501 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2502 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2503 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2504 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2505 geometry->add_property("edit-vertical-pane-pos", string(buf));
2507 node->add_child_nocopy (*geometry);
2510 maybe_add_mixer_strip_width (*node);
2512 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2514 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2515 node->add_property ("zoom", buf);
2516 node->add_property ("snap-to", enum_2_string (_snap_type));
2517 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2518 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2519 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2520 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2521 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2522 node->add_property ("edit-point", enum_2_string (_edit_point));
2523 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2524 node->add_property ("visible-track-count", buf);
2526 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2527 node->add_property ("playhead", buf);
2528 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2529 node->add_property ("left-frame", buf);
2530 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2531 node->add_property ("y-origin", buf);
2533 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2534 node->add_property ("maximised", _maximised ? "yes" : "no");
2535 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2536 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2537 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2538 node->add_property ("mouse-mode", enum2str(mouse_mode));
2539 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2541 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2543 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2544 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2547 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2549 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2550 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2553 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2554 node->add_property (X_("editor-list-page"), buf);
2556 if (button_bindings) {
2557 XMLNode* bb = new XMLNode (X_("Buttons"));
2558 button_bindings->save (*bb);
2559 node->add_child_nocopy (*bb);
2562 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2564 node->add_child_nocopy (selection->get_state ());
2565 node->add_child_nocopy (_regions->get_state ());
2567 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2568 node->add_property ("nudge-clock-value", buf);
2573 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2574 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2576 * @return pair: TimeAxisView that y is over, layer index.
2578 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2579 * in stacked or expanded region display mode, otherwise 0.
2581 std::pair<TimeAxisView *, double>
2582 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2584 if (!trackview_relative_offset) {
2585 y -= _trackview_group->canvas_origin().y;
2589 return std::make_pair ( (TimeAxisView *) 0, 0);
2592 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2594 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2601 return std::make_pair ( (TimeAxisView *) 0, 0);
2604 /** Snap a position to the grid, if appropriate, taking into account current
2605 * grid settings and also the state of any snap modifier keys that may be pressed.
2606 * @param start Position to snap.
2607 * @param event Event to get current key modifier information from, or 0.
2610 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2612 if (!_session || !event) {
2616 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2617 if (_snap_mode == SnapOff) {
2618 snap_to_internal (start, direction, for_mark);
2621 if (_snap_mode != SnapOff) {
2622 snap_to_internal (start, direction, for_mark);
2623 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2624 /* SnapOff, but we pressed the snap_delta modifier */
2625 snap_to_internal (start, direction, for_mark);
2631 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2633 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2637 snap_to_internal (start, direction, for_mark, ensure_snap);
2641 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2643 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2644 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2646 switch (_snap_type) {
2647 case SnapToTimecodeFrame:
2648 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2649 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2650 /* start is already on a whole timecode frame, do nothing */
2651 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2652 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2654 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2658 case SnapToTimecodeSeconds:
2659 if (_session->config.get_timecode_offset_negative()) {
2660 start += _session->config.get_timecode_offset ();
2662 start -= _session->config.get_timecode_offset ();
2664 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2665 (start % one_timecode_second == 0)) {
2666 /* start is already on a whole second, do nothing */
2667 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2668 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2670 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2673 if (_session->config.get_timecode_offset_negative()) {
2674 start -= _session->config.get_timecode_offset ();
2676 start += _session->config.get_timecode_offset ();
2680 case SnapToTimecodeMinutes:
2681 if (_session->config.get_timecode_offset_negative()) {
2682 start += _session->config.get_timecode_offset ();
2684 start -= _session->config.get_timecode_offset ();
2686 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2687 (start % one_timecode_minute == 0)) {
2688 /* start is already on a whole minute, do nothing */
2689 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2690 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2692 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2694 if (_session->config.get_timecode_offset_negative()) {
2695 start -= _session->config.get_timecode_offset ();
2697 start += _session->config.get_timecode_offset ();
2701 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2702 abort(); /*NOTREACHED*/
2707 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2709 const framepos_t one_second = _session->frame_rate();
2710 const framepos_t one_minute = _session->frame_rate() * 60;
2711 framepos_t presnap = start;
2715 switch (_snap_type) {
2716 case SnapToTimecodeFrame:
2717 case SnapToTimecodeSeconds:
2718 case SnapToTimecodeMinutes:
2719 return timecode_snap_to_internal (start, direction, for_mark);
2722 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2723 start % (one_second/75) == 0) {
2724 /* start is already on a whole CD frame, do nothing */
2725 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2726 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2728 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2733 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2734 start % one_second == 0) {
2735 /* start is already on a whole second, do nothing */
2736 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2737 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2739 start = (framepos_t) floor ((double) start / one_second) * one_second;
2744 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2745 start % one_minute == 0) {
2746 /* start is already on a whole minute, do nothing */
2747 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2748 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2750 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2755 start = _session->tempo_map().round_to_bar (start, direction);
2759 start = _session->tempo_map().round_to_beat (start, direction);
2762 case SnapToBeatDiv128:
2763 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2765 case SnapToBeatDiv64:
2766 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2768 case SnapToBeatDiv32:
2769 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2771 case SnapToBeatDiv28:
2772 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2774 case SnapToBeatDiv24:
2775 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2777 case SnapToBeatDiv20:
2778 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2780 case SnapToBeatDiv16:
2781 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2783 case SnapToBeatDiv14:
2784 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2786 case SnapToBeatDiv12:
2787 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2789 case SnapToBeatDiv10:
2790 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2792 case SnapToBeatDiv8:
2793 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2795 case SnapToBeatDiv7:
2796 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2798 case SnapToBeatDiv6:
2799 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2801 case SnapToBeatDiv5:
2802 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2804 case SnapToBeatDiv4:
2805 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2807 case SnapToBeatDiv3:
2808 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2810 case SnapToBeatDiv2:
2811 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2819 _session->locations()->marks_either_side (start, before, after);
2821 if (before == max_framepos && after == max_framepos) {
2822 /* No marks to snap to, so just don't snap */
2824 } else if (before == max_framepos) {
2826 } else if (after == max_framepos) {
2828 } else if (before != max_framepos && after != max_framepos) {
2829 /* have before and after */
2830 if ((start - before) < (after - start)) {
2839 case SnapToRegionStart:
2840 case SnapToRegionEnd:
2841 case SnapToRegionSync:
2842 case SnapToRegionBoundary:
2843 if (!region_boundary_cache.empty()) {
2845 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2846 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2848 if (direction > 0) {
2849 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2851 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2854 if (next != region_boundary_cache.begin ()) {
2859 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2860 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2862 if (start > (p + n) / 2) {
2871 switch (_snap_mode) {
2881 if (presnap > start) {
2882 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2886 } else if (presnap < start) {
2887 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2893 /* handled at entry */
2901 Editor::setup_toolbar ()
2903 HBox* mode_box = manage(new HBox);
2904 mode_box->set_border_width (2);
2905 mode_box->set_spacing(2);
2907 HBox* mouse_mode_box = manage (new HBox);
2908 HBox* mouse_mode_hbox = manage (new HBox);
2909 VBox* mouse_mode_vbox = manage (new VBox);
2910 Alignment* mouse_mode_align = manage (new Alignment);
2912 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2913 mouse_mode_size_group->add_widget (smart_mode_button);
2914 mouse_mode_size_group->add_widget (mouse_move_button);
2915 mouse_mode_size_group->add_widget (mouse_cut_button);
2916 mouse_mode_size_group->add_widget (mouse_select_button);
2917 mouse_mode_size_group->add_widget (mouse_timefx_button);
2918 mouse_mode_size_group->add_widget (mouse_audition_button);
2919 mouse_mode_size_group->add_widget (mouse_draw_button);
2920 mouse_mode_size_group->add_widget (mouse_content_button);
2922 mouse_mode_size_group->add_widget (zoom_in_button);
2923 mouse_mode_size_group->add_widget (zoom_out_button);
2924 mouse_mode_size_group->add_widget (zoom_preset_selector);
2925 mouse_mode_size_group->add_widget (zoom_out_full_button);
2926 mouse_mode_size_group->add_widget (zoom_focus_selector);
2928 mouse_mode_size_group->add_widget (tav_shrink_button);
2929 mouse_mode_size_group->add_widget (tav_expand_button);
2930 mouse_mode_size_group->add_widget (visible_tracks_selector);
2932 mouse_mode_size_group->add_widget (snap_type_selector);
2933 mouse_mode_size_group->add_widget (snap_mode_selector);
2935 mouse_mode_size_group->add_widget (edit_point_selector);
2936 mouse_mode_size_group->add_widget (edit_mode_selector);
2938 mouse_mode_size_group->add_widget (*nudge_clock);
2939 mouse_mode_size_group->add_widget (nudge_forward_button);
2940 mouse_mode_size_group->add_widget (nudge_backward_button);
2942 mouse_mode_hbox->set_spacing (2);
2944 if (!ARDOUR::Profile->get_trx()) {
2945 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2948 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2949 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2951 if (!ARDOUR::Profile->get_mixbus()) {
2952 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2955 if (!ARDOUR::Profile->get_trx()) {
2956 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2957 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2958 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2959 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2962 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2964 mouse_mode_align->add (*mouse_mode_vbox);
2965 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2967 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2969 edit_mode_selector.set_name ("mouse mode button");
2971 if (!ARDOUR::Profile->get_trx()) {
2972 mode_box->pack_start (edit_mode_selector, false, false);
2974 mode_box->pack_start (*mouse_mode_box, false, false);
2976 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2977 _mouse_mode_tearoff->set_name ("MouseModeBase");
2978 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2980 if (Profile->get_sae() || Profile->get_mixbus() ) {
2981 _mouse_mode_tearoff->set_can_be_torn_off (false);
2984 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2985 &_mouse_mode_tearoff->tearoff_window()));
2986 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2987 &_mouse_mode_tearoff->tearoff_window(), 1));
2988 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2989 &_mouse_mode_tearoff->tearoff_window()));
2990 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2991 &_mouse_mode_tearoff->tearoff_window(), 1));
2995 _zoom_box.set_spacing (2);
2996 _zoom_box.set_border_width (2);
3000 zoom_preset_selector.set_name ("zoom button");
3001 zoom_preset_selector.set_image(::get_icon ("time_exp"));
3002 zoom_preset_selector.set_size_request (42, -1);
3004 zoom_in_button.set_name ("zoom button");
3005 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3006 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3007 zoom_in_button.set_related_action (act);
3009 zoom_out_button.set_name ("zoom button");
3010 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3011 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3012 zoom_out_button.set_related_action (act);
3014 zoom_out_full_button.set_name ("zoom button");
3015 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3016 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3017 zoom_out_full_button.set_related_action (act);
3019 zoom_focus_selector.set_name ("zoom button");
3021 if (ARDOUR::Profile->get_mixbus()) {
3022 _zoom_box.pack_start (zoom_preset_selector, false, false);
3023 } else if (ARDOUR::Profile->get_trx()) {
3024 mode_box->pack_start (zoom_out_button, false, false);
3025 mode_box->pack_start (zoom_in_button, false, false);
3027 _zoom_box.pack_start (zoom_out_button, false, false);
3028 _zoom_box.pack_start (zoom_in_button, false, false);
3029 _zoom_box.pack_start (zoom_out_full_button, false, false);
3030 _zoom_box.pack_start (zoom_focus_selector, false, false);
3033 /* Track zoom buttons */
3034 visible_tracks_selector.set_name ("zoom button");
3035 if (Profile->get_mixbus()) {
3036 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3037 visible_tracks_selector.set_size_request (42, -1);
3039 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3042 tav_expand_button.set_name ("zoom button");
3043 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3044 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3045 tav_expand_button.set_related_action (act);
3047 tav_shrink_button.set_name ("zoom button");
3048 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3049 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3050 tav_shrink_button.set_related_action (act);
3052 if (ARDOUR::Profile->get_mixbus()) {
3053 _zoom_box.pack_start (visible_tracks_selector);
3054 } else if (ARDOUR::Profile->get_trx()) {
3055 _zoom_box.pack_start (tav_shrink_button);
3056 _zoom_box.pack_start (tav_expand_button);
3058 _zoom_box.pack_start (visible_tracks_selector);
3059 _zoom_box.pack_start (tav_shrink_button);
3060 _zoom_box.pack_start (tav_expand_button);
3063 if (!ARDOUR::Profile->get_trx()) {
3064 _zoom_tearoff = manage (new TearOff (_zoom_box));
3066 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3067 &_zoom_tearoff->tearoff_window()));
3068 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3069 &_zoom_tearoff->tearoff_window(), 0));
3070 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3071 &_zoom_tearoff->tearoff_window()));
3072 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3073 &_zoom_tearoff->tearoff_window(), 0));
3076 if (Profile->get_sae() || Profile->get_mixbus() ) {
3077 _zoom_tearoff->set_can_be_torn_off (false);
3080 snap_box.set_spacing (2);
3081 snap_box.set_border_width (2);
3083 snap_type_selector.set_name ("mouse mode button");
3085 snap_mode_selector.set_name ("mouse mode button");
3087 edit_point_selector.set_name ("mouse mode button");
3089 snap_box.pack_start (snap_mode_selector, false, false);
3090 snap_box.pack_start (snap_type_selector, false, false);
3091 snap_box.pack_start (edit_point_selector, false, false);
3095 HBox *nudge_box = manage (new HBox);
3096 nudge_box->set_spacing (2);
3097 nudge_box->set_border_width (2);
3099 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3100 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3102 nudge_box->pack_start (nudge_backward_button, false, false);
3103 nudge_box->pack_start (nudge_forward_button, false, false);
3104 nudge_box->pack_start (*nudge_clock, false, false);
3107 /* Pack everything in... */
3109 HBox* hbox = manage (new HBox);
3110 hbox->set_spacing(2);
3112 _tools_tearoff = manage (new TearOff (*hbox));
3113 _tools_tearoff->set_name ("MouseModeBase");
3114 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3116 if (Profile->get_sae() || Profile->get_mixbus()) {
3117 _tools_tearoff->set_can_be_torn_off (false);
3120 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3121 &_tools_tearoff->tearoff_window()));
3122 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3123 &_tools_tearoff->tearoff_window(), 0));
3124 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3125 &_tools_tearoff->tearoff_window()));
3126 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3127 &_tools_tearoff->tearoff_window(), 0));
3129 toolbar_hbox.set_spacing (2);
3130 toolbar_hbox.set_border_width (1);
3132 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3133 if (!ARDOUR::Profile->get_trx()) {
3134 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3135 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3138 if (!ARDOUR::Profile->get_trx()) {
3139 hbox->pack_start (snap_box, false, false);
3140 hbox->pack_start (*nudge_box, false, false);
3142 hbox->pack_start (panic_box, false, false);
3146 toolbar_base.set_name ("ToolBarBase");
3147 toolbar_base.add (toolbar_hbox);
3149 _toolbar_viewport.add (toolbar_base);
3150 /* stick to the required height but allow width to vary if there's not enough room */
3151 _toolbar_viewport.set_size_request (1, -1);
3153 toolbar_frame.set_shadow_type (SHADOW_OUT);
3154 toolbar_frame.set_name ("BaseFrame");
3155 toolbar_frame.add (_toolbar_viewport);
3159 Editor::build_edit_point_menu ()
3161 using namespace Menu_Helpers;
3163 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3164 if(!Profile->get_mixbus())
3165 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3166 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3168 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3172 Editor::build_edit_mode_menu ()
3174 using namespace Menu_Helpers;
3176 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3177 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3178 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3179 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3181 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3185 Editor::build_snap_mode_menu ()
3187 using namespace Menu_Helpers;
3189 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3190 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3191 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3193 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3197 Editor::build_snap_type_menu ()
3199 using namespace Menu_Helpers;
3201 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3202 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3203 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3204 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3205 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3206 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3207 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3208 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3209 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3210 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3211 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3212 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3213 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3214 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3215 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3216 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3217 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3218 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3219 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3220 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3221 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3222 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3223 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3224 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3225 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3226 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3227 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3228 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3229 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3230 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3232 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3237 Editor::setup_tooltips ()
3239 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3240 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3241 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3242 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3243 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3244 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3245 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3246 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3247 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3248 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3249 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3250 set_tooltip (zoom_in_button, _("Zoom In"));
3251 set_tooltip (zoom_out_button, _("Zoom Out"));
3252 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3253 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3254 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3255 set_tooltip (tav_expand_button, _("Expand Tracks"));
3256 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3257 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3258 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3259 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3260 set_tooltip (edit_point_selector, _("Edit Point"));
3261 set_tooltip (edit_mode_selector, _("Edit Mode"));
3262 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3266 Editor::convert_drop_to_paths (
3267 vector<string>& paths,
3268 const RefPtr<Gdk::DragContext>& /*context*/,
3271 const SelectionData& data,
3275 if (_session == 0) {
3279 vector<string> uris = data.get_uris();
3283 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3284 are actually URI lists. So do it by hand.
3287 if (data.get_target() != "text/plain") {
3291 /* Parse the "uri-list" format that Nautilus provides,
3292 where each pathname is delimited by \r\n.
3294 THERE MAY BE NO NULL TERMINATING CHAR!!!
3297 string txt = data.get_text();
3301 p = (char *) malloc (txt.length() + 1);
3302 txt.copy (p, txt.length(), 0);
3303 p[txt.length()] = '\0';
3309 while (g_ascii_isspace (*p))
3313 while (*q && (*q != '\n') && (*q != '\r')) {
3320 while (q > p && g_ascii_isspace (*q))
3325 uris.push_back (string (p, q - p + 1));
3329 p = strchr (p, '\n');
3341 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3342 if ((*i).substr (0,7) == "file://") {
3343 paths.push_back (Glib::filename_from_uri (*i));
3351 Editor::new_tempo_section ()
3356 Editor::map_transport_state ()
3358 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3360 if (_session && _session->transport_stopped()) {
3361 have_pending_keyboard_selection = false;
3364 update_loop_range_view ();
3370 Editor::begin_selection_op_history ()
3372 selection_op_cmd_depth = 0;
3373 selection_op_history_it = 0;
3375 while(!selection_op_history.empty()) {
3376 delete selection_op_history.front();
3377 selection_op_history.pop_front();
3380 selection_undo_action->set_sensitive (false);
3381 selection_redo_action->set_sensitive (false);
3382 selection_op_history.push_front (&_selection_memento->get_state ());
3386 Editor::begin_reversible_selection_op (string name)
3389 //cerr << name << endl;
3390 /* begin/commit pairs can be nested */
3391 selection_op_cmd_depth++;
3396 Editor::commit_reversible_selection_op ()
3399 if (selection_op_cmd_depth == 1) {
3401 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3403 The user has undone some selection ops and then made a new one,
3404 making anything earlier in the list invalid.
3407 list<XMLNode *>::iterator it = selection_op_history.begin();
3408 list<XMLNode *>::iterator e_it = it;
3409 advance (e_it, selection_op_history_it);
3411 for ( ; it != e_it; ++it) {
3414 selection_op_history.erase (selection_op_history.begin(), e_it);
3417 selection_op_history.push_front (&_selection_memento->get_state ());
3418 selection_op_history_it = 0;
3420 selection_undo_action->set_sensitive (true);
3421 selection_redo_action->set_sensitive (false);
3424 if (selection_op_cmd_depth > 0) {
3425 selection_op_cmd_depth--;
3431 Editor::undo_selection_op ()
3434 selection_op_history_it++;
3436 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3437 if (n == selection_op_history_it) {
3438 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3439 selection_redo_action->set_sensitive (true);
3443 /* is there an earlier entry? */
3444 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3445 selection_undo_action->set_sensitive (false);
3451 Editor::redo_selection_op ()
3454 if (selection_op_history_it > 0) {
3455 selection_op_history_it--;
3458 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3459 if (n == selection_op_history_it) {
3460 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3461 selection_undo_action->set_sensitive (true);
3466 if (selection_op_history_it == 0) {
3467 selection_redo_action->set_sensitive (false);
3473 Editor::begin_reversible_command (string name)
3476 before.push_back (&_selection_memento->get_state ());
3477 _session->begin_reversible_command (name);
3482 Editor::begin_reversible_command (GQuark q)
3485 before.push_back (&_selection_memento->get_state ());
3486 _session->begin_reversible_command (q);
3491 Editor::abort_reversible_command ()
3494 while(!before.empty()) {
3495 delete before.front();
3498 _session->abort_reversible_command ();
3503 Editor::commit_reversible_command ()
3506 if (before.size() == 1) {
3507 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3508 redo_action->set_sensitive(false);
3509 undo_action->set_sensitive(true);
3510 begin_selection_op_history ();
3513 if (before.empty()) {
3514 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3519 _session->commit_reversible_command ();
3524 Editor::history_changed ()
3528 if (undo_action && _session) {
3529 if (_session->undo_depth() == 0) {
3530 label = S_("Command|Undo");
3532 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3534 undo_action->property_label() = label;
3537 if (redo_action && _session) {
3538 if (_session->redo_depth() == 0) {
3540 redo_action->set_sensitive (false);
3542 label = string_compose(_("Redo (%1)"), _session->next_redo());
3543 redo_action->set_sensitive (true);
3545 redo_action->property_label() = label;
3550 Editor::duplicate_range (bool with_dialog)
3554 RegionSelection rs = get_regions_from_selection_and_entered ();
3556 if ( selection->time.length() == 0 && rs.empty()) {
3562 ArdourDialog win (_("Duplicate"));
3563 Label label (_("Number of duplications:"));
3564 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3565 SpinButton spinner (adjustment, 0.0, 1);
3568 win.get_vbox()->set_spacing (12);
3569 win.get_vbox()->pack_start (hbox);
3570 hbox.set_border_width (6);
3571 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3573 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3574 place, visually. so do this by hand.
3577 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3578 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3579 spinner.grab_focus();
3585 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3586 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3587 win.set_default_response (RESPONSE_ACCEPT);
3589 spinner.grab_focus ();
3591 switch (win.run ()) {
3592 case RESPONSE_ACCEPT:
3598 times = adjustment.get_value();
3601 if ((current_mouse_mode() == Editing::MouseRange)) {
3602 if (selection->time.length()) {
3603 duplicate_selection (times);
3605 } else if (get_smart_mode()) {
3606 if (selection->time.length()) {
3607 duplicate_selection (times);
3609 duplicate_some_regions (rs, times);
3611 duplicate_some_regions (rs, times);
3616 Editor::set_edit_mode (EditMode m)
3618 Config->set_edit_mode (m);
3622 Editor::cycle_edit_mode ()
3624 switch (Config->get_edit_mode()) {
3626 if (Profile->get_sae()) {
3627 Config->set_edit_mode (Lock);
3629 Config->set_edit_mode (Ripple);
3634 Config->set_edit_mode (Lock);
3637 Config->set_edit_mode (Slide);
3643 Editor::edit_mode_selection_done ( EditMode m )
3645 Config->set_edit_mode ( m );
3649 Editor::snap_type_selection_done (SnapType snaptype)
3651 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3653 ract->set_active ();
3658 Editor::snap_mode_selection_done (SnapMode mode)
3660 RefPtr<RadioAction> ract = snap_mode_action (mode);
3663 ract->set_active (true);
3668 Editor::cycle_edit_point (bool with_marker)
3670 if(Profile->get_mixbus())
3671 with_marker = false;
3673 switch (_edit_point) {
3675 set_edit_point_preference (EditAtPlayhead);
3677 case EditAtPlayhead:
3679 set_edit_point_preference (EditAtSelectedMarker);
3681 set_edit_point_preference (EditAtMouse);
3684 case EditAtSelectedMarker:
3685 set_edit_point_preference (EditAtMouse);
3691 Editor::edit_point_selection_done (EditPoint ep)
3693 set_edit_point_preference ( ep );
3697 Editor::build_zoom_focus_menu ()
3699 using namespace Menu_Helpers;
3701 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3702 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3703 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3704 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3705 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3706 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3708 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3712 Editor::zoom_focus_selection_done ( ZoomFocus f )
3714 RefPtr<RadioAction> ract = zoom_focus_action (f);
3716 ract->set_active ();
3721 Editor::build_track_count_menu ()
3723 using namespace Menu_Helpers;
3725 if (!Profile->get_mixbus()) {
3726 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3727 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3728 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3729 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3730 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3731 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3732 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3733 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3734 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3735 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3736 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3737 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3738 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3740 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3741 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3742 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3743 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3744 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3745 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3746 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3747 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3748 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3749 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3751 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3752 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3753 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3754 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3755 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3756 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3757 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3758 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3759 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3760 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3761 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3766 Editor::set_zoom_preset (int64_t ms)
3769 temporal_zoom_session();
3773 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3774 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3778 Editor::set_visible_track_count (int32_t n)
3780 _visible_track_count = n;
3782 /* if the canvas hasn't really been allocated any size yet, just
3783 record the desired number of visible tracks and return. when canvas
3784 allocation happens, we will get called again and then we can do the
3788 if (_visible_canvas_height <= 1) {
3794 DisplaySuspender ds;
3796 if (_visible_track_count > 0) {
3797 h = trackviews_height() / _visible_track_count;
3798 std::ostringstream s;
3799 s << _visible_track_count;
3801 } else if (_visible_track_count == 0) {
3803 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3804 if ((*i)->marked_for_display()) {
3808 h = trackviews_height() / n;
3811 /* negative value means that the visible track count has
3812 been overridden by explicit track height changes.
3814 visible_tracks_selector.set_text (X_("*"));
3818 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3819 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3822 if (str != visible_tracks_selector.get_text()) {
3823 visible_tracks_selector.set_text (str);
3828 Editor::override_visible_track_count ()
3830 _visible_track_count = -1;
3831 visible_tracks_selector.set_text ( _("*") );
3835 Editor::edit_controls_button_release (GdkEventButton* ev)
3837 if (Keyboard::is_context_menu_event (ev)) {
3838 ARDOUR_UI::instance()->add_route (this);
3839 } else if (ev->button == 1) {
3840 selection->clear_tracks ();
3847 Editor::mouse_select_button_release (GdkEventButton* ev)
3849 /* this handles just right-clicks */
3851 if (ev->button != 3) {
3859 Editor::set_zoom_focus (ZoomFocus f)
3861 string str = zoom_focus_strings[(int)f];
3863 if (str != zoom_focus_selector.get_text()) {
3864 zoom_focus_selector.set_text (str);
3867 if (zoom_focus != f) {
3874 Editor::cycle_zoom_focus ()
3876 switch (zoom_focus) {
3878 set_zoom_focus (ZoomFocusRight);
3880 case ZoomFocusRight:
3881 set_zoom_focus (ZoomFocusCenter);
3883 case ZoomFocusCenter:
3884 set_zoom_focus (ZoomFocusPlayhead);
3886 case ZoomFocusPlayhead:
3887 set_zoom_focus (ZoomFocusMouse);
3889 case ZoomFocusMouse:
3890 set_zoom_focus (ZoomFocusEdit);
3893 set_zoom_focus (ZoomFocusLeft);
3899 Editor::ensure_float (Window& win)
3901 win.set_transient_for (*this);
3905 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3907 /* recover or initialize pane positions. do this here rather than earlier because
3908 we don't want the positions to change the child allocations, which they seem to do.
3914 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3923 XMLNode* geometry = find_named_node (*node, "geometry");
3925 if (which == static_cast<Paned*> (&edit_pane)) {
3927 if (done & Horizontal) {
3931 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3932 _notebook_shrunk = string_is_affirmative (prop->value ());
3935 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3936 /* initial allocation is 90% to canvas, 10% to notebook */
3937 pos = (int) floor (alloc.get_width() * 0.90f);
3938 snprintf (buf, sizeof(buf), "%d", pos);
3940 pos = atoi (prop->value());
3943 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3944 edit_pane.set_position (pos);
3947 done = (Pane) (done | Horizontal);
3949 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3951 if (done & Vertical) {
3955 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3956 /* initial allocation is 90% to canvas, 10% to summary */
3957 pos = (int) floor (alloc.get_height() * 0.90f);
3958 snprintf (buf, sizeof(buf), "%d", pos);
3961 pos = atoi (prop->value());
3964 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3965 editor_summary_pane.set_position (pos);
3968 done = (Pane) (done | Vertical);
3973 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3975 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3976 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3977 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3978 top_hbox.remove (toolbar_frame);
3983 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3985 if (toolbar_frame.get_parent() == 0) {
3986 top_hbox.pack_end (toolbar_frame);
3991 Editor::set_show_measures (bool yn)
3993 if (_show_measures != yn) {
3996 if ((_show_measures = yn) == true) {
3998 tempo_lines->show();
4001 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
4002 ARDOUR::TempoMap::BBTPointList::const_iterator end;
4004 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
4005 draw_measures (begin, end);
4013 Editor::toggle_follow_playhead ()
4015 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
4017 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4018 set_follow_playhead (tact->get_active());
4022 /** @param yn true to follow playhead, otherwise false.
4023 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4026 Editor::set_follow_playhead (bool yn, bool catch_up)
4028 if (_follow_playhead != yn) {
4029 if ((_follow_playhead = yn) == true && catch_up) {
4031 reset_x_origin_to_follow_playhead ();
4038 Editor::toggle_stationary_playhead ()
4040 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4042 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4043 set_stationary_playhead (tact->get_active());
4048 Editor::set_stationary_playhead (bool yn)
4050 if (_stationary_playhead != yn) {
4051 if ((_stationary_playhead = yn) == true) {
4053 // FIXME need a 3.0 equivalent of this 2.X call
4054 // update_current_screen ();
4061 Editor::playlist_selector () const
4063 return *_playlist_selector;
4067 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4069 if (paste_count == 0) {
4070 /* don't bother calculating an offset that will be zero anyway */
4074 /* calculate basic unsnapped multi-paste offset */
4075 framecnt_t offset = paste_count * duration;
4077 /* snap offset so pos + offset is aligned to the grid */
4078 framepos_t offset_pos = pos + offset;
4079 snap_to(offset_pos, RoundUpMaybe);
4080 offset = offset_pos - pos;
4086 Editor::get_grid_beat_divisions(framepos_t position)
4088 switch (_snap_type) {
4089 case SnapToBeatDiv128: return 128;
4090 case SnapToBeatDiv64: return 64;
4091 case SnapToBeatDiv32: return 32;
4092 case SnapToBeatDiv28: return 28;
4093 case SnapToBeatDiv24: return 24;
4094 case SnapToBeatDiv20: return 20;
4095 case SnapToBeatDiv16: return 16;
4096 case SnapToBeatDiv14: return 14;
4097 case SnapToBeatDiv12: return 12;
4098 case SnapToBeatDiv10: return 10;
4099 case SnapToBeatDiv8: return 8;
4100 case SnapToBeatDiv7: return 7;
4101 case SnapToBeatDiv6: return 6;
4102 case SnapToBeatDiv5: return 5;
4103 case SnapToBeatDiv4: return 4;
4104 case SnapToBeatDiv3: return 3;
4105 case SnapToBeatDiv2: return 2;
4112 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4116 const unsigned divisions = get_grid_beat_divisions(position);
4118 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4121 switch (_snap_type) {
4123 return Evoral::Beats(1.0);
4126 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
4134 return Evoral::Beats();
4138 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4142 ret = nudge_clock->current_duration (pos);
4143 next = ret + 1; /* XXXX fix me */
4149 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4151 ArdourDialog dialog (_("Playlist Deletion"));
4152 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4153 "If it is kept, its audio files will not be cleaned.\n"
4154 "If it is deleted, audio files used by it alone will be cleaned."),
4157 dialog.set_position (WIN_POS_CENTER);
4158 dialog.get_vbox()->pack_start (label);
4162 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4163 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4164 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4165 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4166 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4168 // by default gtk uses the left most button
4169 keep->grab_focus ();
4171 switch (dialog.run ()) {
4173 /* keep this and all remaining ones */
4178 /* delete this and all others */
4182 case RESPONSE_ACCEPT:
4183 /* delete the playlist */
4187 case RESPONSE_REJECT:
4188 /* keep the playlist */
4200 Editor::audio_region_selection_covers (framepos_t where)
4202 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4203 if ((*a)->region()->covers (where)) {
4212 Editor::prepare_for_cleanup ()
4214 cut_buffer->clear_regions ();
4215 cut_buffer->clear_playlists ();
4217 selection->clear_regions ();
4218 selection->clear_playlists ();
4220 _regions->suspend_redisplay ();
4224 Editor::finish_cleanup ()
4226 _regions->resume_redisplay ();
4230 Editor::transport_loop_location()
4233 return _session->locations()->auto_loop_location();
4240 Editor::transport_punch_location()
4243 return _session->locations()->auto_punch_location();
4250 Editor::control_layout_scroll (GdkEventScroll* ev)
4252 /* Just forward to the normal canvas scroll method. The coordinate
4253 systems are different but since the canvas is always larger than the
4254 track headers, and aligned with the trackview area, this will work.
4256 In the not too distant future this layout is going away anyway and
4257 headers will be on the canvas.
4259 return canvas_scroll_event (ev, false);
4263 Editor::session_state_saved (string)
4266 _snapshots->redisplay ();
4270 Editor::update_tearoff_visibility()
4272 bool visible = UIConfiguration::instance().get_keep_tearoffs();
4273 _mouse_mode_tearoff->set_visible (visible);
4274 _tools_tearoff->set_visible (visible);
4275 if (_zoom_tearoff) {
4276 _zoom_tearoff->set_visible (visible);
4281 Editor::reattach_all_tearoffs ()
4283 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4284 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4285 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4289 Editor::maximise_editing_space ()
4301 Editor::restore_editing_space ()
4313 * Make new playlists for a given track and also any others that belong
4314 * to the same active route group with the `select' property.
4319 Editor::new_playlists (TimeAxisView* v)
4321 begin_reversible_command (_("new playlists"));
4322 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4323 _session->playlists->get (playlists);
4324 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4325 commit_reversible_command ();
4329 * Use a copy of the current playlist for a given track and also any others that belong
4330 * to the same active route group with the `select' property.
4335 Editor::copy_playlists (TimeAxisView* v)
4337 begin_reversible_command (_("copy playlists"));
4338 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4339 _session->playlists->get (playlists);
4340 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4341 commit_reversible_command ();
4344 /** Clear the current playlist for a given track and also any others that belong
4345 * to the same active route group with the `select' property.
4350 Editor::clear_playlists (TimeAxisView* v)
4352 begin_reversible_command (_("clear playlists"));
4353 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4354 _session->playlists->get (playlists);
4355 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4356 commit_reversible_command ();
4360 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4362 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4366 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4368 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4372 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4374 atv.clear_playlist ();
4378 Editor::on_key_press_event (GdkEventKey* ev)
4380 return key_press_focus_accelerator_handler (*this, ev);
4384 Editor::on_key_release_event (GdkEventKey* ev)
4386 return Gtk::Window::on_key_release_event (ev);
4387 // return key_press_focus_accelerator_handler (*this, ev);
4391 Editor::get_y_origin () const
4393 return vertical_adjustment.get_value ();
4396 /** Queue up a change to the viewport x origin.
4397 * @param frame New x origin.
4400 Editor::reset_x_origin (framepos_t frame)
4402 pending_visual_change.add (VisualChange::TimeOrigin);
4403 pending_visual_change.time_origin = frame;
4404 ensure_visual_change_idle_handler ();
4408 Editor::reset_y_origin (double y)
4410 pending_visual_change.add (VisualChange::YOrigin);
4411 pending_visual_change.y_origin = y;
4412 ensure_visual_change_idle_handler ();
4416 Editor::reset_zoom (framecnt_t spp)
4418 if (spp == samples_per_pixel) {
4422 pending_visual_change.add (VisualChange::ZoomLevel);
4423 pending_visual_change.samples_per_pixel = spp;
4424 ensure_visual_change_idle_handler ();
4428 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4430 reset_x_origin (frame);
4433 if (!no_save_visual) {
4434 undo_visual_stack.push_back (current_visual_state(false));
4438 Editor::VisualState::VisualState (bool with_tracks)
4439 : gui_state (with_tracks ? new GUIObjectState : 0)
4443 Editor::VisualState::~VisualState ()
4448 Editor::VisualState*
4449 Editor::current_visual_state (bool with_tracks)
4451 VisualState* vs = new VisualState (with_tracks);
4452 vs->y_position = vertical_adjustment.get_value();
4453 vs->samples_per_pixel = samples_per_pixel;
4454 vs->leftmost_frame = leftmost_frame;
4455 vs->zoom_focus = zoom_focus;
4458 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4465 Editor::undo_visual_state ()
4467 if (undo_visual_stack.empty()) {
4471 VisualState* vs = undo_visual_stack.back();
4472 undo_visual_stack.pop_back();
4475 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4478 use_visual_state (*vs);
4483 Editor::redo_visual_state ()
4485 if (redo_visual_stack.empty()) {
4489 VisualState* vs = redo_visual_stack.back();
4490 redo_visual_stack.pop_back();
4492 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4493 // why do we check here?
4494 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4497 use_visual_state (*vs);
4502 Editor::swap_visual_state ()
4504 if (undo_visual_stack.empty()) {
4505 redo_visual_state ();
4507 undo_visual_state ();
4512 Editor::use_visual_state (VisualState& vs)
4514 PBD::Unwinder<bool> nsv (no_save_visual, true);
4515 DisplaySuspender ds;
4517 vertical_adjustment.set_value (vs.y_position);
4519 set_zoom_focus (vs.zoom_focus);
4520 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4523 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4525 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4526 (*i)->clear_property_cache();
4527 (*i)->reset_visual_state ();
4531 _routes->update_visibility ();
4534 /** This is the core function that controls the zoom level of the canvas. It is called
4535 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4536 * @param spp new number of samples per pixel
4539 Editor::set_samples_per_pixel (framecnt_t spp)
4545 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4546 const framecnt_t lots_of_pixels = 4000;
4548 /* if the zoom level is greater than what you'd get trying to display 3
4549 * days of audio on a really big screen, then it's too big.
4552 if (spp * lots_of_pixels > three_days) {
4556 samples_per_pixel = spp;
4559 tempo_lines->tempo_map_changed();
4562 bool const showing_time_selection = selection->time.length() > 0;
4564 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4565 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4566 (*i)->reshow_selection (selection->time);
4570 ZoomChanged (); /* EMIT_SIGNAL */
4572 ArdourCanvas::GtkCanvasViewport* c;
4574 c = get_track_canvas();
4576 c->canvas()->zoomed ();
4579 if (playhead_cursor) {
4580 playhead_cursor->set_position (playhead_cursor->current_frame ());
4583 refresh_location_display();
4584 _summary->set_overlays_dirty ();
4586 update_marker_labels ();
4592 Editor::queue_visual_videotimeline_update ()
4595 * pending_visual_change.add (VisualChange::VideoTimeline);
4596 * or maybe even more specific: which videotimeline-image
4597 * currently it calls update_video_timeline() to update
4598 * _all outdated_ images on the video-timeline.
4599 * see 'exposeimg()' in video_image_frame.cc
4601 ensure_visual_change_idle_handler ();
4605 Editor::ensure_visual_change_idle_handler ()
4607 if (pending_visual_change.idle_handler_id < 0) {
4608 // see comment in add_to_idle_resize above.
4609 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4610 pending_visual_change.being_handled = false;
4615 Editor::_idle_visual_changer (void* arg)
4617 return static_cast<Editor*>(arg)->idle_visual_changer ();
4621 Editor::idle_visual_changer ()
4623 /* set_horizontal_position() below (and maybe other calls) call
4624 gtk_main_iteration(), so it's possible that a signal will be handled
4625 half-way through this method. If this signal wants an
4626 idle_visual_changer we must schedule another one after this one, so
4627 mark the idle_handler_id as -1 here to allow that. Also make a note
4628 that we are doing the visual change, so that changes in response to
4629 super-rapid-screen-update can be dropped if we are still processing
4633 pending_visual_change.idle_handler_id = -1;
4634 pending_visual_change.being_handled = true;
4636 VisualChange vc = pending_visual_change;
4638 pending_visual_change.pending = (VisualChange::Type) 0;
4640 visual_changer (vc);
4642 pending_visual_change.being_handled = false;
4644 return 0; /* this is always a one-shot call */
4648 Editor::visual_changer (const VisualChange& vc)
4650 double const last_time_origin = horizontal_position ();
4652 if (vc.pending & VisualChange::ZoomLevel) {
4653 set_samples_per_pixel (vc.samples_per_pixel);
4655 compute_fixed_ruler_scale ();
4657 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4658 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4660 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4661 current_bbt_points_begin, current_bbt_points_end);
4662 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4663 current_bbt_points_begin, current_bbt_points_end);
4664 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4666 update_video_timeline();
4669 if (vc.pending & VisualChange::TimeOrigin) {
4670 set_horizontal_position (vc.time_origin / samples_per_pixel);
4673 if (vc.pending & VisualChange::YOrigin) {
4674 vertical_adjustment.set_value (vc.y_origin);
4677 if (last_time_origin == horizontal_position ()) {
4678 /* changed signal not emitted */
4679 update_fixed_rulers ();
4680 redisplay_tempo (true);
4683 if (!(vc.pending & VisualChange::ZoomLevel)) {
4684 update_video_timeline();
4687 _summary->set_overlays_dirty ();
4690 struct EditorOrderTimeAxisSorter {
4691 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4692 return a->order () < b->order ();
4697 Editor::sort_track_selection (TrackViewList& sel)
4699 EditorOrderTimeAxisSorter cmp;
4704 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4707 framepos_t where = 0;
4708 EditPoint ep = _edit_point;
4710 if (Profile->get_mixbus())
4711 if (ep == EditAtSelectedMarker)
4712 ep = EditAtPlayhead;
4714 if (from_outside_canvas && (ep == EditAtMouse)) {
4715 ep = EditAtPlayhead;
4716 } else if (from_context_menu && (ep == EditAtMouse)) {
4717 return canvas_event_sample (&context_click_event, 0, 0);
4720 if (entered_marker) {
4721 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4722 return entered_marker->position();
4725 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4726 ep = EditAtSelectedMarker;
4729 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4730 ep = EditAtPlayhead;
4734 case EditAtPlayhead:
4735 if (_dragging_playhead) {
4736 if (!mouse_frame (where, ignored)) {
4737 /* XXX not right but what can we do ? */
4741 where = _session->audible_frame();
4743 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4746 case EditAtSelectedMarker:
4747 if (!selection->markers.empty()) {
4749 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4752 where = loc->start();
4756 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4764 if (!mouse_frame (where, ignored)) {
4765 /* XXX not right but what can we do ? */
4769 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4777 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4779 if (!_session) return;
4781 begin_reversible_command (cmd);
4785 if ((tll = transport_loop_location()) == 0) {
4786 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4787 XMLNode &before = _session->locations()->get_state();
4788 _session->locations()->add (loc, true);
4789 _session->set_auto_loop_location (loc);
4790 XMLNode &after = _session->locations()->get_state();
4791 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4793 XMLNode &before = tll->get_state();
4794 tll->set_hidden (false, this);
4795 tll->set (start, end);
4796 XMLNode &after = tll->get_state();
4797 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4800 commit_reversible_command ();
4804 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4806 if (!_session) return;
4808 begin_reversible_command (cmd);
4812 if ((tpl = transport_punch_location()) == 0) {
4813 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4814 XMLNode &before = _session->locations()->get_state();
4815 _session->locations()->add (loc, true);
4816 _session->set_auto_punch_location (loc);
4817 XMLNode &after = _session->locations()->get_state();
4818 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4820 XMLNode &before = tpl->get_state();
4821 tpl->set_hidden (false, this);
4822 tpl->set (start, end);
4823 XMLNode &after = tpl->get_state();
4824 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4827 commit_reversible_command ();
4830 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4831 * @param rs List to which found regions are added.
4832 * @param where Time to look at.
4833 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4836 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4838 const TrackViewList* tracks;
4841 tracks = &track_views;
4846 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4848 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4851 boost::shared_ptr<Track> tr;
4852 boost::shared_ptr<Playlist> pl;
4854 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4856 boost::shared_ptr<RegionList> regions = pl->regions_at (
4857 (framepos_t) floor ( (double) where * tr->speed()));
4859 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4860 RegionView* rv = rtv->view()->find_view (*i);
4871 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4873 const TrackViewList* tracks;
4876 tracks = &track_views;
4881 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4882 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4884 boost::shared_ptr<Track> tr;
4885 boost::shared_ptr<Playlist> pl;
4887 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4889 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4890 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4892 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4894 RegionView* rv = rtv->view()->find_view (*i);
4905 /** Get regions using the following method:
4907 * Make a region list using:
4908 * (a) any selected regions
4909 * (b) the intersection of any selected tracks and the edit point(*)
4910 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4912 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4914 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4918 Editor::get_regions_from_selection_and_edit_point ()
4920 RegionSelection regions;
4922 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4923 regions.add (entered_regionview);
4925 regions = selection->regions;
4928 if ( regions.empty() ) {
4929 TrackViewList tracks = selection->tracks;
4931 if (!tracks.empty()) {
4932 /* no region selected or entered, but some selected tracks:
4933 * act on all regions on the selected tracks at the edit point
4935 framepos_t const where = get_preferred_edit_position ();
4936 get_regions_at(regions, where, tracks);
4943 /** Get regions using the following method:
4945 * Make a region list using:
4946 * (a) any selected regions
4947 * (b) the intersection of any selected tracks and the edit point(*)
4948 * (c) if neither exists, then whatever region is under the mouse
4950 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4952 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4955 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4957 RegionSelection regions;
4959 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4960 regions.add (entered_regionview);
4962 regions = selection->regions;
4965 if ( regions.empty() ) {
4966 TrackViewList tracks = selection->tracks;
4968 if (!tracks.empty()) {
4969 /* no region selected or entered, but some selected tracks:
4970 * act on all regions on the selected tracks at the edit point
4972 get_regions_at(regions, pos, tracks);
4979 /** Start with regions that are selected, or the entered regionview if none are selected.
4980 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4981 * of the regions that we started with.
4985 Editor::get_regions_from_selection_and_entered ()
4987 RegionSelection regions = selection->regions;
4989 if (regions.empty() && entered_regionview) {
4990 regions.add (entered_regionview);
4997 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4999 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5000 RouteTimeAxisView* rtav;
5002 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5003 boost::shared_ptr<Playlist> pl;
5004 std::vector<boost::shared_ptr<Region> > results;
5005 boost::shared_ptr<Track> tr;
5007 if ((tr = rtav->track()) == 0) {
5012 if ((pl = (tr->playlist())) != 0) {
5013 boost::shared_ptr<Region> r = pl->region_by_id (id);
5015 RegionView* rv = rtav->view()->find_view (r);
5017 regions.push_back (rv);
5026 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5029 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5030 MidiTimeAxisView* mtav;
5032 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5034 mtav->get_per_region_note_selection (selection);
5041 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5043 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5045 RouteTimeAxisView* tatv;
5047 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5049 boost::shared_ptr<Playlist> pl;
5050 vector<boost::shared_ptr<Region> > results;
5052 boost::shared_ptr<Track> tr;
5054 if ((tr = tatv->track()) == 0) {
5059 if ((pl = (tr->playlist())) != 0) {
5060 if (src_comparison) {
5061 pl->get_source_equivalent_regions (region, results);
5063 pl->get_region_list_equivalent_regions (region, results);
5067 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5068 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5069 regions.push_back (marv);
5078 Editor::show_rhythm_ferret ()
5080 if (rhythm_ferret == 0) {
5081 rhythm_ferret = new RhythmFerret(*this);
5084 rhythm_ferret->set_session (_session);
5085 rhythm_ferret->show ();
5086 rhythm_ferret->present ();
5090 Editor::first_idle ()
5092 MessageDialog* dialog = 0;
5094 if (track_views.size() > 1) {
5095 Timers::TimerSuspender t;
5096 dialog = new MessageDialog (
5098 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5102 ARDOUR_UI::instance()->flush_pending ();
5105 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5109 // first idle adds route children (automation tracks), so we need to redisplay here
5110 _routes->redisplay ();
5114 if (_session->undo_depth() == 0) {
5115 undo_action->set_sensitive(false);
5117 redo_action->set_sensitive(false);
5118 begin_selection_op_history ();
5124 Editor::_idle_resize (gpointer arg)
5126 return ((Editor*)arg)->idle_resize ();
5130 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5132 if (resize_idle_id < 0) {
5133 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5134 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5135 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5137 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5138 _pending_resize_amount = 0;
5141 /* make a note of the smallest resulting height, so that we can clamp the
5142 lower limit at TimeAxisView::hSmall */
5144 int32_t min_resulting = INT32_MAX;
5146 _pending_resize_amount += h;
5147 _pending_resize_view = view;
5149 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5151 if (selection->tracks.contains (_pending_resize_view)) {
5152 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5153 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5157 if (min_resulting < 0) {
5162 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5163 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5167 /** Handle pending resizing of tracks */
5169 Editor::idle_resize ()
5171 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5173 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5174 selection->tracks.contains (_pending_resize_view)) {
5176 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5177 if (*i != _pending_resize_view) {
5178 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5183 _pending_resize_amount = 0;
5184 _group_tabs->set_dirty ();
5185 resize_idle_id = -1;
5193 ENSURE_GUI_THREAD (*this, &Editor::located);
5196 playhead_cursor->set_position (_session->audible_frame ());
5197 if (_follow_playhead && !_pending_initial_locate) {
5198 reset_x_origin_to_follow_playhead ();
5202 _pending_locate_request = false;
5203 _pending_initial_locate = false;
5207 Editor::region_view_added (RegionView * rv)
5209 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5210 if (rv->region ()->id () == (*pr)) {
5211 selection->add (rv);
5212 selection->regions.pending.erase (pr);
5217 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5219 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5220 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5221 if (rv->region()->id () == (*rnote).first) {
5222 mrv->select_notes ((*rnote).second);
5223 selection->pending_midi_note_selection.erase(rnote);
5229 _summary->set_background_dirty ();
5233 Editor::region_view_removed ()
5235 _summary->set_background_dirty ();
5239 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5241 TrackViewList::const_iterator j = track_views.begin ();
5242 while (j != track_views.end()) {
5243 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5244 if (rtv && rtv->route() == r) {
5255 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5259 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5260 TimeAxisView* tv = axis_view_from_route (*i);
5270 Editor::suspend_route_redisplay ()
5273 _routes->suspend_redisplay();
5278 Editor::resume_route_redisplay ()
5281 _routes->redisplay(); // queue redisplay
5282 _routes->resume_redisplay();
5287 Editor::add_routes (RouteList& routes)
5289 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5291 RouteTimeAxisView *rtv;
5292 list<RouteTimeAxisView*> new_views;
5293 TrackViewList new_selection;
5294 bool from_scratch = (track_views.size() == 0);
5296 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5297 boost::shared_ptr<Route> route = (*x);
5299 if (route->is_auditioner() || route->is_monitor()) {
5303 DataType dt = route->input()->default_type();
5305 if (dt == ARDOUR::DataType::AUDIO) {
5306 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5307 rtv->set_route (route);
5308 } else if (dt == ARDOUR::DataType::MIDI) {
5309 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5310 rtv->set_route (route);
5312 throw unknown_type();
5315 new_views.push_back (rtv);
5316 track_views.push_back (rtv);
5317 new_selection.push_back (rtv);
5319 rtv->effective_gain_display ();
5321 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5322 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5325 if (new_views.size() > 0) {
5326 _routes->routes_added (new_views);
5327 _summary->routes_added (new_views);
5330 if (!from_scratch) {
5331 selection->tracks.clear();
5332 selection->add (new_selection);
5333 begin_selection_op_history();
5336 if (show_editor_mixer_when_tracks_arrive) {
5337 show_editor_mixer (true);
5340 editor_list_button.set_sensitive (true);
5344 Editor::timeaxisview_deleted (TimeAxisView *tv)
5346 if (tv == entered_track) {
5350 if (_session && _session->deletion_in_progress()) {
5351 /* the situation is under control */
5355 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5357 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5359 _routes->route_removed (tv);
5361 TimeAxisView::Children c = tv->get_child_list ();
5362 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5363 if (entered_track == i->get()) {
5368 /* remove it from the list of track views */
5370 TrackViewList::iterator i;
5372 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5373 i = track_views.erase (i);
5376 /* update whatever the current mixer strip is displaying, if revelant */
5378 boost::shared_ptr<Route> route;
5381 route = rtav->route ();
5384 if (current_mixer_strip && current_mixer_strip->route() == route) {
5386 TimeAxisView* next_tv;
5388 if (track_views.empty()) {
5390 } else if (i == track_views.end()) {
5391 next_tv = track_views.front();
5398 set_selected_mixer_strip (*next_tv);
5400 /* make the editor mixer strip go away setting the
5401 * button to inactive (which also unticks the menu option)
5404 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5410 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5412 if (apply_to_selection) {
5413 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5415 TrackSelection::iterator j = i;
5418 hide_track_in_display (*i, false);
5423 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5425 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5426 // this will hide the mixer strip
5427 set_selected_mixer_strip (*tv);
5430 _routes->hide_track_in_display (*tv);
5435 Editor::sync_track_view_list_and_routes ()
5437 track_views = TrackViewList (_routes->views ());
5439 _summary->set_background_dirty();
5440 _group_tabs->set_dirty ();
5442 return false; // do not call again (until needed)
5446 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5448 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5453 /** Find a RouteTimeAxisView by the ID of its route */
5455 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5457 RouteTimeAxisView* v;
5459 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5460 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5461 if(v->route()->id() == id) {
5471 Editor::fit_route_group (RouteGroup *g)
5473 TrackViewList ts = axis_views_from_routes (g->route_list ());
5478 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5480 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5483 _session->cancel_audition ();
5487 if (_session->is_auditioning()) {
5488 _session->cancel_audition ();
5489 if (r == last_audition_region) {
5494 _session->audition_region (r);
5495 last_audition_region = r;
5500 Editor::hide_a_region (boost::shared_ptr<Region> r)
5502 r->set_hidden (true);
5506 Editor::show_a_region (boost::shared_ptr<Region> r)
5508 r->set_hidden (false);
5512 Editor::audition_region_from_region_list ()
5514 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5518 Editor::hide_region_from_region_list ()
5520 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5524 Editor::show_region_in_region_list ()
5526 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5530 Editor::step_edit_status_change (bool yn)
5533 start_step_editing ();
5535 stop_step_editing ();
5540 Editor::start_step_editing ()
5542 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5546 Editor::stop_step_editing ()
5548 step_edit_connection.disconnect ();
5552 Editor::check_step_edit ()
5554 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5555 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5557 mtv->check_step_edit ();
5561 return true; // do it again, till we stop
5565 Editor::scroll_press (Direction dir)
5567 ++_scroll_callbacks;
5569 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5570 /* delay the first auto-repeat */
5576 scroll_backward (1);
5584 scroll_up_one_track ();
5588 scroll_down_one_track ();
5592 /* do hacky auto-repeat */
5593 if (!_scroll_connection.connected ()) {
5595 _scroll_connection = Glib::signal_timeout().connect (
5596 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5599 _scroll_callbacks = 0;
5606 Editor::scroll_release ()
5608 _scroll_connection.disconnect ();
5611 /** Queue a change for the Editor viewport x origin to follow the playhead */
5613 Editor::reset_x_origin_to_follow_playhead ()
5615 framepos_t const frame = playhead_cursor->current_frame ();
5617 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5619 if (_session->transport_speed() < 0) {
5621 if (frame > (current_page_samples() / 2)) {
5622 center_screen (frame-(current_page_samples()/2));
5624 center_screen (current_page_samples()/2);
5631 if (frame < leftmost_frame) {
5633 if (_session->transport_rolling()) {
5634 /* rolling; end up with the playhead at the right of the page */
5635 l = frame - current_page_samples ();
5637 /* not rolling: end up with the playhead 1/4 of the way along the page */
5638 l = frame - current_page_samples() / 4;
5642 if (_session->transport_rolling()) {
5643 /* rolling: end up with the playhead on the left of the page */
5646 /* not rolling: end up with the playhead 3/4 of the way along the page */
5647 l = frame - 3 * current_page_samples() / 4;
5655 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5661 Editor::super_rapid_screen_update ()
5663 if (!_session || !_session->engine().running()) {
5667 /* METERING / MIXER STRIPS */
5669 /* update track meters, if required */
5670 if (is_mapped() && meters_running) {
5671 RouteTimeAxisView* rtv;
5672 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5673 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5674 rtv->fast_update ();
5679 /* and any current mixer strip */
5680 if (current_mixer_strip) {
5681 current_mixer_strip->fast_update ();
5684 /* PLAYHEAD AND VIEWPORT */
5686 framepos_t const frame = _session->audible_frame();
5688 /* There are a few reasons why we might not update the playhead / viewport stuff:
5690 * 1. we don't update things when there's a pending locate request, otherwise
5691 * when the editor requests a locate there is a chance that this method
5692 * will move the playhead before the locate request is processed, causing
5694 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5695 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5698 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5700 last_update_frame = frame;
5702 if (!_dragging_playhead) {
5703 playhead_cursor->set_position (frame);
5706 if (!_stationary_playhead) {
5708 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5709 /* We only do this if we aren't already
5710 handling a visual change (ie if
5711 pending_visual_change.being_handled is
5712 false) so that these requests don't stack
5713 up there are too many of them to handle in
5716 reset_x_origin_to_follow_playhead ();
5721 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5722 framepos_t const frame = playhead_cursor->current_frame ();
5723 double target = ((double)frame - (double)current_page_samples()/3.0);
5724 if (target <= 0.0) {
5727 // compare to EditorCursor::set_position()
5728 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5729 double const new_pos = sample_to_pixel_unrounded (target);
5730 if (rint (new_pos) != rint (old_pos)) {
5731 reset_x_origin (pixel_to_sample (floor (new_pos)));
5742 Editor::session_going_away ()
5744 _have_idled = false;
5746 _session_connections.drop_connections ();
5748 super_rapid_screen_update_connection.disconnect ();
5750 selection->clear ();
5751 cut_buffer->clear ();
5753 clicked_regionview = 0;
5754 clicked_axisview = 0;
5755 clicked_routeview = 0;
5756 entered_regionview = 0;
5758 last_update_frame = 0;
5761 playhead_cursor->hide ();
5763 /* rip everything out of the list displays */
5767 _route_groups->clear ();
5769 /* do this first so that deleting a track doesn't reset cms to null
5770 and thus cause a leak.
5773 if (current_mixer_strip) {
5774 if (current_mixer_strip->get_parent() != 0) {
5775 global_hpacker.remove (*current_mixer_strip);
5777 delete current_mixer_strip;
5778 current_mixer_strip = 0;
5781 /* delete all trackviews */
5783 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5786 track_views.clear ();
5788 nudge_clock->set_session (0);
5790 editor_list_button.set_active(false);
5791 editor_list_button.set_sensitive(false);
5793 /* clear tempo/meter rulers */
5794 remove_metric_marks ();
5796 clear_marker_display ();
5798 stop_step_editing ();
5800 /* get rid of any existing editor mixer strip */
5802 WindowTitle title(Glib::get_application_name());
5803 title += _("Editor");
5805 set_title (title.get_string());
5807 SessionHandlePtr::session_going_away ();
5812 Editor::show_editor_list (bool yn)
5815 _the_notebook.show ();
5817 _the_notebook.hide ();
5822 Editor::change_region_layering_order (bool from_context_menu)
5824 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5826 if (!clicked_routeview) {
5827 if (layering_order_editor) {
5828 layering_order_editor->hide ();
5833 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5839 boost::shared_ptr<Playlist> pl = track->playlist();
5845 if (layering_order_editor == 0) {
5846 layering_order_editor = new RegionLayeringOrderEditor (*this);
5849 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5850 layering_order_editor->maybe_present ();
5854 Editor::update_region_layering_order_editor ()
5856 if (layering_order_editor && layering_order_editor->is_visible ()) {
5857 change_region_layering_order (true);
5862 Editor::setup_fade_images ()
5864 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5865 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5866 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5867 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5868 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5870 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5871 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5872 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5873 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5874 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5876 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5877 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5878 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5879 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5880 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5882 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5883 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5884 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5885 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5886 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5890 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5892 Editor::action_menu_item (std::string const & name)
5894 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5897 return *manage (a->create_menu_item ());
5901 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5903 EventBox* b = manage (new EventBox);
5904 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5905 Label* l = manage (new Label (name));
5909 _the_notebook.append_page (widget, *b);
5913 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5915 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5916 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5919 if (ev->type == GDK_2BUTTON_PRESS) {
5921 /* double-click on a notebook tab shrinks or expands the notebook */
5923 if (_notebook_shrunk) {
5924 if (pre_notebook_shrink_pane_width) {
5925 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5927 _notebook_shrunk = false;
5929 pre_notebook_shrink_pane_width = edit_pane.get_position();
5931 /* this expands the LHS of the edit pane to cover the notebook
5932 PAGE but leaves the tabs visible.
5934 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5935 _notebook_shrunk = true;
5943 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5945 using namespace Menu_Helpers;
5947 MenuList& items = _control_point_context_menu.items ();
5950 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5951 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5952 if (!can_remove_control_point (item)) {
5953 items.back().set_sensitive (false);
5956 _control_point_context_menu.popup (event->button.button, event->button.time);
5960 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5962 using namespace Menu_Helpers;
5964 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5969 /* We need to get the selection here and pass it to the operations, since
5970 popping up the menu will cause a region leave event which clears
5971 entered_regionview. */
5973 MidiRegionView& mrv = note->region_view();
5974 const RegionSelection rs = get_regions_from_selection_and_entered ();
5975 const uint32_t sel_size = mrv.selection_size ();
5977 MenuList& items = _note_context_menu.items();
5981 items.push_back(MenuElem(_("Delete"),
5982 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5985 items.push_back(MenuElem(_("Edit..."),
5986 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5987 if (sel_size != 1) {
5988 items.back().set_sensitive (false);
5991 items.push_back(MenuElem(_("Transpose..."),
5992 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
5995 items.push_back(MenuElem(_("Legatize"),
5996 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5998 items.back().set_sensitive (false);
6001 items.push_back(MenuElem(_("Quantize..."),
6002 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6004 items.push_back(MenuElem(_("Remove Overlap"),
6005 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6007 items.back().set_sensitive (false);
6010 items.push_back(MenuElem(_("Transform..."),
6011 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6013 _note_context_menu.popup (event->button.button, event->button.time);
6017 Editor::zoom_vertical_modifier_released()
6019 _stepping_axis_view = 0;
6023 Editor::ui_parameter_changed (string parameter)
6025 if (parameter == "icon-set") {
6026 while (!_cursor_stack.empty()) {
6027 _cursor_stack.pop_back();
6029 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6030 _cursor_stack.push_back(_cursors->grabber);
6031 } else if (parameter == "draggable-playhead") {
6032 if (_verbose_cursor) {
6033 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());