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 "region_layering_order_editor.h"
119 #include "rgb_macros.h"
120 #include "rhythm_ferret.h"
121 #include "selection.h"
123 #include "tempo_lines.h"
124 #include "time_axis_view.h"
127 #include "verbose_cursor.h"
132 using namespace ARDOUR;
133 using namespace ARDOUR_UI_UTILS;
136 using namespace Glib;
137 using namespace Gtkmm2ext;
138 using namespace Editing;
140 using PBD::internationalize;
142 using Gtkmm2ext::Keyboard;
144 double Editor::timebar_height = 15.0;
146 static const gchar *_snap_type_strings[] = {
180 static const gchar *_snap_mode_strings[] = {
187 static const gchar *_edit_point_strings[] = {
194 static const gchar *_edit_mode_strings[] = {
202 static const gchar *_zoom_focus_strings[] = {
212 #ifdef USE_RUBBERBAND
213 static const gchar *_rb_opt_strings[] = {
216 N_("Balanced multitimbral mixture"),
217 N_("Unpitched percussion with stable notes"),
218 N_("Crisp monophonic instrumental"),
219 N_("Unpitched solo percussion"),
220 N_("Resample without preserving pitch"),
225 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
228 pane_size_watcher (Paned* pane)
230 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
234 Quartz: impossible to access
236 so stop that by preventing it from ever getting too narrow. 35
237 pixels is basically a rough guess at the tab width.
242 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
244 gint pos = pane->get_position ();
246 if (pos > max_width_of_lhs) {
247 pane->set_position (max_width_of_lhs);
252 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
254 , _mouse_changed_selection (false)
255 /* time display buttons */
256 , minsec_label (_("Mins:Secs"))
257 , bbt_label (_("Bars:Beats"))
258 , timecode_label (_("Timecode"))
259 , samples_label (_("Samples"))
260 , tempo_label (_("Tempo"))
261 , meter_label (_("Meter"))
262 , mark_label (_("Location Markers"))
263 , range_mark_label (_("Range Markers"))
264 , transport_mark_label (_("Loop/Punch Ranges"))
265 , cd_mark_label (_("CD Markers"))
266 , videotl_label (_("Video Timeline"))
267 , edit_packer (4, 4, true)
269 /* the values here don't matter: layout widgets
270 reset them as needed.
273 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
274 , horizontal_adjustment (0.0, 0.0, 1e16)
275 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
277 , controls_layout (unused_adjustment, vertical_adjustment)
279 /* tool bar related */
281 , toolbar_selection_clock_table (2,3)
282 , _mouse_mode_tearoff (0)
283 , automation_mode_button (_("mode"))
287 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
288 , selection_op_cmd_depth (0)
289 , selection_op_history_it (0)
293 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
294 , meters_running(false)
295 , _pending_locate_request (false)
296 , _pending_initial_locate (false)
297 , _last_cut_copy_source_track (0)
299 , _region_selection_change_updates_region_list (true)
300 , _following_mixer_selection (false)
301 , _control_point_toggled_on_press (false)
302 , _stepping_axis_view (0)
306 /* we are a singleton */
308 PublicEditor::_instance = this;
312 selection = new Selection (this);
313 cut_buffer = new Selection (this);
314 _selection_memento = new SelectionMemento ();
315 selection_op_history.clear();
318 clicked_regionview = 0;
319 clicked_axisview = 0;
320 clicked_routeview = 0;
321 clicked_control_point = 0;
322 last_update_frame = 0;
325 _drags = new DragManager (this);
328 current_mixer_strip = 0;
331 snap_type_strings = I18N (_snap_type_strings);
332 snap_mode_strings = I18N (_snap_mode_strings);
333 zoom_focus_strings = I18N (_zoom_focus_strings);
334 edit_mode_strings = I18N (_edit_mode_strings);
335 edit_point_strings = I18N (_edit_point_strings);
336 #ifdef USE_RUBBERBAND
337 rb_opt_strings = I18N (_rb_opt_strings);
341 build_edit_mode_menu();
342 build_zoom_focus_menu();
343 build_track_count_menu();
344 build_snap_mode_menu();
345 build_snap_type_menu();
346 build_edit_point_menu();
348 snap_threshold = 5.0;
349 bbt_beat_subdivision = 4;
350 _visible_canvas_width = 0;
351 _visible_canvas_height = 0;
352 autoscroll_horizontal_allowed = false;
353 autoscroll_vertical_allowed = false;
358 current_interthread_info = 0;
359 _show_measures = true;
361 show_gain_after_trim = false;
363 have_pending_keyboard_selection = false;
364 _follow_playhead = true;
365 _stationary_playhead = false;
366 editor_ruler_menu = 0;
367 no_ruler_shown_update = false;
369 range_marker_menu = 0;
370 marker_menu_item = 0;
371 tempo_or_meter_marker_menu = 0;
372 transport_marker_menu = 0;
373 new_transport_marker_menu = 0;
374 editor_mixer_strip_width = Wide;
375 show_editor_mixer_when_tracks_arrive = false;
376 region_edit_menu_split_multichannel_item = 0;
377 region_edit_menu_split_item = 0;
380 current_stepping_trackview = 0;
382 entered_regionview = 0;
384 clear_entered_track = false;
387 button_release_can_deselect = true;
388 _dragging_playhead = false;
389 _dragging_edit_point = false;
390 select_new_marker = false;
392 layering_order_editor = 0;
393 no_save_visual = false;
395 within_track_canvas = false;
397 scrubbing_direction = 0;
401 location_marker_color = ARDOUR_UI::config()->color ("location marker");
402 location_range_color = ARDOUR_UI::config()->color ("location range");
403 location_cd_marker_color = ARDOUR_UI::config()->color ("location cd marker");
404 location_loop_color = ARDOUR_UI::config()->color ("location loop");
405 location_punch_color = ARDOUR_UI::config()->color ("location punch");
407 zoom_focus = ZoomFocusPlayhead;
408 _edit_point = EditAtMouse;
409 _visible_track_count = -1;
411 samples_per_pixel = 2048; /* too early to use reset_zoom () */
413 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
414 TimeAxisView::setup_sizes ();
415 Marker::setup_sizes (timebar_height);
417 _scroll_callbacks = 0;
419 bbt_label.set_name ("EditorRulerLabel");
420 bbt_label.set_size_request (-1, (int)timebar_height);
421 bbt_label.set_alignment (1.0, 0.5);
422 bbt_label.set_padding (5,0);
424 bbt_label.set_no_show_all();
425 minsec_label.set_name ("EditorRulerLabel");
426 minsec_label.set_size_request (-1, (int)timebar_height);
427 minsec_label.set_alignment (1.0, 0.5);
428 minsec_label.set_padding (5,0);
429 minsec_label.hide ();
430 minsec_label.set_no_show_all();
431 timecode_label.set_name ("EditorRulerLabel");
432 timecode_label.set_size_request (-1, (int)timebar_height);
433 timecode_label.set_alignment (1.0, 0.5);
434 timecode_label.set_padding (5,0);
435 timecode_label.hide ();
436 timecode_label.set_no_show_all();
437 samples_label.set_name ("EditorRulerLabel");
438 samples_label.set_size_request (-1, (int)timebar_height);
439 samples_label.set_alignment (1.0, 0.5);
440 samples_label.set_padding (5,0);
441 samples_label.hide ();
442 samples_label.set_no_show_all();
444 tempo_label.set_name ("EditorRulerLabel");
445 tempo_label.set_size_request (-1, (int)timebar_height);
446 tempo_label.set_alignment (1.0, 0.5);
447 tempo_label.set_padding (5,0);
449 tempo_label.set_no_show_all();
451 meter_label.set_name ("EditorRulerLabel");
452 meter_label.set_size_request (-1, (int)timebar_height);
453 meter_label.set_alignment (1.0, 0.5);
454 meter_label.set_padding (5,0);
456 meter_label.set_no_show_all();
458 if (Profile->get_trx()) {
459 mark_label.set_text (_("Markers"));
461 mark_label.set_name ("EditorRulerLabel");
462 mark_label.set_size_request (-1, (int)timebar_height);
463 mark_label.set_alignment (1.0, 0.5);
464 mark_label.set_padding (5,0);
466 mark_label.set_no_show_all();
468 cd_mark_label.set_name ("EditorRulerLabel");
469 cd_mark_label.set_size_request (-1, (int)timebar_height);
470 cd_mark_label.set_alignment (1.0, 0.5);
471 cd_mark_label.set_padding (5,0);
472 cd_mark_label.hide();
473 cd_mark_label.set_no_show_all();
475 videotl_bar_height = 4;
476 videotl_label.set_name ("EditorRulerLabel");
477 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
478 videotl_label.set_alignment (1.0, 0.5);
479 videotl_label.set_padding (5,0);
480 videotl_label.hide();
481 videotl_label.set_no_show_all();
483 range_mark_label.set_name ("EditorRulerLabel");
484 range_mark_label.set_size_request (-1, (int)timebar_height);
485 range_mark_label.set_alignment (1.0, 0.5);
486 range_mark_label.set_padding (5,0);
487 range_mark_label.hide();
488 range_mark_label.set_no_show_all();
490 transport_mark_label.set_name ("EditorRulerLabel");
491 transport_mark_label.set_size_request (-1, (int)timebar_height);
492 transport_mark_label.set_alignment (1.0, 0.5);
493 transport_mark_label.set_padding (5,0);
494 transport_mark_label.hide();
495 transport_mark_label.set_no_show_all();
497 initialize_canvas ();
499 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
501 _summary = new EditorSummary (this);
503 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
504 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
506 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
508 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
509 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
511 edit_controls_vbox.set_spacing (0);
512 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
513 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
515 HBox* h = manage (new HBox);
516 _group_tabs = new EditorGroupTabs (this);
517 if (!ARDOUR::Profile->get_trx()) {
518 h->pack_start (*_group_tabs, PACK_SHRINK);
520 h->pack_start (edit_controls_vbox);
521 controls_layout.add (*h);
523 controls_layout.set_name ("EditControlsBase");
524 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
525 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
526 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
528 _cursors = new MouseCursors;
529 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
530 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
532 /* Push default cursor to ever-present bottom of cursor stack. */
533 push_canvas_cursor(_cursors->grabber);
535 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
537 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
538 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
539 pad_line_1->set_outline_color (0xFF0000FF);
545 edit_packer.set_col_spacings (0);
546 edit_packer.set_row_spacings (0);
547 edit_packer.set_homogeneous (false);
548 edit_packer.set_border_width (0);
549 edit_packer.set_name ("EditorWindow");
551 time_bars_event_box.add (time_bars_vbox);
552 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
553 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
555 /* labels for the time bars */
556 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
558 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
560 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
562 bottom_hbox.set_border_width (2);
563 bottom_hbox.set_spacing (3);
565 _route_groups = new EditorRouteGroups (this);
566 _routes = new EditorRoutes (this);
567 _regions = new EditorRegions (this);
568 _snapshots = new EditorSnapshots (this);
569 _locations = new EditorLocations (this);
571 /* these are static location signals */
573 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
574 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
575 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
577 add_notebook_page (_("Regions"), _regions->widget ());
578 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
579 add_notebook_page (_("Snapshots"), _snapshots->widget ());
580 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
581 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
583 _the_notebook.set_show_tabs (true);
584 _the_notebook.set_scrollable (true);
585 _the_notebook.popup_disable ();
586 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
587 _the_notebook.show_all ();
589 _notebook_shrunk = false;
591 editor_summary_pane.pack1(edit_packer);
593 Button* summary_arrows_left_left = manage (new Button);
594 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
595 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
596 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
598 Button* summary_arrows_left_right = manage (new Button);
599 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
600 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
601 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
603 VBox* summary_arrows_left = manage (new VBox);
604 summary_arrows_left->pack_start (*summary_arrows_left_left);
605 summary_arrows_left->pack_start (*summary_arrows_left_right);
607 Button* summary_arrows_right_up = manage (new Button);
608 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
609 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
610 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
612 Button* summary_arrows_right_down = manage (new Button);
613 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
614 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
615 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
617 VBox* summary_arrows_right = manage (new VBox);
618 summary_arrows_right->pack_start (*summary_arrows_right_up);
619 summary_arrows_right->pack_start (*summary_arrows_right_down);
621 Frame* summary_frame = manage (new Frame);
622 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
624 summary_frame->add (*_summary);
625 summary_frame->show ();
627 _summary_hbox.pack_start (*summary_arrows_left, false, false);
628 _summary_hbox.pack_start (*summary_frame, true, true);
629 _summary_hbox.pack_start (*summary_arrows_right, false, false);
631 if (!ARDOUR::Profile->get_trx()) {
632 editor_summary_pane.pack2 (_summary_hbox);
635 edit_pane.pack1 (editor_summary_pane, true, true);
636 if (!ARDOUR::Profile->get_trx()) {
637 edit_pane.pack2 (_the_notebook, false, true);
640 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
642 /* XXX: editor_summary_pane might need similar to the edit_pane */
644 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
646 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
647 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
649 top_hbox.pack_start (toolbar_frame);
651 HBox *hbox = manage (new HBox);
652 hbox->pack_start (edit_pane, true, true);
654 global_vpacker.pack_start (top_hbox, false, false);
655 global_vpacker.pack_start (*hbox, true, true);
657 global_hpacker.pack_start (global_vpacker, true, true);
659 set_name ("EditorWindow");
660 add_accel_group (ActionManager::ui_manager->get_accel_group());
662 status_bar_hpacker.show ();
664 vpacker.pack_end (status_bar_hpacker, false, false);
665 vpacker.pack_end (global_hpacker, true, true);
667 /* register actions now so that set_state() can find them and set toggles/checks etc */
670 /* when we start using our own keybinding system for the editor, this
671 * will be uncommented
677 set_zoom_focus (zoom_focus);
678 set_visible_track_count (_visible_track_count);
679 _snap_type = SnapToBeat;
680 set_snap_to (_snap_type);
681 _snap_mode = SnapOff;
682 set_snap_mode (_snap_mode);
683 set_mouse_mode (MouseObject, true);
684 pre_internal_snap_type = _snap_type;
685 pre_internal_snap_mode = _snap_mode;
686 internal_snap_type = _snap_type;
687 internal_snap_mode = _snap_mode;
688 set_edit_point_preference (EditAtMouse, true);
690 _playlist_selector = new PlaylistSelector();
691 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
693 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
697 nudge_forward_button.set_name ("nudge button");
698 nudge_forward_button.set_image(::get_icon("nudge_right"));
700 nudge_backward_button.set_name ("nudge button");
701 nudge_backward_button.set_image(::get_icon("nudge_left"));
703 fade_context_menu.set_name ("ArdourContextMenu");
705 /* icons, titles, WM stuff */
707 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
708 Glib::RefPtr<Gdk::Pixbuf> icon;
710 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
711 window_icons.push_back (icon);
713 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
714 window_icons.push_back (icon);
716 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
717 window_icons.push_back (icon);
719 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
720 window_icons.push_back (icon);
722 if (!window_icons.empty()) {
723 // set_icon_list (window_icons);
724 set_default_icon_list (window_icons);
727 WindowTitle title(Glib::get_application_name());
728 title += _("Editor");
729 set_title (title.get_string());
730 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
733 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
735 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
736 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
738 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
740 /* allow external control surfaces/protocols to do various things */
742 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
743 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
744 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
745 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
746 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
747 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
748 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
749 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
750 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
751 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
752 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
753 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
754 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
755 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
757 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
758 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
759 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
760 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
761 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
763 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
765 /* problematic: has to return a value and thus cannot be x-thread */
767 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
769 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
770 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
772 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
774 _ignore_region_action = false;
775 _last_region_menu_was_main = false;
776 _popup_region_menu_item = 0;
778 _ignore_follow_edits = false;
780 _show_marker_lines = false;
782 /* Button bindings */
784 button_bindings = new Bindings;
786 XMLNode* node = button_settings();
788 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
789 button_bindings->load (**i);
795 /* grab current parameter state */
796 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
797 ARDOUR_UI::config()->map_parameters (pc);
799 setup_fade_images ();
806 delete button_bindings;
808 delete _route_groups;
809 delete _track_canvas_viewport;
815 Editor::button_settings () const
817 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
818 XMLNode* node = find_named_node (*settings, X_("Buttons"));
821 node = new XMLNode (X_("Buttons"));
828 Editor::add_toplevel_menu (Container& cont)
830 vpacker.pack_start (cont, false, false);
835 Editor::add_transport_frame (Container& cont)
837 if(ARDOUR::Profile->get_mixbus()) {
838 global_vpacker.pack_start (cont, false, false);
839 global_vpacker.reorder_child (cont, 0);
842 vpacker.pack_start (cont, false, false);
847 Editor::get_smart_mode () const
849 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
853 Editor::catch_vanishing_regionview (RegionView *rv)
855 /* note: the selection will take care of the vanishing
856 audioregionview by itself.
859 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
863 if (clicked_regionview == rv) {
864 clicked_regionview = 0;
867 if (entered_regionview == rv) {
868 set_entered_regionview (0);
871 if (!_all_region_actions_sensitized) {
872 sensitize_all_region_actions (true);
877 Editor::set_entered_regionview (RegionView* rv)
879 if (rv == entered_regionview) {
883 if (entered_regionview) {
884 entered_regionview->exited ();
887 entered_regionview = rv;
889 if (entered_regionview != 0) {
890 entered_regionview->entered ();
893 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
894 /* This RegionView entry might have changed what region actions
895 are allowed, so sensitize them all in case a key is pressed.
897 sensitize_all_region_actions (true);
902 Editor::set_entered_track (TimeAxisView* tav)
905 entered_track->exited ();
911 entered_track->entered ();
916 Editor::show_window ()
918 if (!is_visible ()) {
922 /* XXX: this is a bit unfortunate; it would probably
923 be nicer if we could just call show () above rather
924 than needing the show_all ()
927 /* re-hide stuff if necessary */
928 editor_list_button_toggled ();
929 parameter_changed ("show-summary");
930 parameter_changed ("show-group-tabs");
931 parameter_changed ("show-zoom-tools");
933 /* now reset all audio_time_axis heights, because widgets might need
939 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
940 tv = (static_cast<TimeAxisView*>(*i));
944 if (current_mixer_strip) {
945 current_mixer_strip->hide_things ();
946 current_mixer_strip->parameter_changed ("mixer-element-visibility");
954 Editor::instant_save ()
956 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
961 _session->add_instant_xml(get_state());
963 Config->add_instant_xml(get_state());
968 Editor::control_vertical_zoom_in_all ()
970 tav_zoom_smooth (false, true);
974 Editor::control_vertical_zoom_out_all ()
976 tav_zoom_smooth (true, true);
980 Editor::control_vertical_zoom_in_selected ()
982 tav_zoom_smooth (false, false);
986 Editor::control_vertical_zoom_out_selected ()
988 tav_zoom_smooth (true, false);
992 Editor::control_view (uint32_t view)
994 goto_visual_state (view);
998 Editor::control_unselect ()
1000 selection->clear_tracks ();
1004 Editor::control_select (uint32_t rid, Selection::Operation op)
1006 /* handles the (static) signal from the ControlProtocol class that
1007 * requests setting the selected track to a given RID
1014 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1020 TimeAxisView* tav = axis_view_from_route (r);
1024 case Selection::Add:
1025 selection->add (tav);
1027 case Selection::Toggle:
1028 selection->toggle (tav);
1030 case Selection::Extend:
1032 case Selection::Set:
1033 selection->set (tav);
1037 selection->clear_tracks ();
1042 Editor::control_step_tracks_up ()
1044 scroll_tracks_up_line ();
1048 Editor::control_step_tracks_down ()
1050 scroll_tracks_down_line ();
1054 Editor::control_scroll (float fraction)
1056 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1062 double step = fraction * current_page_samples();
1065 _control_scroll_target is an optional<T>
1067 it acts like a pointer to an framepos_t, with
1068 a operator conversion to boolean to check
1069 that it has a value could possibly use
1070 playhead_cursor->current_frame to store the
1071 value and a boolean in the class to know
1072 when it's out of date
1075 if (!_control_scroll_target) {
1076 _control_scroll_target = _session->transport_frame();
1077 _dragging_playhead = true;
1080 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1081 *_control_scroll_target = 0;
1082 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1083 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1085 *_control_scroll_target += (framepos_t) trunc (step);
1088 /* move visuals, we'll catch up with it later */
1090 playhead_cursor->set_position (*_control_scroll_target);
1091 UpdateAllTransportClocks (*_control_scroll_target);
1093 if (*_control_scroll_target > (current_page_samples() / 2)) {
1094 /* try to center PH in window */
1095 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1101 Now we do a timeout to actually bring the session to the right place
1102 according to the playhead. This is to avoid reading disk buffers on every
1103 call to control_scroll, which is driven by ScrollTimeline and therefore
1104 probably by a control surface wheel which can generate lots of events.
1106 /* cancel the existing timeout */
1108 control_scroll_connection.disconnect ();
1110 /* add the next timeout */
1112 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1116 Editor::deferred_control_scroll (framepos_t /*target*/)
1118 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1119 // reset for next stream
1120 _control_scroll_target = boost::none;
1121 _dragging_playhead = false;
1126 Editor::access_action (std::string action_group, std::string action_item)
1132 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1135 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1143 Editor::on_realize ()
1145 Window::on_realize ();
1148 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1149 start_lock_event_timing ();
1152 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1156 Editor::start_lock_event_timing ()
1158 /* check if we should lock the GUI every 30 seconds */
1160 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1164 Editor::generic_event_handler (GdkEvent* ev)
1167 case GDK_BUTTON_PRESS:
1168 case GDK_BUTTON_RELEASE:
1169 case GDK_MOTION_NOTIFY:
1171 case GDK_KEY_RELEASE:
1172 gettimeofday (&last_event_time, 0);
1175 case GDK_LEAVE_NOTIFY:
1176 switch (ev->crossing.detail) {
1177 case GDK_NOTIFY_UNKNOWN:
1178 case GDK_NOTIFY_INFERIOR:
1179 case GDK_NOTIFY_ANCESTOR:
1181 case GDK_NOTIFY_VIRTUAL:
1182 case GDK_NOTIFY_NONLINEAR:
1183 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1184 /* leaving window, so reset focus, thus ending any and
1185 all text entry operations.
1200 Editor::lock_timeout_callback ()
1202 struct timeval now, delta;
1204 gettimeofday (&now, 0);
1206 timersub (&now, &last_event_time, &delta);
1208 if (delta.tv_sec > (time_t) ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1210 /* don't call again. Returning false will effectively
1211 disconnect us from the timer callback.
1213 unlock() will call start_lock_event_timing() to get things
1223 Editor::map_position_change (framepos_t frame)
1225 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1227 if (_session == 0) {
1231 if (_follow_playhead) {
1232 center_screen (frame);
1235 playhead_cursor->set_position (frame);
1239 Editor::center_screen (framepos_t frame)
1241 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1243 /* if we're off the page, then scroll.
1246 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1247 center_screen_internal (frame, page);
1252 Editor::center_screen_internal (framepos_t frame, float page)
1257 frame -= (framepos_t) page;
1262 reset_x_origin (frame);
1267 Editor::update_title ()
1269 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1272 bool dirty = _session->dirty();
1274 string session_name;
1276 if (_session->snap_name() != _session->name()) {
1277 session_name = _session->snap_name();
1279 session_name = _session->name();
1283 session_name = "*" + session_name;
1286 WindowTitle title(session_name);
1287 title += Glib::get_application_name();
1288 set_title (title.get_string());
1290 /* ::session_going_away() will have taken care of it */
1295 Editor::set_session (Session *t)
1297 SessionHandlePtr::set_session (t);
1303 _playlist_selector->set_session (_session);
1304 nudge_clock->set_session (_session);
1305 _summary->set_session (_session);
1306 _group_tabs->set_session (_session);
1307 _route_groups->set_session (_session);
1308 _regions->set_session (_session);
1309 _snapshots->set_session (_session);
1310 _routes->set_session (_session);
1311 _locations->set_session (_session);
1313 if (rhythm_ferret) {
1314 rhythm_ferret->set_session (_session);
1317 if (analysis_window) {
1318 analysis_window->set_session (_session);
1322 sfbrowser->set_session (_session);
1325 compute_fixed_ruler_scale ();
1327 /* Make sure we have auto loop and auto punch ranges */
1329 Location* loc = _session->locations()->auto_loop_location();
1331 loc->set_name (_("Loop"));
1334 loc = _session->locations()->auto_punch_location();
1337 loc->set_name (_("Punch"));
1340 refresh_location_display ();
1342 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1343 the selected Marker; this needs the LocationMarker list to be available.
1345 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1346 set_state (*node, Stateful::loading_state_version);
1348 /* catch up with the playhead */
1350 _session->request_locate (playhead_cursor->current_frame ());
1351 _pending_initial_locate = true;
1355 /* These signals can all be emitted by a non-GUI thread. Therefore the
1356 handlers for them must not attempt to directly interact with the GUI,
1357 but use PBD::Signal<T>::connect() which accepts an event loop
1358 ("context") where the handler will be asked to run.
1361 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1362 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1363 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1364 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1365 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1366 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1367 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1368 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1369 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1370 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1371 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1372 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1373 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1375 playhead_cursor->show ();
1377 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1378 Config->map_parameters (pc);
1379 _session->config.map_parameters (pc);
1381 restore_ruler_visibility ();
1382 //tempo_map_changed (PropertyChange (0));
1383 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1385 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1386 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1389 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1390 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1393 switch (_snap_type) {
1394 case SnapToRegionStart:
1395 case SnapToRegionEnd:
1396 case SnapToRegionSync:
1397 case SnapToRegionBoundary:
1398 build_region_boundary_cache ();
1405 /* register for undo history */
1406 _session->register_with_memento_command_factory(id(), this);
1407 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1409 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1411 start_updating_meters ();
1415 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1417 if (a->get_name() == "RegionMenu") {
1418 /* When the main menu's region menu is opened, we setup the actions so that they look right
1419 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1420 so we resensitize all region actions when the entered regionview or the region selection
1421 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1422 happens after the region context menu is opened. So we set a flag here, too.
1426 sensitize_the_right_region_actions ();
1427 _last_region_menu_was_main = true;
1432 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1434 using namespace Menu_Helpers;
1436 void (Editor::*emf)(FadeShape);
1437 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1440 images = &_xfade_in_images;
1441 emf = &Editor::set_fade_in_shape;
1443 images = &_xfade_out_images;
1444 emf = &Editor::set_fade_out_shape;
1449 _("Linear (for highly correlated material)"),
1450 *(*images)[FadeLinear],
1451 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1455 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1459 _("Constant power"),
1460 *(*images)[FadeConstantPower],
1461 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1464 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1469 *(*images)[FadeSymmetric],
1470 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1474 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1479 *(*images)[FadeSlow],
1480 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1483 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1488 *(*images)[FadeFast],
1489 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1492 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1495 /** Pop up a context menu for when the user clicks on a start crossfade */
1497 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1499 using namespace Menu_Helpers;
1500 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1505 MenuList& items (xfade_in_context_menu.items());
1508 if (arv->audio_region()->fade_in_active()) {
1509 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1511 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1514 items.push_back (SeparatorElem());
1515 fill_xfade_menu (items, true);
1517 xfade_in_context_menu.popup (button, time);
1520 /** Pop up a context menu for when the user clicks on an end crossfade */
1522 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1524 using namespace Menu_Helpers;
1525 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1530 MenuList& items (xfade_out_context_menu.items());
1533 if (arv->audio_region()->fade_out_active()) {
1534 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1536 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1539 items.push_back (SeparatorElem());
1540 fill_xfade_menu (items, false);
1542 xfade_out_context_menu.popup (button, time);
1546 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1548 using namespace Menu_Helpers;
1549 Menu* (Editor::*build_menu_function)();
1552 switch (item_type) {
1554 case RegionViewName:
1555 case RegionViewNameHighlight:
1556 case LeftFrameHandle:
1557 case RightFrameHandle:
1558 if (with_selection) {
1559 build_menu_function = &Editor::build_track_selection_context_menu;
1561 build_menu_function = &Editor::build_track_region_context_menu;
1566 if (with_selection) {
1567 build_menu_function = &Editor::build_track_selection_context_menu;
1569 build_menu_function = &Editor::build_track_context_menu;
1574 if (clicked_routeview->track()) {
1575 build_menu_function = &Editor::build_track_context_menu;
1577 build_menu_function = &Editor::build_track_bus_context_menu;
1582 /* probably shouldn't happen but if it does, we don't care */
1586 menu = (this->*build_menu_function)();
1587 menu->set_name ("ArdourContextMenu");
1589 /* now handle specific situations */
1591 switch (item_type) {
1593 case RegionViewName:
1594 case RegionViewNameHighlight:
1595 case LeftFrameHandle:
1596 case RightFrameHandle:
1597 if (!with_selection) {
1598 if (region_edit_menu_split_item) {
1599 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1600 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1602 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1605 if (region_edit_menu_split_multichannel_item) {
1606 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1607 region_edit_menu_split_multichannel_item->set_sensitive (true);
1609 region_edit_menu_split_multichannel_item->set_sensitive (false);
1622 /* probably shouldn't happen but if it does, we don't care */
1626 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1628 /* Bounce to disk */
1630 using namespace Menu_Helpers;
1631 MenuList& edit_items = menu->items();
1633 edit_items.push_back (SeparatorElem());
1635 switch (clicked_routeview->audio_track()->freeze_state()) {
1636 case AudioTrack::NoFreeze:
1637 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1640 case AudioTrack::Frozen:
1641 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1644 case AudioTrack::UnFrozen:
1645 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1651 if (item_type == StreamItem && clicked_routeview) {
1652 clicked_routeview->build_underlay_menu(menu);
1655 /* When the region menu is opened, we setup the actions so that they look right
1658 sensitize_the_right_region_actions ();
1659 _last_region_menu_was_main = false;
1661 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1662 menu->popup (button, time);
1666 Editor::build_track_context_menu ()
1668 using namespace Menu_Helpers;
1670 MenuList& edit_items = track_context_menu.items();
1673 add_dstream_context_items (edit_items);
1674 return &track_context_menu;
1678 Editor::build_track_bus_context_menu ()
1680 using namespace Menu_Helpers;
1682 MenuList& edit_items = track_context_menu.items();
1685 add_bus_context_items (edit_items);
1686 return &track_context_menu;
1690 Editor::build_track_region_context_menu ()
1692 using namespace Menu_Helpers;
1693 MenuList& edit_items = track_region_context_menu.items();
1696 /* we've just cleared the track region context menu, so the menu that these
1697 two items were on will have disappeared; stop them dangling.
1699 region_edit_menu_split_item = 0;
1700 region_edit_menu_split_multichannel_item = 0;
1702 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1705 boost::shared_ptr<Track> tr;
1706 boost::shared_ptr<Playlist> pl;
1708 if ((tr = rtv->track())) {
1709 add_region_context_items (edit_items, tr);
1713 add_dstream_context_items (edit_items);
1715 return &track_region_context_menu;
1719 Editor::analyze_region_selection ()
1721 if (analysis_window == 0) {
1722 analysis_window = new AnalysisWindow();
1725 analysis_window->set_session(_session);
1727 analysis_window->show_all();
1730 analysis_window->set_regionmode();
1731 analysis_window->analyze();
1733 analysis_window->present();
1737 Editor::analyze_range_selection()
1739 if (analysis_window == 0) {
1740 analysis_window = new AnalysisWindow();
1743 analysis_window->set_session(_session);
1745 analysis_window->show_all();
1748 analysis_window->set_rangemode();
1749 analysis_window->analyze();
1751 analysis_window->present();
1755 Editor::build_track_selection_context_menu ()
1757 using namespace Menu_Helpers;
1758 MenuList& edit_items = track_selection_context_menu.items();
1759 edit_items.clear ();
1761 add_selection_context_items (edit_items);
1762 // edit_items.push_back (SeparatorElem());
1763 // add_dstream_context_items (edit_items);
1765 return &track_selection_context_menu;
1769 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1771 using namespace Menu_Helpers;
1773 /* OK, stick the region submenu at the top of the list, and then add
1777 RegionSelection rs = get_regions_from_selection_and_entered ();
1779 string::size_type pos = 0;
1780 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1782 /* we have to hack up the region name because "_" has a special
1783 meaning for menu titles.
1786 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1787 menu_item_name.replace (pos, 1, "__");
1791 if (_popup_region_menu_item == 0) {
1792 _popup_region_menu_item = new MenuItem (menu_item_name);
1793 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1794 _popup_region_menu_item->show ();
1796 _popup_region_menu_item->set_label (menu_item_name);
1799 /* No latering allowed in later is higher layering model */
1800 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1801 if (act && Config->get_layer_model() == LaterHigher) {
1802 act->set_sensitive (false);
1804 act->set_sensitive (true);
1807 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1809 edit_items.push_back (*_popup_region_menu_item);
1810 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1811 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1813 edit_items.push_back (SeparatorElem());
1816 /** Add context menu items relevant to selection ranges.
1817 * @param edit_items List to add the items to.
1820 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1822 using namespace Menu_Helpers;
1824 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1825 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1827 edit_items.push_back (SeparatorElem());
1828 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1830 edit_items.push_back (SeparatorElem());
1831 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1833 edit_items.push_back (SeparatorElem());
1835 edit_items.push_back (
1837 _("Move Range Start to Previous Region Boundary"),
1838 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1842 edit_items.push_back (
1844 _("Move Range Start to Next Region Boundary"),
1845 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1849 edit_items.push_back (
1851 _("Move Range End to Previous Region Boundary"),
1852 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1856 edit_items.push_back (
1858 _("Move Range End to Next Region Boundary"),
1859 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1863 edit_items.push_back (SeparatorElem());
1864 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1865 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1867 edit_items.push_back (SeparatorElem());
1868 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1870 edit_items.push_back (SeparatorElem());
1871 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1872 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1873 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1875 edit_items.push_back (SeparatorElem());
1876 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1878 edit_items.push_back (SeparatorElem());
1879 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1880 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1881 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1883 edit_items.push_back (SeparatorElem());
1884 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1885 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1886 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1887 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1888 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1889 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1890 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1896 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1898 using namespace Menu_Helpers;
1902 Menu *play_menu = manage (new Menu);
1903 MenuList& play_items = play_menu->items();
1904 play_menu->set_name ("ArdourContextMenu");
1906 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1907 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1908 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1909 play_items.push_back (SeparatorElem());
1910 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1912 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1916 Menu *select_menu = manage (new Menu);
1917 MenuList& select_items = select_menu->items();
1918 select_menu->set_name ("ArdourContextMenu");
1920 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1921 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1922 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1923 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1924 select_items.push_back (SeparatorElem());
1925 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1926 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1927 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
1928 select_items.push_back (SeparatorElem());
1929 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1930 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1931 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1932 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1933 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1934 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1935 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1937 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1941 Menu *cutnpaste_menu = manage (new Menu);
1942 MenuList& cutnpaste_items = cutnpaste_menu->items();
1943 cutnpaste_menu->set_name ("ArdourContextMenu");
1945 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1946 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1947 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1949 cutnpaste_items.push_back (SeparatorElem());
1951 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1952 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1954 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1956 /* Adding new material */
1958 edit_items.push_back (SeparatorElem());
1959 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1960 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1964 Menu *nudge_menu = manage (new Menu());
1965 MenuList& nudge_items = nudge_menu->items();
1966 nudge_menu->set_name ("ArdourContextMenu");
1968 edit_items.push_back (SeparatorElem());
1969 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1970 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1971 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1972 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1974 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1978 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1980 using namespace Menu_Helpers;
1984 Menu *play_menu = manage (new Menu);
1985 MenuList& play_items = play_menu->items();
1986 play_menu->set_name ("ArdourContextMenu");
1988 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1989 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1990 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1994 Menu *select_menu = manage (new Menu);
1995 MenuList& select_items = select_menu->items();
1996 select_menu->set_name ("ArdourContextMenu");
1998 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1999 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2000 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2001 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2002 select_items.push_back (SeparatorElem());
2003 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2004 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2005 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2006 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2008 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2012 Menu *cutnpaste_menu = manage (new Menu);
2013 MenuList& cutnpaste_items = cutnpaste_menu->items();
2014 cutnpaste_menu->set_name ("ArdourContextMenu");
2016 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2017 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2018 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2020 Menu *nudge_menu = manage (new Menu());
2021 MenuList& nudge_items = nudge_menu->items();
2022 nudge_menu->set_name ("ArdourContextMenu");
2024 edit_items.push_back (SeparatorElem());
2025 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2026 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2027 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2028 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2030 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2034 Editor::snap_type() const
2040 Editor::snap_mode() const
2046 Editor::set_snap_to (SnapType st)
2048 unsigned int snap_ind = (unsigned int)st;
2050 if (internal_editing()) {
2051 internal_snap_type = st;
2053 pre_internal_snap_type = st;
2058 if (snap_ind > snap_type_strings.size() - 1) {
2060 _snap_type = (SnapType)snap_ind;
2063 string str = snap_type_strings[snap_ind];
2065 if (str != snap_type_selector.get_text()) {
2066 snap_type_selector.set_text (str);
2071 switch (_snap_type) {
2072 case SnapToBeatDiv128:
2073 case SnapToBeatDiv64:
2074 case SnapToBeatDiv32:
2075 case SnapToBeatDiv28:
2076 case SnapToBeatDiv24:
2077 case SnapToBeatDiv20:
2078 case SnapToBeatDiv16:
2079 case SnapToBeatDiv14:
2080 case SnapToBeatDiv12:
2081 case SnapToBeatDiv10:
2082 case SnapToBeatDiv8:
2083 case SnapToBeatDiv7:
2084 case SnapToBeatDiv6:
2085 case SnapToBeatDiv5:
2086 case SnapToBeatDiv4:
2087 case SnapToBeatDiv3:
2088 case SnapToBeatDiv2: {
2089 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2090 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2092 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2093 current_bbt_points_begin, current_bbt_points_end);
2094 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2095 current_bbt_points_begin, current_bbt_points_end);
2096 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2100 case SnapToRegionStart:
2101 case SnapToRegionEnd:
2102 case SnapToRegionSync:
2103 case SnapToRegionBoundary:
2104 build_region_boundary_cache ();
2112 redisplay_tempo (false);
2114 SnapChanged (); /* EMIT SIGNAL */
2118 Editor::set_snap_mode (SnapMode mode)
2120 string str = snap_mode_strings[(int)mode];
2122 if (internal_editing()) {
2123 internal_snap_mode = mode;
2125 pre_internal_snap_mode = mode;
2130 if (str != snap_mode_selector.get_text ()) {
2131 snap_mode_selector.set_text (str);
2138 Editor::set_edit_point_preference (EditPoint ep, bool force)
2140 bool changed = (_edit_point != ep);
2143 if (Profile->get_mixbus())
2144 if (ep == EditAtSelectedMarker)
2145 ep = EditAtPlayhead;
2147 string str = edit_point_strings[(int)ep];
2148 if (str != edit_point_selector.get_text ()) {
2149 edit_point_selector.set_text (str);
2152 update_all_enter_cursors();
2154 if (!force && !changed) {
2158 const char* action=NULL;
2160 switch (_edit_point) {
2161 case EditAtPlayhead:
2162 action = "edit-at-playhead";
2164 case EditAtSelectedMarker:
2165 action = "edit-at-marker";
2168 action = "edit-at-mouse";
2172 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2174 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2178 bool in_track_canvas;
2180 if (!mouse_frame (foo, in_track_canvas)) {
2181 in_track_canvas = false;
2184 reset_canvas_action_sensitivity (in_track_canvas);
2190 Editor::set_state (const XMLNode& node, int /*version*/)
2192 const XMLProperty* prop;
2199 g.base_width = default_width;
2200 g.base_height = default_height;
2204 if ((geometry = find_named_node (node, "geometry")) != 0) {
2208 if ((prop = geometry->property("x_size")) == 0) {
2209 prop = geometry->property ("x-size");
2212 g.base_width = atoi(prop->value());
2214 if ((prop = geometry->property("y_size")) == 0) {
2215 prop = geometry->property ("y-size");
2218 g.base_height = atoi(prop->value());
2221 if ((prop = geometry->property ("x_pos")) == 0) {
2222 prop = geometry->property ("x-pos");
2225 x = atoi (prop->value());
2228 if ((prop = geometry->property ("y_pos")) == 0) {
2229 prop = geometry->property ("y-pos");
2232 y = atoi (prop->value());
2236 set_default_size (g.base_width, g.base_height);
2239 if (_session && (prop = node.property ("playhead"))) {
2241 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2243 playhead_cursor->set_position (pos);
2245 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2246 playhead_cursor->set_position (0);
2249 playhead_cursor->set_position (0);
2252 if ((prop = node.property ("mixer-width"))) {
2253 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2256 if ((prop = node.property ("zoom-focus"))) {
2257 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2260 if ((prop = node.property ("zoom"))) {
2261 /* older versions of ardour used floating point samples_per_pixel */
2262 double f = PBD::atof (prop->value());
2263 reset_zoom (llrintf (f));
2265 reset_zoom (samples_per_pixel);
2268 if ((prop = node.property ("visible-track-count"))) {
2269 set_visible_track_count (PBD::atoi (prop->value()));
2272 if ((prop = node.property ("snap-to"))) {
2273 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2276 if ((prop = node.property ("snap-mode"))) {
2277 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2280 if ((prop = node.property ("internal-snap-to"))) {
2281 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2284 if ((prop = node.property ("internal-snap-mode"))) {
2285 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2288 if ((prop = node.property ("pre-internal-snap-to"))) {
2289 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2292 if ((prop = node.property ("pre-internal-snap-mode"))) {
2293 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2296 if ((prop = node.property ("mouse-mode"))) {
2297 MouseMode m = str2mousemode(prop->value());
2298 set_mouse_mode (m, true);
2300 set_mouse_mode (MouseObject, true);
2303 if ((prop = node.property ("left-frame")) != 0) {
2305 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2309 reset_x_origin (pos);
2313 if ((prop = node.property ("y-origin")) != 0) {
2314 reset_y_origin (atof (prop->value ()));
2317 if ((prop = node.property ("join-object-range"))) {
2318 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2319 bool yn = string_is_affirmative (prop->value());
2321 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2322 tact->set_active (!yn);
2323 tact->set_active (yn);
2325 set_mouse_mode(mouse_mode, true);
2328 if ((prop = node.property ("edit-point"))) {
2329 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2332 if ((prop = node.property ("show-measures"))) {
2333 bool yn = string_is_affirmative (prop->value());
2334 _show_measures = yn;
2337 if ((prop = node.property ("follow-playhead"))) {
2338 bool yn = string_is_affirmative (prop->value());
2339 set_follow_playhead (yn);
2342 if ((prop = node.property ("stationary-playhead"))) {
2343 bool yn = string_is_affirmative (prop->value());
2344 set_stationary_playhead (yn);
2347 if ((prop = node.property ("region-list-sort-type"))) {
2348 RegionListSortType st;
2349 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2352 if ((prop = node.property ("show-editor-mixer"))) {
2354 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2357 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2358 bool yn = string_is_affirmative (prop->value());
2360 /* do it twice to force the change */
2362 tact->set_active (!yn);
2363 tact->set_active (yn);
2366 if ((prop = node.property ("show-editor-list"))) {
2368 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2371 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2372 bool yn = string_is_affirmative (prop->value());
2374 /* do it twice to force the change */
2376 tact->set_active (!yn);
2377 tact->set_active (yn);
2380 if ((prop = node.property (X_("editor-list-page")))) {
2381 _the_notebook.set_current_page (atoi (prop->value ()));
2384 if ((prop = node.property (X_("show-marker-lines")))) {
2385 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2387 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2388 bool yn = string_is_affirmative (prop->value ());
2390 tact->set_active (!yn);
2391 tact->set_active (yn);
2394 XMLNodeList children = node.children ();
2395 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2396 selection->set_state (**i, Stateful::current_state_version);
2397 _regions->set_state (**i);
2400 if ((prop = node.property ("maximised"))) {
2401 bool yn = string_is_affirmative (prop->value());
2402 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2404 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2405 bool fs = tact && tact->get_active();
2407 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2411 if ((prop = node.property ("nudge-clock-value"))) {
2413 sscanf (prop->value().c_str(), "%" PRId64, &f);
2414 nudge_clock->set (f);
2416 nudge_clock->set_mode (AudioClock::Timecode);
2417 nudge_clock->set (_session->frame_rate() * 5, true);
2422 * Not all properties may have been in XML, but
2423 * those that are linked to a private variable may need changing
2428 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2430 yn = _show_measures;
2431 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2432 /* do it twice to force the change */
2433 tact->set_active (!yn);
2434 tact->set_active (yn);
2437 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2438 yn = _follow_playhead;
2440 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2441 if (tact->get_active() != yn) {
2442 tact->set_active (yn);
2446 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2447 yn = _stationary_playhead;
2449 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2450 if (tact->get_active() != yn) {
2451 tact->set_active (yn);
2460 Editor::get_state ()
2462 XMLNode* node = new XMLNode ("Editor");
2465 id().print (buf, sizeof (buf));
2466 node->add_property ("id", buf);
2468 if (is_realized()) {
2469 Glib::RefPtr<Gdk::Window> win = get_window();
2471 int x, y, width, height;
2472 win->get_root_origin(x, y);
2473 win->get_size(width, height);
2475 XMLNode* geometry = new XMLNode ("geometry");
2477 snprintf(buf, sizeof(buf), "%d", width);
2478 geometry->add_property("x-size", string(buf));
2479 snprintf(buf, sizeof(buf), "%d", height);
2480 geometry->add_property("y-size", string(buf));
2481 snprintf(buf, sizeof(buf), "%d", x);
2482 geometry->add_property("x-pos", string(buf));
2483 snprintf(buf, sizeof(buf), "%d", y);
2484 geometry->add_property("y-pos", string(buf));
2485 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2486 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2487 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2488 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2489 geometry->add_property("edit-vertical-pane-pos", string(buf));
2491 node->add_child_nocopy (*geometry);
2494 maybe_add_mixer_strip_width (*node);
2496 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2498 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2499 node->add_property ("zoom", buf);
2500 node->add_property ("snap-to", enum_2_string (_snap_type));
2501 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2502 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2503 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2504 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2505 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2506 node->add_property ("edit-point", enum_2_string (_edit_point));
2507 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2508 node->add_property ("visible-track-count", buf);
2510 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2511 node->add_property ("playhead", buf);
2512 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2513 node->add_property ("left-frame", buf);
2514 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2515 node->add_property ("y-origin", buf);
2517 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2518 node->add_property ("maximised", _maximised ? "yes" : "no");
2519 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2520 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2521 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2522 node->add_property ("mouse-mode", enum2str(mouse_mode));
2523 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2525 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2527 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2528 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2531 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2533 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2534 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2537 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2538 node->add_property (X_("editor-list-page"), buf);
2540 if (button_bindings) {
2541 XMLNode* bb = new XMLNode (X_("Buttons"));
2542 button_bindings->save (*bb);
2543 node->add_child_nocopy (*bb);
2546 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2548 node->add_child_nocopy (selection->get_state ());
2549 node->add_child_nocopy (_regions->get_state ());
2551 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2552 node->add_property ("nudge-clock-value", buf);
2557 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2558 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2560 * @return pair: TimeAxisView that y is over, layer index.
2562 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2563 * in stacked or expanded region display mode, otherwise 0.
2565 std::pair<TimeAxisView *, double>
2566 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2568 if (!trackview_relative_offset) {
2569 y -= _trackview_group->canvas_origin().y;
2573 return std::make_pair ( (TimeAxisView *) 0, 0);
2576 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2578 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2585 return std::make_pair ( (TimeAxisView *) 0, 0);
2588 /** Snap a position to the grid, if appropriate, taking into account current
2589 * grid settings and also the state of any snap modifier keys that may be pressed.
2590 * @param start Position to snap.
2591 * @param event Event to get current key modifier information from, or 0.
2594 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2596 if (!_session || !event) {
2600 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2601 if (_snap_mode == SnapOff) {
2602 snap_to_internal (start, direction, for_mark);
2605 if (_snap_mode != SnapOff) {
2606 snap_to_internal (start, direction, for_mark);
2612 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark)
2614 if (!_session || _snap_mode == SnapOff) {
2618 snap_to_internal (start, direction, for_mark);
2622 Editor::snap_to_no_magnets (framepos_t& start, RoundMode direction, bool for_mark)
2624 if (!_session || _snap_mode == SnapOff) {
2628 snap_to_internal (start, direction, for_mark, true);
2632 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2634 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2635 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2637 switch (_snap_type) {
2638 case SnapToTimecodeFrame:
2639 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2640 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2641 /* start is already on a whole timecode frame, do nothing */
2642 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2643 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2645 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2649 case SnapToTimecodeSeconds:
2650 if (_session->config.get_timecode_offset_negative()) {
2651 start += _session->config.get_timecode_offset ();
2653 start -= _session->config.get_timecode_offset ();
2655 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2656 (start % one_timecode_second == 0)) {
2657 /* start is already on a whole second, do nothing */
2658 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2659 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2661 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2664 if (_session->config.get_timecode_offset_negative()) {
2665 start -= _session->config.get_timecode_offset ();
2667 start += _session->config.get_timecode_offset ();
2671 case SnapToTimecodeMinutes:
2672 if (_session->config.get_timecode_offset_negative()) {
2673 start += _session->config.get_timecode_offset ();
2675 start -= _session->config.get_timecode_offset ();
2677 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2678 (start % one_timecode_minute == 0)) {
2679 /* start is already on a whole minute, do nothing */
2680 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2681 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2683 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2685 if (_session->config.get_timecode_offset_negative()) {
2686 start -= _session->config.get_timecode_offset ();
2688 start += _session->config.get_timecode_offset ();
2692 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2693 abort(); /*NOTREACHED*/
2698 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool no_magnets)
2700 const framepos_t one_second = _session->frame_rate();
2701 const framepos_t one_minute = _session->frame_rate() * 60;
2702 framepos_t presnap = start;
2706 switch (_snap_type) {
2707 case SnapToTimecodeFrame:
2708 case SnapToTimecodeSeconds:
2709 case SnapToTimecodeMinutes:
2710 return timecode_snap_to_internal (start, direction, for_mark);
2713 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2714 start % (one_second/75) == 0) {
2715 /* start is already on a whole CD frame, do nothing */
2716 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2717 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2719 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2724 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2725 start % one_second == 0) {
2726 /* start is already on a whole second, do nothing */
2727 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2728 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2730 start = (framepos_t) floor ((double) start / one_second) * one_second;
2735 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2736 start % one_minute == 0) {
2737 /* start is already on a whole minute, do nothing */
2738 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2739 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2741 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2746 start = _session->tempo_map().round_to_bar (start, direction);
2750 start = _session->tempo_map().round_to_beat (start, direction);
2753 case SnapToBeatDiv128:
2754 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2756 case SnapToBeatDiv64:
2757 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2759 case SnapToBeatDiv32:
2760 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2762 case SnapToBeatDiv28:
2763 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2765 case SnapToBeatDiv24:
2766 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2768 case SnapToBeatDiv20:
2769 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2771 case SnapToBeatDiv16:
2772 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2774 case SnapToBeatDiv14:
2775 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2777 case SnapToBeatDiv12:
2778 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2780 case SnapToBeatDiv10:
2781 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2783 case SnapToBeatDiv8:
2784 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2786 case SnapToBeatDiv7:
2787 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2789 case SnapToBeatDiv6:
2790 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2792 case SnapToBeatDiv5:
2793 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2795 case SnapToBeatDiv4:
2796 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2798 case SnapToBeatDiv3:
2799 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2801 case SnapToBeatDiv2:
2802 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2810 _session->locations()->marks_either_side (start, before, after);
2812 if (before == max_framepos && after == max_framepos) {
2813 /* No marks to snap to, so just don't snap */
2815 } else if (before == max_framepos) {
2817 } else if (after == max_framepos) {
2819 } else if (before != max_framepos && after != max_framepos) {
2820 /* have before and after */
2821 if ((start - before) < (after - start)) {
2830 case SnapToRegionStart:
2831 case SnapToRegionEnd:
2832 case SnapToRegionSync:
2833 case SnapToRegionBoundary:
2834 if (!region_boundary_cache.empty()) {
2836 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2837 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2839 if (direction > 0) {
2840 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2842 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2845 if (next != region_boundary_cache.begin ()) {
2850 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2851 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2853 if (start > (p + n) / 2) {
2862 switch (_snap_mode) {
2872 if (presnap > start) {
2873 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2877 } else if (presnap < start) {
2878 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2884 /* handled at entry */
2892 Editor::setup_toolbar ()
2894 HBox* mode_box = manage(new HBox);
2895 mode_box->set_border_width (2);
2896 mode_box->set_spacing(2);
2898 HBox* mouse_mode_box = manage (new HBox);
2899 HBox* mouse_mode_hbox = manage (new HBox);
2900 VBox* mouse_mode_vbox = manage (new VBox);
2901 Alignment* mouse_mode_align = manage (new Alignment);
2903 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2904 mouse_mode_size_group->add_widget (smart_mode_button);
2905 mouse_mode_size_group->add_widget (mouse_move_button);
2906 mouse_mode_size_group->add_widget (mouse_cut_button);
2907 mouse_mode_size_group->add_widget (mouse_select_button);
2908 mouse_mode_size_group->add_widget (mouse_timefx_button);
2909 mouse_mode_size_group->add_widget (mouse_audition_button);
2910 mouse_mode_size_group->add_widget (mouse_draw_button);
2911 mouse_mode_size_group->add_widget (mouse_content_button);
2913 mouse_mode_size_group->add_widget (zoom_in_button);
2914 mouse_mode_size_group->add_widget (zoom_out_button);
2915 mouse_mode_size_group->add_widget (zoom_preset_selector);
2916 mouse_mode_size_group->add_widget (zoom_out_full_button);
2917 mouse_mode_size_group->add_widget (zoom_focus_selector);
2919 mouse_mode_size_group->add_widget (tav_shrink_button);
2920 mouse_mode_size_group->add_widget (tav_expand_button);
2921 mouse_mode_size_group->add_widget (visible_tracks_selector);
2923 mouse_mode_size_group->add_widget (snap_type_selector);
2924 mouse_mode_size_group->add_widget (snap_mode_selector);
2926 mouse_mode_size_group->add_widget (edit_point_selector);
2927 mouse_mode_size_group->add_widget (edit_mode_selector);
2929 mouse_mode_size_group->add_widget (*nudge_clock);
2930 mouse_mode_size_group->add_widget (nudge_forward_button);
2931 mouse_mode_size_group->add_widget (nudge_backward_button);
2933 mouse_mode_hbox->set_spacing (2);
2935 if (!ARDOUR::Profile->get_trx()) {
2936 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2939 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2940 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2942 if (!ARDOUR::Profile->get_mixbus()) {
2943 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2946 if (!ARDOUR::Profile->get_trx()) {
2947 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2948 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2949 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2950 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2953 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2955 mouse_mode_align->add (*mouse_mode_vbox);
2956 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2958 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2960 edit_mode_selector.set_name ("mouse mode button");
2962 if (!ARDOUR::Profile->get_trx()) {
2963 mode_box->pack_start (edit_mode_selector, false, false);
2965 mode_box->pack_start (*mouse_mode_box, false, false);
2967 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2968 _mouse_mode_tearoff->set_name ("MouseModeBase");
2969 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2971 if (Profile->get_sae() || Profile->get_mixbus() ) {
2972 _mouse_mode_tearoff->set_can_be_torn_off (false);
2975 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2976 &_mouse_mode_tearoff->tearoff_window()));
2977 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2978 &_mouse_mode_tearoff->tearoff_window(), 1));
2979 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2980 &_mouse_mode_tearoff->tearoff_window()));
2981 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2982 &_mouse_mode_tearoff->tearoff_window(), 1));
2986 _zoom_box.set_spacing (2);
2987 _zoom_box.set_border_width (2);
2991 zoom_preset_selector.set_name ("zoom button");
2992 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2993 zoom_preset_selector.set_size_request (42, -1);
2995 zoom_in_button.set_name ("zoom button");
2996 zoom_in_button.set_image(::get_icon ("zoom_in"));
2997 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2998 zoom_in_button.set_related_action (act);
3000 zoom_out_button.set_name ("zoom button");
3001 zoom_out_button.set_image(::get_icon ("zoom_out"));
3002 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3003 zoom_out_button.set_related_action (act);
3005 zoom_out_full_button.set_name ("zoom button");
3006 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
3007 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3008 zoom_out_full_button.set_related_action (act);
3010 zoom_focus_selector.set_name ("zoom button");
3012 if (ARDOUR::Profile->get_mixbus()) {
3013 _zoom_box.pack_start (zoom_preset_selector, false, false);
3014 } else if (ARDOUR::Profile->get_trx()) {
3015 mode_box->pack_start (zoom_out_button, false, false);
3016 mode_box->pack_start (zoom_in_button, false, false);
3018 _zoom_box.pack_start (zoom_out_button, false, false);
3019 _zoom_box.pack_start (zoom_in_button, false, false);
3020 _zoom_box.pack_start (zoom_out_full_button, false, false);
3021 _zoom_box.pack_start (zoom_focus_selector, false, false);
3024 /* Track zoom buttons */
3025 visible_tracks_selector.set_name ("zoom button");
3026 if (Profile->get_mixbus()) {
3027 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3028 visible_tracks_selector.set_size_request (42, -1);
3030 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3033 tav_expand_button.set_name ("zoom button");
3034 tav_expand_button.set_image(::get_icon ("tav_exp"));
3035 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3036 tav_expand_button.set_related_action (act);
3038 tav_shrink_button.set_name ("zoom button");
3039 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
3040 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3041 tav_shrink_button.set_related_action (act);
3043 if (ARDOUR::Profile->get_mixbus()) {
3044 _zoom_box.pack_start (visible_tracks_selector);
3045 } else if (ARDOUR::Profile->get_trx()) {
3046 _zoom_box.pack_start (tav_shrink_button);
3047 _zoom_box.pack_start (tav_expand_button);
3049 _zoom_box.pack_start (visible_tracks_selector);
3050 _zoom_box.pack_start (tav_shrink_button);
3051 _zoom_box.pack_start (tav_expand_button);
3054 if (!ARDOUR::Profile->get_trx()) {
3055 _zoom_tearoff = manage (new TearOff (_zoom_box));
3057 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3058 &_zoom_tearoff->tearoff_window()));
3059 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3060 &_zoom_tearoff->tearoff_window(), 0));
3061 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3062 &_zoom_tearoff->tearoff_window()));
3063 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3064 &_zoom_tearoff->tearoff_window(), 0));
3067 if (Profile->get_sae() || Profile->get_mixbus() ) {
3068 _zoom_tearoff->set_can_be_torn_off (false);
3071 snap_box.set_spacing (2);
3072 snap_box.set_border_width (2);
3074 snap_type_selector.set_name ("mouse mode button");
3076 snap_mode_selector.set_name ("mouse mode button");
3078 edit_point_selector.set_name ("mouse mode button");
3080 snap_box.pack_start (snap_mode_selector, false, false);
3081 snap_box.pack_start (snap_type_selector, false, false);
3082 snap_box.pack_start (edit_point_selector, false, false);
3086 HBox *nudge_box = manage (new HBox);
3087 nudge_box->set_spacing (2);
3088 nudge_box->set_border_width (2);
3090 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3091 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3093 nudge_box->pack_start (nudge_backward_button, false, false);
3094 nudge_box->pack_start (nudge_forward_button, false, false);
3095 nudge_box->pack_start (*nudge_clock, false, false);
3098 /* Pack everything in... */
3100 HBox* hbox = manage (new HBox);
3101 hbox->set_spacing(2);
3103 _tools_tearoff = manage (new TearOff (*hbox));
3104 _tools_tearoff->set_name ("MouseModeBase");
3105 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3107 if (Profile->get_sae() || Profile->get_mixbus()) {
3108 _tools_tearoff->set_can_be_torn_off (false);
3111 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3112 &_tools_tearoff->tearoff_window()));
3113 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3114 &_tools_tearoff->tearoff_window(), 0));
3115 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3116 &_tools_tearoff->tearoff_window()));
3117 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3118 &_tools_tearoff->tearoff_window(), 0));
3120 toolbar_hbox.set_spacing (2);
3121 toolbar_hbox.set_border_width (1);
3123 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3124 if (!ARDOUR::Profile->get_trx()) {
3125 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3126 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3129 if (!ARDOUR::Profile->get_trx()) {
3130 hbox->pack_start (snap_box, false, false);
3131 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3132 hbox->pack_start (*nudge_box, false, false);
3134 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3137 hbox->pack_start (panic_box, false, false);
3141 toolbar_base.set_name ("ToolBarBase");
3142 toolbar_base.add (toolbar_hbox);
3144 _toolbar_viewport.add (toolbar_base);
3145 /* stick to the required height but allow width to vary if there's not enough room */
3146 _toolbar_viewport.set_size_request (1, -1);
3148 toolbar_frame.set_shadow_type (SHADOW_OUT);
3149 toolbar_frame.set_name ("BaseFrame");
3150 toolbar_frame.add (_toolbar_viewport);
3154 Editor::build_edit_point_menu ()
3156 using namespace Menu_Helpers;
3158 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3159 if(!Profile->get_mixbus())
3160 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3161 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3163 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3167 Editor::build_edit_mode_menu ()
3169 using namespace Menu_Helpers;
3171 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3172 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3173 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3174 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3176 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3180 Editor::build_snap_mode_menu ()
3182 using namespace Menu_Helpers;
3184 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3185 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3186 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3188 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3192 Editor::build_snap_type_menu ()
3194 using namespace Menu_Helpers;
3196 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3197 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3198 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3199 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3200 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3201 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3202 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3203 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3204 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3205 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3206 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3207 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3208 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3209 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3210 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3211 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3212 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3213 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3214 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3215 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3216 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3217 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3218 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3219 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3220 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3221 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3222 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3223 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3224 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3225 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3227 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3232 Editor::setup_tooltips ()
3234 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Grab mode)"));
3235 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Grab Mode (select/move objects)"));
3236 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split regions)"));
3237 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select time ranges)"));
3238 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3239 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3240 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3241 ARDOUR_UI::instance()->set_tip (mouse_content_button, _("Internal Edit Mode (edit notes and gain curves inside regions)"));
3242 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3243 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3244 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3245 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3246 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3247 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3248 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3249 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3250 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3251 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3252 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3253 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3254 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3255 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3256 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3257 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3261 Editor::convert_drop_to_paths (
3262 vector<string>& paths,
3263 const RefPtr<Gdk::DragContext>& /*context*/,
3266 const SelectionData& data,
3270 if (_session == 0) {
3274 vector<string> uris = data.get_uris();
3278 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3279 are actually URI lists. So do it by hand.
3282 if (data.get_target() != "text/plain") {
3286 /* Parse the "uri-list" format that Nautilus provides,
3287 where each pathname is delimited by \r\n.
3289 THERE MAY BE NO NULL TERMINATING CHAR!!!
3292 string txt = data.get_text();
3296 p = (char *) malloc (txt.length() + 1);
3297 txt.copy (p, txt.length(), 0);
3298 p[txt.length()] = '\0';
3304 while (g_ascii_isspace (*p))
3308 while (*q && (*q != '\n') && (*q != '\r')) {
3315 while (q > p && g_ascii_isspace (*q))
3320 uris.push_back (string (p, q - p + 1));
3324 p = strchr (p, '\n');
3336 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3337 if ((*i).substr (0,7) == "file://") {
3338 paths.push_back (Glib::filename_from_uri (*i));
3346 Editor::new_tempo_section ()
3351 Editor::map_transport_state ()
3353 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3355 if (_session && _session->transport_stopped()) {
3356 have_pending_keyboard_selection = false;
3359 update_loop_range_view ();
3365 Editor::begin_selection_op_history ()
3367 selection_op_cmd_depth = 0;
3368 selection_op_history_it = 0;
3370 while(!selection_op_history.empty()) {
3371 delete selection_op_history.front();
3372 selection_op_history.pop_front();
3375 selection_undo_action->set_sensitive (false);
3376 selection_redo_action->set_sensitive (false);
3377 selection_op_history.push_front (&_selection_memento->get_state ());
3381 Editor::begin_reversible_selection_op (string name)
3384 //cerr << name << endl;
3385 /* begin/commit pairs can be nested */
3386 selection_op_cmd_depth++;
3391 Editor::commit_reversible_selection_op ()
3394 if (selection_op_cmd_depth == 1) {
3396 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3398 The user has undone some selection ops and then made a new one,
3399 making anything earlier in the list invalid.
3402 list<XMLNode *>::iterator it = selection_op_history.begin();
3403 list<XMLNode *>::iterator e_it = it;
3404 advance (e_it, selection_op_history_it);
3406 for ( ; it != e_it; ++it) {
3409 selection_op_history.erase (selection_op_history.begin(), e_it);
3412 selection_op_history.push_front (&_selection_memento->get_state ());
3413 selection_op_history_it = 0;
3415 selection_undo_action->set_sensitive (true);
3416 selection_redo_action->set_sensitive (false);
3419 if (selection_op_cmd_depth > 0) {
3420 selection_op_cmd_depth--;
3426 Editor::undo_selection_op ()
3429 selection_op_history_it++;
3431 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3432 if (n == selection_op_history_it) {
3433 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3434 selection_redo_action->set_sensitive (true);
3438 /* is there an earlier entry? */
3439 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3440 selection_undo_action->set_sensitive (false);
3446 Editor::redo_selection_op ()
3449 if (selection_op_history_it > 0) {
3450 selection_op_history_it--;
3453 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3454 if (n == selection_op_history_it) {
3455 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3456 selection_undo_action->set_sensitive (true);
3461 if (selection_op_history_it == 0) {
3462 selection_redo_action->set_sensitive (false);
3468 Editor::begin_reversible_command (string name)
3471 before.push_back (&_selection_memento->get_state ());
3472 _session->begin_reversible_command (name);
3477 Editor::begin_reversible_command (GQuark q)
3480 before.push_back (&_selection_memento->get_state ());
3481 _session->begin_reversible_command (q);
3486 Editor::abort_reversible_command ()
3489 while(!before.empty()) {
3490 delete before.front();
3493 _session->abort_reversible_command ();
3498 Editor::commit_reversible_command ()
3501 if (before.size() == 1) {
3502 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3503 redo_action->set_sensitive(false);
3504 undo_action->set_sensitive(true);
3505 begin_selection_op_history ();
3508 if (before.empty()) {
3509 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3514 _session->commit_reversible_command ();
3519 Editor::history_changed ()
3523 if (undo_action && _session) {
3524 if (_session->undo_depth() == 0) {
3525 label = S_("Command|Undo");
3527 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3529 undo_action->property_label() = label;
3532 if (redo_action && _session) {
3533 if (_session->redo_depth() == 0) {
3536 label = string_compose(_("Redo (%1)"), _session->next_redo());
3538 redo_action->property_label() = label;
3543 Editor::duplicate_range (bool with_dialog)
3547 RegionSelection rs = get_regions_from_selection_and_entered ();
3549 if ( selection->time.length() == 0 && rs.empty()) {
3555 ArdourDialog win (_("Duplicate"));
3556 Label label (_("Number of duplications:"));
3557 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3558 SpinButton spinner (adjustment, 0.0, 1);
3561 win.get_vbox()->set_spacing (12);
3562 win.get_vbox()->pack_start (hbox);
3563 hbox.set_border_width (6);
3564 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3566 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3567 place, visually. so do this by hand.
3570 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3571 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3572 spinner.grab_focus();
3578 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3579 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3580 win.set_default_response (RESPONSE_ACCEPT);
3582 spinner.grab_focus ();
3584 switch (win.run ()) {
3585 case RESPONSE_ACCEPT:
3591 times = adjustment.get_value();
3594 if ((current_mouse_mode() == Editing::MouseRange)) {
3595 if (selection->time.length()) {
3596 duplicate_selection (times);
3598 } else if (get_smart_mode()) {
3599 if (selection->time.length()) {
3600 duplicate_selection (times);
3602 duplicate_some_regions (rs, times);
3604 duplicate_some_regions (rs, times);
3609 Editor::set_edit_mode (EditMode m)
3611 Config->set_edit_mode (m);
3615 Editor::cycle_edit_mode ()
3617 switch (Config->get_edit_mode()) {
3619 if (Profile->get_sae()) {
3620 Config->set_edit_mode (Lock);
3622 Config->set_edit_mode (Ripple);
3627 Config->set_edit_mode (Lock);
3630 Config->set_edit_mode (Slide);
3636 Editor::edit_mode_selection_done ( EditMode m )
3638 Config->set_edit_mode ( m );
3642 Editor::snap_type_selection_done (SnapType snaptype)
3644 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3646 ract->set_active ();
3651 Editor::snap_mode_selection_done (SnapMode mode)
3653 RefPtr<RadioAction> ract = snap_mode_action (mode);
3656 ract->set_active (true);
3661 Editor::cycle_edit_point (bool with_marker)
3663 if(Profile->get_mixbus())
3664 with_marker = false;
3666 switch (_edit_point) {
3668 set_edit_point_preference (EditAtPlayhead);
3670 case EditAtPlayhead:
3672 set_edit_point_preference (EditAtSelectedMarker);
3674 set_edit_point_preference (EditAtMouse);
3677 case EditAtSelectedMarker:
3678 set_edit_point_preference (EditAtMouse);
3684 Editor::edit_point_selection_done (EditPoint ep)
3686 set_edit_point_preference ( ep );
3690 Editor::build_zoom_focus_menu ()
3692 using namespace Menu_Helpers;
3694 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3695 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3696 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3697 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3698 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3699 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3701 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3705 Editor::zoom_focus_selection_done ( ZoomFocus f )
3707 RefPtr<RadioAction> ract = zoom_focus_action (f);
3709 ract->set_active ();
3714 Editor::build_track_count_menu ()
3716 using namespace Menu_Helpers;
3718 if (!Profile->get_mixbus()) {
3719 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3720 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3721 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3722 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3723 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3724 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3725 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3726 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3727 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3728 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3729 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3730 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3731 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3733 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3734 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3735 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3736 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3737 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3738 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3739 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3740 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3741 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3742 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3744 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3745 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3746 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3747 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3748 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3749 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3750 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3751 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3752 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3753 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3754 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3759 Editor::set_zoom_preset (int64_t ms)
3762 temporal_zoom_session();
3766 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3767 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3771 Editor::set_visible_track_count (int32_t n)
3773 _visible_track_count = n;
3775 /* if the canvas hasn't really been allocated any size yet, just
3776 record the desired number of visible tracks and return. when canvas
3777 allocation happens, we will get called again and then we can do the
3781 if (_visible_canvas_height <= 1) {
3787 DisplaySuspender ds;
3789 if (_visible_track_count > 0) {
3790 h = trackviews_height() / _visible_track_count;
3791 std::ostringstream s;
3792 s << _visible_track_count;
3794 } else if (_visible_track_count == 0) {
3796 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3797 if ((*i)->marked_for_display()) {
3801 h = trackviews_height() / n;
3804 /* negative value means that the visible track count has
3805 been overridden by explicit track height changes.
3807 visible_tracks_selector.set_text (X_("*"));
3811 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3812 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3815 if (str != visible_tracks_selector.get_text()) {
3816 visible_tracks_selector.set_text (str);
3821 Editor::override_visible_track_count ()
3823 _visible_track_count = -1;
3824 visible_tracks_selector.set_text ( _("*") );
3828 Editor::edit_controls_button_release (GdkEventButton* ev)
3830 if (Keyboard::is_context_menu_event (ev)) {
3831 ARDOUR_UI::instance()->add_route (this);
3832 } else if (ev->button == 1) {
3833 selection->clear_tracks ();
3840 Editor::mouse_select_button_release (GdkEventButton* ev)
3842 /* this handles just right-clicks */
3844 if (ev->button != 3) {
3852 Editor::set_zoom_focus (ZoomFocus f)
3854 string str = zoom_focus_strings[(int)f];
3856 if (str != zoom_focus_selector.get_text()) {
3857 zoom_focus_selector.set_text (str);
3860 if (zoom_focus != f) {
3867 Editor::cycle_zoom_focus ()
3869 switch (zoom_focus) {
3871 set_zoom_focus (ZoomFocusRight);
3873 case ZoomFocusRight:
3874 set_zoom_focus (ZoomFocusCenter);
3876 case ZoomFocusCenter:
3877 set_zoom_focus (ZoomFocusPlayhead);
3879 case ZoomFocusPlayhead:
3880 set_zoom_focus (ZoomFocusMouse);
3882 case ZoomFocusMouse:
3883 set_zoom_focus (ZoomFocusEdit);
3886 set_zoom_focus (ZoomFocusLeft);
3892 Editor::ensure_float (Window& win)
3894 win.set_transient_for (*this);
3898 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3900 /* recover or initialize pane positions. do this here rather than earlier because
3901 we don't want the positions to change the child allocations, which they seem to do.
3907 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3916 XMLNode* geometry = find_named_node (*node, "geometry");
3918 if (which == static_cast<Paned*> (&edit_pane)) {
3920 if (done & Horizontal) {
3924 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3925 _notebook_shrunk = string_is_affirmative (prop->value ());
3928 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3929 /* initial allocation is 90% to canvas, 10% to notebook */
3930 pos = (int) floor (alloc.get_width() * 0.90f);
3931 snprintf (buf, sizeof(buf), "%d", pos);
3933 pos = atoi (prop->value());
3936 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3937 edit_pane.set_position (pos);
3940 done = (Pane) (done | Horizontal);
3942 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3944 if (done & Vertical) {
3948 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3949 /* initial allocation is 90% to canvas, 10% to summary */
3950 pos = (int) floor (alloc.get_height() * 0.90f);
3951 snprintf (buf, sizeof(buf), "%d", pos);
3954 pos = atoi (prop->value());
3957 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3958 editor_summary_pane.set_position (pos);
3961 done = (Pane) (done | Vertical);
3966 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3968 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3969 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3970 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3971 top_hbox.remove (toolbar_frame);
3976 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3978 if (toolbar_frame.get_parent() == 0) {
3979 top_hbox.pack_end (toolbar_frame);
3984 Editor::set_show_measures (bool yn)
3986 if (_show_measures != yn) {
3989 if ((_show_measures = yn) == true) {
3991 tempo_lines->show();
3994 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3995 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3997 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3998 draw_measures (begin, end);
4006 Editor::toggle_follow_playhead ()
4008 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
4010 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4011 set_follow_playhead (tact->get_active());
4015 /** @param yn true to follow playhead, otherwise false.
4016 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4019 Editor::set_follow_playhead (bool yn, bool catch_up)
4021 if (_follow_playhead != yn) {
4022 if ((_follow_playhead = yn) == true && catch_up) {
4024 reset_x_origin_to_follow_playhead ();
4031 Editor::toggle_stationary_playhead ()
4033 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4035 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4036 set_stationary_playhead (tact->get_active());
4041 Editor::set_stationary_playhead (bool yn)
4043 if (_stationary_playhead != yn) {
4044 if ((_stationary_playhead = yn) == true) {
4046 // FIXME need a 3.0 equivalent of this 2.X call
4047 // update_current_screen ();
4054 Editor::playlist_selector () const
4056 return *_playlist_selector;
4060 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4062 if (paste_count == 0) {
4063 /* don't bother calculating an offset that will be zero anyway */
4067 /* calculate basic unsnapped multi-paste offset */
4068 framecnt_t offset = paste_count * duration;
4070 /* snap offset so pos + offset is aligned to the grid */
4071 framepos_t offset_pos = pos + offset;
4072 snap_to(offset_pos, RoundUpMaybe);
4073 offset = offset_pos - pos;
4079 Editor::get_grid_beat_divisions(framepos_t position)
4081 switch (_snap_type) {
4082 case SnapToBeatDiv128: return 128;
4083 case SnapToBeatDiv64: return 64;
4084 case SnapToBeatDiv32: return 32;
4085 case SnapToBeatDiv28: return 28;
4086 case SnapToBeatDiv24: return 24;
4087 case SnapToBeatDiv20: return 20;
4088 case SnapToBeatDiv16: return 16;
4089 case SnapToBeatDiv14: return 14;
4090 case SnapToBeatDiv12: return 12;
4091 case SnapToBeatDiv10: return 10;
4092 case SnapToBeatDiv8: return 8;
4093 case SnapToBeatDiv7: return 7;
4094 case SnapToBeatDiv6: return 6;
4095 case SnapToBeatDiv5: return 5;
4096 case SnapToBeatDiv4: return 4;
4097 case SnapToBeatDiv3: return 3;
4098 case SnapToBeatDiv2: return 2;
4105 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4109 const unsigned divisions = get_grid_beat_divisions(position);
4111 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4114 switch (_snap_type) {
4116 return Evoral::Beats(1.0);
4119 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
4127 return Evoral::Beats();
4131 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4135 ret = nudge_clock->current_duration (pos);
4136 next = ret + 1; /* XXXX fix me */
4142 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4144 ArdourDialog dialog (_("Playlist Deletion"));
4145 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4146 "If it is kept, its audio files will not be cleaned.\n"
4147 "If it is deleted, audio files used by it alone will be cleaned."),
4150 dialog.set_position (WIN_POS_CENTER);
4151 dialog.get_vbox()->pack_start (label);
4155 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4156 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4157 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4159 switch (dialog.run ()) {
4160 case RESPONSE_ACCEPT:
4161 /* delete the playlist */
4165 case RESPONSE_REJECT:
4166 /* keep the playlist */
4178 Editor::audio_region_selection_covers (framepos_t where)
4180 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4181 if ((*a)->region()->covers (where)) {
4190 Editor::prepare_for_cleanup ()
4192 cut_buffer->clear_regions ();
4193 cut_buffer->clear_playlists ();
4195 selection->clear_regions ();
4196 selection->clear_playlists ();
4198 _regions->suspend_redisplay ();
4202 Editor::finish_cleanup ()
4204 _regions->resume_redisplay ();
4208 Editor::transport_loop_location()
4211 return _session->locations()->auto_loop_location();
4218 Editor::transport_punch_location()
4221 return _session->locations()->auto_punch_location();
4228 Editor::control_layout_scroll (GdkEventScroll* ev)
4230 /* Just forward to the normal canvas scroll method. The coordinate
4231 systems are different but since the canvas is always larger than the
4232 track headers, and aligned with the trackview area, this will work.
4234 In the not too distant future this layout is going away anyway and
4235 headers will be on the canvas.
4237 return canvas_scroll_event (ev, false);
4241 Editor::session_state_saved (string)
4244 _snapshots->redisplay ();
4248 Editor::update_tearoff_visibility()
4250 bool visible = ARDOUR_UI::config()->get_keep_tearoffs();
4251 _mouse_mode_tearoff->set_visible (visible);
4252 _tools_tearoff->set_visible (visible);
4253 if (_zoom_tearoff) {
4254 _zoom_tearoff->set_visible (visible);
4259 Editor::reattach_all_tearoffs ()
4261 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4262 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4263 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4267 Editor::maximise_editing_space ()
4279 Editor::restore_editing_space ()
4291 * Make new playlists for a given track and also any others that belong
4292 * to the same active route group with the `select' property.
4297 Editor::new_playlists (TimeAxisView* v)
4299 begin_reversible_command (_("new playlists"));
4300 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4301 _session->playlists->get (playlists);
4302 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4303 commit_reversible_command ();
4307 * Use a copy of the current playlist for a given track and also any others that belong
4308 * to the same active route group with the `select' property.
4313 Editor::copy_playlists (TimeAxisView* v)
4315 begin_reversible_command (_("copy playlists"));
4316 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4317 _session->playlists->get (playlists);
4318 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4319 commit_reversible_command ();
4322 /** Clear the current playlist for a given track and also any others that belong
4323 * to the same active route group with the `select' property.
4328 Editor::clear_playlists (TimeAxisView* v)
4330 begin_reversible_command (_("clear playlists"));
4331 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4332 _session->playlists->get (playlists);
4333 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4334 commit_reversible_command ();
4338 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4340 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4344 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4346 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4350 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4352 atv.clear_playlist ();
4356 Editor::on_key_press_event (GdkEventKey* ev)
4358 return key_press_focus_accelerator_handler (*this, ev);
4362 Editor::on_key_release_event (GdkEventKey* ev)
4364 return Gtk::Window::on_key_release_event (ev);
4365 // return key_press_focus_accelerator_handler (*this, ev);
4369 Editor::get_y_origin () const
4371 return vertical_adjustment.get_value ();
4374 /** Queue up a change to the viewport x origin.
4375 * @param frame New x origin.
4378 Editor::reset_x_origin (framepos_t frame)
4380 pending_visual_change.add (VisualChange::TimeOrigin);
4381 pending_visual_change.time_origin = frame;
4382 ensure_visual_change_idle_handler ();
4386 Editor::reset_y_origin (double y)
4388 pending_visual_change.add (VisualChange::YOrigin);
4389 pending_visual_change.y_origin = y;
4390 ensure_visual_change_idle_handler ();
4394 Editor::reset_zoom (framecnt_t spp)
4396 if (spp == samples_per_pixel) {
4400 pending_visual_change.add (VisualChange::ZoomLevel);
4401 pending_visual_change.samples_per_pixel = spp;
4402 ensure_visual_change_idle_handler ();
4406 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4408 reset_x_origin (frame);
4411 if (!no_save_visual) {
4412 undo_visual_stack.push_back (current_visual_state(false));
4416 Editor::VisualState::VisualState (bool with_tracks)
4417 : gui_state (with_tracks ? new GUIObjectState : 0)
4421 Editor::VisualState::~VisualState ()
4426 Editor::VisualState*
4427 Editor::current_visual_state (bool with_tracks)
4429 VisualState* vs = new VisualState (with_tracks);
4430 vs->y_position = vertical_adjustment.get_value();
4431 vs->samples_per_pixel = samples_per_pixel;
4432 vs->leftmost_frame = leftmost_frame;
4433 vs->zoom_focus = zoom_focus;
4436 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4443 Editor::undo_visual_state ()
4445 if (undo_visual_stack.empty()) {
4449 VisualState* vs = undo_visual_stack.back();
4450 undo_visual_stack.pop_back();
4453 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4456 use_visual_state (*vs);
4461 Editor::redo_visual_state ()
4463 if (redo_visual_stack.empty()) {
4467 VisualState* vs = redo_visual_stack.back();
4468 redo_visual_stack.pop_back();
4470 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4471 // why do we check here?
4472 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4475 use_visual_state (*vs);
4480 Editor::swap_visual_state ()
4482 if (undo_visual_stack.empty()) {
4483 redo_visual_state ();
4485 undo_visual_state ();
4490 Editor::use_visual_state (VisualState& vs)
4492 PBD::Unwinder<bool> nsv (no_save_visual, true);
4493 DisplaySuspender ds;
4495 vertical_adjustment.set_value (vs.y_position);
4497 set_zoom_focus (vs.zoom_focus);
4498 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4501 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4503 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4504 (*i)->clear_property_cache();
4505 (*i)->reset_visual_state ();
4509 _routes->update_visibility ();
4512 /** This is the core function that controls the zoom level of the canvas. It is called
4513 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4514 * @param spp new number of samples per pixel
4517 Editor::set_samples_per_pixel (framecnt_t spp)
4523 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4524 const framecnt_t lots_of_pixels = 4000;
4526 /* if the zoom level is greater than what you'd get trying to display 3
4527 * days of audio on a really big screen, then it's too big.
4530 if (spp * lots_of_pixels > three_days) {
4534 samples_per_pixel = spp;
4537 tempo_lines->tempo_map_changed();
4540 bool const showing_time_selection = selection->time.length() > 0;
4542 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4543 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4544 (*i)->reshow_selection (selection->time);
4548 ZoomChanged (); /* EMIT_SIGNAL */
4550 ArdourCanvas::GtkCanvasViewport* c;
4552 c = get_track_canvas();
4554 c->canvas()->zoomed ();
4557 if (playhead_cursor) {
4558 playhead_cursor->set_position (playhead_cursor->current_frame ());
4561 refresh_location_display();
4562 _summary->set_overlays_dirty ();
4564 update_marker_labels ();
4570 Editor::queue_visual_videotimeline_update ()
4573 * pending_visual_change.add (VisualChange::VideoTimeline);
4574 * or maybe even more specific: which videotimeline-image
4575 * currently it calls update_video_timeline() to update
4576 * _all outdated_ images on the video-timeline.
4577 * see 'exposeimg()' in video_image_frame.cc
4579 ensure_visual_change_idle_handler ();
4583 Editor::ensure_visual_change_idle_handler ()
4585 if (pending_visual_change.idle_handler_id < 0) {
4586 // see comment in add_to_idle_resize above.
4587 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4588 pending_visual_change.being_handled = false;
4593 Editor::_idle_visual_changer (void* arg)
4595 return static_cast<Editor*>(arg)->idle_visual_changer ();
4599 Editor::idle_visual_changer ()
4601 /* set_horizontal_position() below (and maybe other calls) call
4602 gtk_main_iteration(), so it's possible that a signal will be handled
4603 half-way through this method. If this signal wants an
4604 idle_visual_changer we must schedule another one after this one, so
4605 mark the idle_handler_id as -1 here to allow that. Also make a note
4606 that we are doing the visual change, so that changes in response to
4607 super-rapid-screen-update can be dropped if we are still processing
4611 pending_visual_change.idle_handler_id = -1;
4612 pending_visual_change.being_handled = true;
4614 VisualChange vc = pending_visual_change;
4616 pending_visual_change.pending = (VisualChange::Type) 0;
4618 visual_changer (vc);
4620 pending_visual_change.being_handled = false;
4622 return 0; /* this is always a one-shot call */
4626 Editor::visual_changer (const VisualChange& vc)
4628 double const last_time_origin = horizontal_position ();
4630 if (vc.pending & VisualChange::ZoomLevel) {
4631 set_samples_per_pixel (vc.samples_per_pixel);
4633 compute_fixed_ruler_scale ();
4635 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4636 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4638 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4639 current_bbt_points_begin, current_bbt_points_end);
4640 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4641 current_bbt_points_begin, current_bbt_points_end);
4642 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4644 update_video_timeline();
4647 if (vc.pending & VisualChange::TimeOrigin) {
4648 set_horizontal_position (vc.time_origin / samples_per_pixel);
4651 if (vc.pending & VisualChange::YOrigin) {
4652 vertical_adjustment.set_value (vc.y_origin);
4655 if (last_time_origin == horizontal_position ()) {
4656 /* changed signal not emitted */
4657 update_fixed_rulers ();
4658 redisplay_tempo (true);
4661 if (!(vc.pending & VisualChange::ZoomLevel)) {
4662 update_video_timeline();
4665 _summary->set_overlays_dirty ();
4668 struct EditorOrderTimeAxisSorter {
4669 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4670 return a->order () < b->order ();
4675 Editor::sort_track_selection (TrackViewList& sel)
4677 EditorOrderTimeAxisSorter cmp;
4682 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4685 framepos_t where = 0;
4686 EditPoint ep = _edit_point;
4688 if (Profile->get_mixbus())
4689 if (ep == EditAtSelectedMarker)
4690 ep = EditAtPlayhead;
4692 if (from_outside_canvas && (ep == EditAtMouse)) {
4693 ep = EditAtPlayhead;
4694 } else if (from_context_menu && (ep == EditAtMouse)) {
4695 return canvas_event_sample (&context_click_event, 0, 0);
4698 if (entered_marker) {
4699 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4700 return entered_marker->position();
4703 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4704 ep = EditAtSelectedMarker;
4707 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4708 ep = EditAtPlayhead;
4712 case EditAtPlayhead:
4713 if (_dragging_playhead) {
4714 if (!mouse_frame (where, ignored)) {
4715 /* XXX not right but what can we do ? */
4719 where = _session->audible_frame();
4721 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4724 case EditAtSelectedMarker:
4725 if (!selection->markers.empty()) {
4727 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4730 where = loc->start();
4734 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4742 if (!mouse_frame (where, ignored)) {
4743 /* XXX not right but what can we do ? */
4747 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4755 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4757 if (!_session) return;
4759 begin_reversible_command (cmd);
4763 if ((tll = transport_loop_location()) == 0) {
4764 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4765 XMLNode &before = _session->locations()->get_state();
4766 _session->locations()->add (loc, true);
4767 _session->set_auto_loop_location (loc);
4768 XMLNode &after = _session->locations()->get_state();
4769 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4771 XMLNode &before = tll->get_state();
4772 tll->set_hidden (false, this);
4773 tll->set (start, end);
4774 XMLNode &after = tll->get_state();
4775 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4778 commit_reversible_command ();
4782 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4784 if (!_session) return;
4786 begin_reversible_command (cmd);
4790 if ((tpl = transport_punch_location()) == 0) {
4791 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4792 XMLNode &before = _session->locations()->get_state();
4793 _session->locations()->add (loc, true);
4794 _session->set_auto_punch_location (loc);
4795 XMLNode &after = _session->locations()->get_state();
4796 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4798 XMLNode &before = tpl->get_state();
4799 tpl->set_hidden (false, this);
4800 tpl->set (start, end);
4801 XMLNode &after = tpl->get_state();
4802 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4805 commit_reversible_command ();
4808 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4809 * @param rs List to which found regions are added.
4810 * @param where Time to look at.
4811 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4814 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4816 const TrackViewList* tracks;
4819 tracks = &track_views;
4824 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4826 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4829 boost::shared_ptr<Track> tr;
4830 boost::shared_ptr<Playlist> pl;
4832 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4834 boost::shared_ptr<RegionList> regions = pl->regions_at (
4835 (framepos_t) floor ( (double) where * tr->speed()));
4837 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4838 RegionView* rv = rtv->view()->find_view (*i);
4849 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4851 const TrackViewList* tracks;
4854 tracks = &track_views;
4859 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4860 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4862 boost::shared_ptr<Track> tr;
4863 boost::shared_ptr<Playlist> pl;
4865 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4867 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4868 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4870 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4872 RegionView* rv = rtv->view()->find_view (*i);
4883 /** Get regions using the following method:
4885 * Make a region list using:
4886 * (a) any selected regions
4887 * (b) the intersection of any selected tracks and the edit point(*)
4888 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4890 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4892 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4896 Editor::get_regions_from_selection_and_edit_point ()
4898 RegionSelection regions;
4900 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4901 regions.add (entered_regionview);
4903 regions = selection->regions;
4906 if ( regions.empty() ) {
4907 TrackViewList tracks = selection->tracks;
4909 if (!tracks.empty()) {
4910 /* no region selected or entered, but some selected tracks:
4911 * act on all regions on the selected tracks at the edit point
4913 framepos_t const where = get_preferred_edit_position ();
4914 get_regions_at(regions, where, tracks);
4921 /** Get regions using the following method:
4923 * Make a region list using:
4924 * (a) any selected regions
4925 * (b) the intersection of any selected tracks and the edit point(*)
4926 * (c) if neither exists, then whatever region is under the mouse
4928 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4930 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4933 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4935 RegionSelection regions;
4937 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4938 regions.add (entered_regionview);
4940 regions = selection->regions;
4943 if ( regions.empty() ) {
4944 TrackViewList tracks = selection->tracks;
4946 if (!tracks.empty()) {
4947 /* no region selected or entered, but some selected tracks:
4948 * act on all regions on the selected tracks at the edit point
4950 get_regions_at(regions, pos, tracks);
4957 /** Start with regions that are selected, or the entered regionview if none are selected.
4958 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4959 * of the regions that we started with.
4963 Editor::get_regions_from_selection_and_entered ()
4965 RegionSelection regions = selection->regions;
4967 if (regions.empty() && entered_regionview) {
4968 regions.add (entered_regionview);
4975 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4977 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4978 RouteTimeAxisView* rtav;
4980 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4981 boost::shared_ptr<Playlist> pl;
4982 std::vector<boost::shared_ptr<Region> > results;
4983 boost::shared_ptr<Track> tr;
4985 if ((tr = rtav->track()) == 0) {
4990 if ((pl = (tr->playlist())) != 0) {
4991 boost::shared_ptr<Region> r = pl->region_by_id (id);
4993 RegionView* rv = rtav->view()->find_view (r);
4995 regions.push_back (rv);
5004 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5007 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5008 MidiTimeAxisView* mtav;
5010 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5012 mtav->get_per_region_note_selection (selection);
5019 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5021 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5023 RouteTimeAxisView* tatv;
5025 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5027 boost::shared_ptr<Playlist> pl;
5028 vector<boost::shared_ptr<Region> > results;
5030 boost::shared_ptr<Track> tr;
5032 if ((tr = tatv->track()) == 0) {
5037 if ((pl = (tr->playlist())) != 0) {
5038 if (src_comparison) {
5039 pl->get_source_equivalent_regions (region, results);
5041 pl->get_region_list_equivalent_regions (region, results);
5045 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5046 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5047 regions.push_back (marv);
5056 Editor::show_rhythm_ferret ()
5058 if (rhythm_ferret == 0) {
5059 rhythm_ferret = new RhythmFerret(*this);
5062 rhythm_ferret->set_session (_session);
5063 rhythm_ferret->show ();
5064 rhythm_ferret->present ();
5068 Editor::first_idle ()
5070 MessageDialog* dialog = 0;
5072 if (track_views.size() > 1) {
5073 dialog = new MessageDialog (
5075 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5079 ARDOUR_UI::instance()->flush_pending ();
5082 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5086 // first idle adds route children (automation tracks), so we need to redisplay here
5087 _routes->redisplay ();
5091 if (_session->undo_depth() == 0) {
5092 undo_action->set_sensitive(false);
5094 redo_action->set_sensitive(false);
5095 begin_selection_op_history ();
5101 Editor::_idle_resize (gpointer arg)
5103 return ((Editor*)arg)->idle_resize ();
5107 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5109 if (resize_idle_id < 0) {
5110 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5111 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5112 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5114 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5115 _pending_resize_amount = 0;
5118 /* make a note of the smallest resulting height, so that we can clamp the
5119 lower limit at TimeAxisView::hSmall */
5121 int32_t min_resulting = INT32_MAX;
5123 _pending_resize_amount += h;
5124 _pending_resize_view = view;
5126 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5128 if (selection->tracks.contains (_pending_resize_view)) {
5129 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5130 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5134 if (min_resulting < 0) {
5139 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5140 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5144 /** Handle pending resizing of tracks */
5146 Editor::idle_resize ()
5148 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5150 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5151 selection->tracks.contains (_pending_resize_view)) {
5153 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5154 if (*i != _pending_resize_view) {
5155 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5160 _pending_resize_amount = 0;
5161 _group_tabs->set_dirty ();
5162 resize_idle_id = -1;
5170 ENSURE_GUI_THREAD (*this, &Editor::located);
5173 playhead_cursor->set_position (_session->audible_frame ());
5174 if (_follow_playhead && !_pending_initial_locate) {
5175 reset_x_origin_to_follow_playhead ();
5179 _pending_locate_request = false;
5180 _pending_initial_locate = false;
5184 Editor::region_view_added (RegionView * rv)
5186 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5187 if (rv->region ()->id () == (*pr)) {
5188 selection->add (rv);
5189 selection->regions.pending.erase (pr);
5194 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5196 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5197 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5198 if (rv->region()->id () == (*rnote).first) {
5199 mrv->select_notes ((*rnote).second);
5200 selection->pending_midi_note_selection.erase(rnote);
5206 _summary->set_background_dirty ();
5210 Editor::region_view_removed ()
5212 _summary->set_background_dirty ();
5216 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5218 TrackViewList::const_iterator j = track_views.begin ();
5219 while (j != track_views.end()) {
5220 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5221 if (rtv && rtv->route() == r) {
5232 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5236 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5237 TimeAxisView* tv = axis_view_from_route (*i);
5247 Editor::suspend_route_redisplay ()
5250 _routes->suspend_redisplay();
5255 Editor::resume_route_redisplay ()
5258 _routes->redisplay(); // queue redisplay
5259 _routes->resume_redisplay();
5264 Editor::add_routes (RouteList& routes)
5266 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5268 RouteTimeAxisView *rtv;
5269 list<RouteTimeAxisView*> new_views;
5270 TrackViewList new_selection;
5271 bool from_scratch = (track_views.size() == 0);
5273 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5274 boost::shared_ptr<Route> route = (*x);
5276 if (route->is_auditioner() || route->is_monitor()) {
5280 DataType dt = route->input()->default_type();
5282 if (dt == ARDOUR::DataType::AUDIO) {
5283 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5284 rtv->set_route (route);
5285 } else if (dt == ARDOUR::DataType::MIDI) {
5286 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5287 rtv->set_route (route);
5289 throw unknown_type();
5292 new_views.push_back (rtv);
5293 track_views.push_back (rtv);
5294 new_selection.push_back (rtv);
5296 rtv->effective_gain_display ();
5298 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5299 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5302 if (new_views.size() > 0) {
5303 _routes->routes_added (new_views);
5304 _summary->routes_added (new_views);
5307 if (!from_scratch) {
5308 selection->tracks.clear();
5309 selection->add (new_selection);
5310 begin_selection_op_history();
5313 if (show_editor_mixer_when_tracks_arrive) {
5314 show_editor_mixer (true);
5317 editor_list_button.set_sensitive (true);
5321 Editor::timeaxisview_deleted (TimeAxisView *tv)
5323 if (tv == entered_track) {
5327 if (_session && _session->deletion_in_progress()) {
5328 /* the situation is under control */
5332 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5334 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5336 _routes->route_removed (tv);
5338 TimeAxisView::Children c = tv->get_child_list ();
5339 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5340 if (entered_track == i->get()) {
5345 /* remove it from the list of track views */
5347 TrackViewList::iterator i;
5349 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5350 i = track_views.erase (i);
5353 /* update whatever the current mixer strip is displaying, if revelant */
5355 boost::shared_ptr<Route> route;
5358 route = rtav->route ();
5361 if (current_mixer_strip && current_mixer_strip->route() == route) {
5363 TimeAxisView* next_tv;
5365 if (track_views.empty()) {
5367 } else if (i == track_views.end()) {
5368 next_tv = track_views.front();
5375 set_selected_mixer_strip (*next_tv);
5377 /* make the editor mixer strip go away setting the
5378 * button to inactive (which also unticks the menu option)
5381 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5387 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5389 if (apply_to_selection) {
5390 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5392 TrackSelection::iterator j = i;
5395 hide_track_in_display (*i, false);
5400 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5402 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5403 // this will hide the mixer strip
5404 set_selected_mixer_strip (*tv);
5407 _routes->hide_track_in_display (*tv);
5412 Editor::sync_track_view_list_and_routes ()
5414 track_views = TrackViewList (_routes->views ());
5416 _summary->set_dirty ();
5417 _group_tabs->set_dirty ();
5419 return false; // do not call again (until needed)
5423 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5425 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5430 /** Find a RouteTimeAxisView by the ID of its route */
5432 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5434 RouteTimeAxisView* v;
5436 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5437 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5438 if(v->route()->id() == id) {
5448 Editor::fit_route_group (RouteGroup *g)
5450 TrackViewList ts = axis_views_from_routes (g->route_list ());
5455 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5457 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5460 _session->cancel_audition ();
5464 if (_session->is_auditioning()) {
5465 _session->cancel_audition ();
5466 if (r == last_audition_region) {
5471 _session->audition_region (r);
5472 last_audition_region = r;
5477 Editor::hide_a_region (boost::shared_ptr<Region> r)
5479 r->set_hidden (true);
5483 Editor::show_a_region (boost::shared_ptr<Region> r)
5485 r->set_hidden (false);
5489 Editor::audition_region_from_region_list ()
5491 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5495 Editor::hide_region_from_region_list ()
5497 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5501 Editor::show_region_in_region_list ()
5503 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5507 Editor::step_edit_status_change (bool yn)
5510 start_step_editing ();
5512 stop_step_editing ();
5517 Editor::start_step_editing ()
5519 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5523 Editor::stop_step_editing ()
5525 step_edit_connection.disconnect ();
5529 Editor::check_step_edit ()
5531 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5532 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5534 mtv->check_step_edit ();
5538 return true; // do it again, till we stop
5542 Editor::scroll_press (Direction dir)
5544 ++_scroll_callbacks;
5546 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5547 /* delay the first auto-repeat */
5553 scroll_backward (1);
5561 scroll_up_one_track ();
5565 scroll_down_one_track ();
5569 /* do hacky auto-repeat */
5570 if (!_scroll_connection.connected ()) {
5572 _scroll_connection = Glib::signal_timeout().connect (
5573 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5576 _scroll_callbacks = 0;
5583 Editor::scroll_release ()
5585 _scroll_connection.disconnect ();
5588 /** Queue a change for the Editor viewport x origin to follow the playhead */
5590 Editor::reset_x_origin_to_follow_playhead ()
5592 framepos_t const frame = playhead_cursor->current_frame ();
5594 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5596 if (_session->transport_speed() < 0) {
5598 if (frame > (current_page_samples() / 2)) {
5599 center_screen (frame-(current_page_samples()/2));
5601 center_screen (current_page_samples()/2);
5608 if (frame < leftmost_frame) {
5610 if (_session->transport_rolling()) {
5611 /* rolling; end up with the playhead at the right of the page */
5612 l = frame - current_page_samples ();
5614 /* not rolling: end up with the playhead 1/4 of the way along the page */
5615 l = frame - current_page_samples() / 4;
5619 if (_session->transport_rolling()) {
5620 /* rolling: end up with the playhead on the left of the page */
5623 /* not rolling: end up with the playhead 3/4 of the way along the page */
5624 l = frame - 3 * current_page_samples() / 4;
5632 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5638 Editor::super_rapid_screen_update ()
5640 if (!_session || !_session->engine().running()) {
5644 /* METERING / MIXER STRIPS */
5646 /* update track meters, if required */
5647 if (is_mapped() && meters_running) {
5648 RouteTimeAxisView* rtv;
5649 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5650 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5651 rtv->fast_update ();
5656 /* and any current mixer strip */
5657 if (current_mixer_strip) {
5658 current_mixer_strip->fast_update ();
5661 /* PLAYHEAD AND VIEWPORT */
5663 framepos_t const frame = _session->audible_frame();
5665 /* There are a few reasons why we might not update the playhead / viewport stuff:
5667 * 1. we don't update things when there's a pending locate request, otherwise
5668 * when the editor requests a locate there is a chance that this method
5669 * will move the playhead before the locate request is processed, causing
5671 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5672 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5675 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5677 last_update_frame = frame;
5679 if (!_dragging_playhead) {
5680 playhead_cursor->set_position (frame);
5683 if (!_stationary_playhead) {
5685 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5686 /* We only do this if we aren't already
5687 handling a visual change (ie if
5688 pending_visual_change.being_handled is
5689 false) so that these requests don't stack
5690 up there are too many of them to handle in
5693 reset_x_origin_to_follow_playhead ();
5698 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5702 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5703 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5704 if (target <= 0.0) {
5707 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5708 target = (target * 0.15) + (current * 0.85);
5714 set_horizontal_position (current);
5723 Editor::session_going_away ()
5725 _have_idled = false;
5727 _session_connections.drop_connections ();
5729 super_rapid_screen_update_connection.disconnect ();
5731 selection->clear ();
5732 cut_buffer->clear ();
5734 clicked_regionview = 0;
5735 clicked_axisview = 0;
5736 clicked_routeview = 0;
5737 entered_regionview = 0;
5739 last_update_frame = 0;
5742 playhead_cursor->hide ();
5744 /* rip everything out of the list displays */
5748 _route_groups->clear ();
5750 /* do this first so that deleting a track doesn't reset cms to null
5751 and thus cause a leak.
5754 if (current_mixer_strip) {
5755 if (current_mixer_strip->get_parent() != 0) {
5756 global_hpacker.remove (*current_mixer_strip);
5758 delete current_mixer_strip;
5759 current_mixer_strip = 0;
5762 /* delete all trackviews */
5764 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5767 track_views.clear ();
5769 nudge_clock->set_session (0);
5771 editor_list_button.set_active(false);
5772 editor_list_button.set_sensitive(false);
5774 /* clear tempo/meter rulers */
5775 remove_metric_marks ();
5777 clear_marker_display ();
5779 stop_step_editing ();
5781 /* get rid of any existing editor mixer strip */
5783 WindowTitle title(Glib::get_application_name());
5784 title += _("Editor");
5786 set_title (title.get_string());
5788 SessionHandlePtr::session_going_away ();
5793 Editor::show_editor_list (bool yn)
5796 _the_notebook.show ();
5798 _the_notebook.hide ();
5803 Editor::change_region_layering_order (bool from_context_menu)
5805 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5807 if (!clicked_routeview) {
5808 if (layering_order_editor) {
5809 layering_order_editor->hide ();
5814 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5820 boost::shared_ptr<Playlist> pl = track->playlist();
5826 if (layering_order_editor == 0) {
5827 layering_order_editor = new RegionLayeringOrderEditor (*this);
5830 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5831 layering_order_editor->maybe_present ();
5835 Editor::update_region_layering_order_editor ()
5837 if (layering_order_editor && layering_order_editor->is_visible ()) {
5838 change_region_layering_order (true);
5843 Editor::setup_fade_images ()
5845 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5846 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5847 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5848 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5849 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5851 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5852 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5853 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5854 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5855 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5857 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5858 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5859 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5860 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5861 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5863 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5864 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5865 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5866 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5867 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5871 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5873 Editor::action_menu_item (std::string const & name)
5875 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5878 return *manage (a->create_menu_item ());
5882 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5884 EventBox* b = manage (new EventBox);
5885 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5886 Label* l = manage (new Label (name));
5890 _the_notebook.append_page (widget, *b);
5894 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5896 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5897 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5900 if (ev->type == GDK_2BUTTON_PRESS) {
5902 /* double-click on a notebook tab shrinks or expands the notebook */
5904 if (_notebook_shrunk) {
5905 if (pre_notebook_shrink_pane_width) {
5906 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5908 _notebook_shrunk = false;
5910 pre_notebook_shrink_pane_width = edit_pane.get_position();
5912 /* this expands the LHS of the edit pane to cover the notebook
5913 PAGE but leaves the tabs visible.
5915 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5916 _notebook_shrunk = true;
5924 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5926 using namespace Menu_Helpers;
5928 MenuList& items = _control_point_context_menu.items ();
5931 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5932 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5933 if (!can_remove_control_point (item)) {
5934 items.back().set_sensitive (false);
5937 _control_point_context_menu.popup (event->button.button, event->button.time);
5941 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5943 using namespace Menu_Helpers;
5945 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5950 /* We need to get the selection here and pass it to the operations, since
5951 popping up the menu will cause a region leave event which clears
5952 entered_regionview. */
5954 MidiRegionView& mrv = note->region_view();
5955 const RegionSelection rs = get_regions_from_selection_and_entered ();
5957 MenuList& items = _note_context_menu.items();
5960 items.push_back(MenuElem(_("Delete"),
5961 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5962 items.push_back(MenuElem(_("Edit..."),
5963 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5964 items.push_back(MenuElem(_("Legatize"),
5965 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5966 items.push_back(MenuElem(_("Quantize..."),
5967 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5968 items.push_back(MenuElem(_("Remove Overlap"),
5969 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5970 items.push_back(MenuElem(_("Transform..."),
5971 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5973 _note_context_menu.popup (event->button.button, event->button.time);
5977 Editor::zoom_vertical_modifier_released()
5979 _stepping_axis_view = 0;
5983 Editor::ui_parameter_changed (string parameter)
5985 if (parameter == "icon-set") {
5986 while (!_cursor_stack.empty()) {
5987 _cursor_stack.pop_back();
5989 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5990 _cursor_stack.push_back(_cursors->grabber);
5991 } else if (parameter == "draggable-playhead") {
5992 if (_verbose_cursor) {
5993 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());