2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include "gtkmm2ext/tearoff.h"
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/audio_track.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/audioregion.h"
71 #include "ardour/lmath.h"
72 #include "ardour/location.h"
73 #include "ardour/profile.h"
74 #include "ardour/route_group.h"
75 #include "ardour/session_playlists.h"
76 #include "ardour/tempo.h"
77 #include "ardour/utils.h"
79 #include "canvas/debug.h"
80 #include "canvas/text.h"
82 #include "control_protocol/control_protocol.h"
85 #include "analysis_window.h"
86 #include "audio_clock.h"
87 #include "audio_region_view.h"
88 #include "audio_streamview.h"
89 #include "audio_time_axis.h"
90 #include "automation_time_axis.h"
91 #include "bundle_manager.h"
92 #include "crossfade_edit.h"
96 #include "editor_cursors.h"
97 #include "editor_drag.h"
98 #include "editor_group_tabs.h"
99 #include "editor_locations.h"
100 #include "editor_regions.h"
101 #include "editor_route_groups.h"
102 #include "editor_routes.h"
103 #include "editor_snapshots.h"
104 #include "editor_summary.h"
105 #include "global_port_matrix.h"
106 #include "gui_object.h"
107 #include "gui_thread.h"
108 #include "keyboard.h"
110 #include "midi_region_view.h"
111 #include "midi_time_axis.h"
112 #include "mixer_strip.h"
113 #include "mixer_ui.h"
114 #include "mouse_cursors.h"
115 #include "note_base.h"
116 #include "playlist_selector.h"
117 #include "public_editor.h"
118 #include "quantize_dialog.h"
119 #include "region_layering_order_editor.h"
120 #include "rgb_macros.h"
121 #include "rhythm_ferret.h"
122 #include "selection.h"
124 #include "tempo_lines.h"
125 #include "time_axis_view.h"
128 #include "verbose_cursor.h"
133 using namespace ARDOUR;
134 using namespace ARDOUR_UI_UTILS;
137 using namespace Glib;
138 using namespace Gtkmm2ext;
139 using namespace Editing;
141 using PBD::internationalize;
143 using Gtkmm2ext::Keyboard;
145 double Editor::timebar_height = 15.0;
147 static const gchar *_snap_type_strings[] = {
181 static const gchar *_snap_mode_strings[] = {
188 static const gchar *_edit_point_strings[] = {
195 static const gchar *_edit_mode_strings[] = {
203 static const gchar *_zoom_focus_strings[] = {
213 #ifdef USE_RUBBERBAND
214 static const gchar *_rb_opt_strings[] = {
217 N_("Balanced multitimbral mixture"),
218 N_("Unpitched percussion with stable notes"),
219 N_("Crisp monophonic instrumental"),
220 N_("Unpitched solo percussion"),
221 N_("Resample without preserving pitch"),
226 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
229 pane_size_watcher (Paned* pane)
231 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
235 Quartz: impossible to access
237 so stop that by preventing it from ever getting too narrow. 35
238 pixels is basically a rough guess at the tab width.
243 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
245 gint pos = pane->get_position ();
247 if (pos > max_width_of_lhs) {
248 pane->set_position (max_width_of_lhs);
253 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
255 , _mouse_changed_selection (false)
256 /* time display buttons */
257 , minsec_label (_("Mins:Secs"))
258 , bbt_label (_("Bars:Beats"))
259 , timecode_label (_("Timecode"))
260 , samples_label (_("Samples"))
261 , tempo_label (_("Tempo"))
262 , meter_label (_("Meter"))
263 , mark_label (_("Location Markers"))
264 , range_mark_label (_("Range Markers"))
265 , transport_mark_label (_("Loop/Punch Ranges"))
266 , cd_mark_label (_("CD Markers"))
267 , videotl_label (_("Video Timeline"))
268 , edit_packer (4, 4, true)
270 /* the values here don't matter: layout widgets
271 reset them as needed.
274 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
275 , horizontal_adjustment (0.0, 0.0, 1e16)
276 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
278 , controls_layout (unused_adjustment, vertical_adjustment)
280 /* tool bar related */
282 , toolbar_selection_clock_table (2,3)
283 , _mouse_mode_tearoff (0)
284 , automation_mode_button (_("mode"))
288 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
289 , selection_op_cmd_depth (0)
290 , selection_op_history_it (0)
294 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
295 , meters_running(false)
296 , _pending_locate_request (false)
297 , _pending_initial_locate (false)
298 , _last_cut_copy_source_track (0)
300 , _region_selection_change_updates_region_list (true)
301 , _following_mixer_selection (false)
302 , _control_point_toggled_on_press (false)
303 , _stepping_axis_view (0)
304 , quantize_dialog (0)
305 , _main_menu_disabler (0)
309 /* we are a singleton */
311 PublicEditor::_instance = this;
315 selection = new Selection (this);
316 cut_buffer = new Selection (this);
317 _selection_memento = new SelectionMemento ();
318 selection_op_history.clear();
321 clicked_regionview = 0;
322 clicked_axisview = 0;
323 clicked_routeview = 0;
324 clicked_control_point = 0;
325 last_update_frame = 0;
328 _drags = new DragManager (this);
331 current_mixer_strip = 0;
334 snap_type_strings = I18N (_snap_type_strings);
335 snap_mode_strings = I18N (_snap_mode_strings);
336 zoom_focus_strings = I18N (_zoom_focus_strings);
337 edit_mode_strings = I18N (_edit_mode_strings);
338 edit_point_strings = I18N (_edit_point_strings);
339 #ifdef USE_RUBBERBAND
340 rb_opt_strings = I18N (_rb_opt_strings);
344 build_edit_mode_menu();
345 build_zoom_focus_menu();
346 build_track_count_menu();
347 build_snap_mode_menu();
348 build_snap_type_menu();
349 build_edit_point_menu();
351 snap_threshold = 5.0;
352 bbt_beat_subdivision = 4;
353 _visible_canvas_width = 0;
354 _visible_canvas_height = 0;
355 autoscroll_horizontal_allowed = false;
356 autoscroll_vertical_allowed = false;
361 current_interthread_info = 0;
362 _show_measures = true;
364 show_gain_after_trim = false;
366 have_pending_keyboard_selection = false;
367 _follow_playhead = true;
368 _stationary_playhead = false;
369 editor_ruler_menu = 0;
370 no_ruler_shown_update = false;
372 range_marker_menu = 0;
373 marker_menu_item = 0;
374 tempo_or_meter_marker_menu = 0;
375 transport_marker_menu = 0;
376 new_transport_marker_menu = 0;
377 editor_mixer_strip_width = Wide;
378 show_editor_mixer_when_tracks_arrive = false;
379 region_edit_menu_split_multichannel_item = 0;
380 region_edit_menu_split_item = 0;
383 current_stepping_trackview = 0;
385 entered_regionview = 0;
387 clear_entered_track = false;
390 button_release_can_deselect = true;
391 _dragging_playhead = false;
392 _dragging_edit_point = false;
393 select_new_marker = false;
395 layering_order_editor = 0;
396 no_save_visual = false;
398 within_track_canvas = false;
400 scrubbing_direction = 0;
404 location_marker_color = ARDOUR_UI::config()->color ("location marker");
405 location_range_color = ARDOUR_UI::config()->color ("location range");
406 location_cd_marker_color = ARDOUR_UI::config()->color ("location cd marker");
407 location_loop_color = ARDOUR_UI::config()->color ("location loop");
408 location_punch_color = ARDOUR_UI::config()->color ("location punch");
410 zoom_focus = ZoomFocusPlayhead;
411 _edit_point = EditAtMouse;
412 _visible_track_count = -1;
414 samples_per_pixel = 2048; /* too early to use reset_zoom () */
416 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
417 TimeAxisView::setup_sizes ();
418 ArdourMarker::setup_sizes (timebar_height);
420 _scroll_callbacks = 0;
422 bbt_label.set_name ("EditorRulerLabel");
423 bbt_label.set_size_request (-1, (int)timebar_height);
424 bbt_label.set_alignment (1.0, 0.5);
425 bbt_label.set_padding (5,0);
427 bbt_label.set_no_show_all();
428 minsec_label.set_name ("EditorRulerLabel");
429 minsec_label.set_size_request (-1, (int)timebar_height);
430 minsec_label.set_alignment (1.0, 0.5);
431 minsec_label.set_padding (5,0);
432 minsec_label.hide ();
433 minsec_label.set_no_show_all();
434 timecode_label.set_name ("EditorRulerLabel");
435 timecode_label.set_size_request (-1, (int)timebar_height);
436 timecode_label.set_alignment (1.0, 0.5);
437 timecode_label.set_padding (5,0);
438 timecode_label.hide ();
439 timecode_label.set_no_show_all();
440 samples_label.set_name ("EditorRulerLabel");
441 samples_label.set_size_request (-1, (int)timebar_height);
442 samples_label.set_alignment (1.0, 0.5);
443 samples_label.set_padding (5,0);
444 samples_label.hide ();
445 samples_label.set_no_show_all();
447 tempo_label.set_name ("EditorRulerLabel");
448 tempo_label.set_size_request (-1, (int)timebar_height);
449 tempo_label.set_alignment (1.0, 0.5);
450 tempo_label.set_padding (5,0);
452 tempo_label.set_no_show_all();
454 meter_label.set_name ("EditorRulerLabel");
455 meter_label.set_size_request (-1, (int)timebar_height);
456 meter_label.set_alignment (1.0, 0.5);
457 meter_label.set_padding (5,0);
459 meter_label.set_no_show_all();
461 if (Profile->get_trx()) {
462 mark_label.set_text (_("Markers"));
464 mark_label.set_name ("EditorRulerLabel");
465 mark_label.set_size_request (-1, (int)timebar_height);
466 mark_label.set_alignment (1.0, 0.5);
467 mark_label.set_padding (5,0);
469 mark_label.set_no_show_all();
471 cd_mark_label.set_name ("EditorRulerLabel");
472 cd_mark_label.set_size_request (-1, (int)timebar_height);
473 cd_mark_label.set_alignment (1.0, 0.5);
474 cd_mark_label.set_padding (5,0);
475 cd_mark_label.hide();
476 cd_mark_label.set_no_show_all();
478 videotl_bar_height = 4;
479 videotl_label.set_name ("EditorRulerLabel");
480 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
481 videotl_label.set_alignment (1.0, 0.5);
482 videotl_label.set_padding (5,0);
483 videotl_label.hide();
484 videotl_label.set_no_show_all();
486 range_mark_label.set_name ("EditorRulerLabel");
487 range_mark_label.set_size_request (-1, (int)timebar_height);
488 range_mark_label.set_alignment (1.0, 0.5);
489 range_mark_label.set_padding (5,0);
490 range_mark_label.hide();
491 range_mark_label.set_no_show_all();
493 transport_mark_label.set_name ("EditorRulerLabel");
494 transport_mark_label.set_size_request (-1, (int)timebar_height);
495 transport_mark_label.set_alignment (1.0, 0.5);
496 transport_mark_label.set_padding (5,0);
497 transport_mark_label.hide();
498 transport_mark_label.set_no_show_all();
500 initialize_canvas ();
502 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
504 _summary = new EditorSummary (this);
506 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
507 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
509 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
511 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
512 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
514 edit_controls_vbox.set_spacing (0);
515 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
516 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
518 HBox* h = manage (new HBox);
519 _group_tabs = new EditorGroupTabs (this);
520 if (!ARDOUR::Profile->get_trx()) {
521 h->pack_start (*_group_tabs, PACK_SHRINK);
523 h->pack_start (edit_controls_vbox);
524 controls_layout.add (*h);
526 controls_layout.set_name ("EditControlsBase");
527 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
528 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
529 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
531 _cursors = new MouseCursors;
532 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
533 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
535 /* Push default cursor to ever-present bottom of cursor stack. */
536 push_canvas_cursor(_cursors->grabber);
538 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
540 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
541 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
542 pad_line_1->set_outline_color (0xFF0000FF);
548 edit_packer.set_col_spacings (0);
549 edit_packer.set_row_spacings (0);
550 edit_packer.set_homogeneous (false);
551 edit_packer.set_border_width (0);
552 edit_packer.set_name ("EditorWindow");
554 time_bars_event_box.add (time_bars_vbox);
555 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
556 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
558 /* labels for the time bars */
559 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
561 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
563 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
565 bottom_hbox.set_border_width (2);
566 bottom_hbox.set_spacing (3);
568 _route_groups = new EditorRouteGroups (this);
569 _routes = new EditorRoutes (this);
570 _regions = new EditorRegions (this);
571 _snapshots = new EditorSnapshots (this);
572 _locations = new EditorLocations (this);
574 /* these are static location signals */
576 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
577 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
578 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
580 add_notebook_page (_("Regions"), _regions->widget ());
581 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
582 add_notebook_page (_("Snapshots"), _snapshots->widget ());
583 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
584 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
586 _the_notebook.set_show_tabs (true);
587 _the_notebook.set_scrollable (true);
588 _the_notebook.popup_disable ();
589 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
590 _the_notebook.show_all ();
592 _notebook_shrunk = false;
594 editor_summary_pane.pack1(edit_packer);
596 Button* summary_arrows_left_left = manage (new Button);
597 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
598 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
599 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
601 Button* summary_arrows_left_right = manage (new Button);
602 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
603 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
604 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
606 VBox* summary_arrows_left = manage (new VBox);
607 summary_arrows_left->pack_start (*summary_arrows_left_left);
608 summary_arrows_left->pack_start (*summary_arrows_left_right);
610 Button* summary_arrows_right_up = manage (new Button);
611 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
612 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
613 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
615 Button* summary_arrows_right_down = manage (new Button);
616 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
617 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
618 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
620 VBox* summary_arrows_right = manage (new VBox);
621 summary_arrows_right->pack_start (*summary_arrows_right_up);
622 summary_arrows_right->pack_start (*summary_arrows_right_down);
624 Frame* summary_frame = manage (new Frame);
625 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
627 summary_frame->add (*_summary);
628 summary_frame->show ();
630 _summary_hbox.pack_start (*summary_arrows_left, false, false);
631 _summary_hbox.pack_start (*summary_frame, true, true);
632 _summary_hbox.pack_start (*summary_arrows_right, false, false);
634 if (!ARDOUR::Profile->get_trx()) {
635 editor_summary_pane.pack2 (_summary_hbox);
638 edit_pane.pack1 (editor_summary_pane, true, true);
639 if (!ARDOUR::Profile->get_trx()) {
640 edit_pane.pack2 (_the_notebook, false, true);
643 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
645 /* XXX: editor_summary_pane might need similar to the edit_pane */
647 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
649 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
650 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
652 top_hbox.pack_start (toolbar_frame);
654 HBox *hbox = manage (new HBox);
655 hbox->pack_start (edit_pane, true, true);
657 global_vpacker.pack_start (top_hbox, false, false);
658 global_vpacker.pack_start (*hbox, true, true);
660 global_hpacker.pack_start (global_vpacker, true, true);
662 set_name ("EditorWindow");
663 add_accel_group (ActionManager::ui_manager->get_accel_group());
665 status_bar_hpacker.show ();
667 vpacker.pack_end (status_bar_hpacker, false, false);
668 vpacker.pack_end (global_hpacker, true, true);
670 /* register actions now so that set_state() can find them and set toggles/checks etc */
673 /* when we start using our own keybinding system for the editor, this
674 * will be uncommented
680 set_zoom_focus (zoom_focus);
681 set_visible_track_count (_visible_track_count);
682 _snap_type = SnapToBeat;
683 set_snap_to (_snap_type);
684 _snap_mode = SnapOff;
685 set_snap_mode (_snap_mode);
686 set_mouse_mode (MouseObject, true);
687 pre_internal_snap_type = _snap_type;
688 pre_internal_snap_mode = _snap_mode;
689 internal_snap_type = _snap_type;
690 internal_snap_mode = _snap_mode;
691 set_edit_point_preference (EditAtMouse, true);
693 _playlist_selector = new PlaylistSelector();
694 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
696 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
700 nudge_forward_button.set_name ("nudge button");
701 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
703 nudge_backward_button.set_name ("nudge button");
704 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
706 fade_context_menu.set_name ("ArdourContextMenu");
708 /* icons, titles, WM stuff */
710 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
711 Glib::RefPtr<Gdk::Pixbuf> icon;
713 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
714 window_icons.push_back (icon);
716 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
717 window_icons.push_back (icon);
719 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
720 window_icons.push_back (icon);
722 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
723 window_icons.push_back (icon);
725 if (!window_icons.empty()) {
726 // set_icon_list (window_icons);
727 set_default_icon_list (window_icons);
730 WindowTitle title(Glib::get_application_name());
731 title += _("Editor");
732 set_title (title.get_string());
733 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
736 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
738 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
739 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
741 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
743 /* allow external control surfaces/protocols to do various things */
745 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
746 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
747 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
748 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
749 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
750 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
751 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
752 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
753 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
754 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
755 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
756 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
757 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
758 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
760 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
761 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
762 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
763 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
764 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
766 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
768 /* problematic: has to return a value and thus cannot be x-thread */
770 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
772 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
773 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
775 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
777 _ignore_region_action = false;
778 _last_region_menu_was_main = false;
779 _popup_region_menu_item = 0;
781 _ignore_follow_edits = false;
783 _show_marker_lines = false;
785 /* Button bindings */
787 button_bindings = new Bindings;
789 XMLNode* node = button_settings();
791 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
792 button_bindings->load (**i);
798 /* grab current parameter state */
799 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
800 ARDOUR_UI::config()->map_parameters (pc);
802 setup_fade_images ();
809 delete button_bindings;
811 delete _route_groups;
812 delete _track_canvas_viewport;
815 delete quantize_dialog;
819 Editor::button_settings () const
821 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
822 XMLNode* node = find_named_node (*settings, X_("Buttons"));
825 node = new XMLNode (X_("Buttons"));
832 Editor::add_toplevel_menu (Container& cont)
834 vpacker.pack_start (cont, false, false);
839 Editor::add_transport_frame (Container& cont)
841 if(ARDOUR::Profile->get_mixbus()) {
842 global_vpacker.pack_start (cont, false, false);
843 global_vpacker.reorder_child (cont, 0);
846 vpacker.pack_start (cont, false, false);
851 Editor::get_smart_mode () const
853 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
857 Editor::catch_vanishing_regionview (RegionView *rv)
859 /* note: the selection will take care of the vanishing
860 audioregionview by itself.
863 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
867 if (clicked_regionview == rv) {
868 clicked_regionview = 0;
871 if (entered_regionview == rv) {
872 set_entered_regionview (0);
875 if (!_all_region_actions_sensitized) {
876 sensitize_all_region_actions (true);
881 Editor::set_entered_regionview (RegionView* rv)
883 if (rv == entered_regionview) {
887 if (entered_regionview) {
888 entered_regionview->exited ();
891 entered_regionview = rv;
893 if (entered_regionview != 0) {
894 entered_regionview->entered ();
897 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
898 /* This RegionView entry might have changed what region actions
899 are allowed, so sensitize them all in case a key is pressed.
901 sensitize_all_region_actions (true);
906 Editor::set_entered_track (TimeAxisView* tav)
909 entered_track->exited ();
915 entered_track->entered ();
920 Editor::show_window ()
922 if (!is_visible ()) {
926 /* XXX: this is a bit unfortunate; it would probably
927 be nicer if we could just call show () above rather
928 than needing the show_all ()
931 /* re-hide stuff if necessary */
932 editor_list_button_toggled ();
933 parameter_changed ("show-summary");
934 parameter_changed ("show-group-tabs");
935 parameter_changed ("show-zoom-tools");
937 /* now reset all audio_time_axis heights, because widgets might need
943 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
944 tv = (static_cast<TimeAxisView*>(*i));
948 if (current_mixer_strip) {
949 current_mixer_strip->hide_things ();
950 current_mixer_strip->parameter_changed ("mixer-element-visibility");
958 Editor::instant_save ()
960 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
965 _session->add_instant_xml(get_state());
967 Config->add_instant_xml(get_state());
972 Editor::control_vertical_zoom_in_all ()
974 tav_zoom_smooth (false, true);
978 Editor::control_vertical_zoom_out_all ()
980 tav_zoom_smooth (true, true);
984 Editor::control_vertical_zoom_in_selected ()
986 tav_zoom_smooth (false, false);
990 Editor::control_vertical_zoom_out_selected ()
992 tav_zoom_smooth (true, false);
996 Editor::control_view (uint32_t view)
998 goto_visual_state (view);
1002 Editor::control_unselect ()
1004 selection->clear_tracks ();
1008 Editor::control_select (uint32_t rid, Selection::Operation op)
1010 /* handles the (static) signal from the ControlProtocol class that
1011 * requests setting the selected track to a given RID
1018 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1024 TimeAxisView* tav = axis_view_from_route (r);
1028 case Selection::Add:
1029 selection->add (tav);
1031 case Selection::Toggle:
1032 selection->toggle (tav);
1034 case Selection::Extend:
1036 case Selection::Set:
1037 selection->set (tav);
1041 selection->clear_tracks ();
1046 Editor::control_step_tracks_up ()
1048 scroll_tracks_up_line ();
1052 Editor::control_step_tracks_down ()
1054 scroll_tracks_down_line ();
1058 Editor::control_scroll (float fraction)
1060 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1066 double step = fraction * current_page_samples();
1069 _control_scroll_target is an optional<T>
1071 it acts like a pointer to an framepos_t, with
1072 a operator conversion to boolean to check
1073 that it has a value could possibly use
1074 playhead_cursor->current_frame to store the
1075 value and a boolean in the class to know
1076 when it's out of date
1079 if (!_control_scroll_target) {
1080 _control_scroll_target = _session->transport_frame();
1081 _dragging_playhead = true;
1084 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1085 *_control_scroll_target = 0;
1086 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1087 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1089 *_control_scroll_target += (framepos_t) trunc (step);
1092 /* move visuals, we'll catch up with it later */
1094 playhead_cursor->set_position (*_control_scroll_target);
1095 UpdateAllTransportClocks (*_control_scroll_target);
1097 if (*_control_scroll_target > (current_page_samples() / 2)) {
1098 /* try to center PH in window */
1099 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1105 Now we do a timeout to actually bring the session to the right place
1106 according to the playhead. This is to avoid reading disk buffers on every
1107 call to control_scroll, which is driven by ScrollTimeline and therefore
1108 probably by a control surface wheel which can generate lots of events.
1110 /* cancel the existing timeout */
1112 control_scroll_connection.disconnect ();
1114 /* add the next timeout */
1116 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1120 Editor::deferred_control_scroll (framepos_t /*target*/)
1122 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1123 // reset for next stream
1124 _control_scroll_target = boost::none;
1125 _dragging_playhead = false;
1130 Editor::access_action (std::string action_group, std::string action_item)
1136 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1139 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1147 Editor::on_realize ()
1149 Window::on_realize ();
1152 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1153 start_lock_event_timing ();
1156 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1160 Editor::start_lock_event_timing ()
1162 /* check if we should lock the GUI every 30 seconds */
1164 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1168 Editor::generic_event_handler (GdkEvent* ev)
1171 case GDK_BUTTON_PRESS:
1172 case GDK_BUTTON_RELEASE:
1173 case GDK_MOTION_NOTIFY:
1175 case GDK_KEY_RELEASE:
1176 gettimeofday (&last_event_time, 0);
1179 case GDK_LEAVE_NOTIFY:
1180 switch (ev->crossing.detail) {
1181 case GDK_NOTIFY_UNKNOWN:
1182 case GDK_NOTIFY_INFERIOR:
1183 case GDK_NOTIFY_ANCESTOR:
1185 case GDK_NOTIFY_VIRTUAL:
1186 case GDK_NOTIFY_NONLINEAR:
1187 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1188 /* leaving window, so reset focus, thus ending any and
1189 all text entry operations.
1204 Editor::lock_timeout_callback ()
1206 struct timeval now, delta;
1208 gettimeofday (&now, 0);
1210 timersub (&now, &last_event_time, &delta);
1212 if (delta.tv_sec > (time_t) ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1214 /* don't call again. Returning false will effectively
1215 disconnect us from the timer callback.
1217 unlock() will call start_lock_event_timing() to get things
1227 Editor::map_position_change (framepos_t frame)
1229 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1231 if (_session == 0) {
1235 if (_follow_playhead) {
1236 center_screen (frame);
1239 playhead_cursor->set_position (frame);
1243 Editor::center_screen (framepos_t frame)
1245 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1247 /* if we're off the page, then scroll.
1250 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1251 center_screen_internal (frame, page);
1256 Editor::center_screen_internal (framepos_t frame, float page)
1261 frame -= (framepos_t) page;
1266 reset_x_origin (frame);
1271 Editor::update_title ()
1273 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1276 bool dirty = _session->dirty();
1278 string session_name;
1280 if (_session->snap_name() != _session->name()) {
1281 session_name = _session->snap_name();
1283 session_name = _session->name();
1287 session_name = "*" + session_name;
1290 WindowTitle title(session_name);
1291 title += Glib::get_application_name();
1292 set_title (title.get_string());
1294 /* ::session_going_away() will have taken care of it */
1299 Editor::set_session (Session *t)
1301 SessionHandlePtr::set_session (t);
1307 _playlist_selector->set_session (_session);
1308 nudge_clock->set_session (_session);
1309 _summary->set_session (_session);
1310 _group_tabs->set_session (_session);
1311 _route_groups->set_session (_session);
1312 _regions->set_session (_session);
1313 _snapshots->set_session (_session);
1314 _routes->set_session (_session);
1315 _locations->set_session (_session);
1317 if (rhythm_ferret) {
1318 rhythm_ferret->set_session (_session);
1321 if (analysis_window) {
1322 analysis_window->set_session (_session);
1326 sfbrowser->set_session (_session);
1329 compute_fixed_ruler_scale ();
1331 /* Make sure we have auto loop and auto punch ranges */
1333 Location* loc = _session->locations()->auto_loop_location();
1335 loc->set_name (_("Loop"));
1338 loc = _session->locations()->auto_punch_location();
1341 loc->set_name (_("Punch"));
1344 refresh_location_display ();
1346 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1347 the selected Marker; this needs the LocationMarker list to be available.
1349 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1350 set_state (*node, Stateful::loading_state_version);
1352 /* catch up with the playhead */
1354 _session->request_locate (playhead_cursor->current_frame ());
1355 _pending_initial_locate = true;
1359 /* These signals can all be emitted by a non-GUI thread. Therefore the
1360 handlers for them must not attempt to directly interact with the GUI,
1361 but use PBD::Signal<T>::connect() which accepts an event loop
1362 ("context") where the handler will be asked to run.
1365 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1366 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1367 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1368 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1369 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1370 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1371 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1372 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1373 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1374 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1375 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1376 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1377 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1379 playhead_cursor->show ();
1381 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1382 Config->map_parameters (pc);
1383 _session->config.map_parameters (pc);
1385 restore_ruler_visibility ();
1386 //tempo_map_changed (PropertyChange (0));
1387 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1389 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1390 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1393 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1394 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1397 switch (_snap_type) {
1398 case SnapToRegionStart:
1399 case SnapToRegionEnd:
1400 case SnapToRegionSync:
1401 case SnapToRegionBoundary:
1402 build_region_boundary_cache ();
1409 /* register for undo history */
1410 _session->register_with_memento_command_factory(id(), this);
1411 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1413 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1415 start_updating_meters ();
1419 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1421 if (a->get_name() == "RegionMenu") {
1422 /* When the main menu's region menu is opened, we setup the actions so that they look right
1423 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1424 so we resensitize all region actions when the entered regionview or the region selection
1425 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1426 happens after the region context menu is opened. So we set a flag here, too.
1430 sensitize_the_right_region_actions ();
1431 _last_region_menu_was_main = true;
1436 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1438 using namespace Menu_Helpers;
1440 void (Editor::*emf)(FadeShape);
1441 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1444 images = &_xfade_in_images;
1445 emf = &Editor::set_fade_in_shape;
1447 images = &_xfade_out_images;
1448 emf = &Editor::set_fade_out_shape;
1453 _("Linear (for highly correlated material)"),
1454 *(*images)[FadeLinear],
1455 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1459 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1463 _("Constant power"),
1464 *(*images)[FadeConstantPower],
1465 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1468 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1473 *(*images)[FadeSymmetric],
1474 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1478 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1483 *(*images)[FadeSlow],
1484 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1487 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1492 *(*images)[FadeFast],
1493 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1496 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1499 /** Pop up a context menu for when the user clicks on a start crossfade */
1501 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1503 using namespace Menu_Helpers;
1504 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1509 MenuList& items (xfade_in_context_menu.items());
1512 if (arv->audio_region()->fade_in_active()) {
1513 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1515 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1518 items.push_back (SeparatorElem());
1519 fill_xfade_menu (items, true);
1521 xfade_in_context_menu.popup (button, time);
1524 /** Pop up a context menu for when the user clicks on an end crossfade */
1526 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1528 using namespace Menu_Helpers;
1529 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1534 MenuList& items (xfade_out_context_menu.items());
1537 if (arv->audio_region()->fade_out_active()) {
1538 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1540 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1543 items.push_back (SeparatorElem());
1544 fill_xfade_menu (items, false);
1546 xfade_out_context_menu.popup (button, time);
1550 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1552 using namespace Menu_Helpers;
1553 Menu* (Editor::*build_menu_function)();
1556 switch (item_type) {
1558 case RegionViewName:
1559 case RegionViewNameHighlight:
1560 case LeftFrameHandle:
1561 case RightFrameHandle:
1562 if (with_selection) {
1563 build_menu_function = &Editor::build_track_selection_context_menu;
1565 build_menu_function = &Editor::build_track_region_context_menu;
1570 if (with_selection) {
1571 build_menu_function = &Editor::build_track_selection_context_menu;
1573 build_menu_function = &Editor::build_track_context_menu;
1578 if (clicked_routeview->track()) {
1579 build_menu_function = &Editor::build_track_context_menu;
1581 build_menu_function = &Editor::build_track_bus_context_menu;
1586 /* probably shouldn't happen but if it does, we don't care */
1590 menu = (this->*build_menu_function)();
1591 menu->set_name ("ArdourContextMenu");
1593 /* now handle specific situations */
1595 switch (item_type) {
1597 case RegionViewName:
1598 case RegionViewNameHighlight:
1599 case LeftFrameHandle:
1600 case RightFrameHandle:
1601 if (!with_selection) {
1602 if (region_edit_menu_split_item) {
1603 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1604 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1606 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1609 if (region_edit_menu_split_multichannel_item) {
1610 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1611 region_edit_menu_split_multichannel_item->set_sensitive (true);
1613 region_edit_menu_split_multichannel_item->set_sensitive (false);
1626 /* probably shouldn't happen but if it does, we don't care */
1630 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1632 /* Bounce to disk */
1634 using namespace Menu_Helpers;
1635 MenuList& edit_items = menu->items();
1637 edit_items.push_back (SeparatorElem());
1639 switch (clicked_routeview->audio_track()->freeze_state()) {
1640 case AudioTrack::NoFreeze:
1641 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1644 case AudioTrack::Frozen:
1645 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1648 case AudioTrack::UnFrozen:
1649 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1655 if (item_type == StreamItem && clicked_routeview) {
1656 clicked_routeview->build_underlay_menu(menu);
1659 /* When the region menu is opened, we setup the actions so that they look right
1662 sensitize_the_right_region_actions ();
1663 _last_region_menu_was_main = false;
1665 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1666 menu->popup (button, time);
1670 Editor::build_track_context_menu ()
1672 using namespace Menu_Helpers;
1674 MenuList& edit_items = track_context_menu.items();
1677 add_dstream_context_items (edit_items);
1678 return &track_context_menu;
1682 Editor::build_track_bus_context_menu ()
1684 using namespace Menu_Helpers;
1686 MenuList& edit_items = track_context_menu.items();
1689 add_bus_context_items (edit_items);
1690 return &track_context_menu;
1694 Editor::build_track_region_context_menu ()
1696 using namespace Menu_Helpers;
1697 MenuList& edit_items = track_region_context_menu.items();
1700 /* we've just cleared the track region context menu, so the menu that these
1701 two items were on will have disappeared; stop them dangling.
1703 region_edit_menu_split_item = 0;
1704 region_edit_menu_split_multichannel_item = 0;
1706 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1709 boost::shared_ptr<Track> tr;
1710 boost::shared_ptr<Playlist> pl;
1712 if ((tr = rtv->track())) {
1713 add_region_context_items (edit_items, tr);
1717 add_dstream_context_items (edit_items);
1719 return &track_region_context_menu;
1723 Editor::analyze_region_selection ()
1725 if (analysis_window == 0) {
1726 analysis_window = new AnalysisWindow();
1729 analysis_window->set_session(_session);
1731 analysis_window->show_all();
1734 analysis_window->set_regionmode();
1735 analysis_window->analyze();
1737 analysis_window->present();
1741 Editor::analyze_range_selection()
1743 if (analysis_window == 0) {
1744 analysis_window = new AnalysisWindow();
1747 analysis_window->set_session(_session);
1749 analysis_window->show_all();
1752 analysis_window->set_rangemode();
1753 analysis_window->analyze();
1755 analysis_window->present();
1759 Editor::build_track_selection_context_menu ()
1761 using namespace Menu_Helpers;
1762 MenuList& edit_items = track_selection_context_menu.items();
1763 edit_items.clear ();
1765 add_selection_context_items (edit_items);
1766 // edit_items.push_back (SeparatorElem());
1767 // add_dstream_context_items (edit_items);
1769 return &track_selection_context_menu;
1773 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1775 using namespace Menu_Helpers;
1777 /* OK, stick the region submenu at the top of the list, and then add
1781 RegionSelection rs = get_regions_from_selection_and_entered ();
1783 string::size_type pos = 0;
1784 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1786 /* we have to hack up the region name because "_" has a special
1787 meaning for menu titles.
1790 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1791 menu_item_name.replace (pos, 1, "__");
1795 if (_popup_region_menu_item == 0) {
1796 _popup_region_menu_item = new MenuItem (menu_item_name);
1797 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1798 _popup_region_menu_item->show ();
1800 _popup_region_menu_item->set_label (menu_item_name);
1803 /* No latering allowed in later is higher layering model */
1804 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1805 if (act && Config->get_layer_model() == LaterHigher) {
1806 act->set_sensitive (false);
1808 act->set_sensitive (true);
1811 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1813 edit_items.push_back (*_popup_region_menu_item);
1814 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1815 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1817 edit_items.push_back (SeparatorElem());
1820 /** Add context menu items relevant to selection ranges.
1821 * @param edit_items List to add the items to.
1824 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1826 using namespace Menu_Helpers;
1828 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1829 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1831 edit_items.push_back (SeparatorElem());
1832 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1834 edit_items.push_back (SeparatorElem());
1835 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1837 edit_items.push_back (SeparatorElem());
1839 edit_items.push_back (
1841 _("Move Range Start to Previous Region Boundary"),
1842 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1846 edit_items.push_back (
1848 _("Move Range Start to Next Region Boundary"),
1849 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1853 edit_items.push_back (
1855 _("Move Range End to Previous Region Boundary"),
1856 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1860 edit_items.push_back (
1862 _("Move Range End to Next Region Boundary"),
1863 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1867 edit_items.push_back (SeparatorElem());
1868 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1869 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1871 edit_items.push_back (SeparatorElem());
1872 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1874 edit_items.push_back (SeparatorElem());
1875 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1876 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1877 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1879 edit_items.push_back (SeparatorElem());
1880 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1882 edit_items.push_back (SeparatorElem());
1883 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1884 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1885 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1887 edit_items.push_back (SeparatorElem());
1888 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1889 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1890 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1891 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1892 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1893 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1894 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1900 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1902 using namespace Menu_Helpers;
1906 Menu *play_menu = manage (new Menu);
1907 MenuList& play_items = play_menu->items();
1908 play_menu->set_name ("ArdourContextMenu");
1910 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1911 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1912 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1913 play_items.push_back (SeparatorElem());
1914 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1916 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1920 Menu *select_menu = manage (new Menu);
1921 MenuList& select_items = select_menu->items();
1922 select_menu->set_name ("ArdourContextMenu");
1924 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1925 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1926 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1927 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1928 select_items.push_back (SeparatorElem());
1929 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1930 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1931 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
1932 select_items.push_back (SeparatorElem());
1933 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1934 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1935 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1936 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1937 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1938 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1939 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1941 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1945 Menu *cutnpaste_menu = manage (new Menu);
1946 MenuList& cutnpaste_items = cutnpaste_menu->items();
1947 cutnpaste_menu->set_name ("ArdourContextMenu");
1949 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1950 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1951 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1953 cutnpaste_items.push_back (SeparatorElem());
1955 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1956 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1958 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1960 /* Adding new material */
1962 edit_items.push_back (SeparatorElem());
1963 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1964 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1968 Menu *nudge_menu = manage (new Menu());
1969 MenuList& nudge_items = nudge_menu->items();
1970 nudge_menu->set_name ("ArdourContextMenu");
1972 edit_items.push_back (SeparatorElem());
1973 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1974 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1975 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1976 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1978 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1982 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1984 using namespace Menu_Helpers;
1988 Menu *play_menu = manage (new Menu);
1989 MenuList& play_items = play_menu->items();
1990 play_menu->set_name ("ArdourContextMenu");
1992 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1993 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1994 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1998 Menu *select_menu = manage (new Menu);
1999 MenuList& select_items = select_menu->items();
2000 select_menu->set_name ("ArdourContextMenu");
2002 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2003 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2004 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2005 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2006 select_items.push_back (SeparatorElem());
2007 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2008 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2009 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2010 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2012 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2016 Menu *cutnpaste_menu = manage (new Menu);
2017 MenuList& cutnpaste_items = cutnpaste_menu->items();
2018 cutnpaste_menu->set_name ("ArdourContextMenu");
2020 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2021 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2022 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2024 Menu *nudge_menu = manage (new Menu());
2025 MenuList& nudge_items = nudge_menu->items();
2026 nudge_menu->set_name ("ArdourContextMenu");
2028 edit_items.push_back (SeparatorElem());
2029 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2030 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2031 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2032 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2034 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2038 Editor::snap_type() const
2044 Editor::snap_mode() const
2050 Editor::set_snap_to (SnapType st)
2052 unsigned int snap_ind = (unsigned int)st;
2054 if (internal_editing()) {
2055 internal_snap_type = st;
2057 pre_internal_snap_type = st;
2062 if (snap_ind > snap_type_strings.size() - 1) {
2064 _snap_type = (SnapType)snap_ind;
2067 string str = snap_type_strings[snap_ind];
2069 if (str != snap_type_selector.get_text()) {
2070 snap_type_selector.set_text (str);
2075 switch (_snap_type) {
2076 case SnapToBeatDiv128:
2077 case SnapToBeatDiv64:
2078 case SnapToBeatDiv32:
2079 case SnapToBeatDiv28:
2080 case SnapToBeatDiv24:
2081 case SnapToBeatDiv20:
2082 case SnapToBeatDiv16:
2083 case SnapToBeatDiv14:
2084 case SnapToBeatDiv12:
2085 case SnapToBeatDiv10:
2086 case SnapToBeatDiv8:
2087 case SnapToBeatDiv7:
2088 case SnapToBeatDiv6:
2089 case SnapToBeatDiv5:
2090 case SnapToBeatDiv4:
2091 case SnapToBeatDiv3:
2092 case SnapToBeatDiv2: {
2093 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2094 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2096 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2097 current_bbt_points_begin, current_bbt_points_end);
2098 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2099 current_bbt_points_begin, current_bbt_points_end);
2100 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2104 case SnapToRegionStart:
2105 case SnapToRegionEnd:
2106 case SnapToRegionSync:
2107 case SnapToRegionBoundary:
2108 build_region_boundary_cache ();
2116 redisplay_tempo (false);
2118 SnapChanged (); /* EMIT SIGNAL */
2122 Editor::set_snap_mode (SnapMode mode)
2124 string str = snap_mode_strings[(int)mode];
2126 if (internal_editing()) {
2127 internal_snap_mode = mode;
2129 pre_internal_snap_mode = mode;
2134 if (str != snap_mode_selector.get_text ()) {
2135 snap_mode_selector.set_text (str);
2142 Editor::set_edit_point_preference (EditPoint ep, bool force)
2144 bool changed = (_edit_point != ep);
2147 if (Profile->get_mixbus())
2148 if (ep == EditAtSelectedMarker)
2149 ep = EditAtPlayhead;
2151 string str = edit_point_strings[(int)ep];
2152 if (str != edit_point_selector.get_text ()) {
2153 edit_point_selector.set_text (str);
2156 update_all_enter_cursors();
2158 if (!force && !changed) {
2162 const char* action=NULL;
2164 switch (_edit_point) {
2165 case EditAtPlayhead:
2166 action = "edit-at-playhead";
2168 case EditAtSelectedMarker:
2169 action = "edit-at-marker";
2172 action = "edit-at-mouse";
2176 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2178 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2182 bool in_track_canvas;
2184 if (!mouse_frame (foo, in_track_canvas)) {
2185 in_track_canvas = false;
2188 reset_canvas_action_sensitivity (in_track_canvas);
2194 Editor::set_state (const XMLNode& node, int /*version*/)
2196 const XMLProperty* prop;
2203 g.base_width = default_width;
2204 g.base_height = default_height;
2208 if ((geometry = find_named_node (node, "geometry")) != 0) {
2212 if ((prop = geometry->property("x_size")) == 0) {
2213 prop = geometry->property ("x-size");
2216 g.base_width = atoi(prop->value());
2218 if ((prop = geometry->property("y_size")) == 0) {
2219 prop = geometry->property ("y-size");
2222 g.base_height = atoi(prop->value());
2225 if ((prop = geometry->property ("x_pos")) == 0) {
2226 prop = geometry->property ("x-pos");
2229 x = atoi (prop->value());
2232 if ((prop = geometry->property ("y_pos")) == 0) {
2233 prop = geometry->property ("y-pos");
2236 y = atoi (prop->value());
2240 set_default_size (g.base_width, g.base_height);
2243 if (_session && (prop = node.property ("playhead"))) {
2245 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2247 playhead_cursor->set_position (pos);
2249 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2250 playhead_cursor->set_position (0);
2253 playhead_cursor->set_position (0);
2256 if ((prop = node.property ("mixer-width"))) {
2257 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2260 if ((prop = node.property ("zoom-focus"))) {
2261 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2264 if ((prop = node.property ("zoom"))) {
2265 /* older versions of ardour used floating point samples_per_pixel */
2266 double f = PBD::atof (prop->value());
2267 reset_zoom (llrintf (f));
2269 reset_zoom (samples_per_pixel);
2272 if ((prop = node.property ("visible-track-count"))) {
2273 set_visible_track_count (PBD::atoi (prop->value()));
2276 if ((prop = node.property ("snap-to"))) {
2277 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2280 if ((prop = node.property ("snap-mode"))) {
2281 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2284 if ((prop = node.property ("internal-snap-to"))) {
2285 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2288 if ((prop = node.property ("internal-snap-mode"))) {
2289 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2292 if ((prop = node.property ("pre-internal-snap-to"))) {
2293 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2296 if ((prop = node.property ("pre-internal-snap-mode"))) {
2297 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2300 if ((prop = node.property ("mouse-mode"))) {
2301 MouseMode m = str2mousemode(prop->value());
2302 set_mouse_mode (m, true);
2304 set_mouse_mode (MouseObject, true);
2307 if ((prop = node.property ("left-frame")) != 0) {
2309 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2313 reset_x_origin (pos);
2317 if ((prop = node.property ("y-origin")) != 0) {
2318 reset_y_origin (atof (prop->value ()));
2321 if ((prop = node.property ("join-object-range"))) {
2322 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2323 bool yn = string_is_affirmative (prop->value());
2325 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2326 tact->set_active (!yn);
2327 tact->set_active (yn);
2329 set_mouse_mode(mouse_mode, true);
2332 if ((prop = node.property ("edit-point"))) {
2333 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2336 if ((prop = node.property ("show-measures"))) {
2337 bool yn = string_is_affirmative (prop->value());
2338 _show_measures = yn;
2341 if ((prop = node.property ("follow-playhead"))) {
2342 bool yn = string_is_affirmative (prop->value());
2343 set_follow_playhead (yn);
2346 if ((prop = node.property ("stationary-playhead"))) {
2347 bool yn = string_is_affirmative (prop->value());
2348 set_stationary_playhead (yn);
2351 if ((prop = node.property ("region-list-sort-type"))) {
2352 RegionListSortType st;
2353 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2356 if ((prop = node.property ("show-editor-mixer"))) {
2358 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2361 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2362 bool yn = string_is_affirmative (prop->value());
2364 /* do it twice to force the change */
2366 tact->set_active (!yn);
2367 tact->set_active (yn);
2370 if ((prop = node.property ("show-editor-list"))) {
2372 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2375 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2376 bool yn = string_is_affirmative (prop->value());
2378 /* do it twice to force the change */
2380 tact->set_active (!yn);
2381 tact->set_active (yn);
2384 if ((prop = node.property (X_("editor-list-page")))) {
2385 _the_notebook.set_current_page (atoi (prop->value ()));
2388 if ((prop = node.property (X_("show-marker-lines")))) {
2389 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2391 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2392 bool yn = string_is_affirmative (prop->value ());
2394 tact->set_active (!yn);
2395 tact->set_active (yn);
2398 XMLNodeList children = node.children ();
2399 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2400 selection->set_state (**i, Stateful::current_state_version);
2401 _regions->set_state (**i);
2404 if ((prop = node.property ("maximised"))) {
2405 bool yn = string_is_affirmative (prop->value());
2406 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2408 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2409 bool fs = tact && tact->get_active();
2411 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2415 if ((prop = node.property ("nudge-clock-value"))) {
2417 sscanf (prop->value().c_str(), "%" PRId64, &f);
2418 nudge_clock->set (f);
2420 nudge_clock->set_mode (AudioClock::Timecode);
2421 nudge_clock->set (_session->frame_rate() * 5, true);
2426 * Not all properties may have been in XML, but
2427 * those that are linked to a private variable may need changing
2432 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2434 yn = _show_measures;
2435 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2436 /* do it twice to force the change */
2437 tact->set_active (!yn);
2438 tact->set_active (yn);
2441 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2442 yn = _follow_playhead;
2444 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2445 if (tact->get_active() != yn) {
2446 tact->set_active (yn);
2450 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2451 yn = _stationary_playhead;
2453 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2454 if (tact->get_active() != yn) {
2455 tact->set_active (yn);
2464 Editor::get_state ()
2466 XMLNode* node = new XMLNode ("Editor");
2469 id().print (buf, sizeof (buf));
2470 node->add_property ("id", buf);
2472 if (is_realized()) {
2473 Glib::RefPtr<Gdk::Window> win = get_window();
2475 int x, y, width, height;
2476 win->get_root_origin(x, y);
2477 win->get_size(width, height);
2479 XMLNode* geometry = new XMLNode ("geometry");
2481 snprintf(buf, sizeof(buf), "%d", width);
2482 geometry->add_property("x-size", string(buf));
2483 snprintf(buf, sizeof(buf), "%d", height);
2484 geometry->add_property("y-size", string(buf));
2485 snprintf(buf, sizeof(buf), "%d", x);
2486 geometry->add_property("x-pos", string(buf));
2487 snprintf(buf, sizeof(buf), "%d", y);
2488 geometry->add_property("y-pos", string(buf));
2489 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2490 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2491 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2492 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2493 geometry->add_property("edit-vertical-pane-pos", string(buf));
2495 node->add_child_nocopy (*geometry);
2498 maybe_add_mixer_strip_width (*node);
2500 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2502 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2503 node->add_property ("zoom", buf);
2504 node->add_property ("snap-to", enum_2_string (_snap_type));
2505 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2506 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2507 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2508 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2509 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2510 node->add_property ("edit-point", enum_2_string (_edit_point));
2511 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2512 node->add_property ("visible-track-count", buf);
2514 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2515 node->add_property ("playhead", buf);
2516 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2517 node->add_property ("left-frame", buf);
2518 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2519 node->add_property ("y-origin", buf);
2521 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2522 node->add_property ("maximised", _maximised ? "yes" : "no");
2523 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2524 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2525 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2526 node->add_property ("mouse-mode", enum2str(mouse_mode));
2527 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2529 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2531 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2532 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2535 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2537 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2538 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2541 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2542 node->add_property (X_("editor-list-page"), buf);
2544 if (button_bindings) {
2545 XMLNode* bb = new XMLNode (X_("Buttons"));
2546 button_bindings->save (*bb);
2547 node->add_child_nocopy (*bb);
2550 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2552 node->add_child_nocopy (selection->get_state ());
2553 node->add_child_nocopy (_regions->get_state ());
2555 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2556 node->add_property ("nudge-clock-value", buf);
2561 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2562 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2564 * @return pair: TimeAxisView that y is over, layer index.
2566 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2567 * in stacked or expanded region display mode, otherwise 0.
2569 std::pair<TimeAxisView *, double>
2570 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2572 if (!trackview_relative_offset) {
2573 y -= _trackview_group->canvas_origin().y;
2577 return std::make_pair ( (TimeAxisView *) 0, 0);
2580 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2582 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2589 return std::make_pair ( (TimeAxisView *) 0, 0);
2592 /** Snap a position to the grid, if appropriate, taking into account current
2593 * grid settings and also the state of any snap modifier keys that may be pressed.
2594 * @param start Position to snap.
2595 * @param event Event to get current key modifier information from, or 0.
2598 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2600 if (!_session || !event) {
2604 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2605 if (_snap_mode == SnapOff) {
2606 snap_to_internal (start, direction, for_mark);
2609 if (_snap_mode != SnapOff) {
2610 snap_to_internal (start, direction, for_mark);
2611 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2612 /* SnapOff, but we pressed the snap_delta modifier */
2613 snap_to_internal (start, direction, for_mark);
2619 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2621 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2625 snap_to_internal (start, direction, for_mark, ensure_snap);
2629 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2631 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2632 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2634 switch (_snap_type) {
2635 case SnapToTimecodeFrame:
2636 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2637 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2638 /* start is already on a whole timecode frame, do nothing */
2639 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2640 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2642 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2646 case SnapToTimecodeSeconds:
2647 if (_session->config.get_timecode_offset_negative()) {
2648 start += _session->config.get_timecode_offset ();
2650 start -= _session->config.get_timecode_offset ();
2652 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2653 (start % one_timecode_second == 0)) {
2654 /* start is already on a whole second, do nothing */
2655 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2656 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2658 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2661 if (_session->config.get_timecode_offset_negative()) {
2662 start -= _session->config.get_timecode_offset ();
2664 start += _session->config.get_timecode_offset ();
2668 case SnapToTimecodeMinutes:
2669 if (_session->config.get_timecode_offset_negative()) {
2670 start += _session->config.get_timecode_offset ();
2672 start -= _session->config.get_timecode_offset ();
2674 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2675 (start % one_timecode_minute == 0)) {
2676 /* start is already on a whole minute, do nothing */
2677 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2678 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2680 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2682 if (_session->config.get_timecode_offset_negative()) {
2683 start -= _session->config.get_timecode_offset ();
2685 start += _session->config.get_timecode_offset ();
2689 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2690 abort(); /*NOTREACHED*/
2695 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2697 const framepos_t one_second = _session->frame_rate();
2698 const framepos_t one_minute = _session->frame_rate() * 60;
2699 framepos_t presnap = start;
2703 switch (_snap_type) {
2704 case SnapToTimecodeFrame:
2705 case SnapToTimecodeSeconds:
2706 case SnapToTimecodeMinutes:
2707 return timecode_snap_to_internal (start, direction, for_mark);
2710 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2711 start % (one_second/75) == 0) {
2712 /* start is already on a whole CD frame, do nothing */
2713 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2714 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2716 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2721 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2722 start % one_second == 0) {
2723 /* start is already on a whole second, do nothing */
2724 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2725 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2727 start = (framepos_t) floor ((double) start / one_second) * one_second;
2732 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2733 start % one_minute == 0) {
2734 /* start is already on a whole minute, do nothing */
2735 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2736 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2738 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2743 start = _session->tempo_map().round_to_bar (start, direction);
2747 start = _session->tempo_map().round_to_beat (start, direction);
2750 case SnapToBeatDiv128:
2751 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2753 case SnapToBeatDiv64:
2754 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2756 case SnapToBeatDiv32:
2757 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2759 case SnapToBeatDiv28:
2760 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2762 case SnapToBeatDiv24:
2763 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2765 case SnapToBeatDiv20:
2766 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2768 case SnapToBeatDiv16:
2769 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2771 case SnapToBeatDiv14:
2772 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2774 case SnapToBeatDiv12:
2775 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2777 case SnapToBeatDiv10:
2778 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2780 case SnapToBeatDiv8:
2781 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2783 case SnapToBeatDiv7:
2784 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2786 case SnapToBeatDiv6:
2787 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2789 case SnapToBeatDiv5:
2790 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2792 case SnapToBeatDiv4:
2793 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2795 case SnapToBeatDiv3:
2796 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2798 case SnapToBeatDiv2:
2799 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2807 _session->locations()->marks_either_side (start, before, after);
2809 if (before == max_framepos && after == max_framepos) {
2810 /* No marks to snap to, so just don't snap */
2812 } else if (before == max_framepos) {
2814 } else if (after == max_framepos) {
2816 } else if (before != max_framepos && after != max_framepos) {
2817 /* have before and after */
2818 if ((start - before) < (after - start)) {
2827 case SnapToRegionStart:
2828 case SnapToRegionEnd:
2829 case SnapToRegionSync:
2830 case SnapToRegionBoundary:
2831 if (!region_boundary_cache.empty()) {
2833 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2834 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2836 if (direction > 0) {
2837 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2839 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2842 if (next != region_boundary_cache.begin ()) {
2847 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2848 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2850 if (start > (p + n) / 2) {
2859 switch (_snap_mode) {
2869 if (presnap > start) {
2870 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2874 } else if (presnap < start) {
2875 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2881 /* handled at entry */
2889 Editor::setup_toolbar ()
2891 HBox* mode_box = manage(new HBox);
2892 mode_box->set_border_width (2);
2893 mode_box->set_spacing(2);
2895 HBox* mouse_mode_box = manage (new HBox);
2896 HBox* mouse_mode_hbox = manage (new HBox);
2897 VBox* mouse_mode_vbox = manage (new VBox);
2898 Alignment* mouse_mode_align = manage (new Alignment);
2900 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2901 mouse_mode_size_group->add_widget (smart_mode_button);
2902 mouse_mode_size_group->add_widget (mouse_move_button);
2903 mouse_mode_size_group->add_widget (mouse_cut_button);
2904 mouse_mode_size_group->add_widget (mouse_select_button);
2905 mouse_mode_size_group->add_widget (mouse_timefx_button);
2906 mouse_mode_size_group->add_widget (mouse_audition_button);
2907 mouse_mode_size_group->add_widget (mouse_draw_button);
2908 mouse_mode_size_group->add_widget (mouse_content_button);
2910 mouse_mode_size_group->add_widget (zoom_in_button);
2911 mouse_mode_size_group->add_widget (zoom_out_button);
2912 mouse_mode_size_group->add_widget (zoom_preset_selector);
2913 mouse_mode_size_group->add_widget (zoom_out_full_button);
2914 mouse_mode_size_group->add_widget (zoom_focus_selector);
2916 mouse_mode_size_group->add_widget (tav_shrink_button);
2917 mouse_mode_size_group->add_widget (tav_expand_button);
2918 mouse_mode_size_group->add_widget (visible_tracks_selector);
2920 mouse_mode_size_group->add_widget (snap_type_selector);
2921 mouse_mode_size_group->add_widget (snap_mode_selector);
2923 mouse_mode_size_group->add_widget (edit_point_selector);
2924 mouse_mode_size_group->add_widget (edit_mode_selector);
2926 mouse_mode_size_group->add_widget (*nudge_clock);
2927 mouse_mode_size_group->add_widget (nudge_forward_button);
2928 mouse_mode_size_group->add_widget (nudge_backward_button);
2930 mouse_mode_hbox->set_spacing (2);
2932 if (!ARDOUR::Profile->get_trx()) {
2933 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2936 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2937 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2939 if (!ARDOUR::Profile->get_mixbus()) {
2940 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2943 if (!ARDOUR::Profile->get_trx()) {
2944 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2945 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2946 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2947 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2950 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2952 mouse_mode_align->add (*mouse_mode_vbox);
2953 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2955 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2957 edit_mode_selector.set_name ("mouse mode button");
2959 if (!ARDOUR::Profile->get_trx()) {
2960 mode_box->pack_start (edit_mode_selector, false, false);
2962 mode_box->pack_start (*mouse_mode_box, false, false);
2964 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2965 _mouse_mode_tearoff->set_name ("MouseModeBase");
2966 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2968 if (Profile->get_sae() || Profile->get_mixbus() ) {
2969 _mouse_mode_tearoff->set_can_be_torn_off (false);
2972 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2973 &_mouse_mode_tearoff->tearoff_window()));
2974 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2975 &_mouse_mode_tearoff->tearoff_window(), 1));
2976 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2977 &_mouse_mode_tearoff->tearoff_window()));
2978 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2979 &_mouse_mode_tearoff->tearoff_window(), 1));
2983 _zoom_box.set_spacing (2);
2984 _zoom_box.set_border_width (2);
2988 zoom_preset_selector.set_name ("zoom button");
2989 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2990 zoom_preset_selector.set_size_request (42, -1);
2992 zoom_in_button.set_name ("zoom button");
2993 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
2994 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2995 zoom_in_button.set_related_action (act);
2997 zoom_out_button.set_name ("zoom button");
2998 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
2999 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3000 zoom_out_button.set_related_action (act);
3002 zoom_out_full_button.set_name ("zoom button");
3003 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3004 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3005 zoom_out_full_button.set_related_action (act);
3007 zoom_focus_selector.set_name ("zoom button");
3009 if (ARDOUR::Profile->get_mixbus()) {
3010 _zoom_box.pack_start (zoom_preset_selector, false, false);
3011 } else if (ARDOUR::Profile->get_trx()) {
3012 mode_box->pack_start (zoom_out_button, false, false);
3013 mode_box->pack_start (zoom_in_button, false, false);
3015 _zoom_box.pack_start (zoom_out_button, false, false);
3016 _zoom_box.pack_start (zoom_in_button, false, false);
3017 _zoom_box.pack_start (zoom_out_full_button, false, false);
3018 _zoom_box.pack_start (zoom_focus_selector, false, false);
3021 /* Track zoom buttons */
3022 visible_tracks_selector.set_name ("zoom button");
3023 if (Profile->get_mixbus()) {
3024 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3025 visible_tracks_selector.set_size_request (42, -1);
3027 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3030 tav_expand_button.set_name ("zoom button");
3031 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3032 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3033 tav_expand_button.set_related_action (act);
3035 tav_shrink_button.set_name ("zoom button");
3036 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3037 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3038 tav_shrink_button.set_related_action (act);
3040 if (ARDOUR::Profile->get_mixbus()) {
3041 _zoom_box.pack_start (visible_tracks_selector);
3042 } else if (ARDOUR::Profile->get_trx()) {
3043 _zoom_box.pack_start (tav_shrink_button);
3044 _zoom_box.pack_start (tav_expand_button);
3046 _zoom_box.pack_start (visible_tracks_selector);
3047 _zoom_box.pack_start (tav_shrink_button);
3048 _zoom_box.pack_start (tav_expand_button);
3051 if (!ARDOUR::Profile->get_trx()) {
3052 _zoom_tearoff = manage (new TearOff (_zoom_box));
3054 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3055 &_zoom_tearoff->tearoff_window()));
3056 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3057 &_zoom_tearoff->tearoff_window(), 0));
3058 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3059 &_zoom_tearoff->tearoff_window()));
3060 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3061 &_zoom_tearoff->tearoff_window(), 0));
3064 if (Profile->get_sae() || Profile->get_mixbus() ) {
3065 _zoom_tearoff->set_can_be_torn_off (false);
3068 snap_box.set_spacing (2);
3069 snap_box.set_border_width (2);
3071 snap_type_selector.set_name ("mouse mode button");
3073 snap_mode_selector.set_name ("mouse mode button");
3075 edit_point_selector.set_name ("mouse mode button");
3077 snap_box.pack_start (snap_mode_selector, false, false);
3078 snap_box.pack_start (snap_type_selector, false, false);
3079 snap_box.pack_start (edit_point_selector, false, false);
3083 HBox *nudge_box = manage (new HBox);
3084 nudge_box->set_spacing (2);
3085 nudge_box->set_border_width (2);
3087 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3088 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3090 nudge_box->pack_start (nudge_backward_button, false, false);
3091 nudge_box->pack_start (nudge_forward_button, false, false);
3092 nudge_box->pack_start (*nudge_clock, false, false);
3095 /* Pack everything in... */
3097 HBox* hbox = manage (new HBox);
3098 hbox->set_spacing(2);
3100 _tools_tearoff = manage (new TearOff (*hbox));
3101 _tools_tearoff->set_name ("MouseModeBase");
3102 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3104 if (Profile->get_sae() || Profile->get_mixbus()) {
3105 _tools_tearoff->set_can_be_torn_off (false);
3108 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3109 &_tools_tearoff->tearoff_window()));
3110 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3111 &_tools_tearoff->tearoff_window(), 0));
3112 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3113 &_tools_tearoff->tearoff_window()));
3114 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3115 &_tools_tearoff->tearoff_window(), 0));
3117 toolbar_hbox.set_spacing (2);
3118 toolbar_hbox.set_border_width (1);
3120 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3121 if (!ARDOUR::Profile->get_trx()) {
3122 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3123 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3126 if (!ARDOUR::Profile->get_trx()) {
3127 hbox->pack_start (snap_box, false, false);
3128 hbox->pack_start (*nudge_box, false, false);
3130 hbox->pack_start (panic_box, false, false);
3134 toolbar_base.set_name ("ToolBarBase");
3135 toolbar_base.add (toolbar_hbox);
3137 _toolbar_viewport.add (toolbar_base);
3138 /* stick to the required height but allow width to vary if there's not enough room */
3139 _toolbar_viewport.set_size_request (1, -1);
3141 toolbar_frame.set_shadow_type (SHADOW_OUT);
3142 toolbar_frame.set_name ("BaseFrame");
3143 toolbar_frame.add (_toolbar_viewport);
3147 Editor::build_edit_point_menu ()
3149 using namespace Menu_Helpers;
3151 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3152 if(!Profile->get_mixbus())
3153 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3154 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3156 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3160 Editor::build_edit_mode_menu ()
3162 using namespace Menu_Helpers;
3164 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3165 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3166 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3167 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3169 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3173 Editor::build_snap_mode_menu ()
3175 using namespace Menu_Helpers;
3177 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3178 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3179 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3181 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3185 Editor::build_snap_type_menu ()
3187 using namespace Menu_Helpers;
3189 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3190 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3191 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3192 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3193 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3194 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3195 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3196 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3197 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3198 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3199 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3200 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3201 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3202 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3203 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3204 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3205 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3206 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3207 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3208 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3209 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3210 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3211 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3212 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3213 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3214 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3215 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3216 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3217 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3218 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3220 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3225 Editor::setup_tooltips ()
3227 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Grab mode)"));
3228 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Grab Mode (select/move objects)"));
3229 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split regions)"));
3230 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select time ranges)"));
3231 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3232 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3233 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3234 ARDOUR_UI::instance()->set_tip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3235 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3236 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3237 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3238 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3239 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3240 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3241 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3242 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3243 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3244 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3245 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3246 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3247 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3248 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3249 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3250 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3254 Editor::convert_drop_to_paths (
3255 vector<string>& paths,
3256 const RefPtr<Gdk::DragContext>& /*context*/,
3259 const SelectionData& data,
3263 if (_session == 0) {
3267 vector<string> uris = data.get_uris();
3271 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3272 are actually URI lists. So do it by hand.
3275 if (data.get_target() != "text/plain") {
3279 /* Parse the "uri-list" format that Nautilus provides,
3280 where each pathname is delimited by \r\n.
3282 THERE MAY BE NO NULL TERMINATING CHAR!!!
3285 string txt = data.get_text();
3289 p = (char *) malloc (txt.length() + 1);
3290 txt.copy (p, txt.length(), 0);
3291 p[txt.length()] = '\0';
3297 while (g_ascii_isspace (*p))
3301 while (*q && (*q != '\n') && (*q != '\r')) {
3308 while (q > p && g_ascii_isspace (*q))
3313 uris.push_back (string (p, q - p + 1));
3317 p = strchr (p, '\n');
3329 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3330 if ((*i).substr (0,7) == "file://") {
3331 paths.push_back (Glib::filename_from_uri (*i));
3339 Editor::new_tempo_section ()
3344 Editor::map_transport_state ()
3346 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3348 if (_session && _session->transport_stopped()) {
3349 have_pending_keyboard_selection = false;
3352 update_loop_range_view ();
3358 Editor::begin_selection_op_history ()
3360 selection_op_cmd_depth = 0;
3361 selection_op_history_it = 0;
3363 while(!selection_op_history.empty()) {
3364 delete selection_op_history.front();
3365 selection_op_history.pop_front();
3368 selection_undo_action->set_sensitive (false);
3369 selection_redo_action->set_sensitive (false);
3370 selection_op_history.push_front (&_selection_memento->get_state ());
3374 Editor::begin_reversible_selection_op (string name)
3377 //cerr << name << endl;
3378 /* begin/commit pairs can be nested */
3379 selection_op_cmd_depth++;
3384 Editor::commit_reversible_selection_op ()
3387 if (selection_op_cmd_depth == 1) {
3389 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3391 The user has undone some selection ops and then made a new one,
3392 making anything earlier in the list invalid.
3395 list<XMLNode *>::iterator it = selection_op_history.begin();
3396 list<XMLNode *>::iterator e_it = it;
3397 advance (e_it, selection_op_history_it);
3399 for ( ; it != e_it; ++it) {
3402 selection_op_history.erase (selection_op_history.begin(), e_it);
3405 selection_op_history.push_front (&_selection_memento->get_state ());
3406 selection_op_history_it = 0;
3408 selection_undo_action->set_sensitive (true);
3409 selection_redo_action->set_sensitive (false);
3412 if (selection_op_cmd_depth > 0) {
3413 selection_op_cmd_depth--;
3419 Editor::undo_selection_op ()
3422 selection_op_history_it++;
3424 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3425 if (n == selection_op_history_it) {
3426 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3427 selection_redo_action->set_sensitive (true);
3431 /* is there an earlier entry? */
3432 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3433 selection_undo_action->set_sensitive (false);
3439 Editor::redo_selection_op ()
3442 if (selection_op_history_it > 0) {
3443 selection_op_history_it--;
3446 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3447 if (n == selection_op_history_it) {
3448 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3449 selection_undo_action->set_sensitive (true);
3454 if (selection_op_history_it == 0) {
3455 selection_redo_action->set_sensitive (false);
3461 Editor::begin_reversible_command (string name)
3464 before.push_back (&_selection_memento->get_state ());
3465 _session->begin_reversible_command (name);
3470 Editor::begin_reversible_command (GQuark q)
3473 before.push_back (&_selection_memento->get_state ());
3474 _session->begin_reversible_command (q);
3479 Editor::abort_reversible_command ()
3482 while(!before.empty()) {
3483 delete before.front();
3486 _session->abort_reversible_command ();
3491 Editor::commit_reversible_command ()
3494 if (before.size() == 1) {
3495 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3496 redo_action->set_sensitive(false);
3497 undo_action->set_sensitive(true);
3498 begin_selection_op_history ();
3501 if (before.empty()) {
3502 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3507 _session->commit_reversible_command ();
3512 Editor::history_changed ()
3516 if (undo_action && _session) {
3517 if (_session->undo_depth() == 0) {
3518 label = S_("Command|Undo");
3520 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3522 undo_action->property_label() = label;
3525 if (redo_action && _session) {
3526 if (_session->redo_depth() == 0) {
3529 label = string_compose(_("Redo (%1)"), _session->next_redo());
3531 redo_action->property_label() = label;
3536 Editor::duplicate_range (bool with_dialog)
3540 RegionSelection rs = get_regions_from_selection_and_entered ();
3542 if ( selection->time.length() == 0 && rs.empty()) {
3548 ArdourDialog win (_("Duplicate"));
3549 Label label (_("Number of duplications:"));
3550 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3551 SpinButton spinner (adjustment, 0.0, 1);
3554 win.get_vbox()->set_spacing (12);
3555 win.get_vbox()->pack_start (hbox);
3556 hbox.set_border_width (6);
3557 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3559 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3560 place, visually. so do this by hand.
3563 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3564 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3565 spinner.grab_focus();
3571 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3572 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3573 win.set_default_response (RESPONSE_ACCEPT);
3575 spinner.grab_focus ();
3577 switch (win.run ()) {
3578 case RESPONSE_ACCEPT:
3584 times = adjustment.get_value();
3587 if ((current_mouse_mode() == Editing::MouseRange)) {
3588 if (selection->time.length()) {
3589 duplicate_selection (times);
3591 } else if (get_smart_mode()) {
3592 if (selection->time.length()) {
3593 duplicate_selection (times);
3595 duplicate_some_regions (rs, times);
3597 duplicate_some_regions (rs, times);
3602 Editor::set_edit_mode (EditMode m)
3604 Config->set_edit_mode (m);
3608 Editor::cycle_edit_mode ()
3610 switch (Config->get_edit_mode()) {
3612 if (Profile->get_sae()) {
3613 Config->set_edit_mode (Lock);
3615 Config->set_edit_mode (Ripple);
3620 Config->set_edit_mode (Lock);
3623 Config->set_edit_mode (Slide);
3629 Editor::edit_mode_selection_done ( EditMode m )
3631 Config->set_edit_mode ( m );
3635 Editor::snap_type_selection_done (SnapType snaptype)
3637 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3639 ract->set_active ();
3644 Editor::snap_mode_selection_done (SnapMode mode)
3646 RefPtr<RadioAction> ract = snap_mode_action (mode);
3649 ract->set_active (true);
3654 Editor::cycle_edit_point (bool with_marker)
3656 if(Profile->get_mixbus())
3657 with_marker = false;
3659 switch (_edit_point) {
3661 set_edit_point_preference (EditAtPlayhead);
3663 case EditAtPlayhead:
3665 set_edit_point_preference (EditAtSelectedMarker);
3667 set_edit_point_preference (EditAtMouse);
3670 case EditAtSelectedMarker:
3671 set_edit_point_preference (EditAtMouse);
3677 Editor::edit_point_selection_done (EditPoint ep)
3679 set_edit_point_preference ( ep );
3683 Editor::build_zoom_focus_menu ()
3685 using namespace Menu_Helpers;
3687 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3688 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3689 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3690 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3691 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3692 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3694 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3698 Editor::zoom_focus_selection_done ( ZoomFocus f )
3700 RefPtr<RadioAction> ract = zoom_focus_action (f);
3702 ract->set_active ();
3707 Editor::build_track_count_menu ()
3709 using namespace Menu_Helpers;
3711 if (!Profile->get_mixbus()) {
3712 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3713 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3714 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3715 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3716 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3717 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3718 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3719 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3720 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3721 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3722 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3723 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3724 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3726 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3727 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3728 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3729 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3730 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3731 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3732 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3733 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3734 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3735 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3737 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3738 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3739 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3740 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3741 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3742 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3743 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3744 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3745 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3746 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3747 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3752 Editor::set_zoom_preset (int64_t ms)
3755 temporal_zoom_session();
3759 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3760 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3764 Editor::set_visible_track_count (int32_t n)
3766 _visible_track_count = n;
3768 /* if the canvas hasn't really been allocated any size yet, just
3769 record the desired number of visible tracks and return. when canvas
3770 allocation happens, we will get called again and then we can do the
3774 if (_visible_canvas_height <= 1) {
3780 DisplaySuspender ds;
3782 if (_visible_track_count > 0) {
3783 h = trackviews_height() / _visible_track_count;
3784 std::ostringstream s;
3785 s << _visible_track_count;
3787 } else if (_visible_track_count == 0) {
3789 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3790 if ((*i)->marked_for_display()) {
3794 h = trackviews_height() / n;
3797 /* negative value means that the visible track count has
3798 been overridden by explicit track height changes.
3800 visible_tracks_selector.set_text (X_("*"));
3804 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3805 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3808 if (str != visible_tracks_selector.get_text()) {
3809 visible_tracks_selector.set_text (str);
3814 Editor::override_visible_track_count ()
3816 _visible_track_count = -1;
3817 visible_tracks_selector.set_text ( _("*") );
3821 Editor::edit_controls_button_release (GdkEventButton* ev)
3823 if (Keyboard::is_context_menu_event (ev)) {
3824 ARDOUR_UI::instance()->add_route (this);
3825 } else if (ev->button == 1) {
3826 selection->clear_tracks ();
3833 Editor::mouse_select_button_release (GdkEventButton* ev)
3835 /* this handles just right-clicks */
3837 if (ev->button != 3) {
3845 Editor::set_zoom_focus (ZoomFocus f)
3847 string str = zoom_focus_strings[(int)f];
3849 if (str != zoom_focus_selector.get_text()) {
3850 zoom_focus_selector.set_text (str);
3853 if (zoom_focus != f) {
3860 Editor::cycle_zoom_focus ()
3862 switch (zoom_focus) {
3864 set_zoom_focus (ZoomFocusRight);
3866 case ZoomFocusRight:
3867 set_zoom_focus (ZoomFocusCenter);
3869 case ZoomFocusCenter:
3870 set_zoom_focus (ZoomFocusPlayhead);
3872 case ZoomFocusPlayhead:
3873 set_zoom_focus (ZoomFocusMouse);
3875 case ZoomFocusMouse:
3876 set_zoom_focus (ZoomFocusEdit);
3879 set_zoom_focus (ZoomFocusLeft);
3885 Editor::ensure_float (Window& win)
3887 win.set_transient_for (*this);
3891 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3893 /* recover or initialize pane positions. do this here rather than earlier because
3894 we don't want the positions to change the child allocations, which they seem to do.
3900 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3909 XMLNode* geometry = find_named_node (*node, "geometry");
3911 if (which == static_cast<Paned*> (&edit_pane)) {
3913 if (done & Horizontal) {
3917 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3918 _notebook_shrunk = string_is_affirmative (prop->value ());
3921 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3922 /* initial allocation is 90% to canvas, 10% to notebook */
3923 pos = (int) floor (alloc.get_width() * 0.90f);
3924 snprintf (buf, sizeof(buf), "%d", pos);
3926 pos = atoi (prop->value());
3929 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3930 edit_pane.set_position (pos);
3933 done = (Pane) (done | Horizontal);
3935 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3937 if (done & Vertical) {
3941 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3942 /* initial allocation is 90% to canvas, 10% to summary */
3943 pos = (int) floor (alloc.get_height() * 0.90f);
3944 snprintf (buf, sizeof(buf), "%d", pos);
3947 pos = atoi (prop->value());
3950 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3951 editor_summary_pane.set_position (pos);
3954 done = (Pane) (done | Vertical);
3959 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3961 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3962 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3963 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3964 top_hbox.remove (toolbar_frame);
3969 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3971 if (toolbar_frame.get_parent() == 0) {
3972 top_hbox.pack_end (toolbar_frame);
3977 Editor::set_show_measures (bool yn)
3979 if (_show_measures != yn) {
3982 if ((_show_measures = yn) == true) {
3984 tempo_lines->show();
3987 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3988 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3990 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3991 draw_measures (begin, end);
3999 Editor::toggle_follow_playhead ()
4001 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
4003 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4004 set_follow_playhead (tact->get_active());
4008 /** @param yn true to follow playhead, otherwise false.
4009 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4012 Editor::set_follow_playhead (bool yn, bool catch_up)
4014 if (_follow_playhead != yn) {
4015 if ((_follow_playhead = yn) == true && catch_up) {
4017 reset_x_origin_to_follow_playhead ();
4024 Editor::toggle_stationary_playhead ()
4026 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4028 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4029 set_stationary_playhead (tact->get_active());
4034 Editor::set_stationary_playhead (bool yn)
4036 if (_stationary_playhead != yn) {
4037 if ((_stationary_playhead = yn) == true) {
4039 // FIXME need a 3.0 equivalent of this 2.X call
4040 // update_current_screen ();
4047 Editor::playlist_selector () const
4049 return *_playlist_selector;
4053 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4055 if (paste_count == 0) {
4056 /* don't bother calculating an offset that will be zero anyway */
4060 /* calculate basic unsnapped multi-paste offset */
4061 framecnt_t offset = paste_count * duration;
4063 /* snap offset so pos + offset is aligned to the grid */
4064 framepos_t offset_pos = pos + offset;
4065 snap_to(offset_pos, RoundUpMaybe);
4066 offset = offset_pos - pos;
4072 Editor::get_grid_beat_divisions(framepos_t position)
4074 switch (_snap_type) {
4075 case SnapToBeatDiv128: return 128;
4076 case SnapToBeatDiv64: return 64;
4077 case SnapToBeatDiv32: return 32;
4078 case SnapToBeatDiv28: return 28;
4079 case SnapToBeatDiv24: return 24;
4080 case SnapToBeatDiv20: return 20;
4081 case SnapToBeatDiv16: return 16;
4082 case SnapToBeatDiv14: return 14;
4083 case SnapToBeatDiv12: return 12;
4084 case SnapToBeatDiv10: return 10;
4085 case SnapToBeatDiv8: return 8;
4086 case SnapToBeatDiv7: return 7;
4087 case SnapToBeatDiv6: return 6;
4088 case SnapToBeatDiv5: return 5;
4089 case SnapToBeatDiv4: return 4;
4090 case SnapToBeatDiv3: return 3;
4091 case SnapToBeatDiv2: return 2;
4098 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4102 const unsigned divisions = get_grid_beat_divisions(position);
4104 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4107 switch (_snap_type) {
4109 return Evoral::Beats(1.0);
4112 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
4120 return Evoral::Beats();
4124 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4128 ret = nudge_clock->current_duration (pos);
4129 next = ret + 1; /* XXXX fix me */
4135 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4137 ArdourDialog dialog (_("Playlist Deletion"));
4138 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4139 "If it is kept, its audio files will not be cleaned.\n"
4140 "If it is deleted, audio files used by it alone will be cleaned."),
4143 dialog.set_position (WIN_POS_CENTER);
4144 dialog.get_vbox()->pack_start (label);
4148 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4149 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4150 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4152 switch (dialog.run ()) {
4153 case RESPONSE_ACCEPT:
4154 /* delete the playlist */
4158 case RESPONSE_REJECT:
4159 /* keep the playlist */
4171 Editor::audio_region_selection_covers (framepos_t where)
4173 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4174 if ((*a)->region()->covers (where)) {
4183 Editor::prepare_for_cleanup ()
4185 cut_buffer->clear_regions ();
4186 cut_buffer->clear_playlists ();
4188 selection->clear_regions ();
4189 selection->clear_playlists ();
4191 _regions->suspend_redisplay ();
4195 Editor::finish_cleanup ()
4197 _regions->resume_redisplay ();
4201 Editor::transport_loop_location()
4204 return _session->locations()->auto_loop_location();
4211 Editor::transport_punch_location()
4214 return _session->locations()->auto_punch_location();
4221 Editor::control_layout_scroll (GdkEventScroll* ev)
4223 /* Just forward to the normal canvas scroll method. The coordinate
4224 systems are different but since the canvas is always larger than the
4225 track headers, and aligned with the trackview area, this will work.
4227 In the not too distant future this layout is going away anyway and
4228 headers will be on the canvas.
4230 return canvas_scroll_event (ev, false);
4234 Editor::session_state_saved (string)
4237 _snapshots->redisplay ();
4241 Editor::update_tearoff_visibility()
4243 bool visible = ARDOUR_UI::config()->get_keep_tearoffs();
4244 _mouse_mode_tearoff->set_visible (visible);
4245 _tools_tearoff->set_visible (visible);
4246 if (_zoom_tearoff) {
4247 _zoom_tearoff->set_visible (visible);
4252 Editor::reattach_all_tearoffs ()
4254 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4255 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4256 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4260 Editor::maximise_editing_space ()
4272 Editor::restore_editing_space ()
4284 * Make new playlists for a given track and also any others that belong
4285 * to the same active route group with the `select' property.
4290 Editor::new_playlists (TimeAxisView* v)
4292 begin_reversible_command (_("new playlists"));
4293 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4294 _session->playlists->get (playlists);
4295 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4296 commit_reversible_command ();
4300 * Use a copy of the current playlist for a given track and also any others that belong
4301 * to the same active route group with the `select' property.
4306 Editor::copy_playlists (TimeAxisView* v)
4308 begin_reversible_command (_("copy playlists"));
4309 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4310 _session->playlists->get (playlists);
4311 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4312 commit_reversible_command ();
4315 /** Clear the current playlist for a given track and also any others that belong
4316 * to the same active route group with the `select' property.
4321 Editor::clear_playlists (TimeAxisView* v)
4323 begin_reversible_command (_("clear playlists"));
4324 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4325 _session->playlists->get (playlists);
4326 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4327 commit_reversible_command ();
4331 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4333 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4337 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4339 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4343 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4345 atv.clear_playlist ();
4349 Editor::on_key_press_event (GdkEventKey* ev)
4351 return key_press_focus_accelerator_handler (*this, ev);
4355 Editor::on_key_release_event (GdkEventKey* ev)
4357 return Gtk::Window::on_key_release_event (ev);
4358 // return key_press_focus_accelerator_handler (*this, ev);
4362 Editor::get_y_origin () const
4364 return vertical_adjustment.get_value ();
4367 /** Queue up a change to the viewport x origin.
4368 * @param frame New x origin.
4371 Editor::reset_x_origin (framepos_t frame)
4373 pending_visual_change.add (VisualChange::TimeOrigin);
4374 pending_visual_change.time_origin = frame;
4375 ensure_visual_change_idle_handler ();
4379 Editor::reset_y_origin (double y)
4381 pending_visual_change.add (VisualChange::YOrigin);
4382 pending_visual_change.y_origin = y;
4383 ensure_visual_change_idle_handler ();
4387 Editor::reset_zoom (framecnt_t spp)
4389 if (spp == samples_per_pixel) {
4393 pending_visual_change.add (VisualChange::ZoomLevel);
4394 pending_visual_change.samples_per_pixel = spp;
4395 ensure_visual_change_idle_handler ();
4399 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4401 reset_x_origin (frame);
4404 if (!no_save_visual) {
4405 undo_visual_stack.push_back (current_visual_state(false));
4409 Editor::VisualState::VisualState (bool with_tracks)
4410 : gui_state (with_tracks ? new GUIObjectState : 0)
4414 Editor::VisualState::~VisualState ()
4419 Editor::VisualState*
4420 Editor::current_visual_state (bool with_tracks)
4422 VisualState* vs = new VisualState (with_tracks);
4423 vs->y_position = vertical_adjustment.get_value();
4424 vs->samples_per_pixel = samples_per_pixel;
4425 vs->leftmost_frame = leftmost_frame;
4426 vs->zoom_focus = zoom_focus;
4429 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4436 Editor::undo_visual_state ()
4438 if (undo_visual_stack.empty()) {
4442 VisualState* vs = undo_visual_stack.back();
4443 undo_visual_stack.pop_back();
4446 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4449 use_visual_state (*vs);
4454 Editor::redo_visual_state ()
4456 if (redo_visual_stack.empty()) {
4460 VisualState* vs = redo_visual_stack.back();
4461 redo_visual_stack.pop_back();
4463 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4464 // why do we check here?
4465 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4468 use_visual_state (*vs);
4473 Editor::swap_visual_state ()
4475 if (undo_visual_stack.empty()) {
4476 redo_visual_state ();
4478 undo_visual_state ();
4483 Editor::use_visual_state (VisualState& vs)
4485 PBD::Unwinder<bool> nsv (no_save_visual, true);
4486 DisplaySuspender ds;
4488 vertical_adjustment.set_value (vs.y_position);
4490 set_zoom_focus (vs.zoom_focus);
4491 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4494 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4496 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4497 (*i)->clear_property_cache();
4498 (*i)->reset_visual_state ();
4502 _routes->update_visibility ();
4505 /** This is the core function that controls the zoom level of the canvas. It is called
4506 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4507 * @param spp new number of samples per pixel
4510 Editor::set_samples_per_pixel (framecnt_t spp)
4516 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4517 const framecnt_t lots_of_pixels = 4000;
4519 /* if the zoom level is greater than what you'd get trying to display 3
4520 * days of audio on a really big screen, then it's too big.
4523 if (spp * lots_of_pixels > three_days) {
4527 samples_per_pixel = spp;
4530 tempo_lines->tempo_map_changed();
4533 bool const showing_time_selection = selection->time.length() > 0;
4535 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4536 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4537 (*i)->reshow_selection (selection->time);
4541 ZoomChanged (); /* EMIT_SIGNAL */
4543 ArdourCanvas::GtkCanvasViewport* c;
4545 c = get_track_canvas();
4547 c->canvas()->zoomed ();
4550 if (playhead_cursor) {
4551 playhead_cursor->set_position (playhead_cursor->current_frame ());
4554 refresh_location_display();
4555 _summary->set_overlays_dirty ();
4557 update_marker_labels ();
4563 Editor::queue_visual_videotimeline_update ()
4566 * pending_visual_change.add (VisualChange::VideoTimeline);
4567 * or maybe even more specific: which videotimeline-image
4568 * currently it calls update_video_timeline() to update
4569 * _all outdated_ images on the video-timeline.
4570 * see 'exposeimg()' in video_image_frame.cc
4572 ensure_visual_change_idle_handler ();
4576 Editor::ensure_visual_change_idle_handler ()
4578 if (pending_visual_change.idle_handler_id < 0) {
4579 // see comment in add_to_idle_resize above.
4580 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4581 pending_visual_change.being_handled = false;
4586 Editor::_idle_visual_changer (void* arg)
4588 return static_cast<Editor*>(arg)->idle_visual_changer ();
4592 Editor::idle_visual_changer ()
4594 /* set_horizontal_position() below (and maybe other calls) call
4595 gtk_main_iteration(), so it's possible that a signal will be handled
4596 half-way through this method. If this signal wants an
4597 idle_visual_changer we must schedule another one after this one, so
4598 mark the idle_handler_id as -1 here to allow that. Also make a note
4599 that we are doing the visual change, so that changes in response to
4600 super-rapid-screen-update can be dropped if we are still processing
4604 pending_visual_change.idle_handler_id = -1;
4605 pending_visual_change.being_handled = true;
4607 VisualChange vc = pending_visual_change;
4609 pending_visual_change.pending = (VisualChange::Type) 0;
4611 visual_changer (vc);
4613 pending_visual_change.being_handled = false;
4615 return 0; /* this is always a one-shot call */
4619 Editor::visual_changer (const VisualChange& vc)
4621 double const last_time_origin = horizontal_position ();
4623 if (vc.pending & VisualChange::ZoomLevel) {
4624 set_samples_per_pixel (vc.samples_per_pixel);
4626 compute_fixed_ruler_scale ();
4628 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4629 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4631 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4632 current_bbt_points_begin, current_bbt_points_end);
4633 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4634 current_bbt_points_begin, current_bbt_points_end);
4635 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4637 update_video_timeline();
4640 if (vc.pending & VisualChange::TimeOrigin) {
4641 set_horizontal_position (vc.time_origin / samples_per_pixel);
4644 if (vc.pending & VisualChange::YOrigin) {
4645 vertical_adjustment.set_value (vc.y_origin);
4648 if (last_time_origin == horizontal_position ()) {
4649 /* changed signal not emitted */
4650 update_fixed_rulers ();
4651 redisplay_tempo (true);
4654 if (!(vc.pending & VisualChange::ZoomLevel)) {
4655 update_video_timeline();
4658 _summary->set_overlays_dirty ();
4661 struct EditorOrderTimeAxisSorter {
4662 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4663 return a->order () < b->order ();
4668 Editor::sort_track_selection (TrackViewList& sel)
4670 EditorOrderTimeAxisSorter cmp;
4675 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4678 framepos_t where = 0;
4679 EditPoint ep = _edit_point;
4681 if (Profile->get_mixbus())
4682 if (ep == EditAtSelectedMarker)
4683 ep = EditAtPlayhead;
4685 if (from_outside_canvas && (ep == EditAtMouse)) {
4686 ep = EditAtPlayhead;
4687 } else if (from_context_menu && (ep == EditAtMouse)) {
4688 return canvas_event_sample (&context_click_event, 0, 0);
4691 if (entered_marker) {
4692 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4693 return entered_marker->position();
4696 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4697 ep = EditAtSelectedMarker;
4700 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4701 ep = EditAtPlayhead;
4705 case EditAtPlayhead:
4706 if (_dragging_playhead) {
4707 if (!mouse_frame (where, ignored)) {
4708 /* XXX not right but what can we do ? */
4712 where = _session->audible_frame();
4714 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4717 case EditAtSelectedMarker:
4718 if (!selection->markers.empty()) {
4720 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4723 where = loc->start();
4727 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4735 if (!mouse_frame (where, ignored)) {
4736 /* XXX not right but what can we do ? */
4740 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4748 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4750 if (!_session) return;
4752 begin_reversible_command (cmd);
4756 if ((tll = transport_loop_location()) == 0) {
4757 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4758 XMLNode &before = _session->locations()->get_state();
4759 _session->locations()->add (loc, true);
4760 _session->set_auto_loop_location (loc);
4761 XMLNode &after = _session->locations()->get_state();
4762 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4764 XMLNode &before = tll->get_state();
4765 tll->set_hidden (false, this);
4766 tll->set (start, end);
4767 XMLNode &after = tll->get_state();
4768 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4771 commit_reversible_command ();
4775 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4777 if (!_session) return;
4779 begin_reversible_command (cmd);
4783 if ((tpl = transport_punch_location()) == 0) {
4784 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4785 XMLNode &before = _session->locations()->get_state();
4786 _session->locations()->add (loc, true);
4787 _session->set_auto_punch_location (loc);
4788 XMLNode &after = _session->locations()->get_state();
4789 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4791 XMLNode &before = tpl->get_state();
4792 tpl->set_hidden (false, this);
4793 tpl->set (start, end);
4794 XMLNode &after = tpl->get_state();
4795 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4798 commit_reversible_command ();
4801 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4802 * @param rs List to which found regions are added.
4803 * @param where Time to look at.
4804 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4807 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4809 const TrackViewList* tracks;
4812 tracks = &track_views;
4817 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4819 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4822 boost::shared_ptr<Track> tr;
4823 boost::shared_ptr<Playlist> pl;
4825 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4827 boost::shared_ptr<RegionList> regions = pl->regions_at (
4828 (framepos_t) floor ( (double) where * tr->speed()));
4830 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4831 RegionView* rv = rtv->view()->find_view (*i);
4842 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4844 const TrackViewList* tracks;
4847 tracks = &track_views;
4852 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4853 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4855 boost::shared_ptr<Track> tr;
4856 boost::shared_ptr<Playlist> pl;
4858 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4860 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4861 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4863 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4865 RegionView* rv = rtv->view()->find_view (*i);
4876 /** Get regions using the following method:
4878 * Make a region list using:
4879 * (a) any selected regions
4880 * (b) the intersection of any selected tracks and the edit point(*)
4881 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4883 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4885 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4889 Editor::get_regions_from_selection_and_edit_point ()
4891 RegionSelection regions;
4893 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4894 regions.add (entered_regionview);
4896 regions = selection->regions;
4899 if ( regions.empty() ) {
4900 TrackViewList tracks = selection->tracks;
4902 if (!tracks.empty()) {
4903 /* no region selected or entered, but some selected tracks:
4904 * act on all regions on the selected tracks at the edit point
4906 framepos_t const where = get_preferred_edit_position ();
4907 get_regions_at(regions, where, tracks);
4914 /** Get regions using the following method:
4916 * Make a region list using:
4917 * (a) any selected regions
4918 * (b) the intersection of any selected tracks and the edit point(*)
4919 * (c) if neither exists, then whatever region is under the mouse
4921 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4923 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4926 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4928 RegionSelection regions;
4930 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4931 regions.add (entered_regionview);
4933 regions = selection->regions;
4936 if ( regions.empty() ) {
4937 TrackViewList tracks = selection->tracks;
4939 if (!tracks.empty()) {
4940 /* no region selected or entered, but some selected tracks:
4941 * act on all regions on the selected tracks at the edit point
4943 get_regions_at(regions, pos, tracks);
4950 /** Start with regions that are selected, or the entered regionview if none are selected.
4951 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4952 * of the regions that we started with.
4956 Editor::get_regions_from_selection_and_entered ()
4958 RegionSelection regions = selection->regions;
4960 if (regions.empty() && entered_regionview) {
4961 regions.add (entered_regionview);
4968 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4970 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4971 RouteTimeAxisView* rtav;
4973 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4974 boost::shared_ptr<Playlist> pl;
4975 std::vector<boost::shared_ptr<Region> > results;
4976 boost::shared_ptr<Track> tr;
4978 if ((tr = rtav->track()) == 0) {
4983 if ((pl = (tr->playlist())) != 0) {
4984 boost::shared_ptr<Region> r = pl->region_by_id (id);
4986 RegionView* rv = rtav->view()->find_view (r);
4988 regions.push_back (rv);
4997 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5000 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5001 MidiTimeAxisView* mtav;
5003 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5005 mtav->get_per_region_note_selection (selection);
5012 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5014 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5016 RouteTimeAxisView* tatv;
5018 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5020 boost::shared_ptr<Playlist> pl;
5021 vector<boost::shared_ptr<Region> > results;
5023 boost::shared_ptr<Track> tr;
5025 if ((tr = tatv->track()) == 0) {
5030 if ((pl = (tr->playlist())) != 0) {
5031 if (src_comparison) {
5032 pl->get_source_equivalent_regions (region, results);
5034 pl->get_region_list_equivalent_regions (region, results);
5038 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5039 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5040 regions.push_back (marv);
5049 Editor::show_rhythm_ferret ()
5051 if (rhythm_ferret == 0) {
5052 rhythm_ferret = new RhythmFerret(*this);
5055 rhythm_ferret->set_session (_session);
5056 rhythm_ferret->show ();
5057 rhythm_ferret->present ();
5061 Editor::first_idle ()
5063 MessageDialog* dialog = 0;
5065 if (track_views.size() > 1) {
5066 dialog = new MessageDialog (
5068 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5072 ARDOUR_UI::instance()->flush_pending ();
5075 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5079 // first idle adds route children (automation tracks), so we need to redisplay here
5080 _routes->redisplay ();
5084 if (_session->undo_depth() == 0) {
5085 undo_action->set_sensitive(false);
5087 redo_action->set_sensitive(false);
5088 begin_selection_op_history ();
5094 Editor::_idle_resize (gpointer arg)
5096 return ((Editor*)arg)->idle_resize ();
5100 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5102 if (resize_idle_id < 0) {
5103 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5104 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5105 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5107 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5108 _pending_resize_amount = 0;
5111 /* make a note of the smallest resulting height, so that we can clamp the
5112 lower limit at TimeAxisView::hSmall */
5114 int32_t min_resulting = INT32_MAX;
5116 _pending_resize_amount += h;
5117 _pending_resize_view = view;
5119 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5121 if (selection->tracks.contains (_pending_resize_view)) {
5122 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5123 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5127 if (min_resulting < 0) {
5132 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5133 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5137 /** Handle pending resizing of tracks */
5139 Editor::idle_resize ()
5141 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5143 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5144 selection->tracks.contains (_pending_resize_view)) {
5146 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5147 if (*i != _pending_resize_view) {
5148 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5153 _pending_resize_amount = 0;
5154 _group_tabs->set_dirty ();
5155 resize_idle_id = -1;
5163 ENSURE_GUI_THREAD (*this, &Editor::located);
5166 playhead_cursor->set_position (_session->audible_frame ());
5167 if (_follow_playhead && !_pending_initial_locate) {
5168 reset_x_origin_to_follow_playhead ();
5172 _pending_locate_request = false;
5173 _pending_initial_locate = false;
5177 Editor::region_view_added (RegionView * rv)
5179 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5180 if (rv->region ()->id () == (*pr)) {
5181 selection->add (rv);
5182 selection->regions.pending.erase (pr);
5187 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5189 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5190 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5191 if (rv->region()->id () == (*rnote).first) {
5192 mrv->select_notes ((*rnote).second);
5193 selection->pending_midi_note_selection.erase(rnote);
5199 _summary->set_background_dirty ();
5203 Editor::region_view_removed ()
5205 _summary->set_background_dirty ();
5209 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5211 TrackViewList::const_iterator j = track_views.begin ();
5212 while (j != track_views.end()) {
5213 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5214 if (rtv && rtv->route() == r) {
5225 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5229 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5230 TimeAxisView* tv = axis_view_from_route (*i);
5240 Editor::suspend_route_redisplay ()
5243 _routes->suspend_redisplay();
5248 Editor::resume_route_redisplay ()
5251 _routes->redisplay(); // queue redisplay
5252 _routes->resume_redisplay();
5257 Editor::add_routes (RouteList& routes)
5259 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5261 RouteTimeAxisView *rtv;
5262 list<RouteTimeAxisView*> new_views;
5263 TrackViewList new_selection;
5264 bool from_scratch = (track_views.size() == 0);
5266 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5267 boost::shared_ptr<Route> route = (*x);
5269 if (route->is_auditioner() || route->is_monitor()) {
5273 DataType dt = route->input()->default_type();
5275 if (dt == ARDOUR::DataType::AUDIO) {
5276 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5277 rtv->set_route (route);
5278 } else if (dt == ARDOUR::DataType::MIDI) {
5279 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5280 rtv->set_route (route);
5282 throw unknown_type();
5285 new_views.push_back (rtv);
5286 track_views.push_back (rtv);
5287 new_selection.push_back (rtv);
5289 rtv->effective_gain_display ();
5291 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5292 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5295 if (new_views.size() > 0) {
5296 _routes->routes_added (new_views);
5297 _summary->routes_added (new_views);
5300 if (!from_scratch) {
5301 selection->tracks.clear();
5302 selection->add (new_selection);
5303 begin_selection_op_history();
5306 if (show_editor_mixer_when_tracks_arrive) {
5307 show_editor_mixer (true);
5310 editor_list_button.set_sensitive (true);
5314 Editor::timeaxisview_deleted (TimeAxisView *tv)
5316 if (tv == entered_track) {
5320 if (_session && _session->deletion_in_progress()) {
5321 /* the situation is under control */
5325 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5327 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5329 _routes->route_removed (tv);
5331 TimeAxisView::Children c = tv->get_child_list ();
5332 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5333 if (entered_track == i->get()) {
5338 /* remove it from the list of track views */
5340 TrackViewList::iterator i;
5342 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5343 i = track_views.erase (i);
5346 /* update whatever the current mixer strip is displaying, if revelant */
5348 boost::shared_ptr<Route> route;
5351 route = rtav->route ();
5354 if (current_mixer_strip && current_mixer_strip->route() == route) {
5356 TimeAxisView* next_tv;
5358 if (track_views.empty()) {
5360 } else if (i == track_views.end()) {
5361 next_tv = track_views.front();
5368 set_selected_mixer_strip (*next_tv);
5370 /* make the editor mixer strip go away setting the
5371 * button to inactive (which also unticks the menu option)
5374 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5380 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5382 if (apply_to_selection) {
5383 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5385 TrackSelection::iterator j = i;
5388 hide_track_in_display (*i, false);
5393 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5395 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5396 // this will hide the mixer strip
5397 set_selected_mixer_strip (*tv);
5400 _routes->hide_track_in_display (*tv);
5405 Editor::sync_track_view_list_and_routes ()
5407 track_views = TrackViewList (_routes->views ());
5409 _summary->set_background_dirty();
5410 _group_tabs->set_dirty ();
5412 return false; // do not call again (until needed)
5416 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5418 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5423 /** Find a RouteTimeAxisView by the ID of its route */
5425 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5427 RouteTimeAxisView* v;
5429 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5430 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5431 if(v->route()->id() == id) {
5441 Editor::fit_route_group (RouteGroup *g)
5443 TrackViewList ts = axis_views_from_routes (g->route_list ());
5448 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5450 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5453 _session->cancel_audition ();
5457 if (_session->is_auditioning()) {
5458 _session->cancel_audition ();
5459 if (r == last_audition_region) {
5464 _session->audition_region (r);
5465 last_audition_region = r;
5470 Editor::hide_a_region (boost::shared_ptr<Region> r)
5472 r->set_hidden (true);
5476 Editor::show_a_region (boost::shared_ptr<Region> r)
5478 r->set_hidden (false);
5482 Editor::audition_region_from_region_list ()
5484 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5488 Editor::hide_region_from_region_list ()
5490 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5494 Editor::show_region_in_region_list ()
5496 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5500 Editor::step_edit_status_change (bool yn)
5503 start_step_editing ();
5505 stop_step_editing ();
5510 Editor::start_step_editing ()
5512 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5516 Editor::stop_step_editing ()
5518 step_edit_connection.disconnect ();
5522 Editor::check_step_edit ()
5524 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5525 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5527 mtv->check_step_edit ();
5531 return true; // do it again, till we stop
5535 Editor::scroll_press (Direction dir)
5537 ++_scroll_callbacks;
5539 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5540 /* delay the first auto-repeat */
5546 scroll_backward (1);
5554 scroll_up_one_track ();
5558 scroll_down_one_track ();
5562 /* do hacky auto-repeat */
5563 if (!_scroll_connection.connected ()) {
5565 _scroll_connection = Glib::signal_timeout().connect (
5566 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5569 _scroll_callbacks = 0;
5576 Editor::scroll_release ()
5578 _scroll_connection.disconnect ();
5581 /** Queue a change for the Editor viewport x origin to follow the playhead */
5583 Editor::reset_x_origin_to_follow_playhead ()
5585 framepos_t const frame = playhead_cursor->current_frame ();
5587 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5589 if (_session->transport_speed() < 0) {
5591 if (frame > (current_page_samples() / 2)) {
5592 center_screen (frame-(current_page_samples()/2));
5594 center_screen (current_page_samples()/2);
5601 if (frame < leftmost_frame) {
5603 if (_session->transport_rolling()) {
5604 /* rolling; end up with the playhead at the right of the page */
5605 l = frame - current_page_samples ();
5607 /* not rolling: end up with the playhead 1/4 of the way along the page */
5608 l = frame - current_page_samples() / 4;
5612 if (_session->transport_rolling()) {
5613 /* rolling: end up with the playhead on the left of the page */
5616 /* not rolling: end up with the playhead 3/4 of the way along the page */
5617 l = frame - 3 * current_page_samples() / 4;
5625 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5631 Editor::super_rapid_screen_update ()
5633 if (!_session || !_session->engine().running()) {
5637 /* METERING / MIXER STRIPS */
5639 /* update track meters, if required */
5640 if (is_mapped() && meters_running) {
5641 RouteTimeAxisView* rtv;
5642 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5643 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5644 rtv->fast_update ();
5649 /* and any current mixer strip */
5650 if (current_mixer_strip) {
5651 current_mixer_strip->fast_update ();
5654 /* PLAYHEAD AND VIEWPORT */
5656 framepos_t const frame = _session->audible_frame();
5658 /* There are a few reasons why we might not update the playhead / viewport stuff:
5660 * 1. we don't update things when there's a pending locate request, otherwise
5661 * when the editor requests a locate there is a chance that this method
5662 * will move the playhead before the locate request is processed, causing
5664 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5665 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5668 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5670 last_update_frame = frame;
5672 if (!_dragging_playhead) {
5673 playhead_cursor->set_position (frame);
5676 if (!_stationary_playhead) {
5678 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5679 /* We only do this if we aren't already
5680 handling a visual change (ie if
5681 pending_visual_change.being_handled is
5682 false) so that these requests don't stack
5683 up there are too many of them to handle in
5686 reset_x_origin_to_follow_playhead ();
5691 if (!_dragging_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5692 framepos_t const frame = playhead_cursor->current_frame ();
5693 double target = ((double)frame - (double)current_page_samples()/3.0);
5694 if (target <= 0.0) {
5697 // compare to EditorCursor::set_position()
5698 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5699 double const new_pos = sample_to_pixel_unrounded (target);
5700 if (rint (new_pos) != rint (old_pos)) {
5701 reset_x_origin (pixel_to_sample (floor (new_pos)));
5712 Editor::session_going_away ()
5714 _have_idled = false;
5716 _session_connections.drop_connections ();
5718 super_rapid_screen_update_connection.disconnect ();
5720 selection->clear ();
5721 cut_buffer->clear ();
5723 clicked_regionview = 0;
5724 clicked_axisview = 0;
5725 clicked_routeview = 0;
5726 entered_regionview = 0;
5728 last_update_frame = 0;
5731 playhead_cursor->hide ();
5733 /* rip everything out of the list displays */
5737 _route_groups->clear ();
5739 /* do this first so that deleting a track doesn't reset cms to null
5740 and thus cause a leak.
5743 if (current_mixer_strip) {
5744 if (current_mixer_strip->get_parent() != 0) {
5745 global_hpacker.remove (*current_mixer_strip);
5747 delete current_mixer_strip;
5748 current_mixer_strip = 0;
5751 /* delete all trackviews */
5753 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5756 track_views.clear ();
5758 nudge_clock->set_session (0);
5760 editor_list_button.set_active(false);
5761 editor_list_button.set_sensitive(false);
5763 /* clear tempo/meter rulers */
5764 remove_metric_marks ();
5766 clear_marker_display ();
5768 stop_step_editing ();
5770 /* get rid of any existing editor mixer strip */
5772 WindowTitle title(Glib::get_application_name());
5773 title += _("Editor");
5775 set_title (title.get_string());
5777 SessionHandlePtr::session_going_away ();
5782 Editor::show_editor_list (bool yn)
5785 _the_notebook.show ();
5787 _the_notebook.hide ();
5792 Editor::change_region_layering_order (bool from_context_menu)
5794 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5796 if (!clicked_routeview) {
5797 if (layering_order_editor) {
5798 layering_order_editor->hide ();
5803 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5809 boost::shared_ptr<Playlist> pl = track->playlist();
5815 if (layering_order_editor == 0) {
5816 layering_order_editor = new RegionLayeringOrderEditor (*this);
5819 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5820 layering_order_editor->maybe_present ();
5824 Editor::update_region_layering_order_editor ()
5826 if (layering_order_editor && layering_order_editor->is_visible ()) {
5827 change_region_layering_order (true);
5832 Editor::setup_fade_images ()
5834 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5835 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5836 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5837 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5838 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5840 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5841 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5842 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5843 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5844 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5846 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5847 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5848 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5849 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5850 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5852 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5853 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5854 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5855 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5856 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5860 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5862 Editor::action_menu_item (std::string const & name)
5864 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5867 return *manage (a->create_menu_item ());
5871 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5873 EventBox* b = manage (new EventBox);
5874 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5875 Label* l = manage (new Label (name));
5879 _the_notebook.append_page (widget, *b);
5883 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5885 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5886 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5889 if (ev->type == GDK_2BUTTON_PRESS) {
5891 /* double-click on a notebook tab shrinks or expands the notebook */
5893 if (_notebook_shrunk) {
5894 if (pre_notebook_shrink_pane_width) {
5895 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5897 _notebook_shrunk = false;
5899 pre_notebook_shrink_pane_width = edit_pane.get_position();
5901 /* this expands the LHS of the edit pane to cover the notebook
5902 PAGE but leaves the tabs visible.
5904 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5905 _notebook_shrunk = true;
5913 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5915 using namespace Menu_Helpers;
5917 MenuList& items = _control_point_context_menu.items ();
5920 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5921 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5922 if (!can_remove_control_point (item)) {
5923 items.back().set_sensitive (false);
5926 _control_point_context_menu.popup (event->button.button, event->button.time);
5930 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5932 using namespace Menu_Helpers;
5934 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5939 /* We need to get the selection here and pass it to the operations, since
5940 popping up the menu will cause a region leave event which clears
5941 entered_regionview. */
5943 MidiRegionView& mrv = note->region_view();
5944 const RegionSelection rs = get_regions_from_selection_and_entered ();
5946 MenuList& items = _note_context_menu.items();
5949 items.push_back(MenuElem(_("Delete"),
5950 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5951 items.push_back(MenuElem(_("Edit..."),
5952 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5953 items.push_back(MenuElem(_("Legatize"),
5954 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5955 items.push_back(MenuElem(_("Quantize..."),
5956 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5957 items.push_back(MenuElem(_("Remove Overlap"),
5958 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5959 items.push_back(MenuElem(_("Transform..."),
5960 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5962 _note_context_menu.popup (event->button.button, event->button.time);
5966 Editor::zoom_vertical_modifier_released()
5968 _stepping_axis_view = 0;
5972 Editor::ui_parameter_changed (string parameter)
5974 if (parameter == "icon-set") {
5975 while (!_cursor_stack.empty()) {
5976 _cursor_stack.pop_back();
5978 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5979 _cursor_stack.push_back(_cursors->grabber);
5980 } else if (parameter == "draggable-playhead") {
5981 if (_verbose_cursor) {
5982 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());