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"
128 #include "verbose_cursor.h"
133 using namespace ARDOUR;
134 using namespace ARDOUR_UI_UTILS;
137 using namespace Glib;
138 using namespace Gtkmm2ext;
139 using namespace Editing;
141 using PBD::internationalize;
143 using Gtkmm2ext::Keyboard;
145 double Editor::timebar_height = 15.0;
147 static const gchar *_snap_type_strings[] = {
181 static const gchar *_snap_mode_strings[] = {
188 static const gchar *_edit_point_strings[] = {
195 static const gchar *_edit_mode_strings[] = {
203 static const gchar *_zoom_focus_strings[] = {
213 #ifdef USE_RUBBERBAND
214 static const gchar *_rb_opt_strings[] = {
217 N_("Balanced multitimbral mixture"),
218 N_("Unpitched percussion with stable notes"),
219 N_("Crisp monophonic instrumental"),
220 N_("Unpitched solo percussion"),
221 N_("Resample without preserving pitch"),
226 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
229 pane_size_watcher (Paned* pane)
231 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
235 Quartz: impossible to access
237 so stop that by preventing it from ever getting too narrow. 35
238 pixels is basically a rough guess at the tab width.
243 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
245 gint pos = pane->get_position ();
247 if (pos > max_width_of_lhs) {
248 pane->set_position (max_width_of_lhs);
253 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
255 , _mouse_changed_selection (false)
256 /* time display buttons */
257 , minsec_label (_("Mins:Secs"))
258 , bbt_label (_("Bars:Beats"))
259 , timecode_label (_("Timecode"))
260 , samples_label (_("Samples"))
261 , tempo_label (_("Tempo"))
262 , meter_label (_("Meter"))
263 , mark_label (_("Location Markers"))
264 , range_mark_label (_("Range Markers"))
265 , transport_mark_label (_("Loop/Punch Ranges"))
266 , cd_mark_label (_("CD Markers"))
267 , videotl_label (_("Video Timeline"))
268 , edit_packer (4, 4, true)
270 /* the values here don't matter: layout widgets
271 reset them as needed.
274 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
275 , horizontal_adjustment (0.0, 0.0, 1e16)
276 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
278 , controls_layout (unused_adjustment, vertical_adjustment)
280 /* tool bar related */
282 , toolbar_selection_clock_table (2,3)
283 , _mouse_mode_tearoff (0)
284 , automation_mode_button (_("mode"))
288 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
289 , selection_op_cmd_depth (0)
290 , selection_op_history_it (0)
294 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
295 , meters_running(false)
296 , _pending_locate_request (false)
297 , _pending_initial_locate (false)
298 , _last_cut_copy_source_track (0)
300 , _region_selection_change_updates_region_list (true)
301 , _following_mixer_selection (false)
302 , _control_point_toggled_on_press (false)
303 , _stepping_axis_view (0)
304 , quantize_dialog (0)
305 , _main_menu_disabler (0)
309 /* we are a singleton */
311 PublicEditor::_instance = this;
315 selection = new Selection (this);
316 cut_buffer = new Selection (this);
317 _selection_memento = new SelectionMemento ();
318 selection_op_history.clear();
321 clicked_regionview = 0;
322 clicked_axisview = 0;
323 clicked_routeview = 0;
324 clicked_control_point = 0;
325 last_update_frame = 0;
328 _drags = new DragManager (this);
331 current_mixer_strip = 0;
334 snap_type_strings = I18N (_snap_type_strings);
335 snap_mode_strings = I18N (_snap_mode_strings);
336 zoom_focus_strings = I18N (_zoom_focus_strings);
337 edit_mode_strings = I18N (_edit_mode_strings);
338 edit_point_strings = I18N (_edit_point_strings);
339 #ifdef USE_RUBBERBAND
340 rb_opt_strings = I18N (_rb_opt_strings);
344 build_edit_mode_menu();
345 build_zoom_focus_menu();
346 build_track_count_menu();
347 build_snap_mode_menu();
348 build_snap_type_menu();
349 build_edit_point_menu();
351 snap_threshold = 5.0;
352 bbt_beat_subdivision = 4;
353 _visible_canvas_width = 0;
354 _visible_canvas_height = 0;
355 autoscroll_horizontal_allowed = false;
356 autoscroll_vertical_allowed = false;
361 current_interthread_info = 0;
362 _show_measures = true;
364 show_gain_after_trim = false;
366 have_pending_keyboard_selection = false;
367 _follow_playhead = true;
368 _stationary_playhead = false;
369 editor_ruler_menu = 0;
370 no_ruler_shown_update = false;
372 range_marker_menu = 0;
373 marker_menu_item = 0;
374 tempo_or_meter_marker_menu = 0;
375 transport_marker_menu = 0;
376 new_transport_marker_menu = 0;
377 editor_mixer_strip_width = Wide;
378 show_editor_mixer_when_tracks_arrive = false;
379 region_edit_menu_split_multichannel_item = 0;
380 region_edit_menu_split_item = 0;
383 mouse_mode = MouseObject;
384 current_stepping_trackview = 0;
386 entered_regionview = 0;
388 clear_entered_track = false;
391 button_release_can_deselect = true;
392 _dragging_playhead = false;
393 _dragging_edit_point = false;
394 select_new_marker = false;
396 layering_order_editor = 0;
397 no_save_visual = false;
399 within_track_canvas = false;
401 scrubbing_direction = 0;
405 location_marker_color = ARDOUR_UI::config()->color ("location marker");
406 location_range_color = ARDOUR_UI::config()->color ("location range");
407 location_cd_marker_color = ARDOUR_UI::config()->color ("location cd marker");
408 location_loop_color = ARDOUR_UI::config()->color ("location loop");
409 location_punch_color = ARDOUR_UI::config()->color ("location punch");
411 zoom_focus = ZoomFocusPlayhead;
412 _edit_point = EditAtMouse;
413 _visible_track_count = -1;
415 samples_per_pixel = 2048; /* too early to use reset_zoom () */
417 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
418 TimeAxisView::setup_sizes ();
419 ArdourMarker::setup_sizes (timebar_height);
421 _scroll_callbacks = 0;
423 bbt_label.set_name ("EditorRulerLabel");
424 bbt_label.set_size_request (-1, (int)timebar_height);
425 bbt_label.set_alignment (1.0, 0.5);
426 bbt_label.set_padding (5,0);
428 bbt_label.set_no_show_all();
429 minsec_label.set_name ("EditorRulerLabel");
430 minsec_label.set_size_request (-1, (int)timebar_height);
431 minsec_label.set_alignment (1.0, 0.5);
432 minsec_label.set_padding (5,0);
433 minsec_label.hide ();
434 minsec_label.set_no_show_all();
435 timecode_label.set_name ("EditorRulerLabel");
436 timecode_label.set_size_request (-1, (int)timebar_height);
437 timecode_label.set_alignment (1.0, 0.5);
438 timecode_label.set_padding (5,0);
439 timecode_label.hide ();
440 timecode_label.set_no_show_all();
441 samples_label.set_name ("EditorRulerLabel");
442 samples_label.set_size_request (-1, (int)timebar_height);
443 samples_label.set_alignment (1.0, 0.5);
444 samples_label.set_padding (5,0);
445 samples_label.hide ();
446 samples_label.set_no_show_all();
448 tempo_label.set_name ("EditorRulerLabel");
449 tempo_label.set_size_request (-1, (int)timebar_height);
450 tempo_label.set_alignment (1.0, 0.5);
451 tempo_label.set_padding (5,0);
453 tempo_label.set_no_show_all();
455 meter_label.set_name ("EditorRulerLabel");
456 meter_label.set_size_request (-1, (int)timebar_height);
457 meter_label.set_alignment (1.0, 0.5);
458 meter_label.set_padding (5,0);
460 meter_label.set_no_show_all();
462 if (Profile->get_trx()) {
463 mark_label.set_text (_("Markers"));
465 mark_label.set_name ("EditorRulerLabel");
466 mark_label.set_size_request (-1, (int)timebar_height);
467 mark_label.set_alignment (1.0, 0.5);
468 mark_label.set_padding (5,0);
470 mark_label.set_no_show_all();
472 cd_mark_label.set_name ("EditorRulerLabel");
473 cd_mark_label.set_size_request (-1, (int)timebar_height);
474 cd_mark_label.set_alignment (1.0, 0.5);
475 cd_mark_label.set_padding (5,0);
476 cd_mark_label.hide();
477 cd_mark_label.set_no_show_all();
479 videotl_bar_height = 4;
480 videotl_label.set_name ("EditorRulerLabel");
481 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
482 videotl_label.set_alignment (1.0, 0.5);
483 videotl_label.set_padding (5,0);
484 videotl_label.hide();
485 videotl_label.set_no_show_all();
487 range_mark_label.set_name ("EditorRulerLabel");
488 range_mark_label.set_size_request (-1, (int)timebar_height);
489 range_mark_label.set_alignment (1.0, 0.5);
490 range_mark_label.set_padding (5,0);
491 range_mark_label.hide();
492 range_mark_label.set_no_show_all();
494 transport_mark_label.set_name ("EditorRulerLabel");
495 transport_mark_label.set_size_request (-1, (int)timebar_height);
496 transport_mark_label.set_alignment (1.0, 0.5);
497 transport_mark_label.set_padding (5,0);
498 transport_mark_label.hide();
499 transport_mark_label.set_no_show_all();
501 initialize_canvas ();
503 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
505 _summary = new EditorSummary (this);
507 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
508 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
510 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
512 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
513 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
515 edit_controls_vbox.set_spacing (0);
516 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
517 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
519 HBox* h = manage (new HBox);
520 _group_tabs = new EditorGroupTabs (this);
521 if (!ARDOUR::Profile->get_trx()) {
522 h->pack_start (*_group_tabs, PACK_SHRINK);
524 h->pack_start (edit_controls_vbox);
525 controls_layout.add (*h);
527 controls_layout.set_name ("EditControlsBase");
528 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
529 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
530 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
532 _cursors = new MouseCursors;
533 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
534 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
536 /* Push default cursor to ever-present bottom of cursor stack. */
537 push_canvas_cursor(_cursors->grabber);
539 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
541 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
542 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
543 pad_line_1->set_outline_color (0xFF0000FF);
549 edit_packer.set_col_spacings (0);
550 edit_packer.set_row_spacings (0);
551 edit_packer.set_homogeneous (false);
552 edit_packer.set_border_width (0);
553 edit_packer.set_name ("EditorWindow");
555 time_bars_event_box.add (time_bars_vbox);
556 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
557 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
559 /* labels for the time bars */
560 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
562 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
564 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
566 bottom_hbox.set_border_width (2);
567 bottom_hbox.set_spacing (3);
569 _route_groups = new EditorRouteGroups (this);
570 _routes = new EditorRoutes (this);
571 _regions = new EditorRegions (this);
572 _snapshots = new EditorSnapshots (this);
573 _locations = new EditorLocations (this);
575 /* these are static location signals */
577 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
578 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
579 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
581 add_notebook_page (_("Regions"), _regions->widget ());
582 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
583 add_notebook_page (_("Snapshots"), _snapshots->widget ());
584 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
585 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
587 _the_notebook.set_show_tabs (true);
588 _the_notebook.set_scrollable (true);
589 _the_notebook.popup_disable ();
590 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
591 _the_notebook.show_all ();
593 _notebook_shrunk = false;
595 editor_summary_pane.pack1(edit_packer);
597 Button* summary_arrows_left_left = manage (new Button);
598 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
599 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
600 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
602 Button* summary_arrows_left_right = manage (new Button);
603 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
604 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
605 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
607 VBox* summary_arrows_left = manage (new VBox);
608 summary_arrows_left->pack_start (*summary_arrows_left_left);
609 summary_arrows_left->pack_start (*summary_arrows_left_right);
611 Button* summary_arrows_right_up = manage (new Button);
612 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
613 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
614 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
616 Button* summary_arrows_right_down = manage (new Button);
617 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
618 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
619 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
621 VBox* summary_arrows_right = manage (new VBox);
622 summary_arrows_right->pack_start (*summary_arrows_right_up);
623 summary_arrows_right->pack_start (*summary_arrows_right_down);
625 Frame* summary_frame = manage (new Frame);
626 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
628 summary_frame->add (*_summary);
629 summary_frame->show ();
631 _summary_hbox.pack_start (*summary_arrows_left, false, false);
632 _summary_hbox.pack_start (*summary_frame, true, true);
633 _summary_hbox.pack_start (*summary_arrows_right, false, false);
635 if (!ARDOUR::Profile->get_trx()) {
636 editor_summary_pane.pack2 (_summary_hbox);
639 edit_pane.pack1 (editor_summary_pane, true, true);
640 if (!ARDOUR::Profile->get_trx()) {
641 edit_pane.pack2 (_the_notebook, false, true);
644 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
646 /* XXX: editor_summary_pane might need similar to the edit_pane */
648 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
650 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
651 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
653 top_hbox.pack_start (toolbar_frame);
655 HBox *hbox = manage (new HBox);
656 hbox->pack_start (edit_pane, true, true);
658 global_vpacker.pack_start (top_hbox, false, false);
659 global_vpacker.pack_start (*hbox, true, true);
661 global_hpacker.pack_start (global_vpacker, true, true);
663 set_name ("EditorWindow");
664 add_accel_group (ActionManager::ui_manager->get_accel_group());
666 status_bar_hpacker.show ();
668 vpacker.pack_end (status_bar_hpacker, false, false);
669 vpacker.pack_end (global_hpacker, true, true);
671 /* register actions now so that set_state() can find them and set toggles/checks etc */
674 /* when we start using our own keybinding system for the editor, this
675 * will be uncommented
681 set_zoom_focus (zoom_focus);
682 set_visible_track_count (_visible_track_count);
683 _snap_type = SnapToBeat;
684 set_snap_to (_snap_type);
685 _snap_mode = SnapOff;
686 set_snap_mode (_snap_mode);
687 set_mouse_mode (MouseObject, true);
688 pre_internal_snap_type = _snap_type;
689 pre_internal_snap_mode = _snap_mode;
690 internal_snap_type = _snap_type;
691 internal_snap_mode = _snap_mode;
692 set_edit_point_preference (EditAtMouse, true);
694 _playlist_selector = new PlaylistSelector();
695 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
697 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
701 nudge_forward_button.set_name ("nudge button");
702 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
704 nudge_backward_button.set_name ("nudge button");
705 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
707 fade_context_menu.set_name ("ArdourContextMenu");
709 /* icons, titles, WM stuff */
711 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
712 Glib::RefPtr<Gdk::Pixbuf> icon;
714 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
715 window_icons.push_back (icon);
717 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
718 window_icons.push_back (icon);
720 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
721 window_icons.push_back (icon);
723 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
724 window_icons.push_back (icon);
726 if (!window_icons.empty()) {
727 // set_icon_list (window_icons);
728 set_default_icon_list (window_icons);
731 WindowTitle title(Glib::get_application_name());
732 title += _("Editor");
733 set_title (title.get_string());
734 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
737 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
739 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
740 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
742 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
744 /* allow external control surfaces/protocols to do various things */
746 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
747 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
748 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
749 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
750 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
751 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
752 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
753 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
754 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
755 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
756 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
757 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
758 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
759 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
761 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
762 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
763 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
764 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
765 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
767 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
769 /* problematic: has to return a value and thus cannot be x-thread */
771 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
773 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
774 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
776 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
778 _ignore_region_action = false;
779 _last_region_menu_was_main = false;
780 _popup_region_menu_item = 0;
782 _ignore_follow_edits = false;
784 _show_marker_lines = false;
786 /* Button bindings */
788 button_bindings = new Bindings;
790 XMLNode* node = button_settings();
792 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
793 button_bindings->load (**i);
799 /* grab current parameter state */
800 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
801 ARDOUR_UI::config()->map_parameters (pc);
803 setup_fade_images ();
810 delete button_bindings;
812 delete _route_groups;
813 delete _track_canvas_viewport;
816 delete quantize_dialog;
822 delete _playlist_selector;
826 Editor::button_settings () const
828 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
829 XMLNode* node = find_named_node (*settings, X_("Buttons"));
832 node = new XMLNode (X_("Buttons"));
839 Editor::add_toplevel_menu (Container& cont)
841 vpacker.pack_start (cont, false, false);
846 Editor::add_transport_frame (Container& cont)
848 if(ARDOUR::Profile->get_mixbus()) {
849 global_vpacker.pack_start (cont, false, false);
850 global_vpacker.reorder_child (cont, 0);
853 vpacker.pack_start (cont, false, false);
858 Editor::get_smart_mode () const
860 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
864 Editor::catch_vanishing_regionview (RegionView *rv)
866 /* note: the selection will take care of the vanishing
867 audioregionview by itself.
870 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
874 if (clicked_regionview == rv) {
875 clicked_regionview = 0;
878 if (entered_regionview == rv) {
879 set_entered_regionview (0);
882 if (!_all_region_actions_sensitized) {
883 sensitize_all_region_actions (true);
888 Editor::set_entered_regionview (RegionView* rv)
890 if (rv == entered_regionview) {
894 if (entered_regionview) {
895 entered_regionview->exited ();
898 entered_regionview = rv;
900 if (entered_regionview != 0) {
901 entered_regionview->entered ();
904 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
905 /* This RegionView entry might have changed what region actions
906 are allowed, so sensitize them all in case a key is pressed.
908 sensitize_all_region_actions (true);
913 Editor::set_entered_track (TimeAxisView* tav)
916 entered_track->exited ();
922 entered_track->entered ();
927 Editor::show_window ()
929 if (!is_visible ()) {
933 /* XXX: this is a bit unfortunate; it would probably
934 be nicer if we could just call show () above rather
935 than needing the show_all ()
938 /* re-hide stuff if necessary */
939 editor_list_button_toggled ();
940 parameter_changed ("show-summary");
941 parameter_changed ("show-group-tabs");
942 parameter_changed ("show-zoom-tools");
944 /* now reset all audio_time_axis heights, because widgets might need
950 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
951 tv = (static_cast<TimeAxisView*>(*i));
955 if (current_mixer_strip) {
956 current_mixer_strip->hide_things ();
957 current_mixer_strip->parameter_changed ("mixer-element-visibility");
965 Editor::instant_save ()
967 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
972 _session->add_instant_xml(get_state());
974 Config->add_instant_xml(get_state());
979 Editor::control_vertical_zoom_in_all ()
981 tav_zoom_smooth (false, true);
985 Editor::control_vertical_zoom_out_all ()
987 tav_zoom_smooth (true, true);
991 Editor::control_vertical_zoom_in_selected ()
993 tav_zoom_smooth (false, false);
997 Editor::control_vertical_zoom_out_selected ()
999 tav_zoom_smooth (true, false);
1003 Editor::control_view (uint32_t view)
1005 goto_visual_state (view);
1009 Editor::control_unselect ()
1011 selection->clear_tracks ();
1015 Editor::control_select (uint32_t rid, Selection::Operation op)
1017 /* handles the (static) signal from the ControlProtocol class that
1018 * requests setting the selected track to a given RID
1025 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1031 TimeAxisView* tav = axis_view_from_route (r);
1035 case Selection::Add:
1036 selection->add (tav);
1038 case Selection::Toggle:
1039 selection->toggle (tav);
1041 case Selection::Extend:
1043 case Selection::Set:
1044 selection->set (tav);
1048 selection->clear_tracks ();
1053 Editor::control_step_tracks_up ()
1055 scroll_tracks_up_line ();
1059 Editor::control_step_tracks_down ()
1061 scroll_tracks_down_line ();
1065 Editor::control_scroll (float fraction)
1067 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1073 double step = fraction * current_page_samples();
1076 _control_scroll_target is an optional<T>
1078 it acts like a pointer to an framepos_t, with
1079 a operator conversion to boolean to check
1080 that it has a value could possibly use
1081 playhead_cursor->current_frame to store the
1082 value and a boolean in the class to know
1083 when it's out of date
1086 if (!_control_scroll_target) {
1087 _control_scroll_target = _session->transport_frame();
1088 _dragging_playhead = true;
1091 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1092 *_control_scroll_target = 0;
1093 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1094 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1096 *_control_scroll_target += (framepos_t) trunc (step);
1099 /* move visuals, we'll catch up with it later */
1101 playhead_cursor->set_position (*_control_scroll_target);
1102 UpdateAllTransportClocks (*_control_scroll_target);
1104 if (*_control_scroll_target > (current_page_samples() / 2)) {
1105 /* try to center PH in window */
1106 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1112 Now we do a timeout to actually bring the session to the right place
1113 according to the playhead. This is to avoid reading disk buffers on every
1114 call to control_scroll, which is driven by ScrollTimeline and therefore
1115 probably by a control surface wheel which can generate lots of events.
1117 /* cancel the existing timeout */
1119 control_scroll_connection.disconnect ();
1121 /* add the next timeout */
1123 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1127 Editor::deferred_control_scroll (framepos_t /*target*/)
1129 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1130 // reset for next stream
1131 _control_scroll_target = boost::none;
1132 _dragging_playhead = false;
1137 Editor::access_action (std::string action_group, std::string action_item)
1143 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1146 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1154 Editor::on_realize ()
1156 Window::on_realize ();
1159 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1160 start_lock_event_timing ();
1163 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1167 Editor::start_lock_event_timing ()
1169 /* check if we should lock the GUI every 30 seconds */
1171 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1175 Editor::generic_event_handler (GdkEvent* ev)
1178 case GDK_BUTTON_PRESS:
1179 case GDK_BUTTON_RELEASE:
1180 case GDK_MOTION_NOTIFY:
1182 case GDK_KEY_RELEASE:
1183 gettimeofday (&last_event_time, 0);
1186 case GDK_LEAVE_NOTIFY:
1187 switch (ev->crossing.detail) {
1188 case GDK_NOTIFY_UNKNOWN:
1189 case GDK_NOTIFY_INFERIOR:
1190 case GDK_NOTIFY_ANCESTOR:
1192 case GDK_NOTIFY_VIRTUAL:
1193 case GDK_NOTIFY_NONLINEAR:
1194 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1195 /* leaving window, so reset focus, thus ending any and
1196 all text entry operations.
1211 Editor::lock_timeout_callback ()
1213 struct timeval now, delta;
1215 gettimeofday (&now, 0);
1217 timersub (&now, &last_event_time, &delta);
1219 if (delta.tv_sec > (time_t) ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1221 /* don't call again. Returning false will effectively
1222 disconnect us from the timer callback.
1224 unlock() will call start_lock_event_timing() to get things
1234 Editor::map_position_change (framepos_t frame)
1236 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1238 if (_session == 0) {
1242 if (_follow_playhead) {
1243 center_screen (frame);
1246 playhead_cursor->set_position (frame);
1250 Editor::center_screen (framepos_t frame)
1252 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1254 /* if we're off the page, then scroll.
1257 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1258 center_screen_internal (frame, page);
1263 Editor::center_screen_internal (framepos_t frame, float page)
1268 frame -= (framepos_t) page;
1273 reset_x_origin (frame);
1278 Editor::update_title ()
1280 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1283 bool dirty = _session->dirty();
1285 string session_name;
1287 if (_session->snap_name() != _session->name()) {
1288 session_name = _session->snap_name();
1290 session_name = _session->name();
1294 session_name = "*" + session_name;
1297 WindowTitle title(session_name);
1298 title += Glib::get_application_name();
1299 set_title (title.get_string());
1301 /* ::session_going_away() will have taken care of it */
1306 Editor::set_session (Session *t)
1308 SessionHandlePtr::set_session (t);
1314 _playlist_selector->set_session (_session);
1315 nudge_clock->set_session (_session);
1316 _summary->set_session (_session);
1317 _group_tabs->set_session (_session);
1318 _route_groups->set_session (_session);
1319 _regions->set_session (_session);
1320 _snapshots->set_session (_session);
1321 _routes->set_session (_session);
1322 _locations->set_session (_session);
1324 if (rhythm_ferret) {
1325 rhythm_ferret->set_session (_session);
1328 if (analysis_window) {
1329 analysis_window->set_session (_session);
1333 sfbrowser->set_session (_session);
1336 compute_fixed_ruler_scale ();
1338 /* Make sure we have auto loop and auto punch ranges */
1340 Location* loc = _session->locations()->auto_loop_location();
1342 loc->set_name (_("Loop"));
1345 loc = _session->locations()->auto_punch_location();
1348 loc->set_name (_("Punch"));
1351 refresh_location_display ();
1353 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1354 the selected Marker; this needs the LocationMarker list to be available.
1356 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1357 set_state (*node, Stateful::loading_state_version);
1359 /* catch up with the playhead */
1361 _session->request_locate (playhead_cursor->current_frame ());
1362 _pending_initial_locate = true;
1366 /* These signals can all be emitted by a non-GUI thread. Therefore the
1367 handlers for them must not attempt to directly interact with the GUI,
1368 but use PBD::Signal<T>::connect() which accepts an event loop
1369 ("context") where the handler will be asked to run.
1372 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1373 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1374 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1375 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1376 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1377 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1378 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1379 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1380 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1381 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1382 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1383 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1384 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1386 playhead_cursor->show ();
1388 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1389 Config->map_parameters (pc);
1390 _session->config.map_parameters (pc);
1392 restore_ruler_visibility ();
1393 //tempo_map_changed (PropertyChange (0));
1394 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1396 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1397 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1400 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1401 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1404 switch (_snap_type) {
1405 case SnapToRegionStart:
1406 case SnapToRegionEnd:
1407 case SnapToRegionSync:
1408 case SnapToRegionBoundary:
1409 build_region_boundary_cache ();
1416 /* register for undo history */
1417 _session->register_with_memento_command_factory(id(), this);
1418 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1420 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1422 start_updating_meters ();
1426 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1428 if (a->get_name() == "RegionMenu") {
1429 /* When the main menu's region menu is opened, we setup the actions so that they look right
1430 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1431 so we resensitize all region actions when the entered regionview or the region selection
1432 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1433 happens after the region context menu is opened. So we set a flag here, too.
1437 sensitize_the_right_region_actions ();
1438 _last_region_menu_was_main = true;
1443 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1445 using namespace Menu_Helpers;
1447 void (Editor::*emf)(FadeShape);
1448 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1451 images = &_xfade_in_images;
1452 emf = &Editor::set_fade_in_shape;
1454 images = &_xfade_out_images;
1455 emf = &Editor::set_fade_out_shape;
1460 _("Linear (for highly correlated material)"),
1461 *(*images)[FadeLinear],
1462 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1466 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1470 _("Constant power"),
1471 *(*images)[FadeConstantPower],
1472 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1475 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1480 *(*images)[FadeSymmetric],
1481 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1485 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1490 *(*images)[FadeSlow],
1491 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1494 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1499 *(*images)[FadeFast],
1500 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1503 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1506 /** Pop up a context menu for when the user clicks on a start crossfade */
1508 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1510 using namespace Menu_Helpers;
1511 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1516 MenuList& items (xfade_in_context_menu.items());
1519 if (arv->audio_region()->fade_in_active()) {
1520 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1522 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1525 items.push_back (SeparatorElem());
1526 fill_xfade_menu (items, true);
1528 xfade_in_context_menu.popup (button, time);
1531 /** Pop up a context menu for when the user clicks on an end crossfade */
1533 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1535 using namespace Menu_Helpers;
1536 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1541 MenuList& items (xfade_out_context_menu.items());
1544 if (arv->audio_region()->fade_out_active()) {
1545 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1547 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1550 items.push_back (SeparatorElem());
1551 fill_xfade_menu (items, false);
1553 xfade_out_context_menu.popup (button, time);
1557 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1559 using namespace Menu_Helpers;
1560 Menu* (Editor::*build_menu_function)();
1563 switch (item_type) {
1565 case RegionViewName:
1566 case RegionViewNameHighlight:
1567 case LeftFrameHandle:
1568 case RightFrameHandle:
1569 if (with_selection) {
1570 build_menu_function = &Editor::build_track_selection_context_menu;
1572 build_menu_function = &Editor::build_track_region_context_menu;
1577 if (with_selection) {
1578 build_menu_function = &Editor::build_track_selection_context_menu;
1580 build_menu_function = &Editor::build_track_context_menu;
1585 if (clicked_routeview->track()) {
1586 build_menu_function = &Editor::build_track_context_menu;
1588 build_menu_function = &Editor::build_track_bus_context_menu;
1593 /* probably shouldn't happen but if it does, we don't care */
1597 menu = (this->*build_menu_function)();
1598 menu->set_name ("ArdourContextMenu");
1600 /* now handle specific situations */
1602 switch (item_type) {
1604 case RegionViewName:
1605 case RegionViewNameHighlight:
1606 case LeftFrameHandle:
1607 case RightFrameHandle:
1608 if (!with_selection) {
1609 if (region_edit_menu_split_item) {
1610 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1611 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1613 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1616 if (region_edit_menu_split_multichannel_item) {
1617 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1618 region_edit_menu_split_multichannel_item->set_sensitive (true);
1620 region_edit_menu_split_multichannel_item->set_sensitive (false);
1633 /* probably shouldn't happen but if it does, we don't care */
1637 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1639 /* Bounce to disk */
1641 using namespace Menu_Helpers;
1642 MenuList& edit_items = menu->items();
1644 edit_items.push_back (SeparatorElem());
1646 switch (clicked_routeview->audio_track()->freeze_state()) {
1647 case AudioTrack::NoFreeze:
1648 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1651 case AudioTrack::Frozen:
1652 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1655 case AudioTrack::UnFrozen:
1656 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1662 if (item_type == StreamItem && clicked_routeview) {
1663 clicked_routeview->build_underlay_menu(menu);
1666 /* When the region menu is opened, we setup the actions so that they look right
1669 sensitize_the_right_region_actions ();
1670 _last_region_menu_was_main = false;
1672 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1673 menu->popup (button, time);
1677 Editor::build_track_context_menu ()
1679 using namespace Menu_Helpers;
1681 MenuList& edit_items = track_context_menu.items();
1684 add_dstream_context_items (edit_items);
1685 return &track_context_menu;
1689 Editor::build_track_bus_context_menu ()
1691 using namespace Menu_Helpers;
1693 MenuList& edit_items = track_context_menu.items();
1696 add_bus_context_items (edit_items);
1697 return &track_context_menu;
1701 Editor::build_track_region_context_menu ()
1703 using namespace Menu_Helpers;
1704 MenuList& edit_items = track_region_context_menu.items();
1707 /* we've just cleared the track region context menu, so the menu that these
1708 two items were on will have disappeared; stop them dangling.
1710 region_edit_menu_split_item = 0;
1711 region_edit_menu_split_multichannel_item = 0;
1713 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1716 boost::shared_ptr<Track> tr;
1717 boost::shared_ptr<Playlist> pl;
1719 if ((tr = rtv->track())) {
1720 add_region_context_items (edit_items, tr);
1724 add_dstream_context_items (edit_items);
1726 return &track_region_context_menu;
1730 Editor::analyze_region_selection ()
1732 if (analysis_window == 0) {
1733 analysis_window = new AnalysisWindow();
1736 analysis_window->set_session(_session);
1738 analysis_window->show_all();
1741 analysis_window->set_regionmode();
1742 analysis_window->analyze();
1744 analysis_window->present();
1748 Editor::analyze_range_selection()
1750 if (analysis_window == 0) {
1751 analysis_window = new AnalysisWindow();
1754 analysis_window->set_session(_session);
1756 analysis_window->show_all();
1759 analysis_window->set_rangemode();
1760 analysis_window->analyze();
1762 analysis_window->present();
1766 Editor::build_track_selection_context_menu ()
1768 using namespace Menu_Helpers;
1769 MenuList& edit_items = track_selection_context_menu.items();
1770 edit_items.clear ();
1772 add_selection_context_items (edit_items);
1773 // edit_items.push_back (SeparatorElem());
1774 // add_dstream_context_items (edit_items);
1776 return &track_selection_context_menu;
1780 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1782 using namespace Menu_Helpers;
1784 /* OK, stick the region submenu at the top of the list, and then add
1788 RegionSelection rs = get_regions_from_selection_and_entered ();
1790 string::size_type pos = 0;
1791 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1793 /* we have to hack up the region name because "_" has a special
1794 meaning for menu titles.
1797 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1798 menu_item_name.replace (pos, 1, "__");
1802 if (_popup_region_menu_item == 0) {
1803 _popup_region_menu_item = new MenuItem (menu_item_name);
1804 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1805 _popup_region_menu_item->show ();
1807 _popup_region_menu_item->set_label (menu_item_name);
1810 /* No latering allowed in later is higher layering model */
1811 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1812 if (act && Config->get_layer_model() == LaterHigher) {
1813 act->set_sensitive (false);
1815 act->set_sensitive (true);
1818 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1820 edit_items.push_back (*_popup_region_menu_item);
1821 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1822 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1824 edit_items.push_back (SeparatorElem());
1827 /** Add context menu items relevant to selection ranges.
1828 * @param edit_items List to add the items to.
1831 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1833 using namespace Menu_Helpers;
1835 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1836 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1838 edit_items.push_back (SeparatorElem());
1839 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1841 edit_items.push_back (SeparatorElem());
1842 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1844 edit_items.push_back (SeparatorElem());
1846 edit_items.push_back (
1848 _("Move Range Start to Previous Region Boundary"),
1849 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1853 edit_items.push_back (
1855 _("Move Range Start to Next Region Boundary"),
1856 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1860 edit_items.push_back (
1862 _("Move Range End to Previous Region Boundary"),
1863 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1867 edit_items.push_back (
1869 _("Move Range End to Next Region Boundary"),
1870 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1874 edit_items.push_back (SeparatorElem());
1875 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1876 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1878 edit_items.push_back (SeparatorElem());
1879 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1881 edit_items.push_back (SeparatorElem());
1882 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1883 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1884 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1886 edit_items.push_back (SeparatorElem());
1887 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1889 edit_items.push_back (SeparatorElem());
1890 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1891 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1892 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1894 edit_items.push_back (SeparatorElem());
1895 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1896 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1897 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1898 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1899 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1900 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1901 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1907 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1909 using namespace Menu_Helpers;
1913 Menu *play_menu = manage (new Menu);
1914 MenuList& play_items = play_menu->items();
1915 play_menu->set_name ("ArdourContextMenu");
1917 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1918 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1919 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1920 play_items.push_back (SeparatorElem());
1921 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1923 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1927 Menu *select_menu = manage (new Menu);
1928 MenuList& select_items = select_menu->items();
1929 select_menu->set_name ("ArdourContextMenu");
1931 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1932 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1933 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1934 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1935 select_items.push_back (SeparatorElem());
1936 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1937 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1938 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
1939 select_items.push_back (SeparatorElem());
1940 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1941 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1942 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1943 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1944 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1945 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1946 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1948 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1952 Menu *cutnpaste_menu = manage (new Menu);
1953 MenuList& cutnpaste_items = cutnpaste_menu->items();
1954 cutnpaste_menu->set_name ("ArdourContextMenu");
1956 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1957 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1958 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1960 cutnpaste_items.push_back (SeparatorElem());
1962 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1963 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1965 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1967 /* Adding new material */
1969 edit_items.push_back (SeparatorElem());
1970 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1971 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1975 Menu *nudge_menu = manage (new Menu());
1976 MenuList& nudge_items = nudge_menu->items();
1977 nudge_menu->set_name ("ArdourContextMenu");
1979 edit_items.push_back (SeparatorElem());
1980 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1981 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1982 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1983 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1985 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1989 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1991 using namespace Menu_Helpers;
1995 Menu *play_menu = manage (new Menu);
1996 MenuList& play_items = play_menu->items();
1997 play_menu->set_name ("ArdourContextMenu");
1999 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2000 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2001 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2005 Menu *select_menu = manage (new Menu);
2006 MenuList& select_items = select_menu->items();
2007 select_menu->set_name ("ArdourContextMenu");
2009 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2010 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2011 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2012 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2013 select_items.push_back (SeparatorElem());
2014 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2015 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2016 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2017 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2019 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2023 Menu *cutnpaste_menu = manage (new Menu);
2024 MenuList& cutnpaste_items = cutnpaste_menu->items();
2025 cutnpaste_menu->set_name ("ArdourContextMenu");
2027 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2028 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2029 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2031 Menu *nudge_menu = manage (new Menu());
2032 MenuList& nudge_items = nudge_menu->items();
2033 nudge_menu->set_name ("ArdourContextMenu");
2035 edit_items.push_back (SeparatorElem());
2036 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2037 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2038 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2039 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2041 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2045 Editor::snap_type() const
2051 Editor::snap_mode() const
2057 Editor::set_snap_to (SnapType st)
2059 unsigned int snap_ind = (unsigned int)st;
2061 if (internal_editing()) {
2062 internal_snap_type = st;
2064 pre_internal_snap_type = st;
2069 if (snap_ind > snap_type_strings.size() - 1) {
2071 _snap_type = (SnapType)snap_ind;
2074 string str = snap_type_strings[snap_ind];
2076 if (str != snap_type_selector.get_text()) {
2077 snap_type_selector.set_text (str);
2082 switch (_snap_type) {
2083 case SnapToBeatDiv128:
2084 case SnapToBeatDiv64:
2085 case SnapToBeatDiv32:
2086 case SnapToBeatDiv28:
2087 case SnapToBeatDiv24:
2088 case SnapToBeatDiv20:
2089 case SnapToBeatDiv16:
2090 case SnapToBeatDiv14:
2091 case SnapToBeatDiv12:
2092 case SnapToBeatDiv10:
2093 case SnapToBeatDiv8:
2094 case SnapToBeatDiv7:
2095 case SnapToBeatDiv6:
2096 case SnapToBeatDiv5:
2097 case SnapToBeatDiv4:
2098 case SnapToBeatDiv3:
2099 case SnapToBeatDiv2: {
2100 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2101 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2103 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2104 current_bbt_points_begin, current_bbt_points_end);
2105 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2106 current_bbt_points_begin, current_bbt_points_end);
2107 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2111 case SnapToRegionStart:
2112 case SnapToRegionEnd:
2113 case SnapToRegionSync:
2114 case SnapToRegionBoundary:
2115 build_region_boundary_cache ();
2123 redisplay_tempo (false);
2125 SnapChanged (); /* EMIT SIGNAL */
2129 Editor::set_snap_mode (SnapMode mode)
2131 string str = snap_mode_strings[(int)mode];
2133 if (internal_editing()) {
2134 internal_snap_mode = mode;
2136 pre_internal_snap_mode = mode;
2141 if (str != snap_mode_selector.get_text ()) {
2142 snap_mode_selector.set_text (str);
2149 Editor::set_edit_point_preference (EditPoint ep, bool force)
2151 bool changed = (_edit_point != ep);
2154 if (Profile->get_mixbus())
2155 if (ep == EditAtSelectedMarker)
2156 ep = EditAtPlayhead;
2158 string str = edit_point_strings[(int)ep];
2159 if (str != edit_point_selector.get_text ()) {
2160 edit_point_selector.set_text (str);
2163 update_all_enter_cursors();
2165 if (!force && !changed) {
2169 const char* action=NULL;
2171 switch (_edit_point) {
2172 case EditAtPlayhead:
2173 action = "edit-at-playhead";
2175 case EditAtSelectedMarker:
2176 action = "edit-at-marker";
2179 action = "edit-at-mouse";
2183 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2185 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2189 bool in_track_canvas;
2191 if (!mouse_frame (foo, in_track_canvas)) {
2192 in_track_canvas = false;
2195 reset_canvas_action_sensitivity (in_track_canvas);
2201 Editor::set_state (const XMLNode& node, int /*version*/)
2203 const XMLProperty* prop;
2210 g.base_width = default_width;
2211 g.base_height = default_height;
2215 if ((geometry = find_named_node (node, "geometry")) != 0) {
2219 if ((prop = geometry->property("x_size")) == 0) {
2220 prop = geometry->property ("x-size");
2223 g.base_width = atoi(prop->value());
2225 if ((prop = geometry->property("y_size")) == 0) {
2226 prop = geometry->property ("y-size");
2229 g.base_height = atoi(prop->value());
2232 if ((prop = geometry->property ("x_pos")) == 0) {
2233 prop = geometry->property ("x-pos");
2236 x = atoi (prop->value());
2239 if ((prop = geometry->property ("y_pos")) == 0) {
2240 prop = geometry->property ("y-pos");
2243 y = atoi (prop->value());
2247 set_default_size (g.base_width, g.base_height);
2250 if (_session && (prop = node.property ("playhead"))) {
2252 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2254 playhead_cursor->set_position (pos);
2256 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2257 playhead_cursor->set_position (0);
2260 playhead_cursor->set_position (0);
2263 if ((prop = node.property ("mixer-width"))) {
2264 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2267 if ((prop = node.property ("zoom-focus"))) {
2268 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2271 if ((prop = node.property ("zoom"))) {
2272 /* older versions of ardour used floating point samples_per_pixel */
2273 double f = PBD::atof (prop->value());
2274 reset_zoom (llrintf (f));
2276 reset_zoom (samples_per_pixel);
2279 if ((prop = node.property ("visible-track-count"))) {
2280 set_visible_track_count (PBD::atoi (prop->value()));
2283 if ((prop = node.property ("snap-to"))) {
2284 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2287 if ((prop = node.property ("snap-mode"))) {
2288 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2291 if ((prop = node.property ("internal-snap-to"))) {
2292 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2295 if ((prop = node.property ("internal-snap-mode"))) {
2296 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2299 if ((prop = node.property ("pre-internal-snap-to"))) {
2300 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2303 if ((prop = node.property ("pre-internal-snap-mode"))) {
2304 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2307 if ((prop = node.property ("mouse-mode"))) {
2308 MouseMode m = str2mousemode(prop->value());
2309 set_mouse_mode (m, true);
2311 set_mouse_mode (MouseObject, true);
2314 if ((prop = node.property ("left-frame")) != 0) {
2316 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2320 reset_x_origin (pos);
2324 if ((prop = node.property ("y-origin")) != 0) {
2325 reset_y_origin (atof (prop->value ()));
2328 if ((prop = node.property ("join-object-range"))) {
2329 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2330 bool yn = string_is_affirmative (prop->value());
2332 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2333 tact->set_active (!yn);
2334 tact->set_active (yn);
2336 set_mouse_mode(mouse_mode, true);
2339 if ((prop = node.property ("edit-point"))) {
2340 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2343 if ((prop = node.property ("show-measures"))) {
2344 bool yn = string_is_affirmative (prop->value());
2345 _show_measures = yn;
2348 if ((prop = node.property ("follow-playhead"))) {
2349 bool yn = string_is_affirmative (prop->value());
2350 set_follow_playhead (yn);
2353 if ((prop = node.property ("stationary-playhead"))) {
2354 bool yn = string_is_affirmative (prop->value());
2355 set_stationary_playhead (yn);
2358 if ((prop = node.property ("region-list-sort-type"))) {
2359 RegionListSortType st;
2360 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2363 if ((prop = node.property ("show-editor-mixer"))) {
2365 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2368 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2369 bool yn = string_is_affirmative (prop->value());
2371 /* do it twice to force the change */
2373 tact->set_active (!yn);
2374 tact->set_active (yn);
2377 if ((prop = node.property ("show-editor-list"))) {
2379 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2382 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2383 bool yn = string_is_affirmative (prop->value());
2385 /* do it twice to force the change */
2387 tact->set_active (!yn);
2388 tact->set_active (yn);
2391 if ((prop = node.property (X_("editor-list-page")))) {
2392 _the_notebook.set_current_page (atoi (prop->value ()));
2395 if ((prop = node.property (X_("show-marker-lines")))) {
2396 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2398 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2399 bool yn = string_is_affirmative (prop->value ());
2401 tact->set_active (!yn);
2402 tact->set_active (yn);
2405 XMLNodeList children = node.children ();
2406 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2407 selection->set_state (**i, Stateful::current_state_version);
2408 _regions->set_state (**i);
2411 if ((prop = node.property ("maximised"))) {
2412 bool yn = string_is_affirmative (prop->value());
2413 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2415 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2416 bool fs = tact && tact->get_active();
2418 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2422 if ((prop = node.property ("nudge-clock-value"))) {
2424 sscanf (prop->value().c_str(), "%" PRId64, &f);
2425 nudge_clock->set (f);
2427 nudge_clock->set_mode (AudioClock::Timecode);
2428 nudge_clock->set (_session->frame_rate() * 5, true);
2433 * Not all properties may have been in XML, but
2434 * those that are linked to a private variable may need changing
2439 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2441 yn = _show_measures;
2442 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2443 /* do it twice to force the change */
2444 tact->set_active (!yn);
2445 tact->set_active (yn);
2448 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2449 yn = _follow_playhead;
2451 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2452 if (tact->get_active() != yn) {
2453 tact->set_active (yn);
2457 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2458 yn = _stationary_playhead;
2460 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2461 if (tact->get_active() != yn) {
2462 tact->set_active (yn);
2471 Editor::get_state ()
2473 XMLNode* node = new XMLNode ("Editor");
2476 id().print (buf, sizeof (buf));
2477 node->add_property ("id", buf);
2479 if (is_realized()) {
2480 Glib::RefPtr<Gdk::Window> win = get_window();
2482 int x, y, width, height;
2483 win->get_root_origin(x, y);
2484 win->get_size(width, height);
2486 XMLNode* geometry = new XMLNode ("geometry");
2488 snprintf(buf, sizeof(buf), "%d", width);
2489 geometry->add_property("x-size", string(buf));
2490 snprintf(buf, sizeof(buf), "%d", height);
2491 geometry->add_property("y-size", string(buf));
2492 snprintf(buf, sizeof(buf), "%d", x);
2493 geometry->add_property("x-pos", string(buf));
2494 snprintf(buf, sizeof(buf), "%d", y);
2495 geometry->add_property("y-pos", string(buf));
2496 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2497 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2498 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2499 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2500 geometry->add_property("edit-vertical-pane-pos", string(buf));
2502 node->add_child_nocopy (*geometry);
2505 maybe_add_mixer_strip_width (*node);
2507 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2509 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2510 node->add_property ("zoom", buf);
2511 node->add_property ("snap-to", enum_2_string (_snap_type));
2512 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2513 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2514 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2515 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2516 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2517 node->add_property ("edit-point", enum_2_string (_edit_point));
2518 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2519 node->add_property ("visible-track-count", buf);
2521 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2522 node->add_property ("playhead", buf);
2523 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2524 node->add_property ("left-frame", buf);
2525 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2526 node->add_property ("y-origin", buf);
2528 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2529 node->add_property ("maximised", _maximised ? "yes" : "no");
2530 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2531 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2532 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2533 node->add_property ("mouse-mode", enum2str(mouse_mode));
2534 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2536 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2538 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2539 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2542 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2544 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2545 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2548 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2549 node->add_property (X_("editor-list-page"), buf);
2551 if (button_bindings) {
2552 XMLNode* bb = new XMLNode (X_("Buttons"));
2553 button_bindings->save (*bb);
2554 node->add_child_nocopy (*bb);
2557 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2559 node->add_child_nocopy (selection->get_state ());
2560 node->add_child_nocopy (_regions->get_state ());
2562 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2563 node->add_property ("nudge-clock-value", buf);
2568 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2569 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2571 * @return pair: TimeAxisView that y is over, layer index.
2573 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2574 * in stacked or expanded region display mode, otherwise 0.
2576 std::pair<TimeAxisView *, double>
2577 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2579 if (!trackview_relative_offset) {
2580 y -= _trackview_group->canvas_origin().y;
2584 return std::make_pair ( (TimeAxisView *) 0, 0);
2587 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2589 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2596 return std::make_pair ( (TimeAxisView *) 0, 0);
2599 /** Snap a position to the grid, if appropriate, taking into account current
2600 * grid settings and also the state of any snap modifier keys that may be pressed.
2601 * @param start Position to snap.
2602 * @param event Event to get current key modifier information from, or 0.
2605 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2607 if (!_session || !event) {
2611 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2612 if (_snap_mode == SnapOff) {
2613 snap_to_internal (start, direction, for_mark);
2616 if (_snap_mode != SnapOff) {
2617 snap_to_internal (start, direction, for_mark);
2618 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2619 /* SnapOff, but we pressed the snap_delta modifier */
2620 snap_to_internal (start, direction, for_mark);
2626 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2628 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2632 snap_to_internal (start, direction, for_mark, ensure_snap);
2636 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2638 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2639 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2641 switch (_snap_type) {
2642 case SnapToTimecodeFrame:
2643 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2644 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2645 /* start is already on a whole timecode frame, do nothing */
2646 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2647 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2649 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2653 case SnapToTimecodeSeconds:
2654 if (_session->config.get_timecode_offset_negative()) {
2655 start += _session->config.get_timecode_offset ();
2657 start -= _session->config.get_timecode_offset ();
2659 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2660 (start % one_timecode_second == 0)) {
2661 /* start is already on a whole second, do nothing */
2662 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2663 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2665 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2668 if (_session->config.get_timecode_offset_negative()) {
2669 start -= _session->config.get_timecode_offset ();
2671 start += _session->config.get_timecode_offset ();
2675 case SnapToTimecodeMinutes:
2676 if (_session->config.get_timecode_offset_negative()) {
2677 start += _session->config.get_timecode_offset ();
2679 start -= _session->config.get_timecode_offset ();
2681 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2682 (start % one_timecode_minute == 0)) {
2683 /* start is already on a whole minute, do nothing */
2684 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2685 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2687 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2689 if (_session->config.get_timecode_offset_negative()) {
2690 start -= _session->config.get_timecode_offset ();
2692 start += _session->config.get_timecode_offset ();
2696 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2697 abort(); /*NOTREACHED*/
2702 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2704 const framepos_t one_second = _session->frame_rate();
2705 const framepos_t one_minute = _session->frame_rate() * 60;
2706 framepos_t presnap = start;
2710 switch (_snap_type) {
2711 case SnapToTimecodeFrame:
2712 case SnapToTimecodeSeconds:
2713 case SnapToTimecodeMinutes:
2714 return timecode_snap_to_internal (start, direction, for_mark);
2717 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2718 start % (one_second/75) == 0) {
2719 /* start is already on a whole CD frame, do nothing */
2720 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2721 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2723 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2728 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2729 start % one_second == 0) {
2730 /* start is already on a whole second, do nothing */
2731 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2732 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2734 start = (framepos_t) floor ((double) start / one_second) * one_second;
2739 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2740 start % one_minute == 0) {
2741 /* start is already on a whole minute, do nothing */
2742 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2743 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2745 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2750 start = _session->tempo_map().round_to_bar (start, direction);
2754 start = _session->tempo_map().round_to_beat (start, direction);
2757 case SnapToBeatDiv128:
2758 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2760 case SnapToBeatDiv64:
2761 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2763 case SnapToBeatDiv32:
2764 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2766 case SnapToBeatDiv28:
2767 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2769 case SnapToBeatDiv24:
2770 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2772 case SnapToBeatDiv20:
2773 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2775 case SnapToBeatDiv16:
2776 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2778 case SnapToBeatDiv14:
2779 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2781 case SnapToBeatDiv12:
2782 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2784 case SnapToBeatDiv10:
2785 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2787 case SnapToBeatDiv8:
2788 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2790 case SnapToBeatDiv7:
2791 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2793 case SnapToBeatDiv6:
2794 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2796 case SnapToBeatDiv5:
2797 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2799 case SnapToBeatDiv4:
2800 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2802 case SnapToBeatDiv3:
2803 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2805 case SnapToBeatDiv2:
2806 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2814 _session->locations()->marks_either_side (start, before, after);
2816 if (before == max_framepos && after == max_framepos) {
2817 /* No marks to snap to, so just don't snap */
2819 } else if (before == max_framepos) {
2821 } else if (after == max_framepos) {
2823 } else if (before != max_framepos && after != max_framepos) {
2824 /* have before and after */
2825 if ((start - before) < (after - start)) {
2834 case SnapToRegionStart:
2835 case SnapToRegionEnd:
2836 case SnapToRegionSync:
2837 case SnapToRegionBoundary:
2838 if (!region_boundary_cache.empty()) {
2840 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2841 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2843 if (direction > 0) {
2844 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2846 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2849 if (next != region_boundary_cache.begin ()) {
2854 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2855 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2857 if (start > (p + n) / 2) {
2866 switch (_snap_mode) {
2876 if (presnap > start) {
2877 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2881 } else if (presnap < start) {
2882 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2888 /* handled at entry */
2896 Editor::setup_toolbar ()
2898 HBox* mode_box = manage(new HBox);
2899 mode_box->set_border_width (2);
2900 mode_box->set_spacing(2);
2902 HBox* mouse_mode_box = manage (new HBox);
2903 HBox* mouse_mode_hbox = manage (new HBox);
2904 VBox* mouse_mode_vbox = manage (new VBox);
2905 Alignment* mouse_mode_align = manage (new Alignment);
2907 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2908 mouse_mode_size_group->add_widget (smart_mode_button);
2909 mouse_mode_size_group->add_widget (mouse_move_button);
2910 mouse_mode_size_group->add_widget (mouse_cut_button);
2911 mouse_mode_size_group->add_widget (mouse_select_button);
2912 mouse_mode_size_group->add_widget (mouse_timefx_button);
2913 mouse_mode_size_group->add_widget (mouse_audition_button);
2914 mouse_mode_size_group->add_widget (mouse_draw_button);
2915 mouse_mode_size_group->add_widget (mouse_content_button);
2917 mouse_mode_size_group->add_widget (zoom_in_button);
2918 mouse_mode_size_group->add_widget (zoom_out_button);
2919 mouse_mode_size_group->add_widget (zoom_preset_selector);
2920 mouse_mode_size_group->add_widget (zoom_out_full_button);
2921 mouse_mode_size_group->add_widget (zoom_focus_selector);
2923 mouse_mode_size_group->add_widget (tav_shrink_button);
2924 mouse_mode_size_group->add_widget (tav_expand_button);
2925 mouse_mode_size_group->add_widget (visible_tracks_selector);
2927 mouse_mode_size_group->add_widget (snap_type_selector);
2928 mouse_mode_size_group->add_widget (snap_mode_selector);
2930 mouse_mode_size_group->add_widget (edit_point_selector);
2931 mouse_mode_size_group->add_widget (edit_mode_selector);
2933 mouse_mode_size_group->add_widget (*nudge_clock);
2934 mouse_mode_size_group->add_widget (nudge_forward_button);
2935 mouse_mode_size_group->add_widget (nudge_backward_button);
2937 mouse_mode_hbox->set_spacing (2);
2939 if (!ARDOUR::Profile->get_trx()) {
2940 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2943 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2944 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2946 if (!ARDOUR::Profile->get_mixbus()) {
2947 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2950 if (!ARDOUR::Profile->get_trx()) {
2951 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2952 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2953 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2954 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2957 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2959 mouse_mode_align->add (*mouse_mode_vbox);
2960 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2962 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2964 edit_mode_selector.set_name ("mouse mode button");
2966 if (!ARDOUR::Profile->get_trx()) {
2967 mode_box->pack_start (edit_mode_selector, false, false);
2969 mode_box->pack_start (*mouse_mode_box, false, false);
2971 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2972 _mouse_mode_tearoff->set_name ("MouseModeBase");
2973 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2975 if (Profile->get_sae() || Profile->get_mixbus() ) {
2976 _mouse_mode_tearoff->set_can_be_torn_off (false);
2979 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2980 &_mouse_mode_tearoff->tearoff_window()));
2981 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2982 &_mouse_mode_tearoff->tearoff_window(), 1));
2983 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2984 &_mouse_mode_tearoff->tearoff_window()));
2985 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2986 &_mouse_mode_tearoff->tearoff_window(), 1));
2990 _zoom_box.set_spacing (2);
2991 _zoom_box.set_border_width (2);
2995 zoom_preset_selector.set_name ("zoom button");
2996 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2997 zoom_preset_selector.set_size_request (42, -1);
2999 zoom_in_button.set_name ("zoom button");
3000 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3001 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3002 zoom_in_button.set_related_action (act);
3004 zoom_out_button.set_name ("zoom button");
3005 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3006 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3007 zoom_out_button.set_related_action (act);
3009 zoom_out_full_button.set_name ("zoom button");
3010 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3011 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3012 zoom_out_full_button.set_related_action (act);
3014 zoom_focus_selector.set_name ("zoom button");
3016 if (ARDOUR::Profile->get_mixbus()) {
3017 _zoom_box.pack_start (zoom_preset_selector, false, false);
3018 } else if (ARDOUR::Profile->get_trx()) {
3019 mode_box->pack_start (zoom_out_button, false, false);
3020 mode_box->pack_start (zoom_in_button, false, false);
3022 _zoom_box.pack_start (zoom_out_button, false, false);
3023 _zoom_box.pack_start (zoom_in_button, false, false);
3024 _zoom_box.pack_start (zoom_out_full_button, false, false);
3025 _zoom_box.pack_start (zoom_focus_selector, false, false);
3028 /* Track zoom buttons */
3029 visible_tracks_selector.set_name ("zoom button");
3030 if (Profile->get_mixbus()) {
3031 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3032 visible_tracks_selector.set_size_request (42, -1);
3034 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3037 tav_expand_button.set_name ("zoom button");
3038 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3039 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3040 tav_expand_button.set_related_action (act);
3042 tav_shrink_button.set_name ("zoom button");
3043 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3044 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3045 tav_shrink_button.set_related_action (act);
3047 if (ARDOUR::Profile->get_mixbus()) {
3048 _zoom_box.pack_start (visible_tracks_selector);
3049 } else if (ARDOUR::Profile->get_trx()) {
3050 _zoom_box.pack_start (tav_shrink_button);
3051 _zoom_box.pack_start (tav_expand_button);
3053 _zoom_box.pack_start (visible_tracks_selector);
3054 _zoom_box.pack_start (tav_shrink_button);
3055 _zoom_box.pack_start (tav_expand_button);
3058 if (!ARDOUR::Profile->get_trx()) {
3059 _zoom_tearoff = manage (new TearOff (_zoom_box));
3061 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3062 &_zoom_tearoff->tearoff_window()));
3063 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3064 &_zoom_tearoff->tearoff_window(), 0));
3065 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3066 &_zoom_tearoff->tearoff_window()));
3067 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3068 &_zoom_tearoff->tearoff_window(), 0));
3071 if (Profile->get_sae() || Profile->get_mixbus() ) {
3072 _zoom_tearoff->set_can_be_torn_off (false);
3075 snap_box.set_spacing (2);
3076 snap_box.set_border_width (2);
3078 snap_type_selector.set_name ("mouse mode button");
3080 snap_mode_selector.set_name ("mouse mode button");
3082 edit_point_selector.set_name ("mouse mode button");
3084 snap_box.pack_start (snap_mode_selector, false, false);
3085 snap_box.pack_start (snap_type_selector, false, false);
3086 snap_box.pack_start (edit_point_selector, false, false);
3090 HBox *nudge_box = manage (new HBox);
3091 nudge_box->set_spacing (2);
3092 nudge_box->set_border_width (2);
3094 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3095 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3097 nudge_box->pack_start (nudge_backward_button, false, false);
3098 nudge_box->pack_start (nudge_forward_button, false, false);
3099 nudge_box->pack_start (*nudge_clock, false, false);
3102 /* Pack everything in... */
3104 HBox* hbox = manage (new HBox);
3105 hbox->set_spacing(2);
3107 _tools_tearoff = manage (new TearOff (*hbox));
3108 _tools_tearoff->set_name ("MouseModeBase");
3109 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3111 if (Profile->get_sae() || Profile->get_mixbus()) {
3112 _tools_tearoff->set_can_be_torn_off (false);
3115 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3116 &_tools_tearoff->tearoff_window()));
3117 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3118 &_tools_tearoff->tearoff_window(), 0));
3119 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3120 &_tools_tearoff->tearoff_window()));
3121 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3122 &_tools_tearoff->tearoff_window(), 0));
3124 toolbar_hbox.set_spacing (2);
3125 toolbar_hbox.set_border_width (1);
3127 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3128 if (!ARDOUR::Profile->get_trx()) {
3129 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3130 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3133 if (!ARDOUR::Profile->get_trx()) {
3134 hbox->pack_start (snap_box, false, false);
3135 hbox->pack_start (*nudge_box, false, false);
3137 hbox->pack_start (panic_box, false, false);
3141 toolbar_base.set_name ("ToolBarBase");
3142 toolbar_base.add (toolbar_hbox);
3144 _toolbar_viewport.add (toolbar_base);
3145 /* stick to the required height but allow width to vary if there's not enough room */
3146 _toolbar_viewport.set_size_request (1, -1);
3148 toolbar_frame.set_shadow_type (SHADOW_OUT);
3149 toolbar_frame.set_name ("BaseFrame");
3150 toolbar_frame.add (_toolbar_viewport);
3154 Editor::build_edit_point_menu ()
3156 using namespace Menu_Helpers;
3158 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3159 if(!Profile->get_mixbus())
3160 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3161 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3163 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3167 Editor::build_edit_mode_menu ()
3169 using namespace Menu_Helpers;
3171 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3172 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3173 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3174 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3176 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3180 Editor::build_snap_mode_menu ()
3182 using namespace Menu_Helpers;
3184 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3185 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3186 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3188 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3192 Editor::build_snap_type_menu ()
3194 using namespace Menu_Helpers;
3196 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3197 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3198 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3199 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3200 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3201 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3202 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3203 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3204 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3205 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3206 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3207 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3208 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3209 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3210 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3211 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3212 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3213 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3214 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3215 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3216 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3217 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3218 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3219 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3220 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3221 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3222 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3223 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3224 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3225 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3227 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3232 Editor::setup_tooltips ()
3234 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Grab mode)"));
3235 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Grab Mode (select/move objects)"));
3236 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split regions)"));
3237 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select time ranges)"));
3238 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3239 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3240 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3241 ARDOUR_UI::instance()->set_tip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3242 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3243 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3244 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3245 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3246 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3247 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3248 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3249 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3250 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3251 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3252 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3253 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3254 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3255 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3256 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3257 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3261 Editor::convert_drop_to_paths (
3262 vector<string>& paths,
3263 const RefPtr<Gdk::DragContext>& /*context*/,
3266 const SelectionData& data,
3270 if (_session == 0) {
3274 vector<string> uris = data.get_uris();
3278 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3279 are actually URI lists. So do it by hand.
3282 if (data.get_target() != "text/plain") {
3286 /* Parse the "uri-list" format that Nautilus provides,
3287 where each pathname is delimited by \r\n.
3289 THERE MAY BE NO NULL TERMINATING CHAR!!!
3292 string txt = data.get_text();
3296 p = (char *) malloc (txt.length() + 1);
3297 txt.copy (p, txt.length(), 0);
3298 p[txt.length()] = '\0';
3304 while (g_ascii_isspace (*p))
3308 while (*q && (*q != '\n') && (*q != '\r')) {
3315 while (q > p && g_ascii_isspace (*q))
3320 uris.push_back (string (p, q - p + 1));
3324 p = strchr (p, '\n');
3336 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3337 if ((*i).substr (0,7) == "file://") {
3338 paths.push_back (Glib::filename_from_uri (*i));
3346 Editor::new_tempo_section ()
3351 Editor::map_transport_state ()
3353 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3355 if (_session && _session->transport_stopped()) {
3356 have_pending_keyboard_selection = false;
3359 update_loop_range_view ();
3365 Editor::begin_selection_op_history ()
3367 selection_op_cmd_depth = 0;
3368 selection_op_history_it = 0;
3370 while(!selection_op_history.empty()) {
3371 delete selection_op_history.front();
3372 selection_op_history.pop_front();
3375 selection_undo_action->set_sensitive (false);
3376 selection_redo_action->set_sensitive (false);
3377 selection_op_history.push_front (&_selection_memento->get_state ());
3381 Editor::begin_reversible_selection_op (string name)
3384 //cerr << name << endl;
3385 /* begin/commit pairs can be nested */
3386 selection_op_cmd_depth++;
3391 Editor::commit_reversible_selection_op ()
3394 if (selection_op_cmd_depth == 1) {
3396 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3398 The user has undone some selection ops and then made a new one,
3399 making anything earlier in the list invalid.
3402 list<XMLNode *>::iterator it = selection_op_history.begin();
3403 list<XMLNode *>::iterator e_it = it;
3404 advance (e_it, selection_op_history_it);
3406 for ( ; it != e_it; ++it) {
3409 selection_op_history.erase (selection_op_history.begin(), e_it);
3412 selection_op_history.push_front (&_selection_memento->get_state ());
3413 selection_op_history_it = 0;
3415 selection_undo_action->set_sensitive (true);
3416 selection_redo_action->set_sensitive (false);
3419 if (selection_op_cmd_depth > 0) {
3420 selection_op_cmd_depth--;
3426 Editor::undo_selection_op ()
3429 selection_op_history_it++;
3431 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3432 if (n == selection_op_history_it) {
3433 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3434 selection_redo_action->set_sensitive (true);
3438 /* is there an earlier entry? */
3439 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3440 selection_undo_action->set_sensitive (false);
3446 Editor::redo_selection_op ()
3449 if (selection_op_history_it > 0) {
3450 selection_op_history_it--;
3453 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3454 if (n == selection_op_history_it) {
3455 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3456 selection_undo_action->set_sensitive (true);
3461 if (selection_op_history_it == 0) {
3462 selection_redo_action->set_sensitive (false);
3468 Editor::begin_reversible_command (string name)
3471 before.push_back (&_selection_memento->get_state ());
3472 _session->begin_reversible_command (name);
3477 Editor::begin_reversible_command (GQuark q)
3480 before.push_back (&_selection_memento->get_state ());
3481 _session->begin_reversible_command (q);
3486 Editor::abort_reversible_command ()
3489 while(!before.empty()) {
3490 delete before.front();
3493 _session->abort_reversible_command ();
3498 Editor::commit_reversible_command ()
3501 if (before.size() == 1) {
3502 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3503 redo_action->set_sensitive(false);
3504 undo_action->set_sensitive(true);
3505 begin_selection_op_history ();
3508 if (before.empty()) {
3509 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3514 _session->commit_reversible_command ();
3519 Editor::history_changed ()
3523 if (undo_action && _session) {
3524 if (_session->undo_depth() == 0) {
3525 label = S_("Command|Undo");
3527 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3529 undo_action->property_label() = label;
3532 if (redo_action && _session) {
3533 if (_session->redo_depth() == 0) {
3536 label = string_compose(_("Redo (%1)"), _session->next_redo());
3538 redo_action->property_label() = label;
3543 Editor::duplicate_range (bool with_dialog)
3547 RegionSelection rs = get_regions_from_selection_and_entered ();
3549 if ( selection->time.length() == 0 && rs.empty()) {
3555 ArdourDialog win (_("Duplicate"));
3556 Label label (_("Number of duplications:"));
3557 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3558 SpinButton spinner (adjustment, 0.0, 1);
3561 win.get_vbox()->set_spacing (12);
3562 win.get_vbox()->pack_start (hbox);
3563 hbox.set_border_width (6);
3564 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3566 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3567 place, visually. so do this by hand.
3570 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3571 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3572 spinner.grab_focus();
3578 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3579 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3580 win.set_default_response (RESPONSE_ACCEPT);
3582 spinner.grab_focus ();
3584 switch (win.run ()) {
3585 case RESPONSE_ACCEPT:
3591 times = adjustment.get_value();
3594 if ((current_mouse_mode() == Editing::MouseRange)) {
3595 if (selection->time.length()) {
3596 duplicate_selection (times);
3598 } else if (get_smart_mode()) {
3599 if (selection->time.length()) {
3600 duplicate_selection (times);
3602 duplicate_some_regions (rs, times);
3604 duplicate_some_regions (rs, times);
3609 Editor::set_edit_mode (EditMode m)
3611 Config->set_edit_mode (m);
3615 Editor::cycle_edit_mode ()
3617 switch (Config->get_edit_mode()) {
3619 if (Profile->get_sae()) {
3620 Config->set_edit_mode (Lock);
3622 Config->set_edit_mode (Ripple);
3627 Config->set_edit_mode (Lock);
3630 Config->set_edit_mode (Slide);
3636 Editor::edit_mode_selection_done ( EditMode m )
3638 Config->set_edit_mode ( m );
3642 Editor::snap_type_selection_done (SnapType snaptype)
3644 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3646 ract->set_active ();
3651 Editor::snap_mode_selection_done (SnapMode mode)
3653 RefPtr<RadioAction> ract = snap_mode_action (mode);
3656 ract->set_active (true);
3661 Editor::cycle_edit_point (bool with_marker)
3663 if(Profile->get_mixbus())
3664 with_marker = false;
3666 switch (_edit_point) {
3668 set_edit_point_preference (EditAtPlayhead);
3670 case EditAtPlayhead:
3672 set_edit_point_preference (EditAtSelectedMarker);
3674 set_edit_point_preference (EditAtMouse);
3677 case EditAtSelectedMarker:
3678 set_edit_point_preference (EditAtMouse);
3684 Editor::edit_point_selection_done (EditPoint ep)
3686 set_edit_point_preference ( ep );
3690 Editor::build_zoom_focus_menu ()
3692 using namespace Menu_Helpers;
3694 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3695 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3696 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3697 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3698 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3699 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3701 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3705 Editor::zoom_focus_selection_done ( ZoomFocus f )
3707 RefPtr<RadioAction> ract = zoom_focus_action (f);
3709 ract->set_active ();
3714 Editor::build_track_count_menu ()
3716 using namespace Menu_Helpers;
3718 if (!Profile->get_mixbus()) {
3719 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3720 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3721 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3722 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3723 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3724 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3725 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3726 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3727 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3728 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3729 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3730 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3731 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3733 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3734 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3735 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3736 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3737 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3738 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3739 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3740 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3741 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3742 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3744 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3745 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3746 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3747 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3748 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3749 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3750 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3751 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3752 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3753 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3754 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3759 Editor::set_zoom_preset (int64_t ms)
3762 temporal_zoom_session();
3766 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3767 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3771 Editor::set_visible_track_count (int32_t n)
3773 _visible_track_count = n;
3775 /* if the canvas hasn't really been allocated any size yet, just
3776 record the desired number of visible tracks and return. when canvas
3777 allocation happens, we will get called again and then we can do the
3781 if (_visible_canvas_height <= 1) {
3787 DisplaySuspender ds;
3789 if (_visible_track_count > 0) {
3790 h = trackviews_height() / _visible_track_count;
3791 std::ostringstream s;
3792 s << _visible_track_count;
3794 } else if (_visible_track_count == 0) {
3796 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3797 if ((*i)->marked_for_display()) {
3801 h = trackviews_height() / n;
3804 /* negative value means that the visible track count has
3805 been overridden by explicit track height changes.
3807 visible_tracks_selector.set_text (X_("*"));
3811 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3812 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3815 if (str != visible_tracks_selector.get_text()) {
3816 visible_tracks_selector.set_text (str);
3821 Editor::override_visible_track_count ()
3823 _visible_track_count = -1;
3824 visible_tracks_selector.set_text ( _("*") );
3828 Editor::edit_controls_button_release (GdkEventButton* ev)
3830 if (Keyboard::is_context_menu_event (ev)) {
3831 ARDOUR_UI::instance()->add_route (this);
3832 } else if (ev->button == 1) {
3833 selection->clear_tracks ();
3840 Editor::mouse_select_button_release (GdkEventButton* ev)
3842 /* this handles just right-clicks */
3844 if (ev->button != 3) {
3852 Editor::set_zoom_focus (ZoomFocus f)
3854 string str = zoom_focus_strings[(int)f];
3856 if (str != zoom_focus_selector.get_text()) {
3857 zoom_focus_selector.set_text (str);
3860 if (zoom_focus != f) {
3867 Editor::cycle_zoom_focus ()
3869 switch (zoom_focus) {
3871 set_zoom_focus (ZoomFocusRight);
3873 case ZoomFocusRight:
3874 set_zoom_focus (ZoomFocusCenter);
3876 case ZoomFocusCenter:
3877 set_zoom_focus (ZoomFocusPlayhead);
3879 case ZoomFocusPlayhead:
3880 set_zoom_focus (ZoomFocusMouse);
3882 case ZoomFocusMouse:
3883 set_zoom_focus (ZoomFocusEdit);
3886 set_zoom_focus (ZoomFocusLeft);
3892 Editor::ensure_float (Window& win)
3894 win.set_transient_for (*this);
3898 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3900 /* recover or initialize pane positions. do this here rather than earlier because
3901 we don't want the positions to change the child allocations, which they seem to do.
3907 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3916 XMLNode* geometry = find_named_node (*node, "geometry");
3918 if (which == static_cast<Paned*> (&edit_pane)) {
3920 if (done & Horizontal) {
3924 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3925 _notebook_shrunk = string_is_affirmative (prop->value ());
3928 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3929 /* initial allocation is 90% to canvas, 10% to notebook */
3930 pos = (int) floor (alloc.get_width() * 0.90f);
3931 snprintf (buf, sizeof(buf), "%d", pos);
3933 pos = atoi (prop->value());
3936 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3937 edit_pane.set_position (pos);
3940 done = (Pane) (done | Horizontal);
3942 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3944 if (done & Vertical) {
3948 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3949 /* initial allocation is 90% to canvas, 10% to summary */
3950 pos = (int) floor (alloc.get_height() * 0.90f);
3951 snprintf (buf, sizeof(buf), "%d", pos);
3954 pos = atoi (prop->value());
3957 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3958 editor_summary_pane.set_position (pos);
3961 done = (Pane) (done | Vertical);
3966 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3968 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3969 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3970 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3971 top_hbox.remove (toolbar_frame);
3976 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3978 if (toolbar_frame.get_parent() == 0) {
3979 top_hbox.pack_end (toolbar_frame);
3984 Editor::set_show_measures (bool yn)
3986 if (_show_measures != yn) {
3989 if ((_show_measures = yn) == true) {
3991 tempo_lines->show();
3994 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3995 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3997 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3998 draw_measures (begin, end);
4006 Editor::toggle_follow_playhead ()
4008 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
4010 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4011 set_follow_playhead (tact->get_active());
4015 /** @param yn true to follow playhead, otherwise false.
4016 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4019 Editor::set_follow_playhead (bool yn, bool catch_up)
4021 if (_follow_playhead != yn) {
4022 if ((_follow_playhead = yn) == true && catch_up) {
4024 reset_x_origin_to_follow_playhead ();
4031 Editor::toggle_stationary_playhead ()
4033 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4035 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4036 set_stationary_playhead (tact->get_active());
4041 Editor::set_stationary_playhead (bool yn)
4043 if (_stationary_playhead != yn) {
4044 if ((_stationary_playhead = yn) == true) {
4046 // FIXME need a 3.0 equivalent of this 2.X call
4047 // update_current_screen ();
4054 Editor::playlist_selector () const
4056 return *_playlist_selector;
4060 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4062 if (paste_count == 0) {
4063 /* don't bother calculating an offset that will be zero anyway */
4067 /* calculate basic unsnapped multi-paste offset */
4068 framecnt_t offset = paste_count * duration;
4070 /* snap offset so pos + offset is aligned to the grid */
4071 framepos_t offset_pos = pos + offset;
4072 snap_to(offset_pos, RoundUpMaybe);
4073 offset = offset_pos - pos;
4079 Editor::get_grid_beat_divisions(framepos_t position)
4081 switch (_snap_type) {
4082 case SnapToBeatDiv128: return 128;
4083 case SnapToBeatDiv64: return 64;
4084 case SnapToBeatDiv32: return 32;
4085 case SnapToBeatDiv28: return 28;
4086 case SnapToBeatDiv24: return 24;
4087 case SnapToBeatDiv20: return 20;
4088 case SnapToBeatDiv16: return 16;
4089 case SnapToBeatDiv14: return 14;
4090 case SnapToBeatDiv12: return 12;
4091 case SnapToBeatDiv10: return 10;
4092 case SnapToBeatDiv8: return 8;
4093 case SnapToBeatDiv7: return 7;
4094 case SnapToBeatDiv6: return 6;
4095 case SnapToBeatDiv5: return 5;
4096 case SnapToBeatDiv4: return 4;
4097 case SnapToBeatDiv3: return 3;
4098 case SnapToBeatDiv2: return 2;
4105 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4109 const unsigned divisions = get_grid_beat_divisions(position);
4111 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4114 switch (_snap_type) {
4116 return Evoral::Beats(1.0);
4119 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
4127 return Evoral::Beats();
4131 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4135 ret = nudge_clock->current_duration (pos);
4136 next = ret + 1; /* XXXX fix me */
4142 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4144 ArdourDialog dialog (_("Playlist Deletion"));
4145 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4146 "If it is kept, its audio files will not be cleaned.\n"
4147 "If it is deleted, audio files used by it alone will be cleaned."),
4150 dialog.set_position (WIN_POS_CENTER);
4151 dialog.get_vbox()->pack_start (label);
4155 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4156 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4157 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4159 switch (dialog.run ()) {
4160 case RESPONSE_ACCEPT:
4161 /* delete the playlist */
4165 case RESPONSE_REJECT:
4166 /* keep the playlist */
4178 Editor::audio_region_selection_covers (framepos_t where)
4180 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4181 if ((*a)->region()->covers (where)) {
4190 Editor::prepare_for_cleanup ()
4192 cut_buffer->clear_regions ();
4193 cut_buffer->clear_playlists ();
4195 selection->clear_regions ();
4196 selection->clear_playlists ();
4198 _regions->suspend_redisplay ();
4202 Editor::finish_cleanup ()
4204 _regions->resume_redisplay ();
4208 Editor::transport_loop_location()
4211 return _session->locations()->auto_loop_location();
4218 Editor::transport_punch_location()
4221 return _session->locations()->auto_punch_location();
4228 Editor::control_layout_scroll (GdkEventScroll* ev)
4230 /* Just forward to the normal canvas scroll method. The coordinate
4231 systems are different but since the canvas is always larger than the
4232 track headers, and aligned with the trackview area, this will work.
4234 In the not too distant future this layout is going away anyway and
4235 headers will be on the canvas.
4237 return canvas_scroll_event (ev, false);
4241 Editor::session_state_saved (string)
4244 _snapshots->redisplay ();
4248 Editor::update_tearoff_visibility()
4250 bool visible = ARDOUR_UI::config()->get_keep_tearoffs();
4251 _mouse_mode_tearoff->set_visible (visible);
4252 _tools_tearoff->set_visible (visible);
4253 if (_zoom_tearoff) {
4254 _zoom_tearoff->set_visible (visible);
4259 Editor::reattach_all_tearoffs ()
4261 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4262 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4263 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4267 Editor::maximise_editing_space ()
4279 Editor::restore_editing_space ()
4291 * Make new playlists for a given track and also any others that belong
4292 * to the same active route group with the `select' property.
4297 Editor::new_playlists (TimeAxisView* v)
4299 begin_reversible_command (_("new playlists"));
4300 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4301 _session->playlists->get (playlists);
4302 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4303 commit_reversible_command ();
4307 * Use a copy of the current playlist for a given track and also any others that belong
4308 * to the same active route group with the `select' property.
4313 Editor::copy_playlists (TimeAxisView* v)
4315 begin_reversible_command (_("copy playlists"));
4316 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4317 _session->playlists->get (playlists);
4318 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4319 commit_reversible_command ();
4322 /** Clear the current playlist for a given track and also any others that belong
4323 * to the same active route group with the `select' property.
4328 Editor::clear_playlists (TimeAxisView* v)
4330 begin_reversible_command (_("clear playlists"));
4331 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4332 _session->playlists->get (playlists);
4333 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4334 commit_reversible_command ();
4338 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4340 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4344 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4346 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4350 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4352 atv.clear_playlist ();
4356 Editor::on_key_press_event (GdkEventKey* ev)
4358 return key_press_focus_accelerator_handler (*this, ev);
4362 Editor::on_key_release_event (GdkEventKey* ev)
4364 return Gtk::Window::on_key_release_event (ev);
4365 // return key_press_focus_accelerator_handler (*this, ev);
4369 Editor::get_y_origin () const
4371 return vertical_adjustment.get_value ();
4374 /** Queue up a change to the viewport x origin.
4375 * @param frame New x origin.
4378 Editor::reset_x_origin (framepos_t frame)
4380 pending_visual_change.add (VisualChange::TimeOrigin);
4381 pending_visual_change.time_origin = frame;
4382 ensure_visual_change_idle_handler ();
4386 Editor::reset_y_origin (double y)
4388 pending_visual_change.add (VisualChange::YOrigin);
4389 pending_visual_change.y_origin = y;
4390 ensure_visual_change_idle_handler ();
4394 Editor::reset_zoom (framecnt_t spp)
4396 if (spp == samples_per_pixel) {
4400 pending_visual_change.add (VisualChange::ZoomLevel);
4401 pending_visual_change.samples_per_pixel = spp;
4402 ensure_visual_change_idle_handler ();
4406 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4408 reset_x_origin (frame);
4411 if (!no_save_visual) {
4412 undo_visual_stack.push_back (current_visual_state(false));
4416 Editor::VisualState::VisualState (bool with_tracks)
4417 : gui_state (with_tracks ? new GUIObjectState : 0)
4421 Editor::VisualState::~VisualState ()
4426 Editor::VisualState*
4427 Editor::current_visual_state (bool with_tracks)
4429 VisualState* vs = new VisualState (with_tracks);
4430 vs->y_position = vertical_adjustment.get_value();
4431 vs->samples_per_pixel = samples_per_pixel;
4432 vs->leftmost_frame = leftmost_frame;
4433 vs->zoom_focus = zoom_focus;
4436 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4443 Editor::undo_visual_state ()
4445 if (undo_visual_stack.empty()) {
4449 VisualState* vs = undo_visual_stack.back();
4450 undo_visual_stack.pop_back();
4453 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4456 use_visual_state (*vs);
4461 Editor::redo_visual_state ()
4463 if (redo_visual_stack.empty()) {
4467 VisualState* vs = redo_visual_stack.back();
4468 redo_visual_stack.pop_back();
4470 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4471 // why do we check here?
4472 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4475 use_visual_state (*vs);
4480 Editor::swap_visual_state ()
4482 if (undo_visual_stack.empty()) {
4483 redo_visual_state ();
4485 undo_visual_state ();
4490 Editor::use_visual_state (VisualState& vs)
4492 PBD::Unwinder<bool> nsv (no_save_visual, true);
4493 DisplaySuspender ds;
4495 vertical_adjustment.set_value (vs.y_position);
4497 set_zoom_focus (vs.zoom_focus);
4498 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4501 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4503 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4504 (*i)->clear_property_cache();
4505 (*i)->reset_visual_state ();
4509 _routes->update_visibility ();
4512 /** This is the core function that controls the zoom level of the canvas. It is called
4513 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4514 * @param spp new number of samples per pixel
4517 Editor::set_samples_per_pixel (framecnt_t spp)
4523 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4524 const framecnt_t lots_of_pixels = 4000;
4526 /* if the zoom level is greater than what you'd get trying to display 3
4527 * days of audio on a really big screen, then it's too big.
4530 if (spp * lots_of_pixels > three_days) {
4534 samples_per_pixel = spp;
4537 tempo_lines->tempo_map_changed();
4540 bool const showing_time_selection = selection->time.length() > 0;
4542 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4543 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4544 (*i)->reshow_selection (selection->time);
4548 ZoomChanged (); /* EMIT_SIGNAL */
4550 ArdourCanvas::GtkCanvasViewport* c;
4552 c = get_track_canvas();
4554 c->canvas()->zoomed ();
4557 if (playhead_cursor) {
4558 playhead_cursor->set_position (playhead_cursor->current_frame ());
4561 refresh_location_display();
4562 _summary->set_overlays_dirty ();
4564 update_marker_labels ();
4570 Editor::queue_visual_videotimeline_update ()
4573 * pending_visual_change.add (VisualChange::VideoTimeline);
4574 * or maybe even more specific: which videotimeline-image
4575 * currently it calls update_video_timeline() to update
4576 * _all outdated_ images on the video-timeline.
4577 * see 'exposeimg()' in video_image_frame.cc
4579 ensure_visual_change_idle_handler ();
4583 Editor::ensure_visual_change_idle_handler ()
4585 if (pending_visual_change.idle_handler_id < 0) {
4586 // see comment in add_to_idle_resize above.
4587 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4588 pending_visual_change.being_handled = false;
4593 Editor::_idle_visual_changer (void* arg)
4595 return static_cast<Editor*>(arg)->idle_visual_changer ();
4599 Editor::idle_visual_changer ()
4601 /* set_horizontal_position() below (and maybe other calls) call
4602 gtk_main_iteration(), so it's possible that a signal will be handled
4603 half-way through this method. If this signal wants an
4604 idle_visual_changer we must schedule another one after this one, so
4605 mark the idle_handler_id as -1 here to allow that. Also make a note
4606 that we are doing the visual change, so that changes in response to
4607 super-rapid-screen-update can be dropped if we are still processing
4611 pending_visual_change.idle_handler_id = -1;
4612 pending_visual_change.being_handled = true;
4614 VisualChange vc = pending_visual_change;
4616 pending_visual_change.pending = (VisualChange::Type) 0;
4618 visual_changer (vc);
4620 pending_visual_change.being_handled = false;
4622 return 0; /* this is always a one-shot call */
4626 Editor::visual_changer (const VisualChange& vc)
4628 double const last_time_origin = horizontal_position ();
4630 if (vc.pending & VisualChange::ZoomLevel) {
4631 set_samples_per_pixel (vc.samples_per_pixel);
4633 compute_fixed_ruler_scale ();
4635 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4636 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4638 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4639 current_bbt_points_begin, current_bbt_points_end);
4640 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4641 current_bbt_points_begin, current_bbt_points_end);
4642 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4644 update_video_timeline();
4647 if (vc.pending & VisualChange::TimeOrigin) {
4648 set_horizontal_position (vc.time_origin / samples_per_pixel);
4651 if (vc.pending & VisualChange::YOrigin) {
4652 vertical_adjustment.set_value (vc.y_origin);
4655 if (last_time_origin == horizontal_position ()) {
4656 /* changed signal not emitted */
4657 update_fixed_rulers ();
4658 redisplay_tempo (true);
4661 if (!(vc.pending & VisualChange::ZoomLevel)) {
4662 update_video_timeline();
4665 _summary->set_overlays_dirty ();
4668 struct EditorOrderTimeAxisSorter {
4669 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4670 return a->order () < b->order ();
4675 Editor::sort_track_selection (TrackViewList& sel)
4677 EditorOrderTimeAxisSorter cmp;
4682 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4685 framepos_t where = 0;
4686 EditPoint ep = _edit_point;
4688 if (Profile->get_mixbus())
4689 if (ep == EditAtSelectedMarker)
4690 ep = EditAtPlayhead;
4692 if (from_outside_canvas && (ep == EditAtMouse)) {
4693 ep = EditAtPlayhead;
4694 } else if (from_context_menu && (ep == EditAtMouse)) {
4695 return canvas_event_sample (&context_click_event, 0, 0);
4698 if (entered_marker) {
4699 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4700 return entered_marker->position();
4703 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4704 ep = EditAtSelectedMarker;
4707 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4708 ep = EditAtPlayhead;
4712 case EditAtPlayhead:
4713 if (_dragging_playhead) {
4714 if (!mouse_frame (where, ignored)) {
4715 /* XXX not right but what can we do ? */
4719 where = _session->audible_frame();
4721 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4724 case EditAtSelectedMarker:
4725 if (!selection->markers.empty()) {
4727 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4730 where = loc->start();
4734 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4742 if (!mouse_frame (where, ignored)) {
4743 /* XXX not right but what can we do ? */
4747 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4755 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4757 if (!_session) return;
4759 begin_reversible_command (cmd);
4763 if ((tll = transport_loop_location()) == 0) {
4764 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4765 XMLNode &before = _session->locations()->get_state();
4766 _session->locations()->add (loc, true);
4767 _session->set_auto_loop_location (loc);
4768 XMLNode &after = _session->locations()->get_state();
4769 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4771 XMLNode &before = tll->get_state();
4772 tll->set_hidden (false, this);
4773 tll->set (start, end);
4774 XMLNode &after = tll->get_state();
4775 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4778 commit_reversible_command ();
4782 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4784 if (!_session) return;
4786 begin_reversible_command (cmd);
4790 if ((tpl = transport_punch_location()) == 0) {
4791 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4792 XMLNode &before = _session->locations()->get_state();
4793 _session->locations()->add (loc, true);
4794 _session->set_auto_punch_location (loc);
4795 XMLNode &after = _session->locations()->get_state();
4796 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4798 XMLNode &before = tpl->get_state();
4799 tpl->set_hidden (false, this);
4800 tpl->set (start, end);
4801 XMLNode &after = tpl->get_state();
4802 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4805 commit_reversible_command ();
4808 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4809 * @param rs List to which found regions are added.
4810 * @param where Time to look at.
4811 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4814 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4816 const TrackViewList* tracks;
4819 tracks = &track_views;
4824 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4826 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4829 boost::shared_ptr<Track> tr;
4830 boost::shared_ptr<Playlist> pl;
4832 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4834 boost::shared_ptr<RegionList> regions = pl->regions_at (
4835 (framepos_t) floor ( (double) where * tr->speed()));
4837 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4838 RegionView* rv = rtv->view()->find_view (*i);
4849 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4851 const TrackViewList* tracks;
4854 tracks = &track_views;
4859 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4860 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4862 boost::shared_ptr<Track> tr;
4863 boost::shared_ptr<Playlist> pl;
4865 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4867 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4868 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4870 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4872 RegionView* rv = rtv->view()->find_view (*i);
4883 /** Get regions using the following method:
4885 * Make a region list using:
4886 * (a) any selected regions
4887 * (b) the intersection of any selected tracks and the edit point(*)
4888 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4890 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4892 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4896 Editor::get_regions_from_selection_and_edit_point ()
4898 RegionSelection regions;
4900 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4901 regions.add (entered_regionview);
4903 regions = selection->regions;
4906 if ( regions.empty() ) {
4907 TrackViewList tracks = selection->tracks;
4909 if (!tracks.empty()) {
4910 /* no region selected or entered, but some selected tracks:
4911 * act on all regions on the selected tracks at the edit point
4913 framepos_t const where = get_preferred_edit_position ();
4914 get_regions_at(regions, where, tracks);
4921 /** Get regions using the following method:
4923 * Make a region list using:
4924 * (a) any selected regions
4925 * (b) the intersection of any selected tracks and the edit point(*)
4926 * (c) if neither exists, then whatever region is under the mouse
4928 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4930 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4933 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4935 RegionSelection regions;
4937 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4938 regions.add (entered_regionview);
4940 regions = selection->regions;
4943 if ( regions.empty() ) {
4944 TrackViewList tracks = selection->tracks;
4946 if (!tracks.empty()) {
4947 /* no region selected or entered, but some selected tracks:
4948 * act on all regions on the selected tracks at the edit point
4950 get_regions_at(regions, pos, tracks);
4957 /** Start with regions that are selected, or the entered regionview if none are selected.
4958 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4959 * of the regions that we started with.
4963 Editor::get_regions_from_selection_and_entered ()
4965 RegionSelection regions = selection->regions;
4967 if (regions.empty() && entered_regionview) {
4968 regions.add (entered_regionview);
4975 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4977 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4978 RouteTimeAxisView* rtav;
4980 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4981 boost::shared_ptr<Playlist> pl;
4982 std::vector<boost::shared_ptr<Region> > results;
4983 boost::shared_ptr<Track> tr;
4985 if ((tr = rtav->track()) == 0) {
4990 if ((pl = (tr->playlist())) != 0) {
4991 boost::shared_ptr<Region> r = pl->region_by_id (id);
4993 RegionView* rv = rtav->view()->find_view (r);
4995 regions.push_back (rv);
5004 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5007 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5008 MidiTimeAxisView* mtav;
5010 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5012 mtav->get_per_region_note_selection (selection);
5019 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5021 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5023 RouteTimeAxisView* tatv;
5025 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5027 boost::shared_ptr<Playlist> pl;
5028 vector<boost::shared_ptr<Region> > results;
5030 boost::shared_ptr<Track> tr;
5032 if ((tr = tatv->track()) == 0) {
5037 if ((pl = (tr->playlist())) != 0) {
5038 if (src_comparison) {
5039 pl->get_source_equivalent_regions (region, results);
5041 pl->get_region_list_equivalent_regions (region, results);
5045 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5046 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5047 regions.push_back (marv);
5056 Editor::show_rhythm_ferret ()
5058 if (rhythm_ferret == 0) {
5059 rhythm_ferret = new RhythmFerret(*this);
5062 rhythm_ferret->set_session (_session);
5063 rhythm_ferret->show ();
5064 rhythm_ferret->present ();
5068 Editor::first_idle ()
5070 MessageDialog* dialog = 0;
5072 if (track_views.size() > 1) {
5073 dialog = new MessageDialog (
5075 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5079 ARDOUR_UI::instance()->flush_pending ();
5082 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5086 // first idle adds route children (automation tracks), so we need to redisplay here
5087 _routes->redisplay ();
5091 if (_session->undo_depth() == 0) {
5092 undo_action->set_sensitive(false);
5094 redo_action->set_sensitive(false);
5095 begin_selection_op_history ();
5101 Editor::_idle_resize (gpointer arg)
5103 return ((Editor*)arg)->idle_resize ();
5107 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5109 if (resize_idle_id < 0) {
5110 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5111 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5112 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5114 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5115 _pending_resize_amount = 0;
5118 /* make a note of the smallest resulting height, so that we can clamp the
5119 lower limit at TimeAxisView::hSmall */
5121 int32_t min_resulting = INT32_MAX;
5123 _pending_resize_amount += h;
5124 _pending_resize_view = view;
5126 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5128 if (selection->tracks.contains (_pending_resize_view)) {
5129 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5130 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5134 if (min_resulting < 0) {
5139 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5140 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5144 /** Handle pending resizing of tracks */
5146 Editor::idle_resize ()
5148 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5150 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5151 selection->tracks.contains (_pending_resize_view)) {
5153 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5154 if (*i != _pending_resize_view) {
5155 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5160 _pending_resize_amount = 0;
5161 _group_tabs->set_dirty ();
5162 resize_idle_id = -1;
5170 ENSURE_GUI_THREAD (*this, &Editor::located);
5173 playhead_cursor->set_position (_session->audible_frame ());
5174 if (_follow_playhead && !_pending_initial_locate) {
5175 reset_x_origin_to_follow_playhead ();
5179 _pending_locate_request = false;
5180 _pending_initial_locate = false;
5184 Editor::region_view_added (RegionView * rv)
5186 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5187 if (rv->region ()->id () == (*pr)) {
5188 selection->add (rv);
5189 selection->regions.pending.erase (pr);
5194 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5196 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5197 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5198 if (rv->region()->id () == (*rnote).first) {
5199 mrv->select_notes ((*rnote).second);
5200 selection->pending_midi_note_selection.erase(rnote);
5206 _summary->set_background_dirty ();
5210 Editor::region_view_removed ()
5212 _summary->set_background_dirty ();
5216 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5218 TrackViewList::const_iterator j = track_views.begin ();
5219 while (j != track_views.end()) {
5220 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5221 if (rtv && rtv->route() == r) {
5232 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5236 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5237 TimeAxisView* tv = axis_view_from_route (*i);
5247 Editor::suspend_route_redisplay ()
5250 _routes->suspend_redisplay();
5255 Editor::resume_route_redisplay ()
5258 _routes->redisplay(); // queue redisplay
5259 _routes->resume_redisplay();
5264 Editor::add_routes (RouteList& routes)
5266 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5268 RouteTimeAxisView *rtv;
5269 list<RouteTimeAxisView*> new_views;
5270 TrackViewList new_selection;
5271 bool from_scratch = (track_views.size() == 0);
5273 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5274 boost::shared_ptr<Route> route = (*x);
5276 if (route->is_auditioner() || route->is_monitor()) {
5280 DataType dt = route->input()->default_type();
5282 if (dt == ARDOUR::DataType::AUDIO) {
5283 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5284 rtv->set_route (route);
5285 } else if (dt == ARDOUR::DataType::MIDI) {
5286 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5287 rtv->set_route (route);
5289 throw unknown_type();
5292 new_views.push_back (rtv);
5293 track_views.push_back (rtv);
5294 new_selection.push_back (rtv);
5296 rtv->effective_gain_display ();
5298 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5299 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5302 if (new_views.size() > 0) {
5303 _routes->routes_added (new_views);
5304 _summary->routes_added (new_views);
5307 if (!from_scratch) {
5308 selection->tracks.clear();
5309 selection->add (new_selection);
5310 begin_selection_op_history();
5313 if (show_editor_mixer_when_tracks_arrive) {
5314 show_editor_mixer (true);
5317 editor_list_button.set_sensitive (true);
5321 Editor::timeaxisview_deleted (TimeAxisView *tv)
5323 if (tv == entered_track) {
5327 if (_session && _session->deletion_in_progress()) {
5328 /* the situation is under control */
5332 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5334 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5336 _routes->route_removed (tv);
5338 TimeAxisView::Children c = tv->get_child_list ();
5339 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5340 if (entered_track == i->get()) {
5345 /* remove it from the list of track views */
5347 TrackViewList::iterator i;
5349 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5350 i = track_views.erase (i);
5353 /* update whatever the current mixer strip is displaying, if revelant */
5355 boost::shared_ptr<Route> route;
5358 route = rtav->route ();
5361 if (current_mixer_strip && current_mixer_strip->route() == route) {
5363 TimeAxisView* next_tv;
5365 if (track_views.empty()) {
5367 } else if (i == track_views.end()) {
5368 next_tv = track_views.front();
5375 set_selected_mixer_strip (*next_tv);
5377 /* make the editor mixer strip go away setting the
5378 * button to inactive (which also unticks the menu option)
5381 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5387 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5389 if (apply_to_selection) {
5390 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5392 TrackSelection::iterator j = i;
5395 hide_track_in_display (*i, false);
5400 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5402 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5403 // this will hide the mixer strip
5404 set_selected_mixer_strip (*tv);
5407 _routes->hide_track_in_display (*tv);
5412 Editor::sync_track_view_list_and_routes ()
5414 track_views = TrackViewList (_routes->views ());
5416 _summary->set_background_dirty();
5417 _group_tabs->set_dirty ();
5419 return false; // do not call again (until needed)
5423 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5425 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5430 /** Find a RouteTimeAxisView by the ID of its route */
5432 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5434 RouteTimeAxisView* v;
5436 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5437 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5438 if(v->route()->id() == id) {
5448 Editor::fit_route_group (RouteGroup *g)
5450 TrackViewList ts = axis_views_from_routes (g->route_list ());
5455 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5457 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5460 _session->cancel_audition ();
5464 if (_session->is_auditioning()) {
5465 _session->cancel_audition ();
5466 if (r == last_audition_region) {
5471 _session->audition_region (r);
5472 last_audition_region = r;
5477 Editor::hide_a_region (boost::shared_ptr<Region> r)
5479 r->set_hidden (true);
5483 Editor::show_a_region (boost::shared_ptr<Region> r)
5485 r->set_hidden (false);
5489 Editor::audition_region_from_region_list ()
5491 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5495 Editor::hide_region_from_region_list ()
5497 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5501 Editor::show_region_in_region_list ()
5503 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5507 Editor::step_edit_status_change (bool yn)
5510 start_step_editing ();
5512 stop_step_editing ();
5517 Editor::start_step_editing ()
5519 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5523 Editor::stop_step_editing ()
5525 step_edit_connection.disconnect ();
5529 Editor::check_step_edit ()
5531 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5532 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5534 mtv->check_step_edit ();
5538 return true; // do it again, till we stop
5542 Editor::scroll_press (Direction dir)
5544 ++_scroll_callbacks;
5546 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5547 /* delay the first auto-repeat */
5553 scroll_backward (1);
5561 scroll_up_one_track ();
5565 scroll_down_one_track ();
5569 /* do hacky auto-repeat */
5570 if (!_scroll_connection.connected ()) {
5572 _scroll_connection = Glib::signal_timeout().connect (
5573 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5576 _scroll_callbacks = 0;
5583 Editor::scroll_release ()
5585 _scroll_connection.disconnect ();
5588 /** Queue a change for the Editor viewport x origin to follow the playhead */
5590 Editor::reset_x_origin_to_follow_playhead ()
5592 framepos_t const frame = playhead_cursor->current_frame ();
5594 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5596 if (_session->transport_speed() < 0) {
5598 if (frame > (current_page_samples() / 2)) {
5599 center_screen (frame-(current_page_samples()/2));
5601 center_screen (current_page_samples()/2);
5608 if (frame < leftmost_frame) {
5610 if (_session->transport_rolling()) {
5611 /* rolling; end up with the playhead at the right of the page */
5612 l = frame - current_page_samples ();
5614 /* not rolling: end up with the playhead 1/4 of the way along the page */
5615 l = frame - current_page_samples() / 4;
5619 if (_session->transport_rolling()) {
5620 /* rolling: end up with the playhead on the left of the page */
5623 /* not rolling: end up with the playhead 3/4 of the way along the page */
5624 l = frame - 3 * current_page_samples() / 4;
5632 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5638 Editor::super_rapid_screen_update ()
5640 if (!_session || !_session->engine().running()) {
5644 /* METERING / MIXER STRIPS */
5646 /* update track meters, if required */
5647 if (is_mapped() && meters_running) {
5648 RouteTimeAxisView* rtv;
5649 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5650 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5651 rtv->fast_update ();
5656 /* and any current mixer strip */
5657 if (current_mixer_strip) {
5658 current_mixer_strip->fast_update ();
5661 /* PLAYHEAD AND VIEWPORT */
5663 framepos_t const frame = _session->audible_frame();
5665 /* There are a few reasons why we might not update the playhead / viewport stuff:
5667 * 1. we don't update things when there's a pending locate request, otherwise
5668 * when the editor requests a locate there is a chance that this method
5669 * will move the playhead before the locate request is processed, causing
5671 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5672 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5675 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5677 last_update_frame = frame;
5679 if (!_dragging_playhead) {
5680 playhead_cursor->set_position (frame);
5683 if (!_stationary_playhead) {
5685 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5686 /* We only do this if we aren't already
5687 handling a visual change (ie if
5688 pending_visual_change.being_handled is
5689 false) so that these requests don't stack
5690 up there are too many of them to handle in
5693 reset_x_origin_to_follow_playhead ();
5698 if (!_dragging_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5699 framepos_t const frame = playhead_cursor->current_frame ();
5700 double target = ((double)frame - (double)current_page_samples()/3.0);
5701 if (target <= 0.0) {
5704 // compare to EditorCursor::set_position()
5705 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5706 double const new_pos = sample_to_pixel_unrounded (target);
5707 if (rint (new_pos) != rint (old_pos)) {
5708 reset_x_origin (pixel_to_sample (floor (new_pos)));
5719 Editor::session_going_away ()
5721 _have_idled = false;
5723 _session_connections.drop_connections ();
5725 super_rapid_screen_update_connection.disconnect ();
5727 selection->clear ();
5728 cut_buffer->clear ();
5730 clicked_regionview = 0;
5731 clicked_axisview = 0;
5732 clicked_routeview = 0;
5733 entered_regionview = 0;
5735 last_update_frame = 0;
5738 playhead_cursor->hide ();
5740 /* rip everything out of the list displays */
5744 _route_groups->clear ();
5746 /* do this first so that deleting a track doesn't reset cms to null
5747 and thus cause a leak.
5750 if (current_mixer_strip) {
5751 if (current_mixer_strip->get_parent() != 0) {
5752 global_hpacker.remove (*current_mixer_strip);
5754 delete current_mixer_strip;
5755 current_mixer_strip = 0;
5758 /* delete all trackviews */
5760 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5763 track_views.clear ();
5765 nudge_clock->set_session (0);
5767 editor_list_button.set_active(false);
5768 editor_list_button.set_sensitive(false);
5770 /* clear tempo/meter rulers */
5771 remove_metric_marks ();
5773 clear_marker_display ();
5775 stop_step_editing ();
5777 /* get rid of any existing editor mixer strip */
5779 WindowTitle title(Glib::get_application_name());
5780 title += _("Editor");
5782 set_title (title.get_string());
5784 SessionHandlePtr::session_going_away ();
5789 Editor::show_editor_list (bool yn)
5792 _the_notebook.show ();
5794 _the_notebook.hide ();
5799 Editor::change_region_layering_order (bool from_context_menu)
5801 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5803 if (!clicked_routeview) {
5804 if (layering_order_editor) {
5805 layering_order_editor->hide ();
5810 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5816 boost::shared_ptr<Playlist> pl = track->playlist();
5822 if (layering_order_editor == 0) {
5823 layering_order_editor = new RegionLayeringOrderEditor (*this);
5826 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5827 layering_order_editor->maybe_present ();
5831 Editor::update_region_layering_order_editor ()
5833 if (layering_order_editor && layering_order_editor->is_visible ()) {
5834 change_region_layering_order (true);
5839 Editor::setup_fade_images ()
5841 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5842 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5843 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5844 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5845 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5847 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5848 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5849 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5850 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5851 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5853 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5854 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5855 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5856 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5857 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5859 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5860 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5861 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5862 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5863 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5867 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5869 Editor::action_menu_item (std::string const & name)
5871 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5874 return *manage (a->create_menu_item ());
5878 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5880 EventBox* b = manage (new EventBox);
5881 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5882 Label* l = manage (new Label (name));
5886 _the_notebook.append_page (widget, *b);
5890 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5892 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5893 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5896 if (ev->type == GDK_2BUTTON_PRESS) {
5898 /* double-click on a notebook tab shrinks or expands the notebook */
5900 if (_notebook_shrunk) {
5901 if (pre_notebook_shrink_pane_width) {
5902 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5904 _notebook_shrunk = false;
5906 pre_notebook_shrink_pane_width = edit_pane.get_position();
5908 /* this expands the LHS of the edit pane to cover the notebook
5909 PAGE but leaves the tabs visible.
5911 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5912 _notebook_shrunk = true;
5920 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5922 using namespace Menu_Helpers;
5924 MenuList& items = _control_point_context_menu.items ();
5927 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5928 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5929 if (!can_remove_control_point (item)) {
5930 items.back().set_sensitive (false);
5933 _control_point_context_menu.popup (event->button.button, event->button.time);
5937 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5939 using namespace Menu_Helpers;
5941 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5946 /* We need to get the selection here and pass it to the operations, since
5947 popping up the menu will cause a region leave event which clears
5948 entered_regionview. */
5950 MidiRegionView& mrv = note->region_view();
5951 const RegionSelection rs = get_regions_from_selection_and_entered ();
5953 MenuList& items = _note_context_menu.items();
5956 items.push_back(MenuElem(_("Delete"),
5957 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5958 items.push_back(MenuElem(_("Edit..."),
5959 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5960 items.push_back(MenuElem(_("Legatize"),
5961 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5962 items.push_back(MenuElem(_("Quantize..."),
5963 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5964 items.push_back(MenuElem(_("Remove Overlap"),
5965 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5966 items.push_back(MenuElem(_("Transform..."),
5967 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5969 _note_context_menu.popup (event->button.button, event->button.time);
5973 Editor::zoom_vertical_modifier_released()
5975 _stepping_axis_view = 0;
5979 Editor::ui_parameter_changed (string parameter)
5981 if (parameter == "icon-set") {
5982 while (!_cursor_stack.empty()) {
5983 _cursor_stack.pop_back();
5985 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5986 _cursor_stack.push_back(_cursors->grabber);
5987 } else if (parameter == "draggable-playhead") {
5988 if (_verbose_cursor) {
5989 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());