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 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4165 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4166 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4168 switch (dialog.run ()) {
4170 /* keep this and all remaining ones */
4175 /* delete this and all others */
4179 case RESPONSE_ACCEPT:
4180 /* delete the playlist */
4184 case RESPONSE_REJECT:
4185 /* keep the playlist */
4197 Editor::audio_region_selection_covers (framepos_t where)
4199 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4200 if ((*a)->region()->covers (where)) {
4209 Editor::prepare_for_cleanup ()
4211 cut_buffer->clear_regions ();
4212 cut_buffer->clear_playlists ();
4214 selection->clear_regions ();
4215 selection->clear_playlists ();
4217 _regions->suspend_redisplay ();
4221 Editor::finish_cleanup ()
4223 _regions->resume_redisplay ();
4227 Editor::transport_loop_location()
4230 return _session->locations()->auto_loop_location();
4237 Editor::transport_punch_location()
4240 return _session->locations()->auto_punch_location();
4247 Editor::control_layout_scroll (GdkEventScroll* ev)
4249 /* Just forward to the normal canvas scroll method. The coordinate
4250 systems are different but since the canvas is always larger than the
4251 track headers, and aligned with the trackview area, this will work.
4253 In the not too distant future this layout is going away anyway and
4254 headers will be on the canvas.
4256 return canvas_scroll_event (ev, false);
4260 Editor::session_state_saved (string)
4263 _snapshots->redisplay ();
4267 Editor::update_tearoff_visibility()
4269 bool visible = UIConfiguration::instance().get_keep_tearoffs();
4270 _mouse_mode_tearoff->set_visible (visible);
4271 _tools_tearoff->set_visible (visible);
4272 if (_zoom_tearoff) {
4273 _zoom_tearoff->set_visible (visible);
4278 Editor::reattach_all_tearoffs ()
4280 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4281 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4282 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4286 Editor::maximise_editing_space ()
4298 Editor::restore_editing_space ()
4310 * Make new playlists for a given track and also any others that belong
4311 * to the same active route group with the `select' property.
4316 Editor::new_playlists (TimeAxisView* v)
4318 begin_reversible_command (_("new playlists"));
4319 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4320 _session->playlists->get (playlists);
4321 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4322 commit_reversible_command ();
4326 * Use a copy of the current playlist for a given track and also any others that belong
4327 * to the same active route group with the `select' property.
4332 Editor::copy_playlists (TimeAxisView* v)
4334 begin_reversible_command (_("copy playlists"));
4335 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4336 _session->playlists->get (playlists);
4337 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4338 commit_reversible_command ();
4341 /** Clear the current playlist for a given track and also any others that belong
4342 * to the same active route group with the `select' property.
4347 Editor::clear_playlists (TimeAxisView* v)
4349 begin_reversible_command (_("clear playlists"));
4350 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4351 _session->playlists->get (playlists);
4352 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4353 commit_reversible_command ();
4357 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4359 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4363 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4365 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4369 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4371 atv.clear_playlist ();
4375 Editor::on_key_press_event (GdkEventKey* ev)
4377 return key_press_focus_accelerator_handler (*this, ev);
4381 Editor::on_key_release_event (GdkEventKey* ev)
4383 return Gtk::Window::on_key_release_event (ev);
4384 // return key_press_focus_accelerator_handler (*this, ev);
4388 Editor::get_y_origin () const
4390 return vertical_adjustment.get_value ();
4393 /** Queue up a change to the viewport x origin.
4394 * @param frame New x origin.
4397 Editor::reset_x_origin (framepos_t frame)
4399 pending_visual_change.add (VisualChange::TimeOrigin);
4400 pending_visual_change.time_origin = frame;
4401 ensure_visual_change_idle_handler ();
4405 Editor::reset_y_origin (double y)
4407 pending_visual_change.add (VisualChange::YOrigin);
4408 pending_visual_change.y_origin = y;
4409 ensure_visual_change_idle_handler ();
4413 Editor::reset_zoom (framecnt_t spp)
4415 if (spp == samples_per_pixel) {
4419 pending_visual_change.add (VisualChange::ZoomLevel);
4420 pending_visual_change.samples_per_pixel = spp;
4421 ensure_visual_change_idle_handler ();
4425 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4427 reset_x_origin (frame);
4430 if (!no_save_visual) {
4431 undo_visual_stack.push_back (current_visual_state(false));
4435 Editor::VisualState::VisualState (bool with_tracks)
4436 : gui_state (with_tracks ? new GUIObjectState : 0)
4440 Editor::VisualState::~VisualState ()
4445 Editor::VisualState*
4446 Editor::current_visual_state (bool with_tracks)
4448 VisualState* vs = new VisualState (with_tracks);
4449 vs->y_position = vertical_adjustment.get_value();
4450 vs->samples_per_pixel = samples_per_pixel;
4451 vs->leftmost_frame = leftmost_frame;
4452 vs->zoom_focus = zoom_focus;
4455 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4462 Editor::undo_visual_state ()
4464 if (undo_visual_stack.empty()) {
4468 VisualState* vs = undo_visual_stack.back();
4469 undo_visual_stack.pop_back();
4472 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4475 use_visual_state (*vs);
4480 Editor::redo_visual_state ()
4482 if (redo_visual_stack.empty()) {
4486 VisualState* vs = redo_visual_stack.back();
4487 redo_visual_stack.pop_back();
4489 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4490 // why do we check here?
4491 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4494 use_visual_state (*vs);
4499 Editor::swap_visual_state ()
4501 if (undo_visual_stack.empty()) {
4502 redo_visual_state ();
4504 undo_visual_state ();
4509 Editor::use_visual_state (VisualState& vs)
4511 PBD::Unwinder<bool> nsv (no_save_visual, true);
4512 DisplaySuspender ds;
4514 vertical_adjustment.set_value (vs.y_position);
4516 set_zoom_focus (vs.zoom_focus);
4517 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4520 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4522 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4523 (*i)->clear_property_cache();
4524 (*i)->reset_visual_state ();
4528 _routes->update_visibility ();
4531 /** This is the core function that controls the zoom level of the canvas. It is called
4532 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4533 * @param spp new number of samples per pixel
4536 Editor::set_samples_per_pixel (framecnt_t spp)
4542 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4543 const framecnt_t lots_of_pixels = 4000;
4545 /* if the zoom level is greater than what you'd get trying to display 3
4546 * days of audio on a really big screen, then it's too big.
4549 if (spp * lots_of_pixels > three_days) {
4553 samples_per_pixel = spp;
4556 tempo_lines->tempo_map_changed();
4559 bool const showing_time_selection = selection->time.length() > 0;
4561 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4562 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4563 (*i)->reshow_selection (selection->time);
4567 ZoomChanged (); /* EMIT_SIGNAL */
4569 ArdourCanvas::GtkCanvasViewport* c;
4571 c = get_track_canvas();
4573 c->canvas()->zoomed ();
4576 if (playhead_cursor) {
4577 playhead_cursor->set_position (playhead_cursor->current_frame ());
4580 refresh_location_display();
4581 _summary->set_overlays_dirty ();
4583 update_marker_labels ();
4589 Editor::queue_visual_videotimeline_update ()
4592 * pending_visual_change.add (VisualChange::VideoTimeline);
4593 * or maybe even more specific: which videotimeline-image
4594 * currently it calls update_video_timeline() to update
4595 * _all outdated_ images on the video-timeline.
4596 * see 'exposeimg()' in video_image_frame.cc
4598 ensure_visual_change_idle_handler ();
4602 Editor::ensure_visual_change_idle_handler ()
4604 if (pending_visual_change.idle_handler_id < 0) {
4605 // see comment in add_to_idle_resize above.
4606 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4607 pending_visual_change.being_handled = false;
4612 Editor::_idle_visual_changer (void* arg)
4614 return static_cast<Editor*>(arg)->idle_visual_changer ();
4618 Editor::idle_visual_changer ()
4620 /* set_horizontal_position() below (and maybe other calls) call
4621 gtk_main_iteration(), so it's possible that a signal will be handled
4622 half-way through this method. If this signal wants an
4623 idle_visual_changer we must schedule another one after this one, so
4624 mark the idle_handler_id as -1 here to allow that. Also make a note
4625 that we are doing the visual change, so that changes in response to
4626 super-rapid-screen-update can be dropped if we are still processing
4630 pending_visual_change.idle_handler_id = -1;
4631 pending_visual_change.being_handled = true;
4633 VisualChange vc = pending_visual_change;
4635 pending_visual_change.pending = (VisualChange::Type) 0;
4637 visual_changer (vc);
4639 pending_visual_change.being_handled = false;
4641 return 0; /* this is always a one-shot call */
4645 Editor::visual_changer (const VisualChange& vc)
4647 double const last_time_origin = horizontal_position ();
4649 if (vc.pending & VisualChange::ZoomLevel) {
4650 set_samples_per_pixel (vc.samples_per_pixel);
4652 compute_fixed_ruler_scale ();
4654 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4655 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4657 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4658 current_bbt_points_begin, current_bbt_points_end);
4659 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4660 current_bbt_points_begin, current_bbt_points_end);
4661 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4663 update_video_timeline();
4666 if (vc.pending & VisualChange::TimeOrigin) {
4667 set_horizontal_position (vc.time_origin / samples_per_pixel);
4670 if (vc.pending & VisualChange::YOrigin) {
4671 vertical_adjustment.set_value (vc.y_origin);
4674 if (last_time_origin == horizontal_position ()) {
4675 /* changed signal not emitted */
4676 update_fixed_rulers ();
4677 redisplay_tempo (true);
4680 if (!(vc.pending & VisualChange::ZoomLevel)) {
4681 update_video_timeline();
4684 _summary->set_overlays_dirty ();
4687 struct EditorOrderTimeAxisSorter {
4688 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4689 return a->order () < b->order ();
4694 Editor::sort_track_selection (TrackViewList& sel)
4696 EditorOrderTimeAxisSorter cmp;
4701 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4704 framepos_t where = 0;
4705 EditPoint ep = _edit_point;
4707 if (Profile->get_mixbus())
4708 if (ep == EditAtSelectedMarker)
4709 ep = EditAtPlayhead;
4711 if (from_outside_canvas && (ep == EditAtMouse)) {
4712 ep = EditAtPlayhead;
4713 } else if (from_context_menu && (ep == EditAtMouse)) {
4714 return canvas_event_sample (&context_click_event, 0, 0);
4717 if (entered_marker) {
4718 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4719 return entered_marker->position();
4722 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4723 ep = EditAtSelectedMarker;
4726 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4727 ep = EditAtPlayhead;
4731 case EditAtPlayhead:
4732 if (_dragging_playhead) {
4733 if (!mouse_frame (where, ignored)) {
4734 /* XXX not right but what can we do ? */
4738 where = _session->audible_frame();
4740 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4743 case EditAtSelectedMarker:
4744 if (!selection->markers.empty()) {
4746 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4749 where = loc->start();
4753 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4761 if (!mouse_frame (where, ignored)) {
4762 /* XXX not right but what can we do ? */
4766 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4774 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4776 if (!_session) return;
4778 begin_reversible_command (cmd);
4782 if ((tll = transport_loop_location()) == 0) {
4783 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4784 XMLNode &before = _session->locations()->get_state();
4785 _session->locations()->add (loc, true);
4786 _session->set_auto_loop_location (loc);
4787 XMLNode &after = _session->locations()->get_state();
4788 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4790 XMLNode &before = tll->get_state();
4791 tll->set_hidden (false, this);
4792 tll->set (start, end);
4793 XMLNode &after = tll->get_state();
4794 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4797 commit_reversible_command ();
4801 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4803 if (!_session) return;
4805 begin_reversible_command (cmd);
4809 if ((tpl = transport_punch_location()) == 0) {
4810 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4811 XMLNode &before = _session->locations()->get_state();
4812 _session->locations()->add (loc, true);
4813 _session->set_auto_punch_location (loc);
4814 XMLNode &after = _session->locations()->get_state();
4815 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4817 XMLNode &before = tpl->get_state();
4818 tpl->set_hidden (false, this);
4819 tpl->set (start, end);
4820 XMLNode &after = tpl->get_state();
4821 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4824 commit_reversible_command ();
4827 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4828 * @param rs List to which found regions are added.
4829 * @param where Time to look at.
4830 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4833 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4835 const TrackViewList* tracks;
4838 tracks = &track_views;
4843 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4845 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4848 boost::shared_ptr<Track> tr;
4849 boost::shared_ptr<Playlist> pl;
4851 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4853 boost::shared_ptr<RegionList> regions = pl->regions_at (
4854 (framepos_t) floor ( (double) where * tr->speed()));
4856 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4857 RegionView* rv = rtv->view()->find_view (*i);
4868 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4870 const TrackViewList* tracks;
4873 tracks = &track_views;
4878 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4879 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4881 boost::shared_ptr<Track> tr;
4882 boost::shared_ptr<Playlist> pl;
4884 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4886 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4887 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4889 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4891 RegionView* rv = rtv->view()->find_view (*i);
4902 /** Get regions using the following method:
4904 * Make a region list using:
4905 * (a) any selected regions
4906 * (b) the intersection of any selected tracks and the edit point(*)
4907 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4909 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4911 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4915 Editor::get_regions_from_selection_and_edit_point ()
4917 RegionSelection regions;
4919 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4920 regions.add (entered_regionview);
4922 regions = selection->regions;
4925 if ( regions.empty() ) {
4926 TrackViewList tracks = selection->tracks;
4928 if (!tracks.empty()) {
4929 /* no region selected or entered, but some selected tracks:
4930 * act on all regions on the selected tracks at the edit point
4932 framepos_t const where = get_preferred_edit_position ();
4933 get_regions_at(regions, where, tracks);
4940 /** Get regions using the following method:
4942 * Make a region list using:
4943 * (a) any selected regions
4944 * (b) the intersection of any selected tracks and the edit point(*)
4945 * (c) if neither exists, then whatever region is under the mouse
4947 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4949 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4952 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4954 RegionSelection regions;
4956 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4957 regions.add (entered_regionview);
4959 regions = selection->regions;
4962 if ( regions.empty() ) {
4963 TrackViewList tracks = selection->tracks;
4965 if (!tracks.empty()) {
4966 /* no region selected or entered, but some selected tracks:
4967 * act on all regions on the selected tracks at the edit point
4969 get_regions_at(regions, pos, tracks);
4976 /** Start with regions that are selected, or the entered regionview if none are selected.
4977 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4978 * of the regions that we started with.
4982 Editor::get_regions_from_selection_and_entered ()
4984 RegionSelection regions = selection->regions;
4986 if (regions.empty() && entered_regionview) {
4987 regions.add (entered_regionview);
4994 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4996 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4997 RouteTimeAxisView* rtav;
4999 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5000 boost::shared_ptr<Playlist> pl;
5001 std::vector<boost::shared_ptr<Region> > results;
5002 boost::shared_ptr<Track> tr;
5004 if ((tr = rtav->track()) == 0) {
5009 if ((pl = (tr->playlist())) != 0) {
5010 boost::shared_ptr<Region> r = pl->region_by_id (id);
5012 RegionView* rv = rtav->view()->find_view (r);
5014 regions.push_back (rv);
5023 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5026 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5027 MidiTimeAxisView* mtav;
5029 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5031 mtav->get_per_region_note_selection (selection);
5038 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5040 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5042 RouteTimeAxisView* tatv;
5044 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5046 boost::shared_ptr<Playlist> pl;
5047 vector<boost::shared_ptr<Region> > results;
5049 boost::shared_ptr<Track> tr;
5051 if ((tr = tatv->track()) == 0) {
5056 if ((pl = (tr->playlist())) != 0) {
5057 if (src_comparison) {
5058 pl->get_source_equivalent_regions (region, results);
5060 pl->get_region_list_equivalent_regions (region, results);
5064 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5065 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5066 regions.push_back (marv);
5075 Editor::show_rhythm_ferret ()
5077 if (rhythm_ferret == 0) {
5078 rhythm_ferret = new RhythmFerret(*this);
5081 rhythm_ferret->set_session (_session);
5082 rhythm_ferret->show ();
5083 rhythm_ferret->present ();
5087 Editor::first_idle ()
5089 MessageDialog* dialog = 0;
5091 if (track_views.size() > 1) {
5092 Timers::TimerSuspender t;
5093 dialog = new MessageDialog (
5095 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5099 ARDOUR_UI::instance()->flush_pending ();
5102 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5106 // first idle adds route children (automation tracks), so we need to redisplay here
5107 _routes->redisplay ();
5111 if (_session->undo_depth() == 0) {
5112 undo_action->set_sensitive(false);
5114 redo_action->set_sensitive(false);
5115 begin_selection_op_history ();
5121 Editor::_idle_resize (gpointer arg)
5123 return ((Editor*)arg)->idle_resize ();
5127 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5129 if (resize_idle_id < 0) {
5130 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5131 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5132 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5134 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5135 _pending_resize_amount = 0;
5138 /* make a note of the smallest resulting height, so that we can clamp the
5139 lower limit at TimeAxisView::hSmall */
5141 int32_t min_resulting = INT32_MAX;
5143 _pending_resize_amount += h;
5144 _pending_resize_view = view;
5146 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5148 if (selection->tracks.contains (_pending_resize_view)) {
5149 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5150 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5154 if (min_resulting < 0) {
5159 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5160 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5164 /** Handle pending resizing of tracks */
5166 Editor::idle_resize ()
5168 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5170 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5171 selection->tracks.contains (_pending_resize_view)) {
5173 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5174 if (*i != _pending_resize_view) {
5175 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5180 _pending_resize_amount = 0;
5181 _group_tabs->set_dirty ();
5182 resize_idle_id = -1;
5190 ENSURE_GUI_THREAD (*this, &Editor::located);
5193 playhead_cursor->set_position (_session->audible_frame ());
5194 if (_follow_playhead && !_pending_initial_locate) {
5195 reset_x_origin_to_follow_playhead ();
5199 _pending_locate_request = false;
5200 _pending_initial_locate = false;
5204 Editor::region_view_added (RegionView * rv)
5206 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5207 if (rv->region ()->id () == (*pr)) {
5208 selection->add (rv);
5209 selection->regions.pending.erase (pr);
5214 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5216 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5217 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5218 if (rv->region()->id () == (*rnote).first) {
5219 mrv->select_notes ((*rnote).second);
5220 selection->pending_midi_note_selection.erase(rnote);
5226 _summary->set_background_dirty ();
5230 Editor::region_view_removed ()
5232 _summary->set_background_dirty ();
5236 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5238 TrackViewList::const_iterator j = track_views.begin ();
5239 while (j != track_views.end()) {
5240 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5241 if (rtv && rtv->route() == r) {
5252 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5256 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5257 TimeAxisView* tv = axis_view_from_route (*i);
5267 Editor::suspend_route_redisplay ()
5270 _routes->suspend_redisplay();
5275 Editor::resume_route_redisplay ()
5278 _routes->redisplay(); // queue redisplay
5279 _routes->resume_redisplay();
5284 Editor::add_routes (RouteList& routes)
5286 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5288 RouteTimeAxisView *rtv;
5289 list<RouteTimeAxisView*> new_views;
5290 TrackViewList new_selection;
5291 bool from_scratch = (track_views.size() == 0);
5293 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5294 boost::shared_ptr<Route> route = (*x);
5296 if (route->is_auditioner() || route->is_monitor()) {
5300 DataType dt = route->input()->default_type();
5302 if (dt == ARDOUR::DataType::AUDIO) {
5303 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5304 rtv->set_route (route);
5305 } else if (dt == ARDOUR::DataType::MIDI) {
5306 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5307 rtv->set_route (route);
5309 throw unknown_type();
5312 new_views.push_back (rtv);
5313 track_views.push_back (rtv);
5314 new_selection.push_back (rtv);
5316 rtv->effective_gain_display ();
5318 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5319 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5322 if (new_views.size() > 0) {
5323 _routes->routes_added (new_views);
5324 _summary->routes_added (new_views);
5327 if (!from_scratch) {
5328 selection->tracks.clear();
5329 selection->add (new_selection);
5330 begin_selection_op_history();
5333 if (show_editor_mixer_when_tracks_arrive) {
5334 show_editor_mixer (true);
5337 editor_list_button.set_sensitive (true);
5341 Editor::timeaxisview_deleted (TimeAxisView *tv)
5343 if (tv == entered_track) {
5347 if (_session && _session->deletion_in_progress()) {
5348 /* the situation is under control */
5352 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5354 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5356 _routes->route_removed (tv);
5358 TimeAxisView::Children c = tv->get_child_list ();
5359 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5360 if (entered_track == i->get()) {
5365 /* remove it from the list of track views */
5367 TrackViewList::iterator i;
5369 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5370 i = track_views.erase (i);
5373 /* update whatever the current mixer strip is displaying, if revelant */
5375 boost::shared_ptr<Route> route;
5378 route = rtav->route ();
5381 if (current_mixer_strip && current_mixer_strip->route() == route) {
5383 TimeAxisView* next_tv;
5385 if (track_views.empty()) {
5387 } else if (i == track_views.end()) {
5388 next_tv = track_views.front();
5395 set_selected_mixer_strip (*next_tv);
5397 /* make the editor mixer strip go away setting the
5398 * button to inactive (which also unticks the menu option)
5401 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5407 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5409 if (apply_to_selection) {
5410 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5412 TrackSelection::iterator j = i;
5415 hide_track_in_display (*i, false);
5420 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5422 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5423 // this will hide the mixer strip
5424 set_selected_mixer_strip (*tv);
5427 _routes->hide_track_in_display (*tv);
5432 Editor::sync_track_view_list_and_routes ()
5434 track_views = TrackViewList (_routes->views ());
5436 _summary->set_background_dirty();
5437 _group_tabs->set_dirty ();
5439 return false; // do not call again (until needed)
5443 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5445 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5450 /** Find a RouteTimeAxisView by the ID of its route */
5452 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5454 RouteTimeAxisView* v;
5456 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5457 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5458 if(v->route()->id() == id) {
5468 Editor::fit_route_group (RouteGroup *g)
5470 TrackViewList ts = axis_views_from_routes (g->route_list ());
5475 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5477 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5480 _session->cancel_audition ();
5484 if (_session->is_auditioning()) {
5485 _session->cancel_audition ();
5486 if (r == last_audition_region) {
5491 _session->audition_region (r);
5492 last_audition_region = r;
5497 Editor::hide_a_region (boost::shared_ptr<Region> r)
5499 r->set_hidden (true);
5503 Editor::show_a_region (boost::shared_ptr<Region> r)
5505 r->set_hidden (false);
5509 Editor::audition_region_from_region_list ()
5511 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5515 Editor::hide_region_from_region_list ()
5517 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5521 Editor::show_region_in_region_list ()
5523 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5527 Editor::step_edit_status_change (bool yn)
5530 start_step_editing ();
5532 stop_step_editing ();
5537 Editor::start_step_editing ()
5539 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5543 Editor::stop_step_editing ()
5545 step_edit_connection.disconnect ();
5549 Editor::check_step_edit ()
5551 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5552 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5554 mtv->check_step_edit ();
5558 return true; // do it again, till we stop
5562 Editor::scroll_press (Direction dir)
5564 ++_scroll_callbacks;
5566 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5567 /* delay the first auto-repeat */
5573 scroll_backward (1);
5581 scroll_up_one_track ();
5585 scroll_down_one_track ();
5589 /* do hacky auto-repeat */
5590 if (!_scroll_connection.connected ()) {
5592 _scroll_connection = Glib::signal_timeout().connect (
5593 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5596 _scroll_callbacks = 0;
5603 Editor::scroll_release ()
5605 _scroll_connection.disconnect ();
5608 /** Queue a change for the Editor viewport x origin to follow the playhead */
5610 Editor::reset_x_origin_to_follow_playhead ()
5612 framepos_t const frame = playhead_cursor->current_frame ();
5614 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5616 if (_session->transport_speed() < 0) {
5618 if (frame > (current_page_samples() / 2)) {
5619 center_screen (frame-(current_page_samples()/2));
5621 center_screen (current_page_samples()/2);
5628 if (frame < leftmost_frame) {
5630 if (_session->transport_rolling()) {
5631 /* rolling; end up with the playhead at the right of the page */
5632 l = frame - current_page_samples ();
5634 /* not rolling: end up with the playhead 1/4 of the way along the page */
5635 l = frame - current_page_samples() / 4;
5639 if (_session->transport_rolling()) {
5640 /* rolling: end up with the playhead on the left of the page */
5643 /* not rolling: end up with the playhead 3/4 of the way along the page */
5644 l = frame - 3 * current_page_samples() / 4;
5652 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5658 Editor::super_rapid_screen_update ()
5660 if (!_session || !_session->engine().running()) {
5664 /* METERING / MIXER STRIPS */
5666 /* update track meters, if required */
5667 if (is_mapped() && meters_running) {
5668 RouteTimeAxisView* rtv;
5669 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5670 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5671 rtv->fast_update ();
5676 /* and any current mixer strip */
5677 if (current_mixer_strip) {
5678 current_mixer_strip->fast_update ();
5681 /* PLAYHEAD AND VIEWPORT */
5683 framepos_t const frame = _session->audible_frame();
5685 /* There are a few reasons why we might not update the playhead / viewport stuff:
5687 * 1. we don't update things when there's a pending locate request, otherwise
5688 * when the editor requests a locate there is a chance that this method
5689 * will move the playhead before the locate request is processed, causing
5691 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5692 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5695 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5697 last_update_frame = frame;
5699 if (!_dragging_playhead) {
5700 playhead_cursor->set_position (frame);
5703 if (!_stationary_playhead) {
5705 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5706 /* We only do this if we aren't already
5707 handling a visual change (ie if
5708 pending_visual_change.being_handled is
5709 false) so that these requests don't stack
5710 up there are too many of them to handle in
5713 reset_x_origin_to_follow_playhead ();
5718 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5719 framepos_t const frame = playhead_cursor->current_frame ();
5720 double target = ((double)frame - (double)current_page_samples()/3.0);
5721 if (target <= 0.0) {
5724 // compare to EditorCursor::set_position()
5725 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5726 double const new_pos = sample_to_pixel_unrounded (target);
5727 if (rint (new_pos) != rint (old_pos)) {
5728 reset_x_origin (pixel_to_sample (floor (new_pos)));
5739 Editor::session_going_away ()
5741 _have_idled = false;
5743 _session_connections.drop_connections ();
5745 super_rapid_screen_update_connection.disconnect ();
5747 selection->clear ();
5748 cut_buffer->clear ();
5750 clicked_regionview = 0;
5751 clicked_axisview = 0;
5752 clicked_routeview = 0;
5753 entered_regionview = 0;
5755 last_update_frame = 0;
5758 playhead_cursor->hide ();
5760 /* rip everything out of the list displays */
5764 _route_groups->clear ();
5766 /* do this first so that deleting a track doesn't reset cms to null
5767 and thus cause a leak.
5770 if (current_mixer_strip) {
5771 if (current_mixer_strip->get_parent() != 0) {
5772 global_hpacker.remove (*current_mixer_strip);
5774 delete current_mixer_strip;
5775 current_mixer_strip = 0;
5778 /* delete all trackviews */
5780 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5783 track_views.clear ();
5785 nudge_clock->set_session (0);
5787 editor_list_button.set_active(false);
5788 editor_list_button.set_sensitive(false);
5790 /* clear tempo/meter rulers */
5791 remove_metric_marks ();
5793 clear_marker_display ();
5795 stop_step_editing ();
5797 /* get rid of any existing editor mixer strip */
5799 WindowTitle title(Glib::get_application_name());
5800 title += _("Editor");
5802 set_title (title.get_string());
5804 SessionHandlePtr::session_going_away ();
5809 Editor::show_editor_list (bool yn)
5812 _the_notebook.show ();
5814 _the_notebook.hide ();
5819 Editor::change_region_layering_order (bool from_context_menu)
5821 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5823 if (!clicked_routeview) {
5824 if (layering_order_editor) {
5825 layering_order_editor->hide ();
5830 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5836 boost::shared_ptr<Playlist> pl = track->playlist();
5842 if (layering_order_editor == 0) {
5843 layering_order_editor = new RegionLayeringOrderEditor (*this);
5846 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5847 layering_order_editor->maybe_present ();
5851 Editor::update_region_layering_order_editor ()
5853 if (layering_order_editor && layering_order_editor->is_visible ()) {
5854 change_region_layering_order (true);
5859 Editor::setup_fade_images ()
5861 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5862 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5863 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5864 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5865 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5867 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5868 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5869 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5870 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5871 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5873 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5874 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5875 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5876 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5877 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5879 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5880 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5881 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5882 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5883 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5887 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5889 Editor::action_menu_item (std::string const & name)
5891 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5894 return *manage (a->create_menu_item ());
5898 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5900 EventBox* b = manage (new EventBox);
5901 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5902 Label* l = manage (new Label (name));
5906 _the_notebook.append_page (widget, *b);
5910 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5912 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5913 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5916 if (ev->type == GDK_2BUTTON_PRESS) {
5918 /* double-click on a notebook tab shrinks or expands the notebook */
5920 if (_notebook_shrunk) {
5921 if (pre_notebook_shrink_pane_width) {
5922 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5924 _notebook_shrunk = false;
5926 pre_notebook_shrink_pane_width = edit_pane.get_position();
5928 /* this expands the LHS of the edit pane to cover the notebook
5929 PAGE but leaves the tabs visible.
5931 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5932 _notebook_shrunk = true;
5940 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5942 using namespace Menu_Helpers;
5944 MenuList& items = _control_point_context_menu.items ();
5947 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5948 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5949 if (!can_remove_control_point (item)) {
5950 items.back().set_sensitive (false);
5953 _control_point_context_menu.popup (event->button.button, event->button.time);
5957 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5959 using namespace Menu_Helpers;
5961 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5966 /* We need to get the selection here and pass it to the operations, since
5967 popping up the menu will cause a region leave event which clears
5968 entered_regionview. */
5970 MidiRegionView& mrv = note->region_view();
5971 const RegionSelection rs = get_regions_from_selection_and_entered ();
5972 const uint32_t sel_size = mrv.selection_size ();
5974 MenuList& items = _note_context_menu.items();
5978 items.push_back(MenuElem(_("Delete"),
5979 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5982 items.push_back(MenuElem(_("Edit..."),
5983 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5984 if (sel_size != 1) {
5985 items.back().set_sensitive (false);
5988 items.push_back(MenuElem(_("Transpose..."),
5989 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
5992 items.push_back(MenuElem(_("Legatize"),
5993 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5995 items.back().set_sensitive (false);
5998 items.push_back(MenuElem(_("Quantize..."),
5999 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6001 items.push_back(MenuElem(_("Remove Overlap"),
6002 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6004 items.back().set_sensitive (false);
6007 items.push_back(MenuElem(_("Transform..."),
6008 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6010 _note_context_menu.popup (event->button.button, event->button.time);
6014 Editor::zoom_vertical_modifier_released()
6016 _stepping_axis_view = 0;
6020 Editor::ui_parameter_changed (string parameter)
6022 if (parameter == "icon-set") {
6023 while (!_cursor_stack.empty()) {
6024 _cursor_stack.pop_back();
6026 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6027 _cursor_stack.push_back(_cursors->grabber);
6028 } else if (parameter == "draggable-playhead") {
6029 if (_verbose_cursor) {
6030 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());