2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include "gtkmm2ext/tearoff.h"
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/audio_track.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/audioregion.h"
71 #include "ardour/lmath.h"
72 #include "ardour/location.h"
73 #include "ardour/profile.h"
74 #include "ardour/route_group.h"
75 #include "ardour/session_playlists.h"
76 #include "ardour/tempo.h"
77 #include "ardour/utils.h"
79 #include "canvas/debug.h"
80 #include "canvas/text.h"
82 #include "control_protocol/control_protocol.h"
85 #include "analysis_window.h"
86 #include "audio_clock.h"
87 #include "audio_region_view.h"
88 #include "audio_streamview.h"
89 #include "audio_time_axis.h"
90 #include "automation_time_axis.h"
91 #include "bundle_manager.h"
92 #include "crossfade_edit.h"
96 #include "editor_cursors.h"
97 #include "editor_drag.h"
98 #include "editor_group_tabs.h"
99 #include "editor_locations.h"
100 #include "editor_regions.h"
101 #include "editor_route_groups.h"
102 #include "editor_routes.h"
103 #include "editor_snapshots.h"
104 #include "editor_summary.h"
105 #include "global_port_matrix.h"
106 #include "gui_object.h"
107 #include "gui_thread.h"
108 #include "keyboard.h"
110 #include "midi_region_view.h"
111 #include "midi_time_axis.h"
112 #include "mixer_strip.h"
113 #include "mixer_ui.h"
114 #include "mouse_cursors.h"
115 #include "note_base.h"
116 #include "playlist_selector.h"
117 #include "public_editor.h"
118 #include "quantize_dialog.h"
119 #include "region_layering_order_editor.h"
120 #include "rgb_macros.h"
121 #include "rhythm_ferret.h"
122 #include "selection.h"
124 #include "tempo_lines.h"
125 #include "time_axis_view.h"
127 #include "tooltips.h"
128 #include "ui_config.h"
130 #include "verbose_cursor.h"
135 using namespace ARDOUR;
136 using namespace ARDOUR_UI_UTILS;
139 using namespace Glib;
140 using namespace Gtkmm2ext;
141 using namespace Editing;
143 using PBD::internationalize;
145 using Gtkmm2ext::Keyboard;
147 double Editor::timebar_height = 15.0;
149 static const gchar *_snap_type_strings[] = {
183 static const gchar *_snap_mode_strings[] = {
190 static const gchar *_edit_point_strings[] = {
197 static const gchar *_edit_mode_strings[] = {
205 static const gchar *_zoom_focus_strings[] = {
215 #ifdef USE_RUBBERBAND
216 static const gchar *_rb_opt_strings[] = {
219 N_("Balanced multitimbral mixture"),
220 N_("Unpitched percussion with stable notes"),
221 N_("Crisp monophonic instrumental"),
222 N_("Unpitched solo percussion"),
223 N_("Resample without preserving pitch"),
228 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
231 pane_size_watcher (Paned* pane)
233 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
237 Quartz: impossible to access
239 so stop that by preventing it from ever getting too narrow. 35
240 pixels is basically a rough guess at the tab width.
245 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
247 gint pos = pane->get_position ();
249 if (pos > max_width_of_lhs) {
250 pane->set_position (max_width_of_lhs);
255 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
257 , _mouse_changed_selection (false)
258 /* time display buttons */
259 , minsec_label (_("Mins:Secs"))
260 , bbt_label (_("Bars:Beats"))
261 , timecode_label (_("Timecode"))
262 , samples_label (_("Samples"))
263 , tempo_label (_("Tempo"))
264 , meter_label (_("Meter"))
265 , mark_label (_("Location Markers"))
266 , range_mark_label (_("Range Markers"))
267 , transport_mark_label (_("Loop/Punch Ranges"))
268 , cd_mark_label (_("CD Markers"))
269 , videotl_label (_("Video Timeline"))
270 , edit_packer (4, 4, true)
272 /* the values here don't matter: layout widgets
273 reset them as needed.
276 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
277 , horizontal_adjustment (0.0, 0.0, 1e16)
278 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
280 , controls_layout (unused_adjustment, vertical_adjustment)
282 /* tool bar related */
284 , toolbar_selection_clock_table (2,3)
285 , _mouse_mode_tearoff (0)
286 , automation_mode_button (_("mode"))
290 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
291 , selection_op_cmd_depth (0)
292 , selection_op_history_it (0)
296 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
297 , meters_running(false)
298 , _pending_locate_request (false)
299 , _pending_initial_locate (false)
300 , _last_cut_copy_source_track (0)
302 , _region_selection_change_updates_region_list (true)
303 , _following_mixer_selection (false)
304 , _control_point_toggled_on_press (false)
305 , _stepping_axis_view (0)
306 , quantize_dialog (0)
307 , _main_menu_disabler (0)
311 /* we are a singleton */
313 PublicEditor::_instance = this;
317 selection = new Selection (this);
318 cut_buffer = new Selection (this);
319 _selection_memento = new SelectionMemento ();
320 selection_op_history.clear();
323 clicked_regionview = 0;
324 clicked_axisview = 0;
325 clicked_routeview = 0;
326 clicked_selection = 0;
327 clicked_control_point = 0;
328 last_update_frame = 0;
331 _drags = new DragManager (this);
334 current_mixer_strip = 0;
337 snap_type_strings = I18N (_snap_type_strings);
338 snap_mode_strings = I18N (_snap_mode_strings);
339 zoom_focus_strings = I18N (_zoom_focus_strings);
340 edit_mode_strings = I18N (_edit_mode_strings);
341 edit_point_strings = I18N (_edit_point_strings);
342 #ifdef USE_RUBBERBAND
343 rb_opt_strings = I18N (_rb_opt_strings);
347 build_edit_mode_menu();
348 build_zoom_focus_menu();
349 build_track_count_menu();
350 build_snap_mode_menu();
351 build_snap_type_menu();
352 build_edit_point_menu();
354 snap_threshold = 5.0;
355 bbt_beat_subdivision = 4;
356 _visible_canvas_width = 0;
357 _visible_canvas_height = 0;
358 autoscroll_horizontal_allowed = false;
359 autoscroll_vertical_allowed = false;
364 current_interthread_info = 0;
365 _show_measures = true;
367 show_gain_after_trim = false;
369 have_pending_keyboard_selection = false;
370 _follow_playhead = true;
371 _stationary_playhead = false;
372 editor_ruler_menu = 0;
373 no_ruler_shown_update = false;
375 range_marker_menu = 0;
376 marker_menu_item = 0;
377 tempo_or_meter_marker_menu = 0;
378 transport_marker_menu = 0;
379 new_transport_marker_menu = 0;
380 editor_mixer_strip_width = Wide;
381 show_editor_mixer_when_tracks_arrive = false;
382 region_edit_menu_split_multichannel_item = 0;
383 region_edit_menu_split_item = 0;
386 mouse_mode = MouseObject;
387 current_stepping_trackview = 0;
389 entered_regionview = 0;
391 clear_entered_track = false;
394 button_release_can_deselect = true;
395 _dragging_playhead = false;
396 _dragging_edit_point = false;
397 select_new_marker = false;
399 layering_order_editor = 0;
400 no_save_visual = false;
402 within_track_canvas = false;
404 scrubbing_direction = 0;
408 location_marker_color = UIConfiguration::instance().color ("location marker");
409 location_range_color = UIConfiguration::instance().color ("location range");
410 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
411 location_loop_color = UIConfiguration::instance().color ("location loop");
412 location_punch_color = UIConfiguration::instance().color ("location punch");
414 zoom_focus = ZoomFocusPlayhead;
415 _edit_point = EditAtMouse;
416 _visible_track_count = -1;
418 samples_per_pixel = 2048; /* too early to use reset_zoom () */
420 timebar_height = std::max(12., ceil (15. * UIConfiguration::instance().get_ui_scale()));
421 TimeAxisView::setup_sizes ();
422 ArdourMarker::setup_sizes (timebar_height);
424 _scroll_callbacks = 0;
426 bbt_label.set_name ("EditorRulerLabel");
427 bbt_label.set_size_request (-1, (int)timebar_height);
428 bbt_label.set_alignment (1.0, 0.5);
429 bbt_label.set_padding (5,0);
431 bbt_label.set_no_show_all();
432 minsec_label.set_name ("EditorRulerLabel");
433 minsec_label.set_size_request (-1, (int)timebar_height);
434 minsec_label.set_alignment (1.0, 0.5);
435 minsec_label.set_padding (5,0);
436 minsec_label.hide ();
437 minsec_label.set_no_show_all();
438 timecode_label.set_name ("EditorRulerLabel");
439 timecode_label.set_size_request (-1, (int)timebar_height);
440 timecode_label.set_alignment (1.0, 0.5);
441 timecode_label.set_padding (5,0);
442 timecode_label.hide ();
443 timecode_label.set_no_show_all();
444 samples_label.set_name ("EditorRulerLabel");
445 samples_label.set_size_request (-1, (int)timebar_height);
446 samples_label.set_alignment (1.0, 0.5);
447 samples_label.set_padding (5,0);
448 samples_label.hide ();
449 samples_label.set_no_show_all();
451 tempo_label.set_name ("EditorRulerLabel");
452 tempo_label.set_size_request (-1, (int)timebar_height);
453 tempo_label.set_alignment (1.0, 0.5);
454 tempo_label.set_padding (5,0);
456 tempo_label.set_no_show_all();
458 meter_label.set_name ("EditorRulerLabel");
459 meter_label.set_size_request (-1, (int)timebar_height);
460 meter_label.set_alignment (1.0, 0.5);
461 meter_label.set_padding (5,0);
463 meter_label.set_no_show_all();
465 if (Profile->get_trx()) {
466 mark_label.set_text (_("Markers"));
468 mark_label.set_name ("EditorRulerLabel");
469 mark_label.set_size_request (-1, (int)timebar_height);
470 mark_label.set_alignment (1.0, 0.5);
471 mark_label.set_padding (5,0);
473 mark_label.set_no_show_all();
475 cd_mark_label.set_name ("EditorRulerLabel");
476 cd_mark_label.set_size_request (-1, (int)timebar_height);
477 cd_mark_label.set_alignment (1.0, 0.5);
478 cd_mark_label.set_padding (5,0);
479 cd_mark_label.hide();
480 cd_mark_label.set_no_show_all();
482 videotl_bar_height = 4;
483 videotl_label.set_name ("EditorRulerLabel");
484 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
485 videotl_label.set_alignment (1.0, 0.5);
486 videotl_label.set_padding (5,0);
487 videotl_label.hide();
488 videotl_label.set_no_show_all();
490 range_mark_label.set_name ("EditorRulerLabel");
491 range_mark_label.set_size_request (-1, (int)timebar_height);
492 range_mark_label.set_alignment (1.0, 0.5);
493 range_mark_label.set_padding (5,0);
494 range_mark_label.hide();
495 range_mark_label.set_no_show_all();
497 transport_mark_label.set_name ("EditorRulerLabel");
498 transport_mark_label.set_size_request (-1, (int)timebar_height);
499 transport_mark_label.set_alignment (1.0, 0.5);
500 transport_mark_label.set_padding (5,0);
501 transport_mark_label.hide();
502 transport_mark_label.set_no_show_all();
504 initialize_canvas ();
506 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
508 _summary = new EditorSummary (this);
510 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
511 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
513 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
515 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
516 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
518 edit_controls_vbox.set_spacing (0);
519 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
520 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
522 HBox* h = manage (new HBox);
523 _group_tabs = new EditorGroupTabs (this);
524 if (!ARDOUR::Profile->get_trx()) {
525 h->pack_start (*_group_tabs, PACK_SHRINK);
527 h->pack_start (edit_controls_vbox);
528 controls_layout.add (*h);
530 controls_layout.set_name ("EditControlsBase");
531 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
532 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
533 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
535 _cursors = new MouseCursors;
536 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
537 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
539 /* Push default cursor to ever-present bottom of cursor stack. */
540 push_canvas_cursor(_cursors->grabber);
542 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
544 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
545 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
546 pad_line_1->set_outline_color (0xFF0000FF);
552 edit_packer.set_col_spacings (0);
553 edit_packer.set_row_spacings (0);
554 edit_packer.set_homogeneous (false);
555 edit_packer.set_border_width (0);
556 edit_packer.set_name ("EditorWindow");
558 time_bars_event_box.add (time_bars_vbox);
559 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
560 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
562 /* labels for the time bars */
563 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
565 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
567 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
569 bottom_hbox.set_border_width (2);
570 bottom_hbox.set_spacing (3);
572 _route_groups = new EditorRouteGroups (this);
573 _routes = new EditorRoutes (this);
574 _regions = new EditorRegions (this);
575 _snapshots = new EditorSnapshots (this);
576 _locations = new EditorLocations (this);
578 /* these are static location signals */
580 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
581 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
582 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
584 add_notebook_page (_("Regions"), _regions->widget ());
585 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
586 add_notebook_page (_("Snapshots"), _snapshots->widget ());
587 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
588 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
590 _the_notebook.set_show_tabs (true);
591 _the_notebook.set_scrollable (true);
592 _the_notebook.popup_disable ();
593 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
594 _the_notebook.show_all ();
596 _notebook_shrunk = false;
598 editor_summary_pane.pack1(edit_packer);
600 Button* summary_arrows_left_left = manage (new Button);
601 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
602 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
603 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
605 Button* summary_arrows_left_right = manage (new Button);
606 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
607 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
608 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
610 VBox* summary_arrows_left = manage (new VBox);
611 summary_arrows_left->pack_start (*summary_arrows_left_left);
612 summary_arrows_left->pack_start (*summary_arrows_left_right);
614 Button* summary_arrows_right_up = manage (new Button);
615 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
616 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
617 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
619 Button* summary_arrows_right_down = manage (new Button);
620 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
621 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
622 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
624 VBox* summary_arrows_right = manage (new VBox);
625 summary_arrows_right->pack_start (*summary_arrows_right_up);
626 summary_arrows_right->pack_start (*summary_arrows_right_down);
628 Frame* summary_frame = manage (new Frame);
629 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
631 summary_frame->add (*_summary);
632 summary_frame->show ();
634 _summary_hbox.pack_start (*summary_arrows_left, false, false);
635 _summary_hbox.pack_start (*summary_frame, true, true);
636 _summary_hbox.pack_start (*summary_arrows_right, false, false);
638 if (!ARDOUR::Profile->get_trx()) {
639 editor_summary_pane.pack2 (_summary_hbox);
642 edit_pane.pack1 (editor_summary_pane, true, true);
643 if (!ARDOUR::Profile->get_trx()) {
644 edit_pane.pack2 (_the_notebook, false, true);
647 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
649 /* XXX: editor_summary_pane might need similar to the edit_pane */
651 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
653 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
654 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
656 top_hbox.pack_start (toolbar_frame);
658 HBox *hbox = manage (new HBox);
659 hbox->pack_start (edit_pane, true, true);
661 global_vpacker.pack_start (top_hbox, false, false);
662 global_vpacker.pack_start (*hbox, true, true);
664 global_hpacker.pack_start (global_vpacker, true, true);
666 set_name ("EditorWindow");
667 add_accel_group (ActionManager::ui_manager->get_accel_group());
669 status_bar_hpacker.show ();
671 vpacker.pack_end (status_bar_hpacker, false, false);
672 vpacker.pack_end (global_hpacker, true, true);
674 /* register actions now so that set_state() can find them and set toggles/checks etc */
677 /* when we start using our own keybinding system for the editor, this
678 * will be uncommented
684 set_zoom_focus (zoom_focus);
685 set_visible_track_count (_visible_track_count);
686 _snap_type = SnapToBeat;
687 set_snap_to (_snap_type);
688 _snap_mode = SnapOff;
689 set_snap_mode (_snap_mode);
690 set_mouse_mode (MouseObject, true);
691 pre_internal_snap_type = _snap_type;
692 pre_internal_snap_mode = _snap_mode;
693 internal_snap_type = _snap_type;
694 internal_snap_mode = _snap_mode;
695 set_edit_point_preference (EditAtMouse, true);
697 _playlist_selector = new PlaylistSelector();
698 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
700 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
704 nudge_forward_button.set_name ("nudge button");
705 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
707 nudge_backward_button.set_name ("nudge button");
708 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
710 fade_context_menu.set_name ("ArdourContextMenu");
712 /* icons, titles, WM stuff */
714 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
715 Glib::RefPtr<Gdk::Pixbuf> icon;
717 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
718 window_icons.push_back (icon);
720 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
721 window_icons.push_back (icon);
723 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
724 window_icons.push_back (icon);
726 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
727 window_icons.push_back (icon);
729 if (!window_icons.empty()) {
730 // set_icon_list (window_icons);
731 set_default_icon_list (window_icons);
734 WindowTitle title(Glib::get_application_name());
735 title += _("Editor");
736 set_title (title.get_string());
737 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
740 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
742 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
743 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
745 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
747 /* allow external control surfaces/protocols to do various things */
749 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
750 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
751 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
752 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
753 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
754 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
755 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
756 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
757 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
758 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
759 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
760 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
761 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
762 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
764 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
765 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
766 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
767 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
768 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
770 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
772 /* problematic: has to return a value and thus cannot be x-thread */
774 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
776 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
777 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
779 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
781 _ignore_region_action = false;
782 _last_region_menu_was_main = false;
783 _popup_region_menu_item = 0;
785 _ignore_follow_edits = false;
787 _show_marker_lines = false;
789 /* Button bindings */
791 button_bindings = new Bindings;
793 XMLNode* node = button_settings();
795 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
796 button_bindings->load (**i);
802 /* grab current parameter state */
803 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
804 UIConfiguration::instance().map_parameters (pc);
806 setup_fade_images ();
813 delete button_bindings;
815 delete _route_groups;
816 delete _track_canvas_viewport;
819 delete quantize_dialog;
825 delete _playlist_selector;
827 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
833 Editor::button_settings () const
835 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
836 XMLNode* node = find_named_node (*settings, X_("Buttons"));
839 node = new XMLNode (X_("Buttons"));
846 Editor::add_toplevel_menu (Container& cont)
848 vpacker.pack_start (cont, false, false);
853 Editor::add_transport_frame (Container& cont)
855 if(ARDOUR::Profile->get_mixbus()) {
856 global_vpacker.pack_start (cont, false, false);
857 global_vpacker.reorder_child (cont, 0);
860 vpacker.pack_start (cont, false, false);
865 Editor::get_smart_mode () const
867 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
871 Editor::catch_vanishing_regionview (RegionView *rv)
873 /* note: the selection will take care of the vanishing
874 audioregionview by itself.
877 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
881 if (clicked_regionview == rv) {
882 clicked_regionview = 0;
885 if (entered_regionview == rv) {
886 set_entered_regionview (0);
889 if (!_all_region_actions_sensitized) {
890 sensitize_all_region_actions (true);
895 Editor::set_entered_regionview (RegionView* rv)
897 if (rv == entered_regionview) {
901 if (entered_regionview) {
902 entered_regionview->exited ();
905 entered_regionview = rv;
907 if (entered_regionview != 0) {
908 entered_regionview->entered ();
911 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
912 /* This RegionView entry might have changed what region actions
913 are allowed, so sensitize them all in case a key is pressed.
915 sensitize_all_region_actions (true);
920 Editor::set_entered_track (TimeAxisView* tav)
923 entered_track->exited ();
929 entered_track->entered ();
934 Editor::show_window ()
936 if (!is_visible ()) {
940 /* XXX: this is a bit unfortunate; it would probably
941 be nicer if we could just call show () above rather
942 than needing the show_all ()
945 /* re-hide stuff if necessary */
946 editor_list_button_toggled ();
947 parameter_changed ("show-summary");
948 parameter_changed ("show-group-tabs");
949 parameter_changed ("show-zoom-tools");
951 /* now reset all audio_time_axis heights, because widgets might need
957 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
958 tv = (static_cast<TimeAxisView*>(*i));
962 if (current_mixer_strip) {
963 current_mixer_strip->hide_things ();
964 current_mixer_strip->parameter_changed ("mixer-element-visibility");
972 Editor::instant_save ()
974 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
979 _session->add_instant_xml(get_state());
981 Config->add_instant_xml(get_state());
986 Editor::control_vertical_zoom_in_all ()
988 tav_zoom_smooth (false, true);
992 Editor::control_vertical_zoom_out_all ()
994 tav_zoom_smooth (true, true);
998 Editor::control_vertical_zoom_in_selected ()
1000 tav_zoom_smooth (false, false);
1004 Editor::control_vertical_zoom_out_selected ()
1006 tav_zoom_smooth (true, false);
1010 Editor::control_view (uint32_t view)
1012 goto_visual_state (view);
1016 Editor::control_unselect ()
1018 selection->clear_tracks ();
1022 Editor::control_select (uint32_t rid, Selection::Operation op)
1024 /* handles the (static) signal from the ControlProtocol class that
1025 * requests setting the selected track to a given RID
1032 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1038 TimeAxisView* tav = axis_view_from_route (r);
1042 case Selection::Add:
1043 selection->add (tav);
1045 case Selection::Toggle:
1046 selection->toggle (tav);
1048 case Selection::Extend:
1050 case Selection::Set:
1051 selection->set (tav);
1055 selection->clear_tracks ();
1060 Editor::control_step_tracks_up ()
1062 scroll_tracks_up_line ();
1066 Editor::control_step_tracks_down ()
1068 scroll_tracks_down_line ();
1072 Editor::control_scroll (float fraction)
1074 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1080 double step = fraction * current_page_samples();
1083 _control_scroll_target is an optional<T>
1085 it acts like a pointer to an framepos_t, with
1086 a operator conversion to boolean to check
1087 that it has a value could possibly use
1088 playhead_cursor->current_frame to store the
1089 value and a boolean in the class to know
1090 when it's out of date
1093 if (!_control_scroll_target) {
1094 _control_scroll_target = _session->transport_frame();
1095 _dragging_playhead = true;
1098 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1099 *_control_scroll_target = 0;
1100 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1101 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1103 *_control_scroll_target += (framepos_t) trunc (step);
1106 /* move visuals, we'll catch up with it later */
1108 playhead_cursor->set_position (*_control_scroll_target);
1109 UpdateAllTransportClocks (*_control_scroll_target);
1111 if (*_control_scroll_target > (current_page_samples() / 2)) {
1112 /* try to center PH in window */
1113 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1119 Now we do a timeout to actually bring the session to the right place
1120 according to the playhead. This is to avoid reading disk buffers on every
1121 call to control_scroll, which is driven by ScrollTimeline and therefore
1122 probably by a control surface wheel which can generate lots of events.
1124 /* cancel the existing timeout */
1126 control_scroll_connection.disconnect ();
1128 /* add the next timeout */
1130 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1134 Editor::deferred_control_scroll (framepos_t /*target*/)
1136 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1137 // reset for next stream
1138 _control_scroll_target = boost::none;
1139 _dragging_playhead = false;
1144 Editor::access_action (std::string action_group, std::string action_item)
1150 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1153 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1161 Editor::on_realize ()
1163 Window::on_realize ();
1166 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1167 start_lock_event_timing ();
1170 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1174 Editor::start_lock_event_timing ()
1176 /* check if we should lock the GUI every 30 seconds */
1178 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1182 Editor::generic_event_handler (GdkEvent* ev)
1185 case GDK_BUTTON_PRESS:
1186 case GDK_BUTTON_RELEASE:
1187 case GDK_MOTION_NOTIFY:
1189 case GDK_KEY_RELEASE:
1190 gettimeofday (&last_event_time, 0);
1193 case GDK_LEAVE_NOTIFY:
1194 switch (ev->crossing.detail) {
1195 case GDK_NOTIFY_UNKNOWN:
1196 case GDK_NOTIFY_INFERIOR:
1197 case GDK_NOTIFY_ANCESTOR:
1199 case GDK_NOTIFY_VIRTUAL:
1200 case GDK_NOTIFY_NONLINEAR:
1201 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1202 /* leaving window, so reset focus, thus ending any and
1203 all text entry operations.
1218 Editor::lock_timeout_callback ()
1220 struct timeval now, delta;
1222 gettimeofday (&now, 0);
1224 timersub (&now, &last_event_time, &delta);
1226 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1228 /* don't call again. Returning false will effectively
1229 disconnect us from the timer callback.
1231 unlock() will call start_lock_event_timing() to get things
1241 Editor::map_position_change (framepos_t frame)
1243 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1245 if (_session == 0) {
1249 if (_follow_playhead) {
1250 center_screen (frame);
1253 playhead_cursor->set_position (frame);
1257 Editor::center_screen (framepos_t frame)
1259 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1261 /* if we're off the page, then scroll.
1264 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1265 center_screen_internal (frame, page);
1270 Editor::center_screen_internal (framepos_t frame, float page)
1275 frame -= (framepos_t) page;
1280 reset_x_origin (frame);
1285 Editor::update_title ()
1287 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1290 bool dirty = _session->dirty();
1292 string session_name;
1294 if (_session->snap_name() != _session->name()) {
1295 session_name = _session->snap_name();
1297 session_name = _session->name();
1301 session_name = "*" + session_name;
1304 WindowTitle title(session_name);
1305 title += Glib::get_application_name();
1306 set_title (title.get_string());
1308 /* ::session_going_away() will have taken care of it */
1313 Editor::set_session (Session *t)
1315 SessionHandlePtr::set_session (t);
1321 _playlist_selector->set_session (_session);
1322 nudge_clock->set_session (_session);
1323 _summary->set_session (_session);
1324 _group_tabs->set_session (_session);
1325 _route_groups->set_session (_session);
1326 _regions->set_session (_session);
1327 _snapshots->set_session (_session);
1328 _routes->set_session (_session);
1329 _locations->set_session (_session);
1331 if (rhythm_ferret) {
1332 rhythm_ferret->set_session (_session);
1335 if (analysis_window) {
1336 analysis_window->set_session (_session);
1340 sfbrowser->set_session (_session);
1343 compute_fixed_ruler_scale ();
1345 /* Make sure we have auto loop and auto punch ranges */
1347 Location* loc = _session->locations()->auto_loop_location();
1349 loc->set_name (_("Loop"));
1352 loc = _session->locations()->auto_punch_location();
1355 loc->set_name (_("Punch"));
1358 refresh_location_display ();
1360 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1361 the selected Marker; this needs the LocationMarker list to be available.
1363 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1364 set_state (*node, Stateful::loading_state_version);
1366 /* catch up with the playhead */
1368 _session->request_locate (playhead_cursor->current_frame ());
1369 _pending_initial_locate = true;
1373 /* These signals can all be emitted by a non-GUI thread. Therefore the
1374 handlers for them must not attempt to directly interact with the GUI,
1375 but use PBD::Signal<T>::connect() which accepts an event loop
1376 ("context") where the handler will be asked to run.
1379 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1380 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1381 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1382 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1383 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1384 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1385 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1386 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1387 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1388 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1389 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1390 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1391 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1393 playhead_cursor->show ();
1395 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1396 Config->map_parameters (pc);
1397 _session->config.map_parameters (pc);
1399 restore_ruler_visibility ();
1400 //tempo_map_changed (PropertyChange (0));
1401 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1403 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1404 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1407 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1408 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1411 switch (_snap_type) {
1412 case SnapToRegionStart:
1413 case SnapToRegionEnd:
1414 case SnapToRegionSync:
1415 case SnapToRegionBoundary:
1416 build_region_boundary_cache ();
1423 /* register for undo history */
1424 _session->register_with_memento_command_factory(id(), this);
1425 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1427 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1429 start_updating_meters ();
1433 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1435 if (a->get_name() == "RegionMenu") {
1436 /* When the main menu's region menu is opened, we setup the actions so that they look right
1437 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1438 so we resensitize all region actions when the entered regionview or the region selection
1439 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1440 happens after the region context menu is opened. So we set a flag here, too.
1444 sensitize_the_right_region_actions ();
1445 _last_region_menu_was_main = true;
1450 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1452 using namespace Menu_Helpers;
1454 void (Editor::*emf)(FadeShape);
1455 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1458 images = &_xfade_in_images;
1459 emf = &Editor::set_fade_in_shape;
1461 images = &_xfade_out_images;
1462 emf = &Editor::set_fade_out_shape;
1467 _("Linear (for highly correlated material)"),
1468 *(*images)[FadeLinear],
1469 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1473 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1477 _("Constant power"),
1478 *(*images)[FadeConstantPower],
1479 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1482 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1487 *(*images)[FadeSymmetric],
1488 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1492 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1497 *(*images)[FadeSlow],
1498 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1501 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1506 *(*images)[FadeFast],
1507 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1510 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1513 /** Pop up a context menu for when the user clicks on a start crossfade */
1515 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1517 using namespace Menu_Helpers;
1518 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1523 MenuList& items (xfade_in_context_menu.items());
1526 if (arv->audio_region()->fade_in_active()) {
1527 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1529 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1532 items.push_back (SeparatorElem());
1533 fill_xfade_menu (items, true);
1535 xfade_in_context_menu.popup (button, time);
1538 /** Pop up a context menu for when the user clicks on an end crossfade */
1540 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1542 using namespace Menu_Helpers;
1543 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1548 MenuList& items (xfade_out_context_menu.items());
1551 if (arv->audio_region()->fade_out_active()) {
1552 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1554 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1557 items.push_back (SeparatorElem());
1558 fill_xfade_menu (items, false);
1560 xfade_out_context_menu.popup (button, time);
1564 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1566 using namespace Menu_Helpers;
1567 Menu* (Editor::*build_menu_function)();
1570 switch (item_type) {
1572 case RegionViewName:
1573 case RegionViewNameHighlight:
1574 case LeftFrameHandle:
1575 case RightFrameHandle:
1576 if (with_selection) {
1577 build_menu_function = &Editor::build_track_selection_context_menu;
1579 build_menu_function = &Editor::build_track_region_context_menu;
1584 if (with_selection) {
1585 build_menu_function = &Editor::build_track_selection_context_menu;
1587 build_menu_function = &Editor::build_track_context_menu;
1592 if (clicked_routeview->track()) {
1593 build_menu_function = &Editor::build_track_context_menu;
1595 build_menu_function = &Editor::build_track_bus_context_menu;
1600 /* probably shouldn't happen but if it does, we don't care */
1604 menu = (this->*build_menu_function)();
1605 menu->set_name ("ArdourContextMenu");
1607 /* now handle specific situations */
1609 switch (item_type) {
1611 case RegionViewName:
1612 case RegionViewNameHighlight:
1613 case LeftFrameHandle:
1614 case RightFrameHandle:
1615 if (!with_selection) {
1616 if (region_edit_menu_split_item) {
1617 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1618 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1620 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1623 if (region_edit_menu_split_multichannel_item) {
1624 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1625 region_edit_menu_split_multichannel_item->set_sensitive (true);
1627 region_edit_menu_split_multichannel_item->set_sensitive (false);
1640 /* probably shouldn't happen but if it does, we don't care */
1644 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1646 /* Bounce to disk */
1648 using namespace Menu_Helpers;
1649 MenuList& edit_items = menu->items();
1651 edit_items.push_back (SeparatorElem());
1653 switch (clicked_routeview->audio_track()->freeze_state()) {
1654 case AudioTrack::NoFreeze:
1655 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1658 case AudioTrack::Frozen:
1659 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1662 case AudioTrack::UnFrozen:
1663 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1669 if (item_type == StreamItem && clicked_routeview) {
1670 clicked_routeview->build_underlay_menu(menu);
1673 /* When the region menu is opened, we setup the actions so that they look right
1676 sensitize_the_right_region_actions ();
1677 _last_region_menu_was_main = false;
1679 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1680 menu->popup (button, time);
1684 Editor::build_track_context_menu ()
1686 using namespace Menu_Helpers;
1688 MenuList& edit_items = track_context_menu.items();
1691 add_dstream_context_items (edit_items);
1692 return &track_context_menu;
1696 Editor::build_track_bus_context_menu ()
1698 using namespace Menu_Helpers;
1700 MenuList& edit_items = track_context_menu.items();
1703 add_bus_context_items (edit_items);
1704 return &track_context_menu;
1708 Editor::build_track_region_context_menu ()
1710 using namespace Menu_Helpers;
1711 MenuList& edit_items = track_region_context_menu.items();
1714 /* we've just cleared the track region context menu, so the menu that these
1715 two items were on will have disappeared; stop them dangling.
1717 region_edit_menu_split_item = 0;
1718 region_edit_menu_split_multichannel_item = 0;
1720 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1723 boost::shared_ptr<Track> tr;
1724 boost::shared_ptr<Playlist> pl;
1726 if ((tr = rtv->track())) {
1727 add_region_context_items (edit_items, tr);
1731 add_dstream_context_items (edit_items);
1733 return &track_region_context_menu;
1737 Editor::analyze_region_selection ()
1739 if (analysis_window == 0) {
1740 analysis_window = new AnalysisWindow();
1743 analysis_window->set_session(_session);
1745 analysis_window->show_all();
1748 analysis_window->set_regionmode();
1749 analysis_window->analyze();
1751 analysis_window->present();
1755 Editor::analyze_range_selection()
1757 if (analysis_window == 0) {
1758 analysis_window = new AnalysisWindow();
1761 analysis_window->set_session(_session);
1763 analysis_window->show_all();
1766 analysis_window->set_rangemode();
1767 analysis_window->analyze();
1769 analysis_window->present();
1773 Editor::build_track_selection_context_menu ()
1775 using namespace Menu_Helpers;
1776 MenuList& edit_items = track_selection_context_menu.items();
1777 edit_items.clear ();
1779 add_selection_context_items (edit_items);
1780 // edit_items.push_back (SeparatorElem());
1781 // add_dstream_context_items (edit_items);
1783 return &track_selection_context_menu;
1787 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1789 using namespace Menu_Helpers;
1791 /* OK, stick the region submenu at the top of the list, and then add
1795 RegionSelection rs = get_regions_from_selection_and_entered ();
1797 string::size_type pos = 0;
1798 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1800 /* we have to hack up the region name because "_" has a special
1801 meaning for menu titles.
1804 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1805 menu_item_name.replace (pos, 1, "__");
1809 if (_popup_region_menu_item == 0) {
1810 _popup_region_menu_item = new MenuItem (menu_item_name);
1811 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1812 _popup_region_menu_item->show ();
1814 _popup_region_menu_item->set_label (menu_item_name);
1817 /* No latering allowed in later is higher layering model */
1818 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1819 if (act && Config->get_layer_model() == LaterHigher) {
1820 act->set_sensitive (false);
1822 act->set_sensitive (true);
1825 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1827 edit_items.push_back (*_popup_region_menu_item);
1828 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1829 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1831 edit_items.push_back (SeparatorElem());
1834 /** Add context menu items relevant to selection ranges.
1835 * @param edit_items List to add the items to.
1838 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1840 using namespace Menu_Helpers;
1842 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1843 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1845 edit_items.push_back (SeparatorElem());
1846 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1848 edit_items.push_back (SeparatorElem());
1849 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1851 edit_items.push_back (SeparatorElem());
1853 edit_items.push_back (
1855 _("Move Range Start to Previous Region Boundary"),
1856 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1860 edit_items.push_back (
1862 _("Move Range Start to Next Region Boundary"),
1863 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1867 edit_items.push_back (
1869 _("Move Range End to Previous Region Boundary"),
1870 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1874 edit_items.push_back (
1876 _("Move Range End to Next Region Boundary"),
1877 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1881 edit_items.push_back (SeparatorElem());
1882 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1883 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1885 edit_items.push_back (SeparatorElem());
1886 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1888 edit_items.push_back (SeparatorElem());
1889 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1890 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1891 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1893 edit_items.push_back (SeparatorElem());
1894 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1896 edit_items.push_back (SeparatorElem());
1897 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1898 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1900 edit_items.push_back (SeparatorElem());
1901 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1902 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1903 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1904 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1905 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1906 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1907 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1913 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1915 using namespace Menu_Helpers;
1919 Menu *play_menu = manage (new Menu);
1920 MenuList& play_items = play_menu->items();
1921 play_menu->set_name ("ArdourContextMenu");
1923 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1924 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1925 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1926 play_items.push_back (SeparatorElem());
1927 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1929 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1933 Menu *select_menu = manage (new Menu);
1934 MenuList& select_items = select_menu->items();
1935 select_menu->set_name ("ArdourContextMenu");
1937 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1938 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1939 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1940 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1941 select_items.push_back (SeparatorElem());
1942 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1943 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1944 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
1945 select_items.push_back (SeparatorElem());
1946 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
1947 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
1948 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1949 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1950 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1951 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1952 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1954 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1958 Menu *cutnpaste_menu = manage (new Menu);
1959 MenuList& cutnpaste_items = cutnpaste_menu->items();
1960 cutnpaste_menu->set_name ("ArdourContextMenu");
1962 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1963 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1964 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1966 cutnpaste_items.push_back (SeparatorElem());
1968 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1969 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1971 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1973 /* Adding new material */
1975 edit_items.push_back (SeparatorElem());
1976 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1977 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1981 Menu *nudge_menu = manage (new Menu());
1982 MenuList& nudge_items = nudge_menu->items();
1983 nudge_menu->set_name ("ArdourContextMenu");
1985 edit_items.push_back (SeparatorElem());
1986 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1987 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1988 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1989 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1991 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1995 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1997 using namespace Menu_Helpers;
2001 Menu *play_menu = manage (new Menu);
2002 MenuList& play_items = play_menu->items();
2003 play_menu->set_name ("ArdourContextMenu");
2005 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2006 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2007 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2011 Menu *select_menu = manage (new Menu);
2012 MenuList& select_items = select_menu->items();
2013 select_menu->set_name ("ArdourContextMenu");
2015 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2016 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2017 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2018 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2019 select_items.push_back (SeparatorElem());
2020 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2021 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2022 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2023 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2025 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2029 Menu *cutnpaste_menu = manage (new Menu);
2030 MenuList& cutnpaste_items = cutnpaste_menu->items();
2031 cutnpaste_menu->set_name ("ArdourContextMenu");
2033 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2034 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2035 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2037 Menu *nudge_menu = manage (new Menu());
2038 MenuList& nudge_items = nudge_menu->items();
2039 nudge_menu->set_name ("ArdourContextMenu");
2041 edit_items.push_back (SeparatorElem());
2042 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2043 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2044 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2045 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2047 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2051 Editor::snap_type() const
2057 Editor::snap_mode() const
2063 Editor::set_snap_to (SnapType st)
2065 unsigned int snap_ind = (unsigned int)st;
2067 if (internal_editing()) {
2068 internal_snap_type = st;
2070 pre_internal_snap_type = st;
2075 if (snap_ind > snap_type_strings.size() - 1) {
2077 _snap_type = (SnapType)snap_ind;
2080 string str = snap_type_strings[snap_ind];
2082 if (str != snap_type_selector.get_text()) {
2083 snap_type_selector.set_text (str);
2088 switch (_snap_type) {
2089 case SnapToBeatDiv128:
2090 case SnapToBeatDiv64:
2091 case SnapToBeatDiv32:
2092 case SnapToBeatDiv28:
2093 case SnapToBeatDiv24:
2094 case SnapToBeatDiv20:
2095 case SnapToBeatDiv16:
2096 case SnapToBeatDiv14:
2097 case SnapToBeatDiv12:
2098 case SnapToBeatDiv10:
2099 case SnapToBeatDiv8:
2100 case SnapToBeatDiv7:
2101 case SnapToBeatDiv6:
2102 case SnapToBeatDiv5:
2103 case SnapToBeatDiv4:
2104 case SnapToBeatDiv3:
2105 case SnapToBeatDiv2: {
2106 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2107 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2109 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2110 current_bbt_points_begin, current_bbt_points_end);
2111 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2112 current_bbt_points_begin, current_bbt_points_end);
2113 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2117 case SnapToRegionStart:
2118 case SnapToRegionEnd:
2119 case SnapToRegionSync:
2120 case SnapToRegionBoundary:
2121 build_region_boundary_cache ();
2129 redisplay_tempo (false);
2131 SnapChanged (); /* EMIT SIGNAL */
2135 Editor::set_snap_mode (SnapMode mode)
2137 string str = snap_mode_strings[(int)mode];
2139 if (internal_editing()) {
2140 internal_snap_mode = mode;
2142 pre_internal_snap_mode = mode;
2147 if (str != snap_mode_selector.get_text ()) {
2148 snap_mode_selector.set_text (str);
2155 Editor::set_edit_point_preference (EditPoint ep, bool force)
2157 bool changed = (_edit_point != ep);
2160 if (Profile->get_mixbus())
2161 if (ep == EditAtSelectedMarker)
2162 ep = EditAtPlayhead;
2164 string str = edit_point_strings[(int)ep];
2165 if (str != edit_point_selector.get_text ()) {
2166 edit_point_selector.set_text (str);
2169 update_all_enter_cursors();
2171 if (!force && !changed) {
2175 const char* action=NULL;
2177 switch (_edit_point) {
2178 case EditAtPlayhead:
2179 action = "edit-at-playhead";
2181 case EditAtSelectedMarker:
2182 action = "edit-at-marker";
2185 action = "edit-at-mouse";
2189 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2191 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2195 bool in_track_canvas;
2197 if (!mouse_frame (foo, in_track_canvas)) {
2198 in_track_canvas = false;
2201 reset_canvas_action_sensitivity (in_track_canvas);
2207 Editor::set_state (const XMLNode& node, int /*version*/)
2209 const XMLProperty* prop;
2216 g.base_width = default_width;
2217 g.base_height = default_height;
2221 if ((geometry = find_named_node (node, "geometry")) != 0) {
2225 if ((prop = geometry->property("x_size")) == 0) {
2226 prop = geometry->property ("x-size");
2229 g.base_width = atoi(prop->value());
2231 if ((prop = geometry->property("y_size")) == 0) {
2232 prop = geometry->property ("y-size");
2235 g.base_height = atoi(prop->value());
2238 if ((prop = geometry->property ("x_pos")) == 0) {
2239 prop = geometry->property ("x-pos");
2242 x = atoi (prop->value());
2245 if ((prop = geometry->property ("y_pos")) == 0) {
2246 prop = geometry->property ("y-pos");
2249 y = atoi (prop->value());
2253 set_default_size (g.base_width, g.base_height);
2256 if (_session && (prop = node.property ("playhead"))) {
2258 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2260 playhead_cursor->set_position (pos);
2262 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2263 playhead_cursor->set_position (0);
2266 playhead_cursor->set_position (0);
2269 if ((prop = node.property ("mixer-width"))) {
2270 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2273 if ((prop = node.property ("zoom-focus"))) {
2274 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2277 if ((prop = node.property ("zoom"))) {
2278 /* older versions of ardour used floating point samples_per_pixel */
2279 double f = PBD::atof (prop->value());
2280 reset_zoom (llrintf (f));
2282 reset_zoom (samples_per_pixel);
2285 if ((prop = node.property ("visible-track-count"))) {
2286 set_visible_track_count (PBD::atoi (prop->value()));
2289 if ((prop = node.property ("snap-to"))) {
2290 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2293 if ((prop = node.property ("snap-mode"))) {
2294 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2297 if ((prop = node.property ("internal-snap-to"))) {
2298 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2301 if ((prop = node.property ("internal-snap-mode"))) {
2302 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2305 if ((prop = node.property ("pre-internal-snap-to"))) {
2306 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2309 if ((prop = node.property ("pre-internal-snap-mode"))) {
2310 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2313 if ((prop = node.property ("mouse-mode"))) {
2314 MouseMode m = str2mousemode(prop->value());
2315 set_mouse_mode (m, true);
2317 set_mouse_mode (MouseObject, true);
2320 if ((prop = node.property ("left-frame")) != 0) {
2322 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2326 reset_x_origin (pos);
2330 if ((prop = node.property ("y-origin")) != 0) {
2331 reset_y_origin (atof (prop->value ()));
2334 if ((prop = node.property ("join-object-range"))) {
2335 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2336 bool yn = string_is_affirmative (prop->value());
2338 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2339 tact->set_active (!yn);
2340 tact->set_active (yn);
2342 set_mouse_mode(mouse_mode, true);
2345 if ((prop = node.property ("edit-point"))) {
2346 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2349 if ((prop = node.property ("show-measures"))) {
2350 bool yn = string_is_affirmative (prop->value());
2351 _show_measures = yn;
2354 if ((prop = node.property ("follow-playhead"))) {
2355 bool yn = string_is_affirmative (prop->value());
2356 set_follow_playhead (yn);
2359 if ((prop = node.property ("stationary-playhead"))) {
2360 bool yn = string_is_affirmative (prop->value());
2361 set_stationary_playhead (yn);
2364 if ((prop = node.property ("region-list-sort-type"))) {
2365 RegionListSortType st;
2366 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2369 if ((prop = node.property ("show-editor-mixer"))) {
2371 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2374 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2375 bool yn = string_is_affirmative (prop->value());
2377 /* do it twice to force the change */
2379 tact->set_active (!yn);
2380 tact->set_active (yn);
2383 if ((prop = node.property ("show-editor-list"))) {
2385 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2388 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2389 bool yn = string_is_affirmative (prop->value());
2391 /* do it twice to force the change */
2393 tact->set_active (!yn);
2394 tact->set_active (yn);
2397 if ((prop = node.property (X_("editor-list-page")))) {
2398 _the_notebook.set_current_page (atoi (prop->value ()));
2401 if ((prop = node.property (X_("show-marker-lines")))) {
2402 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2404 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2405 bool yn = string_is_affirmative (prop->value ());
2407 tact->set_active (!yn);
2408 tact->set_active (yn);
2411 XMLNodeList children = node.children ();
2412 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2413 selection->set_state (**i, Stateful::current_state_version);
2414 _regions->set_state (**i);
2417 if ((prop = node.property ("maximised"))) {
2418 bool yn = string_is_affirmative (prop->value());
2419 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2421 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2422 bool fs = tact && tact->get_active();
2424 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2428 if ((prop = node.property ("nudge-clock-value"))) {
2430 sscanf (prop->value().c_str(), "%" PRId64, &f);
2431 nudge_clock->set (f);
2433 nudge_clock->set_mode (AudioClock::Timecode);
2434 nudge_clock->set (_session->frame_rate() * 5, true);
2439 * Not all properties may have been in XML, but
2440 * those that are linked to a private variable may need changing
2445 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2447 yn = _show_measures;
2448 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2449 /* do it twice to force the change */
2450 tact->set_active (!yn);
2451 tact->set_active (yn);
2454 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2455 yn = _follow_playhead;
2457 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2458 if (tact->get_active() != yn) {
2459 tact->set_active (yn);
2463 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2464 yn = _stationary_playhead;
2466 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2467 if (tact->get_active() != yn) {
2468 tact->set_active (yn);
2477 Editor::get_state ()
2479 XMLNode* node = new XMLNode ("Editor");
2482 id().print (buf, sizeof (buf));
2483 node->add_property ("id", buf);
2485 if (is_realized()) {
2486 Glib::RefPtr<Gdk::Window> win = get_window();
2488 int x, y, width, height;
2489 win->get_root_origin(x, y);
2490 win->get_size(width, height);
2492 XMLNode* geometry = new XMLNode ("geometry");
2494 snprintf(buf, sizeof(buf), "%d", width);
2495 geometry->add_property("x-size", string(buf));
2496 snprintf(buf, sizeof(buf), "%d", height);
2497 geometry->add_property("y-size", string(buf));
2498 snprintf(buf, sizeof(buf), "%d", x);
2499 geometry->add_property("x-pos", string(buf));
2500 snprintf(buf, sizeof(buf), "%d", y);
2501 geometry->add_property("y-pos", string(buf));
2502 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2503 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2504 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2505 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2506 geometry->add_property("edit-vertical-pane-pos", string(buf));
2508 node->add_child_nocopy (*geometry);
2511 maybe_add_mixer_strip_width (*node);
2513 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2515 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2516 node->add_property ("zoom", buf);
2517 node->add_property ("snap-to", enum_2_string (_snap_type));
2518 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2519 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2520 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2521 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2522 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2523 node->add_property ("edit-point", enum_2_string (_edit_point));
2524 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2525 node->add_property ("visible-track-count", buf);
2527 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2528 node->add_property ("playhead", buf);
2529 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2530 node->add_property ("left-frame", buf);
2531 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2532 node->add_property ("y-origin", buf);
2534 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2535 node->add_property ("maximised", _maximised ? "yes" : "no");
2536 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2537 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2538 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2539 node->add_property ("mouse-mode", enum2str(mouse_mode));
2540 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2542 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2544 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2545 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2548 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2550 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2551 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2554 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2555 node->add_property (X_("editor-list-page"), buf);
2557 if (button_bindings) {
2558 XMLNode* bb = new XMLNode (X_("Buttons"));
2559 button_bindings->save (*bb);
2560 node->add_child_nocopy (*bb);
2563 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2565 node->add_child_nocopy (selection->get_state ());
2566 node->add_child_nocopy (_regions->get_state ());
2568 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2569 node->add_property ("nudge-clock-value", buf);
2574 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2575 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2577 * @return pair: TimeAxisView that y is over, layer index.
2579 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2580 * in stacked or expanded region display mode, otherwise 0.
2582 std::pair<TimeAxisView *, double>
2583 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2585 if (!trackview_relative_offset) {
2586 y -= _trackview_group->canvas_origin().y;
2590 return std::make_pair ( (TimeAxisView *) 0, 0);
2593 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2595 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2602 return std::make_pair ( (TimeAxisView *) 0, 0);
2605 /** Snap a position to the grid, if appropriate, taking into account current
2606 * grid settings and also the state of any snap modifier keys that may be pressed.
2607 * @param start Position to snap.
2608 * @param event Event to get current key modifier information from, or 0.
2611 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2613 if (!_session || !event) {
2617 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2618 if (_snap_mode == SnapOff) {
2619 snap_to_internal (start, direction, for_mark);
2622 if (_snap_mode != SnapOff) {
2623 snap_to_internal (start, direction, for_mark);
2624 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2625 /* SnapOff, but we pressed the snap_delta modifier */
2626 snap_to_internal (start, direction, for_mark);
2632 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2634 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2638 snap_to_internal (start, direction, for_mark, ensure_snap);
2642 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2644 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2645 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2647 switch (_snap_type) {
2648 case SnapToTimecodeFrame:
2649 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2650 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2651 /* start is already on a whole timecode frame, do nothing */
2652 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2653 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2655 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2659 case SnapToTimecodeSeconds:
2660 if (_session->config.get_timecode_offset_negative()) {
2661 start += _session->config.get_timecode_offset ();
2663 start -= _session->config.get_timecode_offset ();
2665 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2666 (start % one_timecode_second == 0)) {
2667 /* start is already on a whole second, do nothing */
2668 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2669 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2671 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2674 if (_session->config.get_timecode_offset_negative()) {
2675 start -= _session->config.get_timecode_offset ();
2677 start += _session->config.get_timecode_offset ();
2681 case SnapToTimecodeMinutes:
2682 if (_session->config.get_timecode_offset_negative()) {
2683 start += _session->config.get_timecode_offset ();
2685 start -= _session->config.get_timecode_offset ();
2687 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2688 (start % one_timecode_minute == 0)) {
2689 /* start is already on a whole minute, do nothing */
2690 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2691 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2693 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2695 if (_session->config.get_timecode_offset_negative()) {
2696 start -= _session->config.get_timecode_offset ();
2698 start += _session->config.get_timecode_offset ();
2702 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2703 abort(); /*NOTREACHED*/
2708 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2710 const framepos_t one_second = _session->frame_rate();
2711 const framepos_t one_minute = _session->frame_rate() * 60;
2712 framepos_t presnap = start;
2716 switch (_snap_type) {
2717 case SnapToTimecodeFrame:
2718 case SnapToTimecodeSeconds:
2719 case SnapToTimecodeMinutes:
2720 return timecode_snap_to_internal (start, direction, for_mark);
2723 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2724 start % (one_second/75) == 0) {
2725 /* start is already on a whole CD frame, do nothing */
2726 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2727 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2729 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2734 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2735 start % one_second == 0) {
2736 /* start is already on a whole second, do nothing */
2737 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2738 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2740 start = (framepos_t) floor ((double) start / one_second) * one_second;
2745 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2746 start % one_minute == 0) {
2747 /* start is already on a whole minute, do nothing */
2748 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2749 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2751 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2756 start = _session->tempo_map().round_to_bar (start, direction);
2760 start = _session->tempo_map().round_to_beat (start, direction);
2763 case SnapToBeatDiv128:
2764 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2766 case SnapToBeatDiv64:
2767 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2769 case SnapToBeatDiv32:
2770 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2772 case SnapToBeatDiv28:
2773 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2775 case SnapToBeatDiv24:
2776 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2778 case SnapToBeatDiv20:
2779 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2781 case SnapToBeatDiv16:
2782 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2784 case SnapToBeatDiv14:
2785 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2787 case SnapToBeatDiv12:
2788 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2790 case SnapToBeatDiv10:
2791 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2793 case SnapToBeatDiv8:
2794 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2796 case SnapToBeatDiv7:
2797 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2799 case SnapToBeatDiv6:
2800 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2802 case SnapToBeatDiv5:
2803 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2805 case SnapToBeatDiv4:
2806 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2808 case SnapToBeatDiv3:
2809 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2811 case SnapToBeatDiv2:
2812 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2820 _session->locations()->marks_either_side (start, before, after);
2822 if (before == max_framepos && after == max_framepos) {
2823 /* No marks to snap to, so just don't snap */
2825 } else if (before == max_framepos) {
2827 } else if (after == max_framepos) {
2829 } else if (before != max_framepos && after != max_framepos) {
2830 /* have before and after */
2831 if ((start - before) < (after - start)) {
2840 case SnapToRegionStart:
2841 case SnapToRegionEnd:
2842 case SnapToRegionSync:
2843 case SnapToRegionBoundary:
2844 if (!region_boundary_cache.empty()) {
2846 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2847 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2849 if (direction > 0) {
2850 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2852 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2855 if (next != region_boundary_cache.begin ()) {
2860 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2861 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2863 if (start > (p + n) / 2) {
2872 switch (_snap_mode) {
2882 if (presnap > start) {
2883 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2887 } else if (presnap < start) {
2888 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2894 /* handled at entry */
2902 Editor::setup_toolbar ()
2904 HBox* mode_box = manage(new HBox);
2905 mode_box->set_border_width (2);
2906 mode_box->set_spacing(2);
2908 HBox* mouse_mode_box = manage (new HBox);
2909 HBox* mouse_mode_hbox = manage (new HBox);
2910 VBox* mouse_mode_vbox = manage (new VBox);
2911 Alignment* mouse_mode_align = manage (new Alignment);
2913 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2914 mouse_mode_size_group->add_widget (smart_mode_button);
2915 mouse_mode_size_group->add_widget (mouse_move_button);
2916 mouse_mode_size_group->add_widget (mouse_cut_button);
2917 mouse_mode_size_group->add_widget (mouse_select_button);
2918 mouse_mode_size_group->add_widget (mouse_timefx_button);
2919 mouse_mode_size_group->add_widget (mouse_audition_button);
2920 mouse_mode_size_group->add_widget (mouse_draw_button);
2921 mouse_mode_size_group->add_widget (mouse_content_button);
2923 mouse_mode_size_group->add_widget (zoom_in_button);
2924 mouse_mode_size_group->add_widget (zoom_out_button);
2925 mouse_mode_size_group->add_widget (zoom_preset_selector);
2926 mouse_mode_size_group->add_widget (zoom_out_full_button);
2927 mouse_mode_size_group->add_widget (zoom_focus_selector);
2929 mouse_mode_size_group->add_widget (tav_shrink_button);
2930 mouse_mode_size_group->add_widget (tav_expand_button);
2931 mouse_mode_size_group->add_widget (visible_tracks_selector);
2933 mouse_mode_size_group->add_widget (snap_type_selector);
2934 mouse_mode_size_group->add_widget (snap_mode_selector);
2936 mouse_mode_size_group->add_widget (edit_point_selector);
2937 mouse_mode_size_group->add_widget (edit_mode_selector);
2939 mouse_mode_size_group->add_widget (*nudge_clock);
2940 mouse_mode_size_group->add_widget (nudge_forward_button);
2941 mouse_mode_size_group->add_widget (nudge_backward_button);
2943 mouse_mode_hbox->set_spacing (2);
2945 if (!ARDOUR::Profile->get_trx()) {
2946 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2949 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2950 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2952 if (!ARDOUR::Profile->get_mixbus()) {
2953 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2956 if (!ARDOUR::Profile->get_trx()) {
2957 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2958 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2959 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2960 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2963 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2965 mouse_mode_align->add (*mouse_mode_vbox);
2966 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2968 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2970 edit_mode_selector.set_name ("mouse mode button");
2972 if (!ARDOUR::Profile->get_trx()) {
2973 mode_box->pack_start (edit_mode_selector, false, false);
2975 mode_box->pack_start (*mouse_mode_box, false, false);
2977 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2978 _mouse_mode_tearoff->set_name ("MouseModeBase");
2979 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2981 if (Profile->get_sae() || Profile->get_mixbus() ) {
2982 _mouse_mode_tearoff->set_can_be_torn_off (false);
2985 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2986 &_mouse_mode_tearoff->tearoff_window()));
2987 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2988 &_mouse_mode_tearoff->tearoff_window(), 1));
2989 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2990 &_mouse_mode_tearoff->tearoff_window()));
2991 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2992 &_mouse_mode_tearoff->tearoff_window(), 1));
2996 _zoom_box.set_spacing (2);
2997 _zoom_box.set_border_width (2);
3001 zoom_preset_selector.set_name ("zoom button");
3002 zoom_preset_selector.set_image(::get_icon ("time_exp"));
3003 zoom_preset_selector.set_size_request (42, -1);
3005 zoom_in_button.set_name ("zoom button");
3006 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3007 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3008 zoom_in_button.set_related_action (act);
3010 zoom_out_button.set_name ("zoom button");
3011 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3012 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3013 zoom_out_button.set_related_action (act);
3015 zoom_out_full_button.set_name ("zoom button");
3016 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3017 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3018 zoom_out_full_button.set_related_action (act);
3020 zoom_focus_selector.set_name ("zoom button");
3022 if (ARDOUR::Profile->get_mixbus()) {
3023 _zoom_box.pack_start (zoom_preset_selector, false, false);
3024 } else if (ARDOUR::Profile->get_trx()) {
3025 mode_box->pack_start (zoom_out_button, false, false);
3026 mode_box->pack_start (zoom_in_button, false, false);
3028 _zoom_box.pack_start (zoom_out_button, false, false);
3029 _zoom_box.pack_start (zoom_in_button, false, false);
3030 _zoom_box.pack_start (zoom_out_full_button, false, false);
3031 _zoom_box.pack_start (zoom_focus_selector, false, false);
3034 /* Track zoom buttons */
3035 visible_tracks_selector.set_name ("zoom button");
3036 if (Profile->get_mixbus()) {
3037 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3038 visible_tracks_selector.set_size_request (42, -1);
3040 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3043 tav_expand_button.set_name ("zoom button");
3044 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3045 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3046 tav_expand_button.set_related_action (act);
3048 tav_shrink_button.set_name ("zoom button");
3049 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3050 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3051 tav_shrink_button.set_related_action (act);
3053 if (ARDOUR::Profile->get_mixbus()) {
3054 _zoom_box.pack_start (visible_tracks_selector);
3055 } else if (ARDOUR::Profile->get_trx()) {
3056 _zoom_box.pack_start (tav_shrink_button);
3057 _zoom_box.pack_start (tav_expand_button);
3059 _zoom_box.pack_start (visible_tracks_selector);
3060 _zoom_box.pack_start (tav_shrink_button);
3061 _zoom_box.pack_start (tav_expand_button);
3064 if (!ARDOUR::Profile->get_trx()) {
3065 _zoom_tearoff = manage (new TearOff (_zoom_box));
3067 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3068 &_zoom_tearoff->tearoff_window()));
3069 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3070 &_zoom_tearoff->tearoff_window(), 0));
3071 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3072 &_zoom_tearoff->tearoff_window()));
3073 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3074 &_zoom_tearoff->tearoff_window(), 0));
3077 if (Profile->get_sae() || Profile->get_mixbus() ) {
3078 _zoom_tearoff->set_can_be_torn_off (false);
3081 snap_box.set_spacing (2);
3082 snap_box.set_border_width (2);
3084 snap_type_selector.set_name ("mouse mode button");
3086 snap_mode_selector.set_name ("mouse mode button");
3088 edit_point_selector.set_name ("mouse mode button");
3090 snap_box.pack_start (snap_mode_selector, false, false);
3091 snap_box.pack_start (snap_type_selector, false, false);
3092 snap_box.pack_start (edit_point_selector, false, false);
3096 HBox *nudge_box = manage (new HBox);
3097 nudge_box->set_spacing (2);
3098 nudge_box->set_border_width (2);
3100 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3101 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3103 nudge_box->pack_start (nudge_backward_button, false, false);
3104 nudge_box->pack_start (nudge_forward_button, false, false);
3105 nudge_box->pack_start (*nudge_clock, false, false);
3108 /* Pack everything in... */
3110 HBox* hbox = manage (new HBox);
3111 hbox->set_spacing(2);
3113 _tools_tearoff = manage (new TearOff (*hbox));
3114 _tools_tearoff->set_name ("MouseModeBase");
3115 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3117 if (Profile->get_sae() || Profile->get_mixbus()) {
3118 _tools_tearoff->set_can_be_torn_off (false);
3121 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3122 &_tools_tearoff->tearoff_window()));
3123 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3124 &_tools_tearoff->tearoff_window(), 0));
3125 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3126 &_tools_tearoff->tearoff_window()));
3127 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3128 &_tools_tearoff->tearoff_window(), 0));
3130 toolbar_hbox.set_spacing (2);
3131 toolbar_hbox.set_border_width (1);
3133 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3134 if (!ARDOUR::Profile->get_trx()) {
3135 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3136 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3139 if (!ARDOUR::Profile->get_trx()) {
3140 hbox->pack_start (snap_box, false, false);
3141 hbox->pack_start (*nudge_box, false, false);
3143 hbox->pack_start (panic_box, false, false);
3147 toolbar_base.set_name ("ToolBarBase");
3148 toolbar_base.add (toolbar_hbox);
3150 _toolbar_viewport.add (toolbar_base);
3151 /* stick to the required height but allow width to vary if there's not enough room */
3152 _toolbar_viewport.set_size_request (1, -1);
3154 toolbar_frame.set_shadow_type (SHADOW_OUT);
3155 toolbar_frame.set_name ("BaseFrame");
3156 toolbar_frame.add (_toolbar_viewport);
3160 Editor::build_edit_point_menu ()
3162 using namespace Menu_Helpers;
3164 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3165 if(!Profile->get_mixbus())
3166 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3167 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3169 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3173 Editor::build_edit_mode_menu ()
3175 using namespace Menu_Helpers;
3177 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3178 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3179 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3180 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3182 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3186 Editor::build_snap_mode_menu ()
3188 using namespace Menu_Helpers;
3190 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3191 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3192 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3194 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3198 Editor::build_snap_type_menu ()
3200 using namespace Menu_Helpers;
3202 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3203 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3204 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3205 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3206 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3207 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3208 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3209 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3210 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3211 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3212 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3213 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3214 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3215 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3216 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3217 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3218 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3219 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3220 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3221 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3222 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3223 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3224 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3225 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3226 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3227 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3228 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3229 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3230 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3231 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3233 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3238 Editor::setup_tooltips ()
3240 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3241 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3242 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3243 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3244 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3245 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3246 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3247 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3248 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3249 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3250 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3251 set_tooltip (zoom_in_button, _("Zoom In"));
3252 set_tooltip (zoom_out_button, _("Zoom Out"));
3253 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3254 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3255 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3256 set_tooltip (tav_expand_button, _("Expand Tracks"));
3257 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3258 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3259 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3260 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3261 set_tooltip (edit_point_selector, _("Edit Point"));
3262 set_tooltip (edit_mode_selector, _("Edit Mode"));
3263 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3267 Editor::convert_drop_to_paths (
3268 vector<string>& paths,
3269 const RefPtr<Gdk::DragContext>& /*context*/,
3272 const SelectionData& data,
3276 if (_session == 0) {
3280 vector<string> uris = data.get_uris();
3284 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3285 are actually URI lists. So do it by hand.
3288 if (data.get_target() != "text/plain") {
3292 /* Parse the "uri-list" format that Nautilus provides,
3293 where each pathname is delimited by \r\n.
3295 THERE MAY BE NO NULL TERMINATING CHAR!!!
3298 string txt = data.get_text();
3302 p = (char *) malloc (txt.length() + 1);
3303 txt.copy (p, txt.length(), 0);
3304 p[txt.length()] = '\0';
3310 while (g_ascii_isspace (*p))
3314 while (*q && (*q != '\n') && (*q != '\r')) {
3321 while (q > p && g_ascii_isspace (*q))
3326 uris.push_back (string (p, q - p + 1));
3330 p = strchr (p, '\n');
3342 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3343 if ((*i).substr (0,7) == "file://") {
3344 paths.push_back (Glib::filename_from_uri (*i));
3352 Editor::new_tempo_section ()
3357 Editor::map_transport_state ()
3359 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3361 if (_session && _session->transport_stopped()) {
3362 have_pending_keyboard_selection = false;
3365 update_loop_range_view ();
3371 Editor::begin_selection_op_history ()
3373 selection_op_cmd_depth = 0;
3374 selection_op_history_it = 0;
3376 while(!selection_op_history.empty()) {
3377 delete selection_op_history.front();
3378 selection_op_history.pop_front();
3381 selection_undo_action->set_sensitive (false);
3382 selection_redo_action->set_sensitive (false);
3383 selection_op_history.push_front (&_selection_memento->get_state ());
3387 Editor::begin_reversible_selection_op (string name)
3390 //cerr << name << endl;
3391 /* begin/commit pairs can be nested */
3392 selection_op_cmd_depth++;
3397 Editor::commit_reversible_selection_op ()
3400 if (selection_op_cmd_depth == 1) {
3402 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3404 The user has undone some selection ops and then made a new one,
3405 making anything earlier in the list invalid.
3408 list<XMLNode *>::iterator it = selection_op_history.begin();
3409 list<XMLNode *>::iterator e_it = it;
3410 advance (e_it, selection_op_history_it);
3412 for ( ; it != e_it; ++it) {
3415 selection_op_history.erase (selection_op_history.begin(), e_it);
3418 selection_op_history.push_front (&_selection_memento->get_state ());
3419 selection_op_history_it = 0;
3421 selection_undo_action->set_sensitive (true);
3422 selection_redo_action->set_sensitive (false);
3425 if (selection_op_cmd_depth > 0) {
3426 selection_op_cmd_depth--;
3432 Editor::undo_selection_op ()
3435 selection_op_history_it++;
3437 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3438 if (n == selection_op_history_it) {
3439 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3440 selection_redo_action->set_sensitive (true);
3444 /* is there an earlier entry? */
3445 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3446 selection_undo_action->set_sensitive (false);
3452 Editor::redo_selection_op ()
3455 if (selection_op_history_it > 0) {
3456 selection_op_history_it--;
3459 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3460 if (n == selection_op_history_it) {
3461 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3462 selection_undo_action->set_sensitive (true);
3467 if (selection_op_history_it == 0) {
3468 selection_redo_action->set_sensitive (false);
3474 Editor::begin_reversible_command (string name)
3477 before.push_back (&_selection_memento->get_state ());
3478 _session->begin_reversible_command (name);
3483 Editor::begin_reversible_command (GQuark q)
3486 before.push_back (&_selection_memento->get_state ());
3487 _session->begin_reversible_command (q);
3492 Editor::abort_reversible_command ()
3495 while(!before.empty()) {
3496 delete before.front();
3499 _session->abort_reversible_command ();
3504 Editor::commit_reversible_command ()
3507 if (before.size() == 1) {
3508 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3509 redo_action->set_sensitive(false);
3510 undo_action->set_sensitive(true);
3511 begin_selection_op_history ();
3514 if (before.empty()) {
3515 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3520 _session->commit_reversible_command ();
3525 Editor::history_changed ()
3529 if (undo_action && _session) {
3530 if (_session->undo_depth() == 0) {
3531 label = S_("Command|Undo");
3533 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3535 undo_action->property_label() = label;
3538 if (redo_action && _session) {
3539 if (_session->redo_depth() == 0) {
3541 redo_action->set_sensitive (false);
3543 label = string_compose(_("Redo (%1)"), _session->next_redo());
3544 redo_action->set_sensitive (true);
3546 redo_action->property_label() = label;
3551 Editor::duplicate_range (bool with_dialog)
3555 RegionSelection rs = get_regions_from_selection_and_entered ();
3557 if ( selection->time.length() == 0 && rs.empty()) {
3563 ArdourDialog win (_("Duplicate"));
3564 Label label (_("Number of duplications:"));
3565 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3566 SpinButton spinner (adjustment, 0.0, 1);
3569 win.get_vbox()->set_spacing (12);
3570 win.get_vbox()->pack_start (hbox);
3571 hbox.set_border_width (6);
3572 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3574 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3575 place, visually. so do this by hand.
3578 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3579 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3580 spinner.grab_focus();
3586 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3587 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3588 win.set_default_response (RESPONSE_ACCEPT);
3590 spinner.grab_focus ();
3592 switch (win.run ()) {
3593 case RESPONSE_ACCEPT:
3599 times = adjustment.get_value();
3602 if ((current_mouse_mode() == Editing::MouseRange)) {
3603 if (selection->time.length()) {
3604 duplicate_selection (times);
3606 } else if (get_smart_mode()) {
3607 if (selection->time.length()) {
3608 duplicate_selection (times);
3610 duplicate_some_regions (rs, times);
3612 duplicate_some_regions (rs, times);
3617 Editor::set_edit_mode (EditMode m)
3619 Config->set_edit_mode (m);
3623 Editor::cycle_edit_mode ()
3625 switch (Config->get_edit_mode()) {
3627 if (Profile->get_sae()) {
3628 Config->set_edit_mode (Lock);
3630 Config->set_edit_mode (Ripple);
3635 Config->set_edit_mode (Lock);
3638 Config->set_edit_mode (Slide);
3644 Editor::edit_mode_selection_done ( EditMode m )
3646 Config->set_edit_mode ( m );
3650 Editor::snap_type_selection_done (SnapType snaptype)
3652 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3654 ract->set_active ();
3659 Editor::snap_mode_selection_done (SnapMode mode)
3661 RefPtr<RadioAction> ract = snap_mode_action (mode);
3664 ract->set_active (true);
3669 Editor::cycle_edit_point (bool with_marker)
3671 if(Profile->get_mixbus())
3672 with_marker = false;
3674 switch (_edit_point) {
3676 set_edit_point_preference (EditAtPlayhead);
3678 case EditAtPlayhead:
3680 set_edit_point_preference (EditAtSelectedMarker);
3682 set_edit_point_preference (EditAtMouse);
3685 case EditAtSelectedMarker:
3686 set_edit_point_preference (EditAtMouse);
3692 Editor::edit_point_selection_done (EditPoint ep)
3694 set_edit_point_preference ( ep );
3698 Editor::build_zoom_focus_menu ()
3700 using namespace Menu_Helpers;
3702 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3703 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3704 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3705 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3706 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3707 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3709 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3713 Editor::zoom_focus_selection_done ( ZoomFocus f )
3715 RefPtr<RadioAction> ract = zoom_focus_action (f);
3717 ract->set_active ();
3722 Editor::build_track_count_menu ()
3724 using namespace Menu_Helpers;
3726 if (!Profile->get_mixbus()) {
3727 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3728 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3729 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3730 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3731 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3732 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3733 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3734 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3735 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3736 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3737 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3738 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3739 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3741 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3742 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3743 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3744 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3745 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3746 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3747 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3748 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3749 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3750 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3752 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3753 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3754 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3755 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3756 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3757 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3758 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3759 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3760 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3761 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3762 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3767 Editor::set_zoom_preset (int64_t ms)
3770 temporal_zoom_session();
3774 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3775 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3779 Editor::set_visible_track_count (int32_t n)
3781 _visible_track_count = n;
3783 /* if the canvas hasn't really been allocated any size yet, just
3784 record the desired number of visible tracks and return. when canvas
3785 allocation happens, we will get called again and then we can do the
3789 if (_visible_canvas_height <= 1) {
3795 DisplaySuspender ds;
3797 if (_visible_track_count > 0) {
3798 h = trackviews_height() / _visible_track_count;
3799 std::ostringstream s;
3800 s << _visible_track_count;
3802 } else if (_visible_track_count == 0) {
3804 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3805 if ((*i)->marked_for_display()) {
3809 h = trackviews_height() / n;
3812 /* negative value means that the visible track count has
3813 been overridden by explicit track height changes.
3815 visible_tracks_selector.set_text (X_("*"));
3819 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3820 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3823 if (str != visible_tracks_selector.get_text()) {
3824 visible_tracks_selector.set_text (str);
3829 Editor::override_visible_track_count ()
3831 _visible_track_count = -1;
3832 visible_tracks_selector.set_text ( _("*") );
3836 Editor::edit_controls_button_release (GdkEventButton* ev)
3838 if (Keyboard::is_context_menu_event (ev)) {
3839 ARDOUR_UI::instance()->add_route (this);
3840 } else if (ev->button == 1) {
3841 selection->clear_tracks ();
3848 Editor::mouse_select_button_release (GdkEventButton* ev)
3850 /* this handles just right-clicks */
3852 if (ev->button != 3) {
3860 Editor::set_zoom_focus (ZoomFocus f)
3862 string str = zoom_focus_strings[(int)f];
3864 if (str != zoom_focus_selector.get_text()) {
3865 zoom_focus_selector.set_text (str);
3868 if (zoom_focus != f) {
3875 Editor::cycle_zoom_focus ()
3877 switch (zoom_focus) {
3879 set_zoom_focus (ZoomFocusRight);
3881 case ZoomFocusRight:
3882 set_zoom_focus (ZoomFocusCenter);
3884 case ZoomFocusCenter:
3885 set_zoom_focus (ZoomFocusPlayhead);
3887 case ZoomFocusPlayhead:
3888 set_zoom_focus (ZoomFocusMouse);
3890 case ZoomFocusMouse:
3891 set_zoom_focus (ZoomFocusEdit);
3894 set_zoom_focus (ZoomFocusLeft);
3900 Editor::ensure_float (Window& win)
3902 win.set_transient_for (*this);
3906 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3908 /* recover or initialize pane positions. do this here rather than earlier because
3909 we don't want the positions to change the child allocations, which they seem to do.
3915 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3924 XMLNode* geometry = find_named_node (*node, "geometry");
3926 if (which == static_cast<Paned*> (&edit_pane)) {
3928 if (done & Horizontal) {
3932 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3933 _notebook_shrunk = string_is_affirmative (prop->value ());
3936 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3937 /* initial allocation is 90% to canvas, 10% to notebook */
3938 pos = (int) floor (alloc.get_width() * 0.90f);
3939 snprintf (buf, sizeof(buf), "%d", pos);
3941 pos = atoi (prop->value());
3944 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3945 edit_pane.set_position (pos);
3948 done = (Pane) (done | Horizontal);
3950 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3952 if (done & Vertical) {
3956 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3957 /* initial allocation is 90% to canvas, 10% to summary */
3958 pos = (int) floor (alloc.get_height() * 0.90f);
3959 snprintf (buf, sizeof(buf), "%d", pos);
3962 pos = atoi (prop->value());
3965 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3966 editor_summary_pane.set_position (pos);
3969 done = (Pane) (done | Vertical);
3974 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3976 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3977 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3978 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3979 top_hbox.remove (toolbar_frame);
3984 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3986 if (toolbar_frame.get_parent() == 0) {
3987 top_hbox.pack_end (toolbar_frame);
3992 Editor::set_show_measures (bool yn)
3994 if (_show_measures != yn) {
3997 if ((_show_measures = yn) == true) {
3999 tempo_lines->show();
4002 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
4003 ARDOUR::TempoMap::BBTPointList::const_iterator end;
4005 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
4006 draw_measures (begin, end);
4014 Editor::toggle_follow_playhead ()
4016 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
4018 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4019 set_follow_playhead (tact->get_active());
4023 /** @param yn true to follow playhead, otherwise false.
4024 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4027 Editor::set_follow_playhead (bool yn, bool catch_up)
4029 if (_follow_playhead != yn) {
4030 if ((_follow_playhead = yn) == true && catch_up) {
4032 reset_x_origin_to_follow_playhead ();
4039 Editor::toggle_stationary_playhead ()
4041 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4043 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4044 set_stationary_playhead (tact->get_active());
4049 Editor::set_stationary_playhead (bool yn)
4051 if (_stationary_playhead != yn) {
4052 if ((_stationary_playhead = yn) == true) {
4054 // FIXME need a 3.0 equivalent of this 2.X call
4055 // update_current_screen ();
4062 Editor::playlist_selector () const
4064 return *_playlist_selector;
4068 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4070 if (paste_count == 0) {
4071 /* don't bother calculating an offset that will be zero anyway */
4075 /* calculate basic unsnapped multi-paste offset */
4076 framecnt_t offset = paste_count * duration;
4078 /* snap offset so pos + offset is aligned to the grid */
4079 framepos_t offset_pos = pos + offset;
4080 snap_to(offset_pos, RoundUpMaybe);
4081 offset = offset_pos - pos;
4087 Editor::get_grid_beat_divisions(framepos_t position)
4089 switch (_snap_type) {
4090 case SnapToBeatDiv128: return 128;
4091 case SnapToBeatDiv64: return 64;
4092 case SnapToBeatDiv32: return 32;
4093 case SnapToBeatDiv28: return 28;
4094 case SnapToBeatDiv24: return 24;
4095 case SnapToBeatDiv20: return 20;
4096 case SnapToBeatDiv16: return 16;
4097 case SnapToBeatDiv14: return 14;
4098 case SnapToBeatDiv12: return 12;
4099 case SnapToBeatDiv10: return 10;
4100 case SnapToBeatDiv8: return 8;
4101 case SnapToBeatDiv7: return 7;
4102 case SnapToBeatDiv6: return 6;
4103 case SnapToBeatDiv5: return 5;
4104 case SnapToBeatDiv4: return 4;
4105 case SnapToBeatDiv3: return 3;
4106 case SnapToBeatDiv2: return 2;
4113 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4117 const unsigned divisions = get_grid_beat_divisions(position);
4119 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4122 switch (_snap_type) {
4124 return Evoral::Beats(1.0);
4127 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
4135 return Evoral::Beats();
4139 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4143 ret = nudge_clock->current_duration (pos);
4144 next = ret + 1; /* XXXX fix me */
4150 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4152 ArdourDialog dialog (_("Playlist Deletion"));
4153 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4154 "If it is kept, its audio files will not be cleaned.\n"
4155 "If it is deleted, audio files used by it alone will be cleaned."),
4158 dialog.set_position (WIN_POS_CENTER);
4159 dialog.get_vbox()->pack_start (label);
4163 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4164 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4165 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4166 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4167 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4169 // by default gtk uses the left most button
4170 keep->grab_focus ();
4172 switch (dialog.run ()) {
4174 /* keep this and all remaining ones */
4179 /* delete this and all others */
4183 case RESPONSE_ACCEPT:
4184 /* delete the playlist */
4188 case RESPONSE_REJECT:
4189 /* keep the playlist */
4201 Editor::audio_region_selection_covers (framepos_t where)
4203 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4204 if ((*a)->region()->covers (where)) {
4213 Editor::prepare_for_cleanup ()
4215 cut_buffer->clear_regions ();
4216 cut_buffer->clear_playlists ();
4218 selection->clear_regions ();
4219 selection->clear_playlists ();
4221 _regions->suspend_redisplay ();
4225 Editor::finish_cleanup ()
4227 _regions->resume_redisplay ();
4231 Editor::transport_loop_location()
4234 return _session->locations()->auto_loop_location();
4241 Editor::transport_punch_location()
4244 return _session->locations()->auto_punch_location();
4251 Editor::control_layout_scroll (GdkEventScroll* ev)
4253 /* Just forward to the normal canvas scroll method. The coordinate
4254 systems are different but since the canvas is always larger than the
4255 track headers, and aligned with the trackview area, this will work.
4257 In the not too distant future this layout is going away anyway and
4258 headers will be on the canvas.
4260 return canvas_scroll_event (ev, false);
4264 Editor::session_state_saved (string)
4267 _snapshots->redisplay ();
4271 Editor::update_tearoff_visibility()
4273 bool visible = UIConfiguration::instance().get_keep_tearoffs();
4274 _mouse_mode_tearoff->set_visible (visible);
4275 _tools_tearoff->set_visible (visible);
4276 if (_zoom_tearoff) {
4277 _zoom_tearoff->set_visible (visible);
4282 Editor::reattach_all_tearoffs ()
4284 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4285 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4286 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4290 Editor::maximise_editing_space ()
4302 Editor::restore_editing_space ()
4314 * Make new playlists for a given track and also any others that belong
4315 * to the same active route group with the `select' property.
4320 Editor::new_playlists (TimeAxisView* v)
4322 begin_reversible_command (_("new playlists"));
4323 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4324 _session->playlists->get (playlists);
4325 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4326 commit_reversible_command ();
4330 * Use a copy of the current playlist for a given track and also any others that belong
4331 * to the same active route group with the `select' property.
4336 Editor::copy_playlists (TimeAxisView* v)
4338 begin_reversible_command (_("copy playlists"));
4339 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4340 _session->playlists->get (playlists);
4341 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4342 commit_reversible_command ();
4345 /** Clear the current playlist for a given track and also any others that belong
4346 * to the same active route group with the `select' property.
4351 Editor::clear_playlists (TimeAxisView* v)
4353 begin_reversible_command (_("clear playlists"));
4354 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4355 _session->playlists->get (playlists);
4356 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4357 commit_reversible_command ();
4361 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4363 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4367 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4369 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4373 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4375 atv.clear_playlist ();
4379 Editor::on_key_press_event (GdkEventKey* ev)
4381 return key_press_focus_accelerator_handler (*this, ev);
4385 Editor::on_key_release_event (GdkEventKey* ev)
4387 return Gtk::Window::on_key_release_event (ev);
4388 // return key_press_focus_accelerator_handler (*this, ev);
4392 Editor::get_y_origin () const
4394 return vertical_adjustment.get_value ();
4397 /** Queue up a change to the viewport x origin.
4398 * @param frame New x origin.
4401 Editor::reset_x_origin (framepos_t frame)
4403 pending_visual_change.add (VisualChange::TimeOrigin);
4404 pending_visual_change.time_origin = frame;
4405 ensure_visual_change_idle_handler ();
4409 Editor::reset_y_origin (double y)
4411 pending_visual_change.add (VisualChange::YOrigin);
4412 pending_visual_change.y_origin = y;
4413 ensure_visual_change_idle_handler ();
4417 Editor::reset_zoom (framecnt_t spp)
4419 if (spp == samples_per_pixel) {
4423 pending_visual_change.add (VisualChange::ZoomLevel);
4424 pending_visual_change.samples_per_pixel = spp;
4425 ensure_visual_change_idle_handler ();
4429 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4431 reset_x_origin (frame);
4434 if (!no_save_visual) {
4435 undo_visual_stack.push_back (current_visual_state(false));
4439 Editor::VisualState::VisualState (bool with_tracks)
4440 : gui_state (with_tracks ? new GUIObjectState : 0)
4444 Editor::VisualState::~VisualState ()
4449 Editor::VisualState*
4450 Editor::current_visual_state (bool with_tracks)
4452 VisualState* vs = new VisualState (with_tracks);
4453 vs->y_position = vertical_adjustment.get_value();
4454 vs->samples_per_pixel = samples_per_pixel;
4455 vs->leftmost_frame = leftmost_frame;
4456 vs->zoom_focus = zoom_focus;
4459 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4466 Editor::undo_visual_state ()
4468 if (undo_visual_stack.empty()) {
4472 VisualState* vs = undo_visual_stack.back();
4473 undo_visual_stack.pop_back();
4476 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4479 use_visual_state (*vs);
4484 Editor::redo_visual_state ()
4486 if (redo_visual_stack.empty()) {
4490 VisualState* vs = redo_visual_stack.back();
4491 redo_visual_stack.pop_back();
4493 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4494 // why do we check here?
4495 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4498 use_visual_state (*vs);
4503 Editor::swap_visual_state ()
4505 if (undo_visual_stack.empty()) {
4506 redo_visual_state ();
4508 undo_visual_state ();
4513 Editor::use_visual_state (VisualState& vs)
4515 PBD::Unwinder<bool> nsv (no_save_visual, true);
4516 DisplaySuspender ds;
4518 vertical_adjustment.set_value (vs.y_position);
4520 set_zoom_focus (vs.zoom_focus);
4521 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4524 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4526 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4527 (*i)->clear_property_cache();
4528 (*i)->reset_visual_state ();
4532 _routes->update_visibility ();
4535 /** This is the core function that controls the zoom level of the canvas. It is called
4536 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4537 * @param spp new number of samples per pixel
4540 Editor::set_samples_per_pixel (framecnt_t spp)
4546 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4547 const framecnt_t lots_of_pixels = 4000;
4549 /* if the zoom level is greater than what you'd get trying to display 3
4550 * days of audio on a really big screen, then it's too big.
4553 if (spp * lots_of_pixels > three_days) {
4557 samples_per_pixel = spp;
4560 tempo_lines->tempo_map_changed();
4563 bool const showing_time_selection = selection->time.length() > 0;
4565 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4566 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4567 (*i)->reshow_selection (selection->time);
4571 ZoomChanged (); /* EMIT_SIGNAL */
4573 ArdourCanvas::GtkCanvasViewport* c;
4575 c = get_track_canvas();
4577 c->canvas()->zoomed ();
4580 if (playhead_cursor) {
4581 playhead_cursor->set_position (playhead_cursor->current_frame ());
4584 refresh_location_display();
4585 _summary->set_overlays_dirty ();
4587 update_marker_labels ();
4593 Editor::queue_visual_videotimeline_update ()
4596 * pending_visual_change.add (VisualChange::VideoTimeline);
4597 * or maybe even more specific: which videotimeline-image
4598 * currently it calls update_video_timeline() to update
4599 * _all outdated_ images on the video-timeline.
4600 * see 'exposeimg()' in video_image_frame.cc
4602 ensure_visual_change_idle_handler ();
4606 Editor::ensure_visual_change_idle_handler ()
4608 if (pending_visual_change.idle_handler_id < 0) {
4609 // see comment in add_to_idle_resize above.
4610 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4611 pending_visual_change.being_handled = false;
4616 Editor::_idle_visual_changer (void* arg)
4618 return static_cast<Editor*>(arg)->idle_visual_changer ();
4622 Editor::idle_visual_changer ()
4624 /* set_horizontal_position() below (and maybe other calls) call
4625 gtk_main_iteration(), so it's possible that a signal will be handled
4626 half-way through this method. If this signal wants an
4627 idle_visual_changer we must schedule another one after this one, so
4628 mark the idle_handler_id as -1 here to allow that. Also make a note
4629 that we are doing the visual change, so that changes in response to
4630 super-rapid-screen-update can be dropped if we are still processing
4634 pending_visual_change.idle_handler_id = -1;
4635 pending_visual_change.being_handled = true;
4637 VisualChange vc = pending_visual_change;
4639 pending_visual_change.pending = (VisualChange::Type) 0;
4641 visual_changer (vc);
4643 pending_visual_change.being_handled = false;
4645 return 0; /* this is always a one-shot call */
4649 Editor::visual_changer (const VisualChange& vc)
4651 double const last_time_origin = horizontal_position ();
4653 if (vc.pending & VisualChange::ZoomLevel) {
4654 set_samples_per_pixel (vc.samples_per_pixel);
4656 compute_fixed_ruler_scale ();
4658 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4659 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4661 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4662 current_bbt_points_begin, current_bbt_points_end);
4663 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4664 current_bbt_points_begin, current_bbt_points_end);
4665 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4667 update_video_timeline();
4670 if (vc.pending & VisualChange::TimeOrigin) {
4671 set_horizontal_position (vc.time_origin / samples_per_pixel);
4674 if (vc.pending & VisualChange::YOrigin) {
4675 vertical_adjustment.set_value (vc.y_origin);
4678 if (last_time_origin == horizontal_position ()) {
4679 /* changed signal not emitted */
4680 update_fixed_rulers ();
4681 redisplay_tempo (true);
4684 if (!(vc.pending & VisualChange::ZoomLevel)) {
4685 update_video_timeline();
4688 _summary->set_overlays_dirty ();
4691 struct EditorOrderTimeAxisSorter {
4692 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4693 return a->order () < b->order ();
4698 Editor::sort_track_selection (TrackViewList& sel)
4700 EditorOrderTimeAxisSorter cmp;
4705 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4708 framepos_t where = 0;
4709 EditPoint ep = _edit_point;
4711 if (Profile->get_mixbus())
4712 if (ep == EditAtSelectedMarker)
4713 ep = EditAtPlayhead;
4715 if (from_outside_canvas && (ep == EditAtMouse)) {
4716 ep = EditAtPlayhead;
4717 } else if (from_context_menu && (ep == EditAtMouse)) {
4718 return canvas_event_sample (&context_click_event, 0, 0);
4721 if (entered_marker) {
4722 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4723 return entered_marker->position();
4726 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4727 ep = EditAtSelectedMarker;
4730 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4731 ep = EditAtPlayhead;
4735 case EditAtPlayhead:
4736 if (_dragging_playhead) {
4737 if (!mouse_frame (where, ignored)) {
4738 /* XXX not right but what can we do ? */
4742 where = _session->audible_frame();
4744 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4747 case EditAtSelectedMarker:
4748 if (!selection->markers.empty()) {
4750 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4753 where = loc->start();
4757 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4765 if (!mouse_frame (where, ignored)) {
4766 /* XXX not right but what can we do ? */
4770 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4778 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4780 if (!_session) return;
4782 begin_reversible_command (cmd);
4786 if ((tll = transport_loop_location()) == 0) {
4787 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4788 XMLNode &before = _session->locations()->get_state();
4789 _session->locations()->add (loc, true);
4790 _session->set_auto_loop_location (loc);
4791 XMLNode &after = _session->locations()->get_state();
4792 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4794 XMLNode &before = tll->get_state();
4795 tll->set_hidden (false, this);
4796 tll->set (start, end);
4797 XMLNode &after = tll->get_state();
4798 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4801 commit_reversible_command ();
4805 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4807 if (!_session) return;
4809 begin_reversible_command (cmd);
4813 if ((tpl = transport_punch_location()) == 0) {
4814 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4815 XMLNode &before = _session->locations()->get_state();
4816 _session->locations()->add (loc, true);
4817 _session->set_auto_punch_location (loc);
4818 XMLNode &after = _session->locations()->get_state();
4819 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4821 XMLNode &before = tpl->get_state();
4822 tpl->set_hidden (false, this);
4823 tpl->set (start, end);
4824 XMLNode &after = tpl->get_state();
4825 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4828 commit_reversible_command ();
4831 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4832 * @param rs List to which found regions are added.
4833 * @param where Time to look at.
4834 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4837 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4839 const TrackViewList* tracks;
4842 tracks = &track_views;
4847 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4849 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4852 boost::shared_ptr<Track> tr;
4853 boost::shared_ptr<Playlist> pl;
4855 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4857 boost::shared_ptr<RegionList> regions = pl->regions_at (
4858 (framepos_t) floor ( (double) where * tr->speed()));
4860 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4861 RegionView* rv = rtv->view()->find_view (*i);
4872 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4874 const TrackViewList* tracks;
4877 tracks = &track_views;
4882 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4883 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4885 boost::shared_ptr<Track> tr;
4886 boost::shared_ptr<Playlist> pl;
4888 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4890 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4891 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4893 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4895 RegionView* rv = rtv->view()->find_view (*i);
4906 /** Get regions using the following method:
4908 * Make a region list using:
4909 * (a) any selected regions
4910 * (b) the intersection of any selected tracks and the edit point(*)
4911 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4913 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4915 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4919 Editor::get_regions_from_selection_and_edit_point ()
4921 RegionSelection regions;
4923 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4924 regions.add (entered_regionview);
4926 regions = selection->regions;
4929 if ( regions.empty() ) {
4930 TrackViewList tracks = selection->tracks;
4932 if (!tracks.empty()) {
4933 /* no region selected or entered, but some selected tracks:
4934 * act on all regions on the selected tracks at the edit point
4936 framepos_t const where = get_preferred_edit_position ();
4937 get_regions_at(regions, where, tracks);
4944 /** Get regions using the following method:
4946 * Make a region list using:
4947 * (a) any selected regions
4948 * (b) the intersection of any selected tracks and the edit point(*)
4949 * (c) if neither exists, then whatever region is under the mouse
4951 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4953 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4956 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4958 RegionSelection regions;
4960 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4961 regions.add (entered_regionview);
4963 regions = selection->regions;
4966 if ( regions.empty() ) {
4967 TrackViewList tracks = selection->tracks;
4969 if (!tracks.empty()) {
4970 /* no region selected or entered, but some selected tracks:
4971 * act on all regions on the selected tracks at the edit point
4973 get_regions_at(regions, pos, tracks);
4980 /** Start with regions that are selected, or the entered regionview if none are selected.
4981 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4982 * of the regions that we started with.
4986 Editor::get_regions_from_selection_and_entered ()
4988 RegionSelection regions = selection->regions;
4990 if (regions.empty() && entered_regionview) {
4991 regions.add (entered_regionview);
4998 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
5000 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5001 RouteTimeAxisView* rtav;
5003 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5004 boost::shared_ptr<Playlist> pl;
5005 std::vector<boost::shared_ptr<Region> > results;
5006 boost::shared_ptr<Track> tr;
5008 if ((tr = rtav->track()) == 0) {
5013 if ((pl = (tr->playlist())) != 0) {
5014 boost::shared_ptr<Region> r = pl->region_by_id (id);
5016 RegionView* rv = rtav->view()->find_view (r);
5018 regions.push_back (rv);
5027 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5030 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5031 MidiTimeAxisView* mtav;
5033 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5035 mtav->get_per_region_note_selection (selection);
5042 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5044 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5046 RouteTimeAxisView* tatv;
5048 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5050 boost::shared_ptr<Playlist> pl;
5051 vector<boost::shared_ptr<Region> > results;
5053 boost::shared_ptr<Track> tr;
5055 if ((tr = tatv->track()) == 0) {
5060 if ((pl = (tr->playlist())) != 0) {
5061 if (src_comparison) {
5062 pl->get_source_equivalent_regions (region, results);
5064 pl->get_region_list_equivalent_regions (region, results);
5068 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5069 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5070 regions.push_back (marv);
5079 Editor::show_rhythm_ferret ()
5081 if (rhythm_ferret == 0) {
5082 rhythm_ferret = new RhythmFerret(*this);
5085 rhythm_ferret->set_session (_session);
5086 rhythm_ferret->show ();
5087 rhythm_ferret->present ();
5091 Editor::first_idle ()
5093 MessageDialog* dialog = 0;
5095 if (track_views.size() > 1) {
5096 Timers::TimerSuspender t;
5097 dialog = new MessageDialog (
5099 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5103 ARDOUR_UI::instance()->flush_pending ();
5106 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5110 // first idle adds route children (automation tracks), so we need to redisplay here
5111 _routes->redisplay ();
5115 if (_session->undo_depth() == 0) {
5116 undo_action->set_sensitive(false);
5118 redo_action->set_sensitive(false);
5119 begin_selection_op_history ();
5125 Editor::_idle_resize (gpointer arg)
5127 return ((Editor*)arg)->idle_resize ();
5131 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5133 if (resize_idle_id < 0) {
5134 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5135 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5136 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5138 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5139 _pending_resize_amount = 0;
5142 /* make a note of the smallest resulting height, so that we can clamp the
5143 lower limit at TimeAxisView::hSmall */
5145 int32_t min_resulting = INT32_MAX;
5147 _pending_resize_amount += h;
5148 _pending_resize_view = view;
5150 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5152 if (selection->tracks.contains (_pending_resize_view)) {
5153 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5154 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5158 if (min_resulting < 0) {
5163 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5164 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5168 /** Handle pending resizing of tracks */
5170 Editor::idle_resize ()
5172 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5174 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5175 selection->tracks.contains (_pending_resize_view)) {
5177 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5178 if (*i != _pending_resize_view) {
5179 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5184 _pending_resize_amount = 0;
5185 _group_tabs->set_dirty ();
5186 resize_idle_id = -1;
5194 ENSURE_GUI_THREAD (*this, &Editor::located);
5197 playhead_cursor->set_position (_session->audible_frame ());
5198 if (_follow_playhead && !_pending_initial_locate) {
5199 reset_x_origin_to_follow_playhead ();
5203 _pending_locate_request = false;
5204 _pending_initial_locate = false;
5208 Editor::region_view_added (RegionView * rv)
5210 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5211 if (rv->region ()->id () == (*pr)) {
5212 selection->add (rv);
5213 selection->regions.pending.erase (pr);
5218 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5220 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5221 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5222 if (rv->region()->id () == (*rnote).first) {
5223 mrv->select_notes ((*rnote).second);
5224 selection->pending_midi_note_selection.erase(rnote);
5230 _summary->set_background_dirty ();
5234 Editor::region_view_removed ()
5236 _summary->set_background_dirty ();
5240 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5242 TrackViewList::const_iterator j = track_views.begin ();
5243 while (j != track_views.end()) {
5244 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5245 if (rtv && rtv->route() == r) {
5256 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5260 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5261 TimeAxisView* tv = axis_view_from_route (*i);
5271 Editor::suspend_route_redisplay ()
5274 _routes->suspend_redisplay();
5279 Editor::resume_route_redisplay ()
5282 _routes->redisplay(); // queue redisplay
5283 _routes->resume_redisplay();
5288 Editor::add_routes (RouteList& routes)
5290 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5292 RouteTimeAxisView *rtv;
5293 list<RouteTimeAxisView*> new_views;
5294 TrackViewList new_selection;
5295 bool from_scratch = (track_views.size() == 0);
5297 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5298 boost::shared_ptr<Route> route = (*x);
5300 if (route->is_auditioner() || route->is_monitor()) {
5304 DataType dt = route->input()->default_type();
5306 if (dt == ARDOUR::DataType::AUDIO) {
5307 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5308 rtv->set_route (route);
5309 } else if (dt == ARDOUR::DataType::MIDI) {
5310 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5311 rtv->set_route (route);
5313 throw unknown_type();
5316 new_views.push_back (rtv);
5317 track_views.push_back (rtv);
5318 new_selection.push_back (rtv);
5320 rtv->effective_gain_display ();
5322 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5323 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5326 if (new_views.size() > 0) {
5327 _routes->routes_added (new_views);
5328 _summary->routes_added (new_views);
5331 if (!from_scratch) {
5332 selection->tracks.clear();
5333 selection->add (new_selection);
5334 begin_selection_op_history();
5337 if (show_editor_mixer_when_tracks_arrive) {
5338 show_editor_mixer (true);
5341 editor_list_button.set_sensitive (true);
5345 Editor::timeaxisview_deleted (TimeAxisView *tv)
5347 if (tv == entered_track) {
5351 if (_session && _session->deletion_in_progress()) {
5352 /* the situation is under control */
5356 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5358 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5360 _routes->route_removed (tv);
5362 TimeAxisView::Children c = tv->get_child_list ();
5363 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5364 if (entered_track == i->get()) {
5369 /* remove it from the list of track views */
5371 TrackViewList::iterator i;
5373 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5374 i = track_views.erase (i);
5377 /* update whatever the current mixer strip is displaying, if revelant */
5379 boost::shared_ptr<Route> route;
5382 route = rtav->route ();
5385 if (current_mixer_strip && current_mixer_strip->route() == route) {
5387 TimeAxisView* next_tv;
5389 if (track_views.empty()) {
5391 } else if (i == track_views.end()) {
5392 next_tv = track_views.front();
5399 set_selected_mixer_strip (*next_tv);
5401 /* make the editor mixer strip go away setting the
5402 * button to inactive (which also unticks the menu option)
5405 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5411 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5413 if (apply_to_selection) {
5414 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5416 TrackSelection::iterator j = i;
5419 hide_track_in_display (*i, false);
5424 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5426 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5427 // this will hide the mixer strip
5428 set_selected_mixer_strip (*tv);
5431 _routes->hide_track_in_display (*tv);
5436 Editor::sync_track_view_list_and_routes ()
5438 track_views = TrackViewList (_routes->views ());
5440 _summary->set_background_dirty();
5441 _group_tabs->set_dirty ();
5443 return false; // do not call again (until needed)
5447 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5449 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5454 /** Find a RouteTimeAxisView by the ID of its route */
5456 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5458 RouteTimeAxisView* v;
5460 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5461 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5462 if(v->route()->id() == id) {
5472 Editor::fit_route_group (RouteGroup *g)
5474 TrackViewList ts = axis_views_from_routes (g->route_list ());
5479 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5481 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5484 _session->cancel_audition ();
5488 if (_session->is_auditioning()) {
5489 _session->cancel_audition ();
5490 if (r == last_audition_region) {
5495 _session->audition_region (r);
5496 last_audition_region = r;
5501 Editor::hide_a_region (boost::shared_ptr<Region> r)
5503 r->set_hidden (true);
5507 Editor::show_a_region (boost::shared_ptr<Region> r)
5509 r->set_hidden (false);
5513 Editor::audition_region_from_region_list ()
5515 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5519 Editor::hide_region_from_region_list ()
5521 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5525 Editor::show_region_in_region_list ()
5527 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5531 Editor::step_edit_status_change (bool yn)
5534 start_step_editing ();
5536 stop_step_editing ();
5541 Editor::start_step_editing ()
5543 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5547 Editor::stop_step_editing ()
5549 step_edit_connection.disconnect ();
5553 Editor::check_step_edit ()
5555 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5556 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5558 mtv->check_step_edit ();
5562 return true; // do it again, till we stop
5566 Editor::scroll_press (Direction dir)
5568 ++_scroll_callbacks;
5570 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5571 /* delay the first auto-repeat */
5577 scroll_backward (1);
5585 scroll_up_one_track ();
5589 scroll_down_one_track ();
5593 /* do hacky auto-repeat */
5594 if (!_scroll_connection.connected ()) {
5596 _scroll_connection = Glib::signal_timeout().connect (
5597 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5600 _scroll_callbacks = 0;
5607 Editor::scroll_release ()
5609 _scroll_connection.disconnect ();
5612 /** Queue a change for the Editor viewport x origin to follow the playhead */
5614 Editor::reset_x_origin_to_follow_playhead ()
5616 framepos_t const frame = playhead_cursor->current_frame ();
5618 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5620 if (_session->transport_speed() < 0) {
5622 if (frame > (current_page_samples() / 2)) {
5623 center_screen (frame-(current_page_samples()/2));
5625 center_screen (current_page_samples()/2);
5632 if (frame < leftmost_frame) {
5634 if (_session->transport_rolling()) {
5635 /* rolling; end up with the playhead at the right of the page */
5636 l = frame - current_page_samples ();
5638 /* not rolling: end up with the playhead 1/4 of the way along the page */
5639 l = frame - current_page_samples() / 4;
5643 if (_session->transport_rolling()) {
5644 /* rolling: end up with the playhead on the left of the page */
5647 /* not rolling: end up with the playhead 3/4 of the way along the page */
5648 l = frame - 3 * current_page_samples() / 4;
5656 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5662 Editor::super_rapid_screen_update ()
5664 if (!_session || !_session->engine().running()) {
5668 /* METERING / MIXER STRIPS */
5670 /* update track meters, if required */
5671 if (is_mapped() && meters_running) {
5672 RouteTimeAxisView* rtv;
5673 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5674 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5675 rtv->fast_update ();
5680 /* and any current mixer strip */
5681 if (current_mixer_strip) {
5682 current_mixer_strip->fast_update ();
5685 /* PLAYHEAD AND VIEWPORT */
5687 framepos_t const frame = _session->audible_frame();
5689 /* There are a few reasons why we might not update the playhead / viewport stuff:
5691 * 1. we don't update things when there's a pending locate request, otherwise
5692 * when the editor requests a locate there is a chance that this method
5693 * will move the playhead before the locate request is processed, causing
5695 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5696 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5699 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5701 last_update_frame = frame;
5703 if (!_dragging_playhead) {
5704 playhead_cursor->set_position (frame);
5707 if (!_stationary_playhead) {
5709 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5710 /* We only do this if we aren't already
5711 handling a visual change (ie if
5712 pending_visual_change.being_handled is
5713 false) so that these requests don't stack
5714 up there are too many of them to handle in
5717 reset_x_origin_to_follow_playhead ();
5722 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5723 framepos_t const frame = playhead_cursor->current_frame ();
5724 double target = ((double)frame - (double)current_page_samples()/2.0);
5725 if (target <= 0.0) {
5728 // compare to EditorCursor::set_position()
5729 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5730 double const new_pos = sample_to_pixel_unrounded (target);
5731 if (rint (new_pos) != rint (old_pos)) {
5732 reset_x_origin (pixel_to_sample (floor (new_pos)));
5743 Editor::session_going_away ()
5745 _have_idled = false;
5747 _session_connections.drop_connections ();
5749 super_rapid_screen_update_connection.disconnect ();
5751 selection->clear ();
5752 cut_buffer->clear ();
5754 clicked_regionview = 0;
5755 clicked_axisview = 0;
5756 clicked_routeview = 0;
5757 entered_regionview = 0;
5759 last_update_frame = 0;
5762 playhead_cursor->hide ();
5764 /* rip everything out of the list displays */
5768 _route_groups->clear ();
5770 /* do this first so that deleting a track doesn't reset cms to null
5771 and thus cause a leak.
5774 if (current_mixer_strip) {
5775 if (current_mixer_strip->get_parent() != 0) {
5776 global_hpacker.remove (*current_mixer_strip);
5778 delete current_mixer_strip;
5779 current_mixer_strip = 0;
5782 /* delete all trackviews */
5784 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5787 track_views.clear ();
5789 nudge_clock->set_session (0);
5791 editor_list_button.set_active(false);
5792 editor_list_button.set_sensitive(false);
5794 /* clear tempo/meter rulers */
5795 remove_metric_marks ();
5797 clear_marker_display ();
5799 stop_step_editing ();
5801 /* get rid of any existing editor mixer strip */
5803 WindowTitle title(Glib::get_application_name());
5804 title += _("Editor");
5806 set_title (title.get_string());
5808 SessionHandlePtr::session_going_away ();
5813 Editor::show_editor_list (bool yn)
5816 _the_notebook.show ();
5818 _the_notebook.hide ();
5823 Editor::change_region_layering_order (bool from_context_menu)
5825 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5827 if (!clicked_routeview) {
5828 if (layering_order_editor) {
5829 layering_order_editor->hide ();
5834 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5840 boost::shared_ptr<Playlist> pl = track->playlist();
5846 if (layering_order_editor == 0) {
5847 layering_order_editor = new RegionLayeringOrderEditor (*this);
5850 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5851 layering_order_editor->maybe_present ();
5855 Editor::update_region_layering_order_editor ()
5857 if (layering_order_editor && layering_order_editor->is_visible ()) {
5858 change_region_layering_order (true);
5863 Editor::setup_fade_images ()
5865 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5866 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5867 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5868 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5869 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5871 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5872 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5873 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5874 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5875 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5877 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5878 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5879 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5880 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5881 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5883 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5884 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5885 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5886 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5887 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5891 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5893 Editor::action_menu_item (std::string const & name)
5895 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5898 return *manage (a->create_menu_item ());
5902 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5904 EventBox* b = manage (new EventBox);
5905 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5906 Label* l = manage (new Label (name));
5910 _the_notebook.append_page (widget, *b);
5914 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5916 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5917 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5920 if (ev->type == GDK_2BUTTON_PRESS) {
5922 /* double-click on a notebook tab shrinks or expands the notebook */
5924 if (_notebook_shrunk) {
5925 if (pre_notebook_shrink_pane_width) {
5926 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5928 _notebook_shrunk = false;
5930 pre_notebook_shrink_pane_width = edit_pane.get_position();
5932 /* this expands the LHS of the edit pane to cover the notebook
5933 PAGE but leaves the tabs visible.
5935 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5936 _notebook_shrunk = true;
5944 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5946 using namespace Menu_Helpers;
5948 MenuList& items = _control_point_context_menu.items ();
5951 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5952 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5953 if (!can_remove_control_point (item)) {
5954 items.back().set_sensitive (false);
5957 _control_point_context_menu.popup (event->button.button, event->button.time);
5961 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5963 using namespace Menu_Helpers;
5965 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5970 /* We need to get the selection here and pass it to the operations, since
5971 popping up the menu will cause a region leave event which clears
5972 entered_regionview. */
5974 MidiRegionView& mrv = note->region_view();
5975 const RegionSelection rs = get_regions_from_selection_and_entered ();
5976 const uint32_t sel_size = mrv.selection_size ();
5978 MenuList& items = _note_context_menu.items();
5982 items.push_back(MenuElem(_("Delete"),
5983 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5986 items.push_back(MenuElem(_("Edit..."),
5987 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5988 if (sel_size != 1) {
5989 items.back().set_sensitive (false);
5992 items.push_back(MenuElem(_("Transpose..."),
5993 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
5996 items.push_back(MenuElem(_("Legatize"),
5997 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5999 items.back().set_sensitive (false);
6002 items.push_back(MenuElem(_("Quantize..."),
6003 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6005 items.push_back(MenuElem(_("Remove Overlap"),
6006 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6008 items.back().set_sensitive (false);
6011 items.push_back(MenuElem(_("Transform..."),
6012 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6014 _note_context_menu.popup (event->button.button, event->button.time);
6018 Editor::zoom_vertical_modifier_released()
6020 _stepping_axis_view = 0;
6024 Editor::ui_parameter_changed (string parameter)
6026 if (parameter == "icon-set") {
6027 while (!_cursor_stack.empty()) {
6028 _cursor_stack.pop_back();
6030 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6031 _cursor_stack.push_back(_cursors->grabber);
6032 } else if (parameter == "draggable-playhead") {
6033 if (_verbose_cursor) {
6034 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());