2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include "gtkmm2ext/tearoff.h"
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/audio_track.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/audioregion.h"
71 #include "ardour/lmath.h"
72 #include "ardour/location.h"
73 #include "ardour/profile.h"
74 #include "ardour/route_group.h"
75 #include "ardour/session_playlists.h"
76 #include "ardour/tempo.h"
77 #include "ardour/utils.h"
79 #include "canvas/debug.h"
80 #include "canvas/text.h"
82 #include "control_protocol/control_protocol.h"
85 #include "analysis_window.h"
86 #include "audio_clock.h"
87 #include "audio_region_view.h"
88 #include "audio_streamview.h"
89 #include "audio_time_axis.h"
90 #include "automation_time_axis.h"
91 #include "bundle_manager.h"
92 #include "crossfade_edit.h"
96 #include "editor_cursors.h"
97 #include "editor_drag.h"
98 #include "editor_group_tabs.h"
99 #include "editor_locations.h"
100 #include "editor_regions.h"
101 #include "editor_route_groups.h"
102 #include "editor_routes.h"
103 #include "editor_snapshots.h"
104 #include "editor_summary.h"
105 #include "global_port_matrix.h"
106 #include "gui_object.h"
107 #include "gui_thread.h"
108 #include "keyboard.h"
110 #include "midi_region_view.h"
111 #include "midi_time_axis.h"
112 #include "mixer_strip.h"
113 #include "mixer_ui.h"
114 #include "mouse_cursors.h"
115 #include "note_base.h"
116 #include "playlist_selector.h"
117 #include "public_editor.h"
118 #include "quantize_dialog.h"
119 #include "region_layering_order_editor.h"
120 #include "rgb_macros.h"
121 #include "rhythm_ferret.h"
122 #include "selection.h"
124 #include "tempo_lines.h"
125 #include "time_axis_view.h"
127 #include "tooltips.h"
128 #include "ui_config.h"
130 #include "verbose_cursor.h"
135 using namespace ARDOUR;
136 using namespace ARDOUR_UI_UTILS;
139 using namespace Glib;
140 using namespace Gtkmm2ext;
141 using namespace Editing;
143 using PBD::internationalize;
145 using Gtkmm2ext::Keyboard;
147 double Editor::timebar_height = 15.0;
149 static const gchar *_snap_type_strings[] = {
183 static const gchar *_snap_mode_strings[] = {
190 static const gchar *_edit_point_strings[] = {
197 static const gchar *_edit_mode_strings[] = {
205 static const gchar *_zoom_focus_strings[] = {
215 #ifdef USE_RUBBERBAND
216 static const gchar *_rb_opt_strings[] = {
219 N_("Balanced multitimbral mixture"),
220 N_("Unpitched percussion with stable notes"),
221 N_("Crisp monophonic instrumental"),
222 N_("Unpitched solo percussion"),
223 N_("Resample without preserving pitch"),
228 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
231 pane_size_watcher (Paned* pane)
233 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
237 Quartz: impossible to access
239 so stop that by preventing it from ever getting too narrow. 35
240 pixels is basically a rough guess at the tab width.
245 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
247 gint pos = pane->get_position ();
249 if (pos > max_width_of_lhs) {
250 pane->set_position (max_width_of_lhs);
255 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
257 , _mouse_changed_selection (false)
258 /* time display buttons */
259 , minsec_label (_("Mins:Secs"))
260 , bbt_label (_("Bars:Beats"))
261 , timecode_label (_("Timecode"))
262 , samples_label (_("Samples"))
263 , tempo_label (_("Tempo"))
264 , meter_label (_("Meter"))
265 , mark_label (_("Location Markers"))
266 , range_mark_label (_("Range Markers"))
267 , transport_mark_label (_("Loop/Punch Ranges"))
268 , cd_mark_label (_("CD Markers"))
269 , videotl_label (_("Video Timeline"))
270 , edit_packer (4, 4, true)
272 /* the values here don't matter: layout widgets
273 reset them as needed.
276 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
277 , horizontal_adjustment (0.0, 0.0, 1e16)
278 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
280 , controls_layout (unused_adjustment, vertical_adjustment)
282 /* tool bar related */
284 , toolbar_selection_clock_table (2,3)
285 , _mouse_mode_tearoff (0)
286 , automation_mode_button (_("mode"))
290 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
291 , selection_op_cmd_depth (0)
292 , selection_op_history_it (0)
296 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
297 , meters_running(false)
298 , _pending_locate_request (false)
299 , _pending_initial_locate (false)
300 , _last_cut_copy_source_track (0)
302 , _region_selection_change_updates_region_list (true)
303 , _following_mixer_selection (false)
304 , _control_point_toggled_on_press (false)
305 , _stepping_axis_view (0)
306 , quantize_dialog (0)
307 , _main_menu_disabler (0)
311 /* we are a singleton */
313 PublicEditor::_instance = this;
317 selection = new Selection (this);
318 cut_buffer = new Selection (this);
319 _selection_memento = new SelectionMemento ();
320 selection_op_history.clear();
323 clicked_regionview = 0;
324 clicked_axisview = 0;
325 clicked_routeview = 0;
326 clicked_control_point = 0;
327 last_update_frame = 0;
330 _drags = new DragManager (this);
333 current_mixer_strip = 0;
336 snap_type_strings = I18N (_snap_type_strings);
337 snap_mode_strings = I18N (_snap_mode_strings);
338 zoom_focus_strings = I18N (_zoom_focus_strings);
339 edit_mode_strings = I18N (_edit_mode_strings);
340 edit_point_strings = I18N (_edit_point_strings);
341 #ifdef USE_RUBBERBAND
342 rb_opt_strings = I18N (_rb_opt_strings);
346 build_edit_mode_menu();
347 build_zoom_focus_menu();
348 build_track_count_menu();
349 build_snap_mode_menu();
350 build_snap_type_menu();
351 build_edit_point_menu();
353 snap_threshold = 5.0;
354 bbt_beat_subdivision = 4;
355 _visible_canvas_width = 0;
356 _visible_canvas_height = 0;
357 autoscroll_horizontal_allowed = false;
358 autoscroll_vertical_allowed = false;
363 current_interthread_info = 0;
364 _show_measures = true;
366 show_gain_after_trim = false;
368 have_pending_keyboard_selection = false;
369 _follow_playhead = true;
370 _stationary_playhead = false;
371 editor_ruler_menu = 0;
372 no_ruler_shown_update = false;
374 range_marker_menu = 0;
375 marker_menu_item = 0;
376 tempo_or_meter_marker_menu = 0;
377 transport_marker_menu = 0;
378 new_transport_marker_menu = 0;
379 editor_mixer_strip_width = Wide;
380 show_editor_mixer_when_tracks_arrive = false;
381 region_edit_menu_split_multichannel_item = 0;
382 region_edit_menu_split_item = 0;
385 mouse_mode = MouseObject;
386 current_stepping_trackview = 0;
388 entered_regionview = 0;
390 clear_entered_track = false;
393 button_release_can_deselect = true;
394 _dragging_playhead = false;
395 _dragging_edit_point = false;
396 select_new_marker = false;
398 layering_order_editor = 0;
399 no_save_visual = false;
401 within_track_canvas = false;
403 scrubbing_direction = 0;
407 location_marker_color = UIConfiguration::instance().color ("location marker");
408 location_range_color = UIConfiguration::instance().color ("location range");
409 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
410 location_loop_color = UIConfiguration::instance().color ("location loop");
411 location_punch_color = UIConfiguration::instance().color ("location punch");
413 zoom_focus = ZoomFocusPlayhead;
414 _edit_point = EditAtMouse;
415 _visible_track_count = -1;
417 samples_per_pixel = 2048; /* too early to use reset_zoom () */
419 timebar_height = std::max(12., ceil (15. * UIConfiguration::instance().get_ui_scale()));
420 TimeAxisView::setup_sizes ();
421 ArdourMarker::setup_sizes (timebar_height);
423 _scroll_callbacks = 0;
425 bbt_label.set_name ("EditorRulerLabel");
426 bbt_label.set_size_request (-1, (int)timebar_height);
427 bbt_label.set_alignment (1.0, 0.5);
428 bbt_label.set_padding (5,0);
430 bbt_label.set_no_show_all();
431 minsec_label.set_name ("EditorRulerLabel");
432 minsec_label.set_size_request (-1, (int)timebar_height);
433 minsec_label.set_alignment (1.0, 0.5);
434 minsec_label.set_padding (5,0);
435 minsec_label.hide ();
436 minsec_label.set_no_show_all();
437 timecode_label.set_name ("EditorRulerLabel");
438 timecode_label.set_size_request (-1, (int)timebar_height);
439 timecode_label.set_alignment (1.0, 0.5);
440 timecode_label.set_padding (5,0);
441 timecode_label.hide ();
442 timecode_label.set_no_show_all();
443 samples_label.set_name ("EditorRulerLabel");
444 samples_label.set_size_request (-1, (int)timebar_height);
445 samples_label.set_alignment (1.0, 0.5);
446 samples_label.set_padding (5,0);
447 samples_label.hide ();
448 samples_label.set_no_show_all();
450 tempo_label.set_name ("EditorRulerLabel");
451 tempo_label.set_size_request (-1, (int)timebar_height);
452 tempo_label.set_alignment (1.0, 0.5);
453 tempo_label.set_padding (5,0);
455 tempo_label.set_no_show_all();
457 meter_label.set_name ("EditorRulerLabel");
458 meter_label.set_size_request (-1, (int)timebar_height);
459 meter_label.set_alignment (1.0, 0.5);
460 meter_label.set_padding (5,0);
462 meter_label.set_no_show_all();
464 if (Profile->get_trx()) {
465 mark_label.set_text (_("Markers"));
467 mark_label.set_name ("EditorRulerLabel");
468 mark_label.set_size_request (-1, (int)timebar_height);
469 mark_label.set_alignment (1.0, 0.5);
470 mark_label.set_padding (5,0);
472 mark_label.set_no_show_all();
474 cd_mark_label.set_name ("EditorRulerLabel");
475 cd_mark_label.set_size_request (-1, (int)timebar_height);
476 cd_mark_label.set_alignment (1.0, 0.5);
477 cd_mark_label.set_padding (5,0);
478 cd_mark_label.hide();
479 cd_mark_label.set_no_show_all();
481 videotl_bar_height = 4;
482 videotl_label.set_name ("EditorRulerLabel");
483 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
484 videotl_label.set_alignment (1.0, 0.5);
485 videotl_label.set_padding (5,0);
486 videotl_label.hide();
487 videotl_label.set_no_show_all();
489 range_mark_label.set_name ("EditorRulerLabel");
490 range_mark_label.set_size_request (-1, (int)timebar_height);
491 range_mark_label.set_alignment (1.0, 0.5);
492 range_mark_label.set_padding (5,0);
493 range_mark_label.hide();
494 range_mark_label.set_no_show_all();
496 transport_mark_label.set_name ("EditorRulerLabel");
497 transport_mark_label.set_size_request (-1, (int)timebar_height);
498 transport_mark_label.set_alignment (1.0, 0.5);
499 transport_mark_label.set_padding (5,0);
500 transport_mark_label.hide();
501 transport_mark_label.set_no_show_all();
503 initialize_canvas ();
505 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
507 _summary = new EditorSummary (this);
509 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
510 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
512 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
514 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
515 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
517 edit_controls_vbox.set_spacing (0);
518 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
519 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
521 HBox* h = manage (new HBox);
522 _group_tabs = new EditorGroupTabs (this);
523 if (!ARDOUR::Profile->get_trx()) {
524 h->pack_start (*_group_tabs, PACK_SHRINK);
526 h->pack_start (edit_controls_vbox);
527 controls_layout.add (*h);
529 controls_layout.set_name ("EditControlsBase");
530 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
531 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
532 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
534 _cursors = new MouseCursors;
535 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
536 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
538 /* Push default cursor to ever-present bottom of cursor stack. */
539 push_canvas_cursor(_cursors->grabber);
541 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
543 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
544 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
545 pad_line_1->set_outline_color (0xFF0000FF);
551 edit_packer.set_col_spacings (0);
552 edit_packer.set_row_spacings (0);
553 edit_packer.set_homogeneous (false);
554 edit_packer.set_border_width (0);
555 edit_packer.set_name ("EditorWindow");
557 time_bars_event_box.add (time_bars_vbox);
558 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
559 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
561 /* labels for the time bars */
562 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
564 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
566 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
568 bottom_hbox.set_border_width (2);
569 bottom_hbox.set_spacing (3);
571 _route_groups = new EditorRouteGroups (this);
572 _routes = new EditorRoutes (this);
573 _regions = new EditorRegions (this);
574 _snapshots = new EditorSnapshots (this);
575 _locations = new EditorLocations (this);
577 /* these are static location signals */
579 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
580 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
581 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
583 add_notebook_page (_("Regions"), _regions->widget ());
584 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
585 add_notebook_page (_("Snapshots"), _snapshots->widget ());
586 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
587 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
589 _the_notebook.set_show_tabs (true);
590 _the_notebook.set_scrollable (true);
591 _the_notebook.popup_disable ();
592 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
593 _the_notebook.show_all ();
595 _notebook_shrunk = false;
597 editor_summary_pane.pack1(edit_packer);
599 Button* summary_arrows_left_left = manage (new Button);
600 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
601 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
602 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
604 Button* summary_arrows_left_right = manage (new Button);
605 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
606 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
607 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
609 VBox* summary_arrows_left = manage (new VBox);
610 summary_arrows_left->pack_start (*summary_arrows_left_left);
611 summary_arrows_left->pack_start (*summary_arrows_left_right);
613 Button* summary_arrows_right_up = manage (new Button);
614 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
615 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
616 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
618 Button* summary_arrows_right_down = manage (new Button);
619 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
620 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
621 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
623 VBox* summary_arrows_right = manage (new VBox);
624 summary_arrows_right->pack_start (*summary_arrows_right_up);
625 summary_arrows_right->pack_start (*summary_arrows_right_down);
627 Frame* summary_frame = manage (new Frame);
628 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
630 summary_frame->add (*_summary);
631 summary_frame->show ();
633 _summary_hbox.pack_start (*summary_arrows_left, false, false);
634 _summary_hbox.pack_start (*summary_frame, true, true);
635 _summary_hbox.pack_start (*summary_arrows_right, false, false);
637 if (!ARDOUR::Profile->get_trx()) {
638 editor_summary_pane.pack2 (_summary_hbox);
641 edit_pane.pack1 (editor_summary_pane, true, true);
642 if (!ARDOUR::Profile->get_trx()) {
643 edit_pane.pack2 (_the_notebook, false, true);
646 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
648 /* XXX: editor_summary_pane might need similar to the edit_pane */
650 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
652 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
653 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
655 top_hbox.pack_start (toolbar_frame);
657 HBox *hbox = manage (new HBox);
658 hbox->pack_start (edit_pane, true, true);
660 global_vpacker.pack_start (top_hbox, false, false);
661 global_vpacker.pack_start (*hbox, true, true);
663 global_hpacker.pack_start (global_vpacker, true, true);
665 set_name ("EditorWindow");
666 add_accel_group (ActionManager::ui_manager->get_accel_group());
668 status_bar_hpacker.show ();
670 vpacker.pack_end (status_bar_hpacker, false, false);
671 vpacker.pack_end (global_hpacker, true, true);
673 /* register actions now so that set_state() can find them and set toggles/checks etc */
676 /* when we start using our own keybinding system for the editor, this
677 * will be uncommented
683 set_zoom_focus (zoom_focus);
684 set_visible_track_count (_visible_track_count);
685 _snap_type = SnapToBeat;
686 set_snap_to (_snap_type);
687 _snap_mode = SnapOff;
688 set_snap_mode (_snap_mode);
689 set_mouse_mode (MouseObject, true);
690 pre_internal_snap_type = _snap_type;
691 pre_internal_snap_mode = _snap_mode;
692 internal_snap_type = _snap_type;
693 internal_snap_mode = _snap_mode;
694 set_edit_point_preference (EditAtMouse, true);
696 _playlist_selector = new PlaylistSelector();
697 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
699 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
703 nudge_forward_button.set_name ("nudge button");
704 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
706 nudge_backward_button.set_name ("nudge button");
707 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
709 fade_context_menu.set_name ("ArdourContextMenu");
711 /* icons, titles, WM stuff */
713 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
714 Glib::RefPtr<Gdk::Pixbuf> icon;
716 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
717 window_icons.push_back (icon);
719 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
720 window_icons.push_back (icon);
722 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
723 window_icons.push_back (icon);
725 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
726 window_icons.push_back (icon);
728 if (!window_icons.empty()) {
729 // set_icon_list (window_icons);
730 set_default_icon_list (window_icons);
733 WindowTitle title(Glib::get_application_name());
734 title += _("Editor");
735 set_title (title.get_string());
736 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
739 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
741 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
742 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
744 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
746 /* allow external control surfaces/protocols to do various things */
748 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
749 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
750 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
751 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
752 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
753 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
754 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
755 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
756 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
757 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
758 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
759 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
760 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
761 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
763 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
764 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
765 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
766 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
767 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
769 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
771 /* problematic: has to return a value and thus cannot be x-thread */
773 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
775 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
776 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
778 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
780 _ignore_region_action = false;
781 _last_region_menu_was_main = false;
782 _popup_region_menu_item = 0;
784 _ignore_follow_edits = false;
786 _show_marker_lines = false;
788 /* Button bindings */
790 button_bindings = new Bindings;
792 XMLNode* node = button_settings();
794 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
795 button_bindings->load (**i);
801 /* grab current parameter state */
802 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
803 UIConfiguration::instance().map_parameters (pc);
805 setup_fade_images ();
812 delete button_bindings;
814 delete _route_groups;
815 delete _track_canvas_viewport;
818 delete quantize_dialog;
824 delete _playlist_selector;
828 Editor::button_settings () const
830 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
831 XMLNode* node = find_named_node (*settings, X_("Buttons"));
834 node = new XMLNode (X_("Buttons"));
841 Editor::add_toplevel_menu (Container& cont)
843 vpacker.pack_start (cont, false, false);
848 Editor::add_transport_frame (Container& cont)
850 if(ARDOUR::Profile->get_mixbus()) {
851 global_vpacker.pack_start (cont, false, false);
852 global_vpacker.reorder_child (cont, 0);
855 vpacker.pack_start (cont, false, false);
860 Editor::get_smart_mode () const
862 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
866 Editor::catch_vanishing_regionview (RegionView *rv)
868 /* note: the selection will take care of the vanishing
869 audioregionview by itself.
872 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
876 if (clicked_regionview == rv) {
877 clicked_regionview = 0;
880 if (entered_regionview == rv) {
881 set_entered_regionview (0);
884 if (!_all_region_actions_sensitized) {
885 sensitize_all_region_actions (true);
890 Editor::set_entered_regionview (RegionView* rv)
892 if (rv == entered_regionview) {
896 if (entered_regionview) {
897 entered_regionview->exited ();
900 entered_regionview = rv;
902 if (entered_regionview != 0) {
903 entered_regionview->entered ();
906 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
907 /* This RegionView entry might have changed what region actions
908 are allowed, so sensitize them all in case a key is pressed.
910 sensitize_all_region_actions (true);
915 Editor::set_entered_track (TimeAxisView* tav)
918 entered_track->exited ();
924 entered_track->entered ();
929 Editor::show_window ()
931 if (!is_visible ()) {
935 /* XXX: this is a bit unfortunate; it would probably
936 be nicer if we could just call show () above rather
937 than needing the show_all ()
940 /* re-hide stuff if necessary */
941 editor_list_button_toggled ();
942 parameter_changed ("show-summary");
943 parameter_changed ("show-group-tabs");
944 parameter_changed ("show-zoom-tools");
946 /* now reset all audio_time_axis heights, because widgets might need
952 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
953 tv = (static_cast<TimeAxisView*>(*i));
957 if (current_mixer_strip) {
958 current_mixer_strip->hide_things ();
959 current_mixer_strip->parameter_changed ("mixer-element-visibility");
967 Editor::instant_save ()
969 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
974 _session->add_instant_xml(get_state());
976 Config->add_instant_xml(get_state());
981 Editor::control_vertical_zoom_in_all ()
983 tav_zoom_smooth (false, true);
987 Editor::control_vertical_zoom_out_all ()
989 tav_zoom_smooth (true, true);
993 Editor::control_vertical_zoom_in_selected ()
995 tav_zoom_smooth (false, false);
999 Editor::control_vertical_zoom_out_selected ()
1001 tav_zoom_smooth (true, false);
1005 Editor::control_view (uint32_t view)
1007 goto_visual_state (view);
1011 Editor::control_unselect ()
1013 selection->clear_tracks ();
1017 Editor::control_select (uint32_t rid, Selection::Operation op)
1019 /* handles the (static) signal from the ControlProtocol class that
1020 * requests setting the selected track to a given RID
1027 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1033 TimeAxisView* tav = axis_view_from_route (r);
1037 case Selection::Add:
1038 selection->add (tav);
1040 case Selection::Toggle:
1041 selection->toggle (tav);
1043 case Selection::Extend:
1045 case Selection::Set:
1046 selection->set (tav);
1050 selection->clear_tracks ();
1055 Editor::control_step_tracks_up ()
1057 scroll_tracks_up_line ();
1061 Editor::control_step_tracks_down ()
1063 scroll_tracks_down_line ();
1067 Editor::control_scroll (float fraction)
1069 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1075 double step = fraction * current_page_samples();
1078 _control_scroll_target is an optional<T>
1080 it acts like a pointer to an framepos_t, with
1081 a operator conversion to boolean to check
1082 that it has a value could possibly use
1083 playhead_cursor->current_frame to store the
1084 value and a boolean in the class to know
1085 when it's out of date
1088 if (!_control_scroll_target) {
1089 _control_scroll_target = _session->transport_frame();
1090 _dragging_playhead = true;
1093 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1094 *_control_scroll_target = 0;
1095 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1096 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1098 *_control_scroll_target += (framepos_t) trunc (step);
1101 /* move visuals, we'll catch up with it later */
1103 playhead_cursor->set_position (*_control_scroll_target);
1104 UpdateAllTransportClocks (*_control_scroll_target);
1106 if (*_control_scroll_target > (current_page_samples() / 2)) {
1107 /* try to center PH in window */
1108 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1114 Now we do a timeout to actually bring the session to the right place
1115 according to the playhead. This is to avoid reading disk buffers on every
1116 call to control_scroll, which is driven by ScrollTimeline and therefore
1117 probably by a control surface wheel which can generate lots of events.
1119 /* cancel the existing timeout */
1121 control_scroll_connection.disconnect ();
1123 /* add the next timeout */
1125 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1129 Editor::deferred_control_scroll (framepos_t /*target*/)
1131 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1132 // reset for next stream
1133 _control_scroll_target = boost::none;
1134 _dragging_playhead = false;
1139 Editor::access_action (std::string action_group, std::string action_item)
1145 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1148 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1156 Editor::on_realize ()
1158 Window::on_realize ();
1161 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1162 start_lock_event_timing ();
1165 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1169 Editor::start_lock_event_timing ()
1171 /* check if we should lock the GUI every 30 seconds */
1173 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1177 Editor::generic_event_handler (GdkEvent* ev)
1180 case GDK_BUTTON_PRESS:
1181 case GDK_BUTTON_RELEASE:
1182 case GDK_MOTION_NOTIFY:
1184 case GDK_KEY_RELEASE:
1185 gettimeofday (&last_event_time, 0);
1188 case GDK_LEAVE_NOTIFY:
1189 switch (ev->crossing.detail) {
1190 case GDK_NOTIFY_UNKNOWN:
1191 case GDK_NOTIFY_INFERIOR:
1192 case GDK_NOTIFY_ANCESTOR:
1194 case GDK_NOTIFY_VIRTUAL:
1195 case GDK_NOTIFY_NONLINEAR:
1196 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1197 /* leaving window, so reset focus, thus ending any and
1198 all text entry operations.
1213 Editor::lock_timeout_callback ()
1215 struct timeval now, delta;
1217 gettimeofday (&now, 0);
1219 timersub (&now, &last_event_time, &delta);
1221 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1223 /* don't call again. Returning false will effectively
1224 disconnect us from the timer callback.
1226 unlock() will call start_lock_event_timing() to get things
1236 Editor::map_position_change (framepos_t frame)
1238 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1240 if (_session == 0) {
1244 if (_follow_playhead) {
1245 center_screen (frame);
1248 playhead_cursor->set_position (frame);
1252 Editor::center_screen (framepos_t frame)
1254 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1256 /* if we're off the page, then scroll.
1259 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1260 center_screen_internal (frame, page);
1265 Editor::center_screen_internal (framepos_t frame, float page)
1270 frame -= (framepos_t) page;
1275 reset_x_origin (frame);
1280 Editor::update_title ()
1282 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1285 bool dirty = _session->dirty();
1287 string session_name;
1289 if (_session->snap_name() != _session->name()) {
1290 session_name = _session->snap_name();
1292 session_name = _session->name();
1296 session_name = "*" + session_name;
1299 WindowTitle title(session_name);
1300 title += Glib::get_application_name();
1301 set_title (title.get_string());
1303 /* ::session_going_away() will have taken care of it */
1308 Editor::set_session (Session *t)
1310 SessionHandlePtr::set_session (t);
1316 _playlist_selector->set_session (_session);
1317 nudge_clock->set_session (_session);
1318 _summary->set_session (_session);
1319 _group_tabs->set_session (_session);
1320 _route_groups->set_session (_session);
1321 _regions->set_session (_session);
1322 _snapshots->set_session (_session);
1323 _routes->set_session (_session);
1324 _locations->set_session (_session);
1326 if (rhythm_ferret) {
1327 rhythm_ferret->set_session (_session);
1330 if (analysis_window) {
1331 analysis_window->set_session (_session);
1335 sfbrowser->set_session (_session);
1338 compute_fixed_ruler_scale ();
1340 /* Make sure we have auto loop and auto punch ranges */
1342 Location* loc = _session->locations()->auto_loop_location();
1344 loc->set_name (_("Loop"));
1347 loc = _session->locations()->auto_punch_location();
1350 loc->set_name (_("Punch"));
1353 refresh_location_display ();
1355 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1356 the selected Marker; this needs the LocationMarker list to be available.
1358 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1359 set_state (*node, Stateful::loading_state_version);
1361 /* catch up with the playhead */
1363 _session->request_locate (playhead_cursor->current_frame ());
1364 _pending_initial_locate = true;
1368 /* These signals can all be emitted by a non-GUI thread. Therefore the
1369 handlers for them must not attempt to directly interact with the GUI,
1370 but use PBD::Signal<T>::connect() which accepts an event loop
1371 ("context") where the handler will be asked to run.
1374 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1375 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1376 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1377 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1378 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1379 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1380 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1381 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1382 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1383 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1384 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1385 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1386 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1388 playhead_cursor->show ();
1390 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1391 Config->map_parameters (pc);
1392 _session->config.map_parameters (pc);
1394 restore_ruler_visibility ();
1395 //tempo_map_changed (PropertyChange (0));
1396 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1398 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1399 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1402 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1403 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1406 switch (_snap_type) {
1407 case SnapToRegionStart:
1408 case SnapToRegionEnd:
1409 case SnapToRegionSync:
1410 case SnapToRegionBoundary:
1411 build_region_boundary_cache ();
1418 /* register for undo history */
1419 _session->register_with_memento_command_factory(id(), this);
1420 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1422 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1424 start_updating_meters ();
1428 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1430 if (a->get_name() == "RegionMenu") {
1431 /* When the main menu's region menu is opened, we setup the actions so that they look right
1432 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1433 so we resensitize all region actions when the entered regionview or the region selection
1434 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1435 happens after the region context menu is opened. So we set a flag here, too.
1439 sensitize_the_right_region_actions ();
1440 _last_region_menu_was_main = true;
1445 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1447 using namespace Menu_Helpers;
1449 void (Editor::*emf)(FadeShape);
1450 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1453 images = &_xfade_in_images;
1454 emf = &Editor::set_fade_in_shape;
1456 images = &_xfade_out_images;
1457 emf = &Editor::set_fade_out_shape;
1462 _("Linear (for highly correlated material)"),
1463 *(*images)[FadeLinear],
1464 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1468 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1472 _("Constant power"),
1473 *(*images)[FadeConstantPower],
1474 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1477 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1482 *(*images)[FadeSymmetric],
1483 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1487 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1492 *(*images)[FadeSlow],
1493 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1496 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1501 *(*images)[FadeFast],
1502 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1505 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1508 /** Pop up a context menu for when the user clicks on a start crossfade */
1510 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1512 using namespace Menu_Helpers;
1513 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1518 MenuList& items (xfade_in_context_menu.items());
1521 if (arv->audio_region()->fade_in_active()) {
1522 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1524 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1527 items.push_back (SeparatorElem());
1528 fill_xfade_menu (items, true);
1530 xfade_in_context_menu.popup (button, time);
1533 /** Pop up a context menu for when the user clicks on an end crossfade */
1535 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1537 using namespace Menu_Helpers;
1538 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1543 MenuList& items (xfade_out_context_menu.items());
1546 if (arv->audio_region()->fade_out_active()) {
1547 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1549 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1552 items.push_back (SeparatorElem());
1553 fill_xfade_menu (items, false);
1555 xfade_out_context_menu.popup (button, time);
1559 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1561 using namespace Menu_Helpers;
1562 Menu* (Editor::*build_menu_function)();
1565 switch (item_type) {
1567 case RegionViewName:
1568 case RegionViewNameHighlight:
1569 case LeftFrameHandle:
1570 case RightFrameHandle:
1571 if (with_selection) {
1572 build_menu_function = &Editor::build_track_selection_context_menu;
1574 build_menu_function = &Editor::build_track_region_context_menu;
1579 if (with_selection) {
1580 build_menu_function = &Editor::build_track_selection_context_menu;
1582 build_menu_function = &Editor::build_track_context_menu;
1587 if (clicked_routeview->track()) {
1588 build_menu_function = &Editor::build_track_context_menu;
1590 build_menu_function = &Editor::build_track_bus_context_menu;
1595 /* probably shouldn't happen but if it does, we don't care */
1599 menu = (this->*build_menu_function)();
1600 menu->set_name ("ArdourContextMenu");
1602 /* now handle specific situations */
1604 switch (item_type) {
1606 case RegionViewName:
1607 case RegionViewNameHighlight:
1608 case LeftFrameHandle:
1609 case RightFrameHandle:
1610 if (!with_selection) {
1611 if (region_edit_menu_split_item) {
1612 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1613 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1615 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1618 if (region_edit_menu_split_multichannel_item) {
1619 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1620 region_edit_menu_split_multichannel_item->set_sensitive (true);
1622 region_edit_menu_split_multichannel_item->set_sensitive (false);
1635 /* probably shouldn't happen but if it does, we don't care */
1639 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1641 /* Bounce to disk */
1643 using namespace Menu_Helpers;
1644 MenuList& edit_items = menu->items();
1646 edit_items.push_back (SeparatorElem());
1648 switch (clicked_routeview->audio_track()->freeze_state()) {
1649 case AudioTrack::NoFreeze:
1650 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1653 case AudioTrack::Frozen:
1654 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1657 case AudioTrack::UnFrozen:
1658 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1664 if (item_type == StreamItem && clicked_routeview) {
1665 clicked_routeview->build_underlay_menu(menu);
1668 /* When the region menu is opened, we setup the actions so that they look right
1671 sensitize_the_right_region_actions ();
1672 _last_region_menu_was_main = false;
1674 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1675 menu->popup (button, time);
1679 Editor::build_track_context_menu ()
1681 using namespace Menu_Helpers;
1683 MenuList& edit_items = track_context_menu.items();
1686 add_dstream_context_items (edit_items);
1687 return &track_context_menu;
1691 Editor::build_track_bus_context_menu ()
1693 using namespace Menu_Helpers;
1695 MenuList& edit_items = track_context_menu.items();
1698 add_bus_context_items (edit_items);
1699 return &track_context_menu;
1703 Editor::build_track_region_context_menu ()
1705 using namespace Menu_Helpers;
1706 MenuList& edit_items = track_region_context_menu.items();
1709 /* we've just cleared the track region context menu, so the menu that these
1710 two items were on will have disappeared; stop them dangling.
1712 region_edit_menu_split_item = 0;
1713 region_edit_menu_split_multichannel_item = 0;
1715 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1718 boost::shared_ptr<Track> tr;
1719 boost::shared_ptr<Playlist> pl;
1721 if ((tr = rtv->track())) {
1722 add_region_context_items (edit_items, tr);
1726 add_dstream_context_items (edit_items);
1728 return &track_region_context_menu;
1732 Editor::analyze_region_selection ()
1734 if (analysis_window == 0) {
1735 analysis_window = new AnalysisWindow();
1738 analysis_window->set_session(_session);
1740 analysis_window->show_all();
1743 analysis_window->set_regionmode();
1744 analysis_window->analyze();
1746 analysis_window->present();
1750 Editor::analyze_range_selection()
1752 if (analysis_window == 0) {
1753 analysis_window = new AnalysisWindow();
1756 analysis_window->set_session(_session);
1758 analysis_window->show_all();
1761 analysis_window->set_rangemode();
1762 analysis_window->analyze();
1764 analysis_window->present();
1768 Editor::build_track_selection_context_menu ()
1770 using namespace Menu_Helpers;
1771 MenuList& edit_items = track_selection_context_menu.items();
1772 edit_items.clear ();
1774 add_selection_context_items (edit_items);
1775 // edit_items.push_back (SeparatorElem());
1776 // add_dstream_context_items (edit_items);
1778 return &track_selection_context_menu;
1782 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1784 using namespace Menu_Helpers;
1786 /* OK, stick the region submenu at the top of the list, and then add
1790 RegionSelection rs = get_regions_from_selection_and_entered ();
1792 string::size_type pos = 0;
1793 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1795 /* we have to hack up the region name because "_" has a special
1796 meaning for menu titles.
1799 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1800 menu_item_name.replace (pos, 1, "__");
1804 if (_popup_region_menu_item == 0) {
1805 _popup_region_menu_item = new MenuItem (menu_item_name);
1806 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1807 _popup_region_menu_item->show ();
1809 _popup_region_menu_item->set_label (menu_item_name);
1812 /* No latering allowed in later is higher layering model */
1813 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1814 if (act && Config->get_layer_model() == LaterHigher) {
1815 act->set_sensitive (false);
1817 act->set_sensitive (true);
1820 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1822 edit_items.push_back (*_popup_region_menu_item);
1823 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1824 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1826 edit_items.push_back (SeparatorElem());
1829 /** Add context menu items relevant to selection ranges.
1830 * @param edit_items List to add the items to.
1833 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1835 using namespace Menu_Helpers;
1837 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1838 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1840 edit_items.push_back (SeparatorElem());
1841 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1843 edit_items.push_back (SeparatorElem());
1844 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1846 edit_items.push_back (SeparatorElem());
1848 edit_items.push_back (
1850 _("Move Range Start to Previous Region Boundary"),
1851 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1855 edit_items.push_back (
1857 _("Move Range Start to Next Region Boundary"),
1858 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1862 edit_items.push_back (
1864 _("Move Range End to Previous Region Boundary"),
1865 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1869 edit_items.push_back (
1871 _("Move Range End to Next Region Boundary"),
1872 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1876 edit_items.push_back (SeparatorElem());
1877 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1878 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1880 edit_items.push_back (SeparatorElem());
1881 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1883 edit_items.push_back (SeparatorElem());
1884 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1885 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1886 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1888 edit_items.push_back (SeparatorElem());
1889 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1891 edit_items.push_back (SeparatorElem());
1892 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1893 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1894 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1896 edit_items.push_back (SeparatorElem());
1897 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1898 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1899 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1900 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1901 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1902 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1903 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1909 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1911 using namespace Menu_Helpers;
1915 Menu *play_menu = manage (new Menu);
1916 MenuList& play_items = play_menu->items();
1917 play_menu->set_name ("ArdourContextMenu");
1919 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1920 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1921 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1922 play_items.push_back (SeparatorElem());
1923 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1925 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1929 Menu *select_menu = manage (new Menu);
1930 MenuList& select_items = select_menu->items();
1931 select_menu->set_name ("ArdourContextMenu");
1933 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1934 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1935 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1936 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1937 select_items.push_back (SeparatorElem());
1938 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1939 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1940 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
1941 select_items.push_back (SeparatorElem());
1942 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1943 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1944 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1945 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1946 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1947 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1948 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1950 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1954 Menu *cutnpaste_menu = manage (new Menu);
1955 MenuList& cutnpaste_items = cutnpaste_menu->items();
1956 cutnpaste_menu->set_name ("ArdourContextMenu");
1958 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1959 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1960 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1962 cutnpaste_items.push_back (SeparatorElem());
1964 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1965 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1967 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1969 /* Adding new material */
1971 edit_items.push_back (SeparatorElem());
1972 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1973 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1977 Menu *nudge_menu = manage (new Menu());
1978 MenuList& nudge_items = nudge_menu->items();
1979 nudge_menu->set_name ("ArdourContextMenu");
1981 edit_items.push_back (SeparatorElem());
1982 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1983 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1984 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1985 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1987 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1991 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1993 using namespace Menu_Helpers;
1997 Menu *play_menu = manage (new Menu);
1998 MenuList& play_items = play_menu->items();
1999 play_menu->set_name ("ArdourContextMenu");
2001 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2002 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2003 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2007 Menu *select_menu = manage (new Menu);
2008 MenuList& select_items = select_menu->items();
2009 select_menu->set_name ("ArdourContextMenu");
2011 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2012 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2013 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2014 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2015 select_items.push_back (SeparatorElem());
2016 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2017 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2018 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2019 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2021 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2025 Menu *cutnpaste_menu = manage (new Menu);
2026 MenuList& cutnpaste_items = cutnpaste_menu->items();
2027 cutnpaste_menu->set_name ("ArdourContextMenu");
2029 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2030 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2031 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2033 Menu *nudge_menu = manage (new Menu());
2034 MenuList& nudge_items = nudge_menu->items();
2035 nudge_menu->set_name ("ArdourContextMenu");
2037 edit_items.push_back (SeparatorElem());
2038 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2039 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2040 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2041 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2043 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2047 Editor::snap_type() const
2053 Editor::snap_mode() const
2059 Editor::set_snap_to (SnapType st)
2061 unsigned int snap_ind = (unsigned int)st;
2063 if (internal_editing()) {
2064 internal_snap_type = st;
2066 pre_internal_snap_type = st;
2071 if (snap_ind > snap_type_strings.size() - 1) {
2073 _snap_type = (SnapType)snap_ind;
2076 string str = snap_type_strings[snap_ind];
2078 if (str != snap_type_selector.get_text()) {
2079 snap_type_selector.set_text (str);
2084 switch (_snap_type) {
2085 case SnapToBeatDiv128:
2086 case SnapToBeatDiv64:
2087 case SnapToBeatDiv32:
2088 case SnapToBeatDiv28:
2089 case SnapToBeatDiv24:
2090 case SnapToBeatDiv20:
2091 case SnapToBeatDiv16:
2092 case SnapToBeatDiv14:
2093 case SnapToBeatDiv12:
2094 case SnapToBeatDiv10:
2095 case SnapToBeatDiv8:
2096 case SnapToBeatDiv7:
2097 case SnapToBeatDiv6:
2098 case SnapToBeatDiv5:
2099 case SnapToBeatDiv4:
2100 case SnapToBeatDiv3:
2101 case SnapToBeatDiv2: {
2102 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2103 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2105 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2106 current_bbt_points_begin, current_bbt_points_end);
2107 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2108 current_bbt_points_begin, current_bbt_points_end);
2109 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2113 case SnapToRegionStart:
2114 case SnapToRegionEnd:
2115 case SnapToRegionSync:
2116 case SnapToRegionBoundary:
2117 build_region_boundary_cache ();
2125 redisplay_tempo (false);
2127 SnapChanged (); /* EMIT SIGNAL */
2131 Editor::set_snap_mode (SnapMode mode)
2133 string str = snap_mode_strings[(int)mode];
2135 if (internal_editing()) {
2136 internal_snap_mode = mode;
2138 pre_internal_snap_mode = mode;
2143 if (str != snap_mode_selector.get_text ()) {
2144 snap_mode_selector.set_text (str);
2151 Editor::set_edit_point_preference (EditPoint ep, bool force)
2153 bool changed = (_edit_point != ep);
2156 if (Profile->get_mixbus())
2157 if (ep == EditAtSelectedMarker)
2158 ep = EditAtPlayhead;
2160 string str = edit_point_strings[(int)ep];
2161 if (str != edit_point_selector.get_text ()) {
2162 edit_point_selector.set_text (str);
2165 update_all_enter_cursors();
2167 if (!force && !changed) {
2171 const char* action=NULL;
2173 switch (_edit_point) {
2174 case EditAtPlayhead:
2175 action = "edit-at-playhead";
2177 case EditAtSelectedMarker:
2178 action = "edit-at-marker";
2181 action = "edit-at-mouse";
2185 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2187 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2191 bool in_track_canvas;
2193 if (!mouse_frame (foo, in_track_canvas)) {
2194 in_track_canvas = false;
2197 reset_canvas_action_sensitivity (in_track_canvas);
2203 Editor::set_state (const XMLNode& node, int /*version*/)
2205 const XMLProperty* prop;
2212 g.base_width = default_width;
2213 g.base_height = default_height;
2217 if ((geometry = find_named_node (node, "geometry")) != 0) {
2221 if ((prop = geometry->property("x_size")) == 0) {
2222 prop = geometry->property ("x-size");
2225 g.base_width = atoi(prop->value());
2227 if ((prop = geometry->property("y_size")) == 0) {
2228 prop = geometry->property ("y-size");
2231 g.base_height = atoi(prop->value());
2234 if ((prop = geometry->property ("x_pos")) == 0) {
2235 prop = geometry->property ("x-pos");
2238 x = atoi (prop->value());
2241 if ((prop = geometry->property ("y_pos")) == 0) {
2242 prop = geometry->property ("y-pos");
2245 y = atoi (prop->value());
2249 set_default_size (g.base_width, g.base_height);
2252 if (_session && (prop = node.property ("playhead"))) {
2254 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2256 playhead_cursor->set_position (pos);
2258 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2259 playhead_cursor->set_position (0);
2262 playhead_cursor->set_position (0);
2265 if ((prop = node.property ("mixer-width"))) {
2266 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2269 if ((prop = node.property ("zoom-focus"))) {
2270 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2273 if ((prop = node.property ("zoom"))) {
2274 /* older versions of ardour used floating point samples_per_pixel */
2275 double f = PBD::atof (prop->value());
2276 reset_zoom (llrintf (f));
2278 reset_zoom (samples_per_pixel);
2281 if ((prop = node.property ("visible-track-count"))) {
2282 set_visible_track_count (PBD::atoi (prop->value()));
2285 if ((prop = node.property ("snap-to"))) {
2286 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2289 if ((prop = node.property ("snap-mode"))) {
2290 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2293 if ((prop = node.property ("internal-snap-to"))) {
2294 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2297 if ((prop = node.property ("internal-snap-mode"))) {
2298 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2301 if ((prop = node.property ("pre-internal-snap-to"))) {
2302 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2305 if ((prop = node.property ("pre-internal-snap-mode"))) {
2306 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2309 if ((prop = node.property ("mouse-mode"))) {
2310 MouseMode m = str2mousemode(prop->value());
2311 set_mouse_mode (m, true);
2313 set_mouse_mode (MouseObject, true);
2316 if ((prop = node.property ("left-frame")) != 0) {
2318 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2322 reset_x_origin (pos);
2326 if ((prop = node.property ("y-origin")) != 0) {
2327 reset_y_origin (atof (prop->value ()));
2330 if ((prop = node.property ("join-object-range"))) {
2331 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2332 bool yn = string_is_affirmative (prop->value());
2334 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2335 tact->set_active (!yn);
2336 tact->set_active (yn);
2338 set_mouse_mode(mouse_mode, true);
2341 if ((prop = node.property ("edit-point"))) {
2342 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2345 if ((prop = node.property ("show-measures"))) {
2346 bool yn = string_is_affirmative (prop->value());
2347 _show_measures = yn;
2350 if ((prop = node.property ("follow-playhead"))) {
2351 bool yn = string_is_affirmative (prop->value());
2352 set_follow_playhead (yn);
2355 if ((prop = node.property ("stationary-playhead"))) {
2356 bool yn = string_is_affirmative (prop->value());
2357 set_stationary_playhead (yn);
2360 if ((prop = node.property ("region-list-sort-type"))) {
2361 RegionListSortType st;
2362 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2365 if ((prop = node.property ("show-editor-mixer"))) {
2367 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2370 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2371 bool yn = string_is_affirmative (prop->value());
2373 /* do it twice to force the change */
2375 tact->set_active (!yn);
2376 tact->set_active (yn);
2379 if ((prop = node.property ("show-editor-list"))) {
2381 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2384 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2385 bool yn = string_is_affirmative (prop->value());
2387 /* do it twice to force the change */
2389 tact->set_active (!yn);
2390 tact->set_active (yn);
2393 if ((prop = node.property (X_("editor-list-page")))) {
2394 _the_notebook.set_current_page (atoi (prop->value ()));
2397 if ((prop = node.property (X_("show-marker-lines")))) {
2398 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2400 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2401 bool yn = string_is_affirmative (prop->value ());
2403 tact->set_active (!yn);
2404 tact->set_active (yn);
2407 XMLNodeList children = node.children ();
2408 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2409 selection->set_state (**i, Stateful::current_state_version);
2410 _regions->set_state (**i);
2413 if ((prop = node.property ("maximised"))) {
2414 bool yn = string_is_affirmative (prop->value());
2415 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2417 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2418 bool fs = tact && tact->get_active();
2420 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2424 if ((prop = node.property ("nudge-clock-value"))) {
2426 sscanf (prop->value().c_str(), "%" PRId64, &f);
2427 nudge_clock->set (f);
2429 nudge_clock->set_mode (AudioClock::Timecode);
2430 nudge_clock->set (_session->frame_rate() * 5, true);
2435 * Not all properties may have been in XML, but
2436 * those that are linked to a private variable may need changing
2441 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2443 yn = _show_measures;
2444 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2445 /* do it twice to force the change */
2446 tact->set_active (!yn);
2447 tact->set_active (yn);
2450 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2451 yn = _follow_playhead;
2453 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2454 if (tact->get_active() != yn) {
2455 tact->set_active (yn);
2459 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2460 yn = _stationary_playhead;
2462 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2463 if (tact->get_active() != yn) {
2464 tact->set_active (yn);
2473 Editor::get_state ()
2475 XMLNode* node = new XMLNode ("Editor");
2478 id().print (buf, sizeof (buf));
2479 node->add_property ("id", buf);
2481 if (is_realized()) {
2482 Glib::RefPtr<Gdk::Window> win = get_window();
2484 int x, y, width, height;
2485 win->get_root_origin(x, y);
2486 win->get_size(width, height);
2488 XMLNode* geometry = new XMLNode ("geometry");
2490 snprintf(buf, sizeof(buf), "%d", width);
2491 geometry->add_property("x-size", string(buf));
2492 snprintf(buf, sizeof(buf), "%d", height);
2493 geometry->add_property("y-size", string(buf));
2494 snprintf(buf, sizeof(buf), "%d", x);
2495 geometry->add_property("x-pos", string(buf));
2496 snprintf(buf, sizeof(buf), "%d", y);
2497 geometry->add_property("y-pos", string(buf));
2498 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2499 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2500 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2501 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2502 geometry->add_property("edit-vertical-pane-pos", string(buf));
2504 node->add_child_nocopy (*geometry);
2507 maybe_add_mixer_strip_width (*node);
2509 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2511 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2512 node->add_property ("zoom", buf);
2513 node->add_property ("snap-to", enum_2_string (_snap_type));
2514 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2515 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2516 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2517 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2518 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2519 node->add_property ("edit-point", enum_2_string (_edit_point));
2520 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2521 node->add_property ("visible-track-count", buf);
2523 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2524 node->add_property ("playhead", buf);
2525 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2526 node->add_property ("left-frame", buf);
2527 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2528 node->add_property ("y-origin", buf);
2530 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2531 node->add_property ("maximised", _maximised ? "yes" : "no");
2532 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2533 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2534 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2535 node->add_property ("mouse-mode", enum2str(mouse_mode));
2536 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2538 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2540 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2541 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2544 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2546 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2547 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2550 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2551 node->add_property (X_("editor-list-page"), buf);
2553 if (button_bindings) {
2554 XMLNode* bb = new XMLNode (X_("Buttons"));
2555 button_bindings->save (*bb);
2556 node->add_child_nocopy (*bb);
2559 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2561 node->add_child_nocopy (selection->get_state ());
2562 node->add_child_nocopy (_regions->get_state ());
2564 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2565 node->add_property ("nudge-clock-value", buf);
2570 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2571 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2573 * @return pair: TimeAxisView that y is over, layer index.
2575 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2576 * in stacked or expanded region display mode, otherwise 0.
2578 std::pair<TimeAxisView *, double>
2579 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2581 if (!trackview_relative_offset) {
2582 y -= _trackview_group->canvas_origin().y;
2586 return std::make_pair ( (TimeAxisView *) 0, 0);
2589 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2591 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2598 return std::make_pair ( (TimeAxisView *) 0, 0);
2601 /** Snap a position to the grid, if appropriate, taking into account current
2602 * grid settings and also the state of any snap modifier keys that may be pressed.
2603 * @param start Position to snap.
2604 * @param event Event to get current key modifier information from, or 0.
2607 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2609 if (!_session || !event) {
2613 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2614 if (_snap_mode == SnapOff) {
2615 snap_to_internal (start, direction, for_mark);
2618 if (_snap_mode != SnapOff) {
2619 snap_to_internal (start, direction, for_mark);
2620 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2621 /* SnapOff, but we pressed the snap_delta modifier */
2622 snap_to_internal (start, direction, for_mark);
2628 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2630 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2634 snap_to_internal (start, direction, for_mark, ensure_snap);
2638 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2640 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2641 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2643 switch (_snap_type) {
2644 case SnapToTimecodeFrame:
2645 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2646 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2647 /* start is already on a whole timecode frame, do nothing */
2648 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2649 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2651 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2655 case SnapToTimecodeSeconds:
2656 if (_session->config.get_timecode_offset_negative()) {
2657 start += _session->config.get_timecode_offset ();
2659 start -= _session->config.get_timecode_offset ();
2661 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2662 (start % one_timecode_second == 0)) {
2663 /* start is already on a whole second, do nothing */
2664 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2665 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2667 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2670 if (_session->config.get_timecode_offset_negative()) {
2671 start -= _session->config.get_timecode_offset ();
2673 start += _session->config.get_timecode_offset ();
2677 case SnapToTimecodeMinutes:
2678 if (_session->config.get_timecode_offset_negative()) {
2679 start += _session->config.get_timecode_offset ();
2681 start -= _session->config.get_timecode_offset ();
2683 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2684 (start % one_timecode_minute == 0)) {
2685 /* start is already on a whole minute, do nothing */
2686 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2687 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2689 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2691 if (_session->config.get_timecode_offset_negative()) {
2692 start -= _session->config.get_timecode_offset ();
2694 start += _session->config.get_timecode_offset ();
2698 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2699 abort(); /*NOTREACHED*/
2704 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2706 const framepos_t one_second = _session->frame_rate();
2707 const framepos_t one_minute = _session->frame_rate() * 60;
2708 framepos_t presnap = start;
2712 switch (_snap_type) {
2713 case SnapToTimecodeFrame:
2714 case SnapToTimecodeSeconds:
2715 case SnapToTimecodeMinutes:
2716 return timecode_snap_to_internal (start, direction, for_mark);
2719 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2720 start % (one_second/75) == 0) {
2721 /* start is already on a whole CD frame, do nothing */
2722 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2723 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2725 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2730 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2731 start % one_second == 0) {
2732 /* start is already on a whole second, do nothing */
2733 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2734 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2736 start = (framepos_t) floor ((double) start / one_second) * one_second;
2741 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2742 start % one_minute == 0) {
2743 /* start is already on a whole minute, do nothing */
2744 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2745 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2747 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2752 start = _session->tempo_map().round_to_bar (start, direction);
2756 start = _session->tempo_map().round_to_beat (start, direction);
2759 case SnapToBeatDiv128:
2760 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2762 case SnapToBeatDiv64:
2763 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2765 case SnapToBeatDiv32:
2766 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2768 case SnapToBeatDiv28:
2769 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2771 case SnapToBeatDiv24:
2772 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2774 case SnapToBeatDiv20:
2775 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2777 case SnapToBeatDiv16:
2778 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2780 case SnapToBeatDiv14:
2781 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2783 case SnapToBeatDiv12:
2784 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2786 case SnapToBeatDiv10:
2787 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2789 case SnapToBeatDiv8:
2790 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2792 case SnapToBeatDiv7:
2793 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2795 case SnapToBeatDiv6:
2796 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2798 case SnapToBeatDiv5:
2799 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2801 case SnapToBeatDiv4:
2802 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2804 case SnapToBeatDiv3:
2805 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2807 case SnapToBeatDiv2:
2808 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2816 _session->locations()->marks_either_side (start, before, after);
2818 if (before == max_framepos && after == max_framepos) {
2819 /* No marks to snap to, so just don't snap */
2821 } else if (before == max_framepos) {
2823 } else if (after == max_framepos) {
2825 } else if (before != max_framepos && after != max_framepos) {
2826 /* have before and after */
2827 if ((start - before) < (after - start)) {
2836 case SnapToRegionStart:
2837 case SnapToRegionEnd:
2838 case SnapToRegionSync:
2839 case SnapToRegionBoundary:
2840 if (!region_boundary_cache.empty()) {
2842 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2843 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2845 if (direction > 0) {
2846 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2848 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2851 if (next != region_boundary_cache.begin ()) {
2856 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2857 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2859 if (start > (p + n) / 2) {
2868 switch (_snap_mode) {
2878 if (presnap > start) {
2879 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2883 } else if (presnap < start) {
2884 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2890 /* handled at entry */
2898 Editor::setup_toolbar ()
2900 HBox* mode_box = manage(new HBox);
2901 mode_box->set_border_width (2);
2902 mode_box->set_spacing(2);
2904 HBox* mouse_mode_box = manage (new HBox);
2905 HBox* mouse_mode_hbox = manage (new HBox);
2906 VBox* mouse_mode_vbox = manage (new VBox);
2907 Alignment* mouse_mode_align = manage (new Alignment);
2909 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2910 mouse_mode_size_group->add_widget (smart_mode_button);
2911 mouse_mode_size_group->add_widget (mouse_move_button);
2912 mouse_mode_size_group->add_widget (mouse_cut_button);
2913 mouse_mode_size_group->add_widget (mouse_select_button);
2914 mouse_mode_size_group->add_widget (mouse_timefx_button);
2915 mouse_mode_size_group->add_widget (mouse_audition_button);
2916 mouse_mode_size_group->add_widget (mouse_draw_button);
2917 mouse_mode_size_group->add_widget (mouse_content_button);
2919 mouse_mode_size_group->add_widget (zoom_in_button);
2920 mouse_mode_size_group->add_widget (zoom_out_button);
2921 mouse_mode_size_group->add_widget (zoom_preset_selector);
2922 mouse_mode_size_group->add_widget (zoom_out_full_button);
2923 mouse_mode_size_group->add_widget (zoom_focus_selector);
2925 mouse_mode_size_group->add_widget (tav_shrink_button);
2926 mouse_mode_size_group->add_widget (tav_expand_button);
2927 mouse_mode_size_group->add_widget (visible_tracks_selector);
2929 mouse_mode_size_group->add_widget (snap_type_selector);
2930 mouse_mode_size_group->add_widget (snap_mode_selector);
2932 mouse_mode_size_group->add_widget (edit_point_selector);
2933 mouse_mode_size_group->add_widget (edit_mode_selector);
2935 mouse_mode_size_group->add_widget (*nudge_clock);
2936 mouse_mode_size_group->add_widget (nudge_forward_button);
2937 mouse_mode_size_group->add_widget (nudge_backward_button);
2939 mouse_mode_hbox->set_spacing (2);
2941 if (!ARDOUR::Profile->get_trx()) {
2942 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2945 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2946 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2948 if (!ARDOUR::Profile->get_mixbus()) {
2949 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2952 if (!ARDOUR::Profile->get_trx()) {
2953 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2954 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2955 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2956 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2959 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2961 mouse_mode_align->add (*mouse_mode_vbox);
2962 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2964 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2966 edit_mode_selector.set_name ("mouse mode button");
2968 if (!ARDOUR::Profile->get_trx()) {
2969 mode_box->pack_start (edit_mode_selector, false, false);
2971 mode_box->pack_start (*mouse_mode_box, false, false);
2973 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2974 _mouse_mode_tearoff->set_name ("MouseModeBase");
2975 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2977 if (Profile->get_sae() || Profile->get_mixbus() ) {
2978 _mouse_mode_tearoff->set_can_be_torn_off (false);
2981 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2982 &_mouse_mode_tearoff->tearoff_window()));
2983 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2984 &_mouse_mode_tearoff->tearoff_window(), 1));
2985 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2986 &_mouse_mode_tearoff->tearoff_window()));
2987 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2988 &_mouse_mode_tearoff->tearoff_window(), 1));
2992 _zoom_box.set_spacing (2);
2993 _zoom_box.set_border_width (2);
2997 zoom_preset_selector.set_name ("zoom button");
2998 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2999 zoom_preset_selector.set_size_request (42, -1);
3001 zoom_in_button.set_name ("zoom button");
3002 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3003 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3004 zoom_in_button.set_related_action (act);
3006 zoom_out_button.set_name ("zoom button");
3007 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3008 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3009 zoom_out_button.set_related_action (act);
3011 zoom_out_full_button.set_name ("zoom button");
3012 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3013 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3014 zoom_out_full_button.set_related_action (act);
3016 zoom_focus_selector.set_name ("zoom button");
3018 if (ARDOUR::Profile->get_mixbus()) {
3019 _zoom_box.pack_start (zoom_preset_selector, false, false);
3020 } else if (ARDOUR::Profile->get_trx()) {
3021 mode_box->pack_start (zoom_out_button, false, false);
3022 mode_box->pack_start (zoom_in_button, false, false);
3024 _zoom_box.pack_start (zoom_out_button, false, false);
3025 _zoom_box.pack_start (zoom_in_button, false, false);
3026 _zoom_box.pack_start (zoom_out_full_button, false, false);
3027 _zoom_box.pack_start (zoom_focus_selector, false, false);
3030 /* Track zoom buttons */
3031 visible_tracks_selector.set_name ("zoom button");
3032 if (Profile->get_mixbus()) {
3033 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3034 visible_tracks_selector.set_size_request (42, -1);
3036 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3039 tav_expand_button.set_name ("zoom button");
3040 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3041 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3042 tav_expand_button.set_related_action (act);
3044 tav_shrink_button.set_name ("zoom button");
3045 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3046 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3047 tav_shrink_button.set_related_action (act);
3049 if (ARDOUR::Profile->get_mixbus()) {
3050 _zoom_box.pack_start (visible_tracks_selector);
3051 } else if (ARDOUR::Profile->get_trx()) {
3052 _zoom_box.pack_start (tav_shrink_button);
3053 _zoom_box.pack_start (tav_expand_button);
3055 _zoom_box.pack_start (visible_tracks_selector);
3056 _zoom_box.pack_start (tav_shrink_button);
3057 _zoom_box.pack_start (tav_expand_button);
3060 if (!ARDOUR::Profile->get_trx()) {
3061 _zoom_tearoff = manage (new TearOff (_zoom_box));
3063 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3064 &_zoom_tearoff->tearoff_window()));
3065 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3066 &_zoom_tearoff->tearoff_window(), 0));
3067 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3068 &_zoom_tearoff->tearoff_window()));
3069 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3070 &_zoom_tearoff->tearoff_window(), 0));
3073 if (Profile->get_sae() || Profile->get_mixbus() ) {
3074 _zoom_tearoff->set_can_be_torn_off (false);
3077 snap_box.set_spacing (2);
3078 snap_box.set_border_width (2);
3080 snap_type_selector.set_name ("mouse mode button");
3082 snap_mode_selector.set_name ("mouse mode button");
3084 edit_point_selector.set_name ("mouse mode button");
3086 snap_box.pack_start (snap_mode_selector, false, false);
3087 snap_box.pack_start (snap_type_selector, false, false);
3088 snap_box.pack_start (edit_point_selector, false, false);
3092 HBox *nudge_box = manage (new HBox);
3093 nudge_box->set_spacing (2);
3094 nudge_box->set_border_width (2);
3096 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3097 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3099 nudge_box->pack_start (nudge_backward_button, false, false);
3100 nudge_box->pack_start (nudge_forward_button, false, false);
3101 nudge_box->pack_start (*nudge_clock, false, false);
3104 /* Pack everything in... */
3106 HBox* hbox = manage (new HBox);
3107 hbox->set_spacing(2);
3109 _tools_tearoff = manage (new TearOff (*hbox));
3110 _tools_tearoff->set_name ("MouseModeBase");
3111 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3113 if (Profile->get_sae() || Profile->get_mixbus()) {
3114 _tools_tearoff->set_can_be_torn_off (false);
3117 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3118 &_tools_tearoff->tearoff_window()));
3119 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3120 &_tools_tearoff->tearoff_window(), 0));
3121 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3122 &_tools_tearoff->tearoff_window()));
3123 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3124 &_tools_tearoff->tearoff_window(), 0));
3126 toolbar_hbox.set_spacing (2);
3127 toolbar_hbox.set_border_width (1);
3129 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3130 if (!ARDOUR::Profile->get_trx()) {
3131 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3132 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3135 if (!ARDOUR::Profile->get_trx()) {
3136 hbox->pack_start (snap_box, false, false);
3137 hbox->pack_start (*nudge_box, false, false);
3139 hbox->pack_start (panic_box, false, false);
3143 toolbar_base.set_name ("ToolBarBase");
3144 toolbar_base.add (toolbar_hbox);
3146 _toolbar_viewport.add (toolbar_base);
3147 /* stick to the required height but allow width to vary if there's not enough room */
3148 _toolbar_viewport.set_size_request (1, -1);
3150 toolbar_frame.set_shadow_type (SHADOW_OUT);
3151 toolbar_frame.set_name ("BaseFrame");
3152 toolbar_frame.add (_toolbar_viewport);
3156 Editor::build_edit_point_menu ()
3158 using namespace Menu_Helpers;
3160 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3161 if(!Profile->get_mixbus())
3162 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3163 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3165 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3169 Editor::build_edit_mode_menu ()
3171 using namespace Menu_Helpers;
3173 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3174 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3175 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3176 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3178 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3182 Editor::build_snap_mode_menu ()
3184 using namespace Menu_Helpers;
3186 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3187 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3188 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3190 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3194 Editor::build_snap_type_menu ()
3196 using namespace Menu_Helpers;
3198 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3199 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3200 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3201 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3202 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3203 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3204 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3205 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3206 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3207 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3208 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3209 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3210 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3211 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3212 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3213 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3214 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3215 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3216 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3217 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3218 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3219 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3220 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3221 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3222 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3223 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3224 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3225 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3226 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3227 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3229 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3234 Editor::setup_tooltips ()
3236 set_tooltip (smart_mode_button, _("Smart Mode (add Range functions to Grab mode)"));
3237 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3238 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3239 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3240 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3241 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3242 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3243 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3244 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3245 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3246 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3247 set_tooltip (zoom_in_button, _("Zoom In"));
3248 set_tooltip (zoom_out_button, _("Zoom Out"));
3249 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3250 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3251 set_tooltip (zoom_focus_selector, _("Zoom focus"));
3252 set_tooltip (tav_expand_button, _("Expand Tracks"));
3253 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3254 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3255 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3256 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3257 set_tooltip (edit_point_selector, _("Edit point"));
3258 set_tooltip (edit_mode_selector, _("Edit Mode"));
3259 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3263 Editor::convert_drop_to_paths (
3264 vector<string>& paths,
3265 const RefPtr<Gdk::DragContext>& /*context*/,
3268 const SelectionData& data,
3272 if (_session == 0) {
3276 vector<string> uris = data.get_uris();
3280 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3281 are actually URI lists. So do it by hand.
3284 if (data.get_target() != "text/plain") {
3288 /* Parse the "uri-list" format that Nautilus provides,
3289 where each pathname is delimited by \r\n.
3291 THERE MAY BE NO NULL TERMINATING CHAR!!!
3294 string txt = data.get_text();
3298 p = (char *) malloc (txt.length() + 1);
3299 txt.copy (p, txt.length(), 0);
3300 p[txt.length()] = '\0';
3306 while (g_ascii_isspace (*p))
3310 while (*q && (*q != '\n') && (*q != '\r')) {
3317 while (q > p && g_ascii_isspace (*q))
3322 uris.push_back (string (p, q - p + 1));
3326 p = strchr (p, '\n');
3338 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3339 if ((*i).substr (0,7) == "file://") {
3340 paths.push_back (Glib::filename_from_uri (*i));
3348 Editor::new_tempo_section ()
3353 Editor::map_transport_state ()
3355 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3357 if (_session && _session->transport_stopped()) {
3358 have_pending_keyboard_selection = false;
3361 update_loop_range_view ();
3367 Editor::begin_selection_op_history ()
3369 selection_op_cmd_depth = 0;
3370 selection_op_history_it = 0;
3372 while(!selection_op_history.empty()) {
3373 delete selection_op_history.front();
3374 selection_op_history.pop_front();
3377 selection_undo_action->set_sensitive (false);
3378 selection_redo_action->set_sensitive (false);
3379 selection_op_history.push_front (&_selection_memento->get_state ());
3383 Editor::begin_reversible_selection_op (string name)
3386 //cerr << name << endl;
3387 /* begin/commit pairs can be nested */
3388 selection_op_cmd_depth++;
3393 Editor::commit_reversible_selection_op ()
3396 if (selection_op_cmd_depth == 1) {
3398 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3400 The user has undone some selection ops and then made a new one,
3401 making anything earlier in the list invalid.
3404 list<XMLNode *>::iterator it = selection_op_history.begin();
3405 list<XMLNode *>::iterator e_it = it;
3406 advance (e_it, selection_op_history_it);
3408 for ( ; it != e_it; ++it) {
3411 selection_op_history.erase (selection_op_history.begin(), e_it);
3414 selection_op_history.push_front (&_selection_memento->get_state ());
3415 selection_op_history_it = 0;
3417 selection_undo_action->set_sensitive (true);
3418 selection_redo_action->set_sensitive (false);
3421 if (selection_op_cmd_depth > 0) {
3422 selection_op_cmd_depth--;
3428 Editor::undo_selection_op ()
3431 selection_op_history_it++;
3433 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3434 if (n == selection_op_history_it) {
3435 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3436 selection_redo_action->set_sensitive (true);
3440 /* is there an earlier entry? */
3441 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3442 selection_undo_action->set_sensitive (false);
3448 Editor::redo_selection_op ()
3451 if (selection_op_history_it > 0) {
3452 selection_op_history_it--;
3455 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3456 if (n == selection_op_history_it) {
3457 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3458 selection_undo_action->set_sensitive (true);
3463 if (selection_op_history_it == 0) {
3464 selection_redo_action->set_sensitive (false);
3470 Editor::begin_reversible_command (string name)
3473 before.push_back (&_selection_memento->get_state ());
3474 _session->begin_reversible_command (name);
3479 Editor::begin_reversible_command (GQuark q)
3482 before.push_back (&_selection_memento->get_state ());
3483 _session->begin_reversible_command (q);
3488 Editor::abort_reversible_command ()
3491 while(!before.empty()) {
3492 delete before.front();
3495 _session->abort_reversible_command ();
3500 Editor::commit_reversible_command ()
3503 if (before.size() == 1) {
3504 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3505 redo_action->set_sensitive(false);
3506 undo_action->set_sensitive(true);
3507 begin_selection_op_history ();
3510 if (before.empty()) {
3511 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3516 _session->commit_reversible_command ();
3521 Editor::history_changed ()
3525 if (undo_action && _session) {
3526 if (_session->undo_depth() == 0) {
3527 label = S_("Command|Undo");
3529 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3531 undo_action->property_label() = label;
3534 if (redo_action && _session) {
3535 if (_session->redo_depth() == 0) {
3538 label = string_compose(_("Redo (%1)"), _session->next_redo());
3540 redo_action->property_label() = label;
3545 Editor::duplicate_range (bool with_dialog)
3549 RegionSelection rs = get_regions_from_selection_and_entered ();
3551 if ( selection->time.length() == 0 && rs.empty()) {
3557 ArdourDialog win (_("Duplicate"));
3558 Label label (_("Number of duplications:"));
3559 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3560 SpinButton spinner (adjustment, 0.0, 1);
3563 win.get_vbox()->set_spacing (12);
3564 win.get_vbox()->pack_start (hbox);
3565 hbox.set_border_width (6);
3566 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3568 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3569 place, visually. so do this by hand.
3572 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3573 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3574 spinner.grab_focus();
3580 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3581 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3582 win.set_default_response (RESPONSE_ACCEPT);
3584 spinner.grab_focus ();
3586 switch (win.run ()) {
3587 case RESPONSE_ACCEPT:
3593 times = adjustment.get_value();
3596 if ((current_mouse_mode() == Editing::MouseRange)) {
3597 if (selection->time.length()) {
3598 duplicate_selection (times);
3600 } else if (get_smart_mode()) {
3601 if (selection->time.length()) {
3602 duplicate_selection (times);
3604 duplicate_some_regions (rs, times);
3606 duplicate_some_regions (rs, times);
3611 Editor::set_edit_mode (EditMode m)
3613 Config->set_edit_mode (m);
3617 Editor::cycle_edit_mode ()
3619 switch (Config->get_edit_mode()) {
3621 if (Profile->get_sae()) {
3622 Config->set_edit_mode (Lock);
3624 Config->set_edit_mode (Ripple);
3629 Config->set_edit_mode (Lock);
3632 Config->set_edit_mode (Slide);
3638 Editor::edit_mode_selection_done ( EditMode m )
3640 Config->set_edit_mode ( m );
3644 Editor::snap_type_selection_done (SnapType snaptype)
3646 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3648 ract->set_active ();
3653 Editor::snap_mode_selection_done (SnapMode mode)
3655 RefPtr<RadioAction> ract = snap_mode_action (mode);
3658 ract->set_active (true);
3663 Editor::cycle_edit_point (bool with_marker)
3665 if(Profile->get_mixbus())
3666 with_marker = false;
3668 switch (_edit_point) {
3670 set_edit_point_preference (EditAtPlayhead);
3672 case EditAtPlayhead:
3674 set_edit_point_preference (EditAtSelectedMarker);
3676 set_edit_point_preference (EditAtMouse);
3679 case EditAtSelectedMarker:
3680 set_edit_point_preference (EditAtMouse);
3686 Editor::edit_point_selection_done (EditPoint ep)
3688 set_edit_point_preference ( ep );
3692 Editor::build_zoom_focus_menu ()
3694 using namespace Menu_Helpers;
3696 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3697 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3698 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3699 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3700 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3701 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3703 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3707 Editor::zoom_focus_selection_done ( ZoomFocus f )
3709 RefPtr<RadioAction> ract = zoom_focus_action (f);
3711 ract->set_active ();
3716 Editor::build_track_count_menu ()
3718 using namespace Menu_Helpers;
3720 if (!Profile->get_mixbus()) {
3721 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3722 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3723 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3724 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3725 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3726 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3727 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3728 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3729 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3730 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3731 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3732 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3733 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3735 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3736 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3737 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3738 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3739 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3740 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3741 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3742 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3743 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3744 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3746 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3747 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3748 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3749 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3750 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3751 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3752 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3753 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3754 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3755 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3756 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3761 Editor::set_zoom_preset (int64_t ms)
3764 temporal_zoom_session();
3768 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3769 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3773 Editor::set_visible_track_count (int32_t n)
3775 _visible_track_count = n;
3777 /* if the canvas hasn't really been allocated any size yet, just
3778 record the desired number of visible tracks and return. when canvas
3779 allocation happens, we will get called again and then we can do the
3783 if (_visible_canvas_height <= 1) {
3789 DisplaySuspender ds;
3791 if (_visible_track_count > 0) {
3792 h = trackviews_height() / _visible_track_count;
3793 std::ostringstream s;
3794 s << _visible_track_count;
3796 } else if (_visible_track_count == 0) {
3798 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3799 if ((*i)->marked_for_display()) {
3803 h = trackviews_height() / n;
3806 /* negative value means that the visible track count has
3807 been overridden by explicit track height changes.
3809 visible_tracks_selector.set_text (X_("*"));
3813 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3814 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3817 if (str != visible_tracks_selector.get_text()) {
3818 visible_tracks_selector.set_text (str);
3823 Editor::override_visible_track_count ()
3825 _visible_track_count = -1;
3826 visible_tracks_selector.set_text ( _("*") );
3830 Editor::edit_controls_button_release (GdkEventButton* ev)
3832 if (Keyboard::is_context_menu_event (ev)) {
3833 ARDOUR_UI::instance()->add_route (this);
3834 } else if (ev->button == 1) {
3835 selection->clear_tracks ();
3842 Editor::mouse_select_button_release (GdkEventButton* ev)
3844 /* this handles just right-clicks */
3846 if (ev->button != 3) {
3854 Editor::set_zoom_focus (ZoomFocus f)
3856 string str = zoom_focus_strings[(int)f];
3858 if (str != zoom_focus_selector.get_text()) {
3859 zoom_focus_selector.set_text (str);
3862 if (zoom_focus != f) {
3869 Editor::cycle_zoom_focus ()
3871 switch (zoom_focus) {
3873 set_zoom_focus (ZoomFocusRight);
3875 case ZoomFocusRight:
3876 set_zoom_focus (ZoomFocusCenter);
3878 case ZoomFocusCenter:
3879 set_zoom_focus (ZoomFocusPlayhead);
3881 case ZoomFocusPlayhead:
3882 set_zoom_focus (ZoomFocusMouse);
3884 case ZoomFocusMouse:
3885 set_zoom_focus (ZoomFocusEdit);
3888 set_zoom_focus (ZoomFocusLeft);
3894 Editor::ensure_float (Window& win)
3896 win.set_transient_for (*this);
3900 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3902 /* recover or initialize pane positions. do this here rather than earlier because
3903 we don't want the positions to change the child allocations, which they seem to do.
3909 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3918 XMLNode* geometry = find_named_node (*node, "geometry");
3920 if (which == static_cast<Paned*> (&edit_pane)) {
3922 if (done & Horizontal) {
3926 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3927 _notebook_shrunk = string_is_affirmative (prop->value ());
3930 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3931 /* initial allocation is 90% to canvas, 10% to notebook */
3932 pos = (int) floor (alloc.get_width() * 0.90f);
3933 snprintf (buf, sizeof(buf), "%d", pos);
3935 pos = atoi (prop->value());
3938 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3939 edit_pane.set_position (pos);
3942 done = (Pane) (done | Horizontal);
3944 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3946 if (done & Vertical) {
3950 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3951 /* initial allocation is 90% to canvas, 10% to summary */
3952 pos = (int) floor (alloc.get_height() * 0.90f);
3953 snprintf (buf, sizeof(buf), "%d", pos);
3956 pos = atoi (prop->value());
3959 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3960 editor_summary_pane.set_position (pos);
3963 done = (Pane) (done | Vertical);
3968 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3970 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3971 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3972 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3973 top_hbox.remove (toolbar_frame);
3978 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3980 if (toolbar_frame.get_parent() == 0) {
3981 top_hbox.pack_end (toolbar_frame);
3986 Editor::set_show_measures (bool yn)
3988 if (_show_measures != yn) {
3991 if ((_show_measures = yn) == true) {
3993 tempo_lines->show();
3996 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3997 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3999 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
4000 draw_measures (begin, end);
4008 Editor::toggle_follow_playhead ()
4010 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
4012 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4013 set_follow_playhead (tact->get_active());
4017 /** @param yn true to follow playhead, otherwise false.
4018 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4021 Editor::set_follow_playhead (bool yn, bool catch_up)
4023 if (_follow_playhead != yn) {
4024 if ((_follow_playhead = yn) == true && catch_up) {
4026 reset_x_origin_to_follow_playhead ();
4033 Editor::toggle_stationary_playhead ()
4035 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4037 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4038 set_stationary_playhead (tact->get_active());
4043 Editor::set_stationary_playhead (bool yn)
4045 if (_stationary_playhead != yn) {
4046 if ((_stationary_playhead = yn) == true) {
4048 // FIXME need a 3.0 equivalent of this 2.X call
4049 // update_current_screen ();
4056 Editor::playlist_selector () const
4058 return *_playlist_selector;
4062 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4064 if (paste_count == 0) {
4065 /* don't bother calculating an offset that will be zero anyway */
4069 /* calculate basic unsnapped multi-paste offset */
4070 framecnt_t offset = paste_count * duration;
4072 /* snap offset so pos + offset is aligned to the grid */
4073 framepos_t offset_pos = pos + offset;
4074 snap_to(offset_pos, RoundUpMaybe);
4075 offset = offset_pos - pos;
4081 Editor::get_grid_beat_divisions(framepos_t position)
4083 switch (_snap_type) {
4084 case SnapToBeatDiv128: return 128;
4085 case SnapToBeatDiv64: return 64;
4086 case SnapToBeatDiv32: return 32;
4087 case SnapToBeatDiv28: return 28;
4088 case SnapToBeatDiv24: return 24;
4089 case SnapToBeatDiv20: return 20;
4090 case SnapToBeatDiv16: return 16;
4091 case SnapToBeatDiv14: return 14;
4092 case SnapToBeatDiv12: return 12;
4093 case SnapToBeatDiv10: return 10;
4094 case SnapToBeatDiv8: return 8;
4095 case SnapToBeatDiv7: return 7;
4096 case SnapToBeatDiv6: return 6;
4097 case SnapToBeatDiv5: return 5;
4098 case SnapToBeatDiv4: return 4;
4099 case SnapToBeatDiv3: return 3;
4100 case SnapToBeatDiv2: return 2;
4107 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4111 const unsigned divisions = get_grid_beat_divisions(position);
4113 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4116 switch (_snap_type) {
4118 return Evoral::Beats(1.0);
4121 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
4129 return Evoral::Beats();
4133 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4137 ret = nudge_clock->current_duration (pos);
4138 next = ret + 1; /* XXXX fix me */
4144 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4146 ArdourDialog dialog (_("Playlist Deletion"));
4147 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4148 "If it is kept, its audio files will not be cleaned.\n"
4149 "If it is deleted, audio files used by it alone will be cleaned."),
4152 dialog.set_position (WIN_POS_CENTER);
4153 dialog.get_vbox()->pack_start (label);
4157 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4158 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4159 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4161 switch (dialog.run ()) {
4162 case RESPONSE_ACCEPT:
4163 /* delete the playlist */
4167 case RESPONSE_REJECT:
4168 /* keep the playlist */
4180 Editor::audio_region_selection_covers (framepos_t where)
4182 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4183 if ((*a)->region()->covers (where)) {
4192 Editor::prepare_for_cleanup ()
4194 cut_buffer->clear_regions ();
4195 cut_buffer->clear_playlists ();
4197 selection->clear_regions ();
4198 selection->clear_playlists ();
4200 _regions->suspend_redisplay ();
4204 Editor::finish_cleanup ()
4206 _regions->resume_redisplay ();
4210 Editor::transport_loop_location()
4213 return _session->locations()->auto_loop_location();
4220 Editor::transport_punch_location()
4223 return _session->locations()->auto_punch_location();
4230 Editor::control_layout_scroll (GdkEventScroll* ev)
4232 /* Just forward to the normal canvas scroll method. The coordinate
4233 systems are different but since the canvas is always larger than the
4234 track headers, and aligned with the trackview area, this will work.
4236 In the not too distant future this layout is going away anyway and
4237 headers will be on the canvas.
4239 return canvas_scroll_event (ev, false);
4243 Editor::session_state_saved (string)
4246 _snapshots->redisplay ();
4250 Editor::update_tearoff_visibility()
4252 bool visible = UIConfiguration::instance().get_keep_tearoffs();
4253 _mouse_mode_tearoff->set_visible (visible);
4254 _tools_tearoff->set_visible (visible);
4255 if (_zoom_tearoff) {
4256 _zoom_tearoff->set_visible (visible);
4261 Editor::reattach_all_tearoffs ()
4263 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4264 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4265 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4269 Editor::maximise_editing_space ()
4281 Editor::restore_editing_space ()
4293 * Make new playlists for a given track and also any others that belong
4294 * to the same active route group with the `select' property.
4299 Editor::new_playlists (TimeAxisView* v)
4301 begin_reversible_command (_("new playlists"));
4302 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4303 _session->playlists->get (playlists);
4304 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4305 commit_reversible_command ();
4309 * Use a copy of the current playlist for a given track and also any others that belong
4310 * to the same active route group with the `select' property.
4315 Editor::copy_playlists (TimeAxisView* v)
4317 begin_reversible_command (_("copy playlists"));
4318 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4319 _session->playlists->get (playlists);
4320 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4321 commit_reversible_command ();
4324 /** Clear the current playlist for a given track and also any others that belong
4325 * to the same active route group with the `select' property.
4330 Editor::clear_playlists (TimeAxisView* v)
4332 begin_reversible_command (_("clear playlists"));
4333 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4334 _session->playlists->get (playlists);
4335 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4336 commit_reversible_command ();
4340 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4342 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4346 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4348 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4352 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4354 atv.clear_playlist ();
4358 Editor::on_key_press_event (GdkEventKey* ev)
4360 return key_press_focus_accelerator_handler (*this, ev);
4364 Editor::on_key_release_event (GdkEventKey* ev)
4366 return Gtk::Window::on_key_release_event (ev);
4367 // return key_press_focus_accelerator_handler (*this, ev);
4371 Editor::get_y_origin () const
4373 return vertical_adjustment.get_value ();
4376 /** Queue up a change to the viewport x origin.
4377 * @param frame New x origin.
4380 Editor::reset_x_origin (framepos_t frame)
4382 pending_visual_change.add (VisualChange::TimeOrigin);
4383 pending_visual_change.time_origin = frame;
4384 ensure_visual_change_idle_handler ();
4388 Editor::reset_y_origin (double y)
4390 pending_visual_change.add (VisualChange::YOrigin);
4391 pending_visual_change.y_origin = y;
4392 ensure_visual_change_idle_handler ();
4396 Editor::reset_zoom (framecnt_t spp)
4398 if (spp == samples_per_pixel) {
4402 pending_visual_change.add (VisualChange::ZoomLevel);
4403 pending_visual_change.samples_per_pixel = spp;
4404 ensure_visual_change_idle_handler ();
4408 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4410 reset_x_origin (frame);
4413 if (!no_save_visual) {
4414 undo_visual_stack.push_back (current_visual_state(false));
4418 Editor::VisualState::VisualState (bool with_tracks)
4419 : gui_state (with_tracks ? new GUIObjectState : 0)
4423 Editor::VisualState::~VisualState ()
4428 Editor::VisualState*
4429 Editor::current_visual_state (bool with_tracks)
4431 VisualState* vs = new VisualState (with_tracks);
4432 vs->y_position = vertical_adjustment.get_value();
4433 vs->samples_per_pixel = samples_per_pixel;
4434 vs->leftmost_frame = leftmost_frame;
4435 vs->zoom_focus = zoom_focus;
4438 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4445 Editor::undo_visual_state ()
4447 if (undo_visual_stack.empty()) {
4451 VisualState* vs = undo_visual_stack.back();
4452 undo_visual_stack.pop_back();
4455 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4458 use_visual_state (*vs);
4463 Editor::redo_visual_state ()
4465 if (redo_visual_stack.empty()) {
4469 VisualState* vs = redo_visual_stack.back();
4470 redo_visual_stack.pop_back();
4472 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4473 // why do we check here?
4474 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4477 use_visual_state (*vs);
4482 Editor::swap_visual_state ()
4484 if (undo_visual_stack.empty()) {
4485 redo_visual_state ();
4487 undo_visual_state ();
4492 Editor::use_visual_state (VisualState& vs)
4494 PBD::Unwinder<bool> nsv (no_save_visual, true);
4495 DisplaySuspender ds;
4497 vertical_adjustment.set_value (vs.y_position);
4499 set_zoom_focus (vs.zoom_focus);
4500 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4503 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4505 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4506 (*i)->clear_property_cache();
4507 (*i)->reset_visual_state ();
4511 _routes->update_visibility ();
4514 /** This is the core function that controls the zoom level of the canvas. It is called
4515 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4516 * @param spp new number of samples per pixel
4519 Editor::set_samples_per_pixel (framecnt_t spp)
4525 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4526 const framecnt_t lots_of_pixels = 4000;
4528 /* if the zoom level is greater than what you'd get trying to display 3
4529 * days of audio on a really big screen, then it's too big.
4532 if (spp * lots_of_pixels > three_days) {
4536 samples_per_pixel = spp;
4539 tempo_lines->tempo_map_changed();
4542 bool const showing_time_selection = selection->time.length() > 0;
4544 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4545 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4546 (*i)->reshow_selection (selection->time);
4550 ZoomChanged (); /* EMIT_SIGNAL */
4552 ArdourCanvas::GtkCanvasViewport* c;
4554 c = get_track_canvas();
4556 c->canvas()->zoomed ();
4559 if (playhead_cursor) {
4560 playhead_cursor->set_position (playhead_cursor->current_frame ());
4563 refresh_location_display();
4564 _summary->set_overlays_dirty ();
4566 update_marker_labels ();
4572 Editor::queue_visual_videotimeline_update ()
4575 * pending_visual_change.add (VisualChange::VideoTimeline);
4576 * or maybe even more specific: which videotimeline-image
4577 * currently it calls update_video_timeline() to update
4578 * _all outdated_ images on the video-timeline.
4579 * see 'exposeimg()' in video_image_frame.cc
4581 ensure_visual_change_idle_handler ();
4585 Editor::ensure_visual_change_idle_handler ()
4587 if (pending_visual_change.idle_handler_id < 0) {
4588 // see comment in add_to_idle_resize above.
4589 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4590 pending_visual_change.being_handled = false;
4595 Editor::_idle_visual_changer (void* arg)
4597 return static_cast<Editor*>(arg)->idle_visual_changer ();
4601 Editor::idle_visual_changer ()
4603 /* set_horizontal_position() below (and maybe other calls) call
4604 gtk_main_iteration(), so it's possible that a signal will be handled
4605 half-way through this method. If this signal wants an
4606 idle_visual_changer we must schedule another one after this one, so
4607 mark the idle_handler_id as -1 here to allow that. Also make a note
4608 that we are doing the visual change, so that changes in response to
4609 super-rapid-screen-update can be dropped if we are still processing
4613 pending_visual_change.idle_handler_id = -1;
4614 pending_visual_change.being_handled = true;
4616 VisualChange vc = pending_visual_change;
4618 pending_visual_change.pending = (VisualChange::Type) 0;
4620 visual_changer (vc);
4622 pending_visual_change.being_handled = false;
4624 return 0; /* this is always a one-shot call */
4628 Editor::visual_changer (const VisualChange& vc)
4630 double const last_time_origin = horizontal_position ();
4632 if (vc.pending & VisualChange::ZoomLevel) {
4633 set_samples_per_pixel (vc.samples_per_pixel);
4635 compute_fixed_ruler_scale ();
4637 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4638 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4640 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4641 current_bbt_points_begin, current_bbt_points_end);
4642 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4643 current_bbt_points_begin, current_bbt_points_end);
4644 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4646 update_video_timeline();
4649 if (vc.pending & VisualChange::TimeOrigin) {
4650 set_horizontal_position (vc.time_origin / samples_per_pixel);
4653 if (vc.pending & VisualChange::YOrigin) {
4654 vertical_adjustment.set_value (vc.y_origin);
4657 if (last_time_origin == horizontal_position ()) {
4658 /* changed signal not emitted */
4659 update_fixed_rulers ();
4660 redisplay_tempo (true);
4663 if (!(vc.pending & VisualChange::ZoomLevel)) {
4664 update_video_timeline();
4667 _summary->set_overlays_dirty ();
4670 struct EditorOrderTimeAxisSorter {
4671 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4672 return a->order () < b->order ();
4677 Editor::sort_track_selection (TrackViewList& sel)
4679 EditorOrderTimeAxisSorter cmp;
4684 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4687 framepos_t where = 0;
4688 EditPoint ep = _edit_point;
4690 if (Profile->get_mixbus())
4691 if (ep == EditAtSelectedMarker)
4692 ep = EditAtPlayhead;
4694 if (from_outside_canvas && (ep == EditAtMouse)) {
4695 ep = EditAtPlayhead;
4696 } else if (from_context_menu && (ep == EditAtMouse)) {
4697 return canvas_event_sample (&context_click_event, 0, 0);
4700 if (entered_marker) {
4701 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4702 return entered_marker->position();
4705 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4706 ep = EditAtSelectedMarker;
4709 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4710 ep = EditAtPlayhead;
4714 case EditAtPlayhead:
4715 if (_dragging_playhead) {
4716 if (!mouse_frame (where, ignored)) {
4717 /* XXX not right but what can we do ? */
4721 where = _session->audible_frame();
4723 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4726 case EditAtSelectedMarker:
4727 if (!selection->markers.empty()) {
4729 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4732 where = loc->start();
4736 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4744 if (!mouse_frame (where, ignored)) {
4745 /* XXX not right but what can we do ? */
4749 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4757 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4759 if (!_session) return;
4761 begin_reversible_command (cmd);
4765 if ((tll = transport_loop_location()) == 0) {
4766 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4767 XMLNode &before = _session->locations()->get_state();
4768 _session->locations()->add (loc, true);
4769 _session->set_auto_loop_location (loc);
4770 XMLNode &after = _session->locations()->get_state();
4771 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4773 XMLNode &before = tll->get_state();
4774 tll->set_hidden (false, this);
4775 tll->set (start, end);
4776 XMLNode &after = tll->get_state();
4777 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4780 commit_reversible_command ();
4784 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4786 if (!_session) return;
4788 begin_reversible_command (cmd);
4792 if ((tpl = transport_punch_location()) == 0) {
4793 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4794 XMLNode &before = _session->locations()->get_state();
4795 _session->locations()->add (loc, true);
4796 _session->set_auto_punch_location (loc);
4797 XMLNode &after = _session->locations()->get_state();
4798 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4800 XMLNode &before = tpl->get_state();
4801 tpl->set_hidden (false, this);
4802 tpl->set (start, end);
4803 XMLNode &after = tpl->get_state();
4804 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4807 commit_reversible_command ();
4810 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4811 * @param rs List to which found regions are added.
4812 * @param where Time to look at.
4813 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4816 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4818 const TrackViewList* tracks;
4821 tracks = &track_views;
4826 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4828 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4831 boost::shared_ptr<Track> tr;
4832 boost::shared_ptr<Playlist> pl;
4834 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4836 boost::shared_ptr<RegionList> regions = pl->regions_at (
4837 (framepos_t) floor ( (double) where * tr->speed()));
4839 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4840 RegionView* rv = rtv->view()->find_view (*i);
4851 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4853 const TrackViewList* tracks;
4856 tracks = &track_views;
4861 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4862 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4864 boost::shared_ptr<Track> tr;
4865 boost::shared_ptr<Playlist> pl;
4867 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4869 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4870 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4872 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4874 RegionView* rv = rtv->view()->find_view (*i);
4885 /** Get regions using the following method:
4887 * Make a region list using:
4888 * (a) any selected regions
4889 * (b) the intersection of any selected tracks and the edit point(*)
4890 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4892 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4894 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4898 Editor::get_regions_from_selection_and_edit_point ()
4900 RegionSelection regions;
4902 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4903 regions.add (entered_regionview);
4905 regions = selection->regions;
4908 if ( regions.empty() ) {
4909 TrackViewList tracks = selection->tracks;
4911 if (!tracks.empty()) {
4912 /* no region selected or entered, but some selected tracks:
4913 * act on all regions on the selected tracks at the edit point
4915 framepos_t const where = get_preferred_edit_position ();
4916 get_regions_at(regions, where, tracks);
4923 /** Get regions using the following method:
4925 * Make a region list using:
4926 * (a) any selected regions
4927 * (b) the intersection of any selected tracks and the edit point(*)
4928 * (c) if neither exists, then whatever region is under the mouse
4930 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4932 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4935 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4937 RegionSelection regions;
4939 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4940 regions.add (entered_regionview);
4942 regions = selection->regions;
4945 if ( regions.empty() ) {
4946 TrackViewList tracks = selection->tracks;
4948 if (!tracks.empty()) {
4949 /* no region selected or entered, but some selected tracks:
4950 * act on all regions on the selected tracks at the edit point
4952 get_regions_at(regions, pos, tracks);
4959 /** Start with regions that are selected, or the entered regionview if none are selected.
4960 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4961 * of the regions that we started with.
4965 Editor::get_regions_from_selection_and_entered ()
4967 RegionSelection regions = selection->regions;
4969 if (regions.empty() && entered_regionview) {
4970 regions.add (entered_regionview);
4977 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4979 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4980 RouteTimeAxisView* rtav;
4982 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4983 boost::shared_ptr<Playlist> pl;
4984 std::vector<boost::shared_ptr<Region> > results;
4985 boost::shared_ptr<Track> tr;
4987 if ((tr = rtav->track()) == 0) {
4992 if ((pl = (tr->playlist())) != 0) {
4993 boost::shared_ptr<Region> r = pl->region_by_id (id);
4995 RegionView* rv = rtav->view()->find_view (r);
4997 regions.push_back (rv);
5006 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5009 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5010 MidiTimeAxisView* mtav;
5012 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5014 mtav->get_per_region_note_selection (selection);
5021 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5023 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5025 RouteTimeAxisView* tatv;
5027 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5029 boost::shared_ptr<Playlist> pl;
5030 vector<boost::shared_ptr<Region> > results;
5032 boost::shared_ptr<Track> tr;
5034 if ((tr = tatv->track()) == 0) {
5039 if ((pl = (tr->playlist())) != 0) {
5040 if (src_comparison) {
5041 pl->get_source_equivalent_regions (region, results);
5043 pl->get_region_list_equivalent_regions (region, results);
5047 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5048 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5049 regions.push_back (marv);
5058 Editor::show_rhythm_ferret ()
5060 if (rhythm_ferret == 0) {
5061 rhythm_ferret = new RhythmFerret(*this);
5064 rhythm_ferret->set_session (_session);
5065 rhythm_ferret->show ();
5066 rhythm_ferret->present ();
5070 Editor::first_idle ()
5072 MessageDialog* dialog = 0;
5074 if (track_views.size() > 1) {
5075 dialog = new MessageDialog (
5077 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5081 ARDOUR_UI::instance()->flush_pending ();
5084 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5088 // first idle adds route children (automation tracks), so we need to redisplay here
5089 _routes->redisplay ();
5093 if (_session->undo_depth() == 0) {
5094 undo_action->set_sensitive(false);
5096 redo_action->set_sensitive(false);
5097 begin_selection_op_history ();
5103 Editor::_idle_resize (gpointer arg)
5105 return ((Editor*)arg)->idle_resize ();
5109 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5111 if (resize_idle_id < 0) {
5112 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5113 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5114 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5116 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5117 _pending_resize_amount = 0;
5120 /* make a note of the smallest resulting height, so that we can clamp the
5121 lower limit at TimeAxisView::hSmall */
5123 int32_t min_resulting = INT32_MAX;
5125 _pending_resize_amount += h;
5126 _pending_resize_view = view;
5128 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5130 if (selection->tracks.contains (_pending_resize_view)) {
5131 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5132 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5136 if (min_resulting < 0) {
5141 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5142 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5146 /** Handle pending resizing of tracks */
5148 Editor::idle_resize ()
5150 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5152 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5153 selection->tracks.contains (_pending_resize_view)) {
5155 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5156 if (*i != _pending_resize_view) {
5157 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5162 _pending_resize_amount = 0;
5163 _group_tabs->set_dirty ();
5164 resize_idle_id = -1;
5172 ENSURE_GUI_THREAD (*this, &Editor::located);
5175 playhead_cursor->set_position (_session->audible_frame ());
5176 if (_follow_playhead && !_pending_initial_locate) {
5177 reset_x_origin_to_follow_playhead ();
5181 _pending_locate_request = false;
5182 _pending_initial_locate = false;
5186 Editor::region_view_added (RegionView * rv)
5188 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5189 if (rv->region ()->id () == (*pr)) {
5190 selection->add (rv);
5191 selection->regions.pending.erase (pr);
5196 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5198 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5199 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5200 if (rv->region()->id () == (*rnote).first) {
5201 mrv->select_notes ((*rnote).second);
5202 selection->pending_midi_note_selection.erase(rnote);
5208 _summary->set_background_dirty ();
5212 Editor::region_view_removed ()
5214 _summary->set_background_dirty ();
5218 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5220 TrackViewList::const_iterator j = track_views.begin ();
5221 while (j != track_views.end()) {
5222 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5223 if (rtv && rtv->route() == r) {
5234 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5238 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5239 TimeAxisView* tv = axis_view_from_route (*i);
5249 Editor::suspend_route_redisplay ()
5252 _routes->suspend_redisplay();
5257 Editor::resume_route_redisplay ()
5260 _routes->redisplay(); // queue redisplay
5261 _routes->resume_redisplay();
5266 Editor::add_routes (RouteList& routes)
5268 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5270 RouteTimeAxisView *rtv;
5271 list<RouteTimeAxisView*> new_views;
5272 TrackViewList new_selection;
5273 bool from_scratch = (track_views.size() == 0);
5275 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5276 boost::shared_ptr<Route> route = (*x);
5278 if (route->is_auditioner() || route->is_monitor()) {
5282 DataType dt = route->input()->default_type();
5284 if (dt == ARDOUR::DataType::AUDIO) {
5285 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5286 rtv->set_route (route);
5287 } else if (dt == ARDOUR::DataType::MIDI) {
5288 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5289 rtv->set_route (route);
5291 throw unknown_type();
5294 new_views.push_back (rtv);
5295 track_views.push_back (rtv);
5296 new_selection.push_back (rtv);
5298 rtv->effective_gain_display ();
5300 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5301 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5304 if (new_views.size() > 0) {
5305 _routes->routes_added (new_views);
5306 _summary->routes_added (new_views);
5309 if (!from_scratch) {
5310 selection->tracks.clear();
5311 selection->add (new_selection);
5312 begin_selection_op_history();
5315 if (show_editor_mixer_when_tracks_arrive) {
5316 show_editor_mixer (true);
5319 editor_list_button.set_sensitive (true);
5323 Editor::timeaxisview_deleted (TimeAxisView *tv)
5325 if (tv == entered_track) {
5329 if (_session && _session->deletion_in_progress()) {
5330 /* the situation is under control */
5334 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5336 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5338 _routes->route_removed (tv);
5340 TimeAxisView::Children c = tv->get_child_list ();
5341 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5342 if (entered_track == i->get()) {
5347 /* remove it from the list of track views */
5349 TrackViewList::iterator i;
5351 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5352 i = track_views.erase (i);
5355 /* update whatever the current mixer strip is displaying, if revelant */
5357 boost::shared_ptr<Route> route;
5360 route = rtav->route ();
5363 if (current_mixer_strip && current_mixer_strip->route() == route) {
5365 TimeAxisView* next_tv;
5367 if (track_views.empty()) {
5369 } else if (i == track_views.end()) {
5370 next_tv = track_views.front();
5377 set_selected_mixer_strip (*next_tv);
5379 /* make the editor mixer strip go away setting the
5380 * button to inactive (which also unticks the menu option)
5383 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5389 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5391 if (apply_to_selection) {
5392 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5394 TrackSelection::iterator j = i;
5397 hide_track_in_display (*i, false);
5402 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5404 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5405 // this will hide the mixer strip
5406 set_selected_mixer_strip (*tv);
5409 _routes->hide_track_in_display (*tv);
5414 Editor::sync_track_view_list_and_routes ()
5416 track_views = TrackViewList (_routes->views ());
5418 _summary->set_background_dirty();
5419 _group_tabs->set_dirty ();
5421 return false; // do not call again (until needed)
5425 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5427 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5432 /** Find a RouteTimeAxisView by the ID of its route */
5434 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5436 RouteTimeAxisView* v;
5438 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5439 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5440 if(v->route()->id() == id) {
5450 Editor::fit_route_group (RouteGroup *g)
5452 TrackViewList ts = axis_views_from_routes (g->route_list ());
5457 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5459 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5462 _session->cancel_audition ();
5466 if (_session->is_auditioning()) {
5467 _session->cancel_audition ();
5468 if (r == last_audition_region) {
5473 _session->audition_region (r);
5474 last_audition_region = r;
5479 Editor::hide_a_region (boost::shared_ptr<Region> r)
5481 r->set_hidden (true);
5485 Editor::show_a_region (boost::shared_ptr<Region> r)
5487 r->set_hidden (false);
5491 Editor::audition_region_from_region_list ()
5493 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5497 Editor::hide_region_from_region_list ()
5499 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5503 Editor::show_region_in_region_list ()
5505 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5509 Editor::step_edit_status_change (bool yn)
5512 start_step_editing ();
5514 stop_step_editing ();
5519 Editor::start_step_editing ()
5521 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5525 Editor::stop_step_editing ()
5527 step_edit_connection.disconnect ();
5531 Editor::check_step_edit ()
5533 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5534 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5536 mtv->check_step_edit ();
5540 return true; // do it again, till we stop
5544 Editor::scroll_press (Direction dir)
5546 ++_scroll_callbacks;
5548 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5549 /* delay the first auto-repeat */
5555 scroll_backward (1);
5563 scroll_up_one_track ();
5567 scroll_down_one_track ();
5571 /* do hacky auto-repeat */
5572 if (!_scroll_connection.connected ()) {
5574 _scroll_connection = Glib::signal_timeout().connect (
5575 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5578 _scroll_callbacks = 0;
5585 Editor::scroll_release ()
5587 _scroll_connection.disconnect ();
5590 /** Queue a change for the Editor viewport x origin to follow the playhead */
5592 Editor::reset_x_origin_to_follow_playhead ()
5594 framepos_t const frame = playhead_cursor->current_frame ();
5596 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5598 if (_session->transport_speed() < 0) {
5600 if (frame > (current_page_samples() / 2)) {
5601 center_screen (frame-(current_page_samples()/2));
5603 center_screen (current_page_samples()/2);
5610 if (frame < leftmost_frame) {
5612 if (_session->transport_rolling()) {
5613 /* rolling; end up with the playhead at the right of the page */
5614 l = frame - current_page_samples ();
5616 /* not rolling: end up with the playhead 1/4 of the way along the page */
5617 l = frame - current_page_samples() / 4;
5621 if (_session->transport_rolling()) {
5622 /* rolling: end up with the playhead on the left of the page */
5625 /* not rolling: end up with the playhead 3/4 of the way along the page */
5626 l = frame - 3 * current_page_samples() / 4;
5634 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5640 Editor::super_rapid_screen_update ()
5642 if (!_session || !_session->engine().running()) {
5646 /* METERING / MIXER STRIPS */
5648 /* update track meters, if required */
5649 if (is_mapped() && meters_running) {
5650 RouteTimeAxisView* rtv;
5651 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5652 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5653 rtv->fast_update ();
5658 /* and any current mixer strip */
5659 if (current_mixer_strip) {
5660 current_mixer_strip->fast_update ();
5663 /* PLAYHEAD AND VIEWPORT */
5665 framepos_t const frame = _session->audible_frame();
5667 /* There are a few reasons why we might not update the playhead / viewport stuff:
5669 * 1. we don't update things when there's a pending locate request, otherwise
5670 * when the editor requests a locate there is a chance that this method
5671 * will move the playhead before the locate request is processed, causing
5673 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5674 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5677 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5679 last_update_frame = frame;
5681 if (!_dragging_playhead) {
5682 playhead_cursor->set_position (frame);
5685 if (!_stationary_playhead) {
5687 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5688 /* We only do this if we aren't already
5689 handling a visual change (ie if
5690 pending_visual_change.being_handled is
5691 false) so that these requests don't stack
5692 up there are too many of them to handle in
5695 reset_x_origin_to_follow_playhead ();
5700 if (!_dragging_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5701 framepos_t const frame = playhead_cursor->current_frame ();
5702 double target = ((double)frame - (double)current_page_samples()/3.0);
5703 if (target <= 0.0) {
5706 // compare to EditorCursor::set_position()
5707 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5708 double const new_pos = sample_to_pixel_unrounded (target);
5709 if (rint (new_pos) != rint (old_pos)) {
5710 reset_x_origin (pixel_to_sample (floor (new_pos)));
5721 Editor::session_going_away ()
5723 _have_idled = false;
5725 _session_connections.drop_connections ();
5727 super_rapid_screen_update_connection.disconnect ();
5729 selection->clear ();
5730 cut_buffer->clear ();
5732 clicked_regionview = 0;
5733 clicked_axisview = 0;
5734 clicked_routeview = 0;
5735 entered_regionview = 0;
5737 last_update_frame = 0;
5740 playhead_cursor->hide ();
5742 /* rip everything out of the list displays */
5746 _route_groups->clear ();
5748 /* do this first so that deleting a track doesn't reset cms to null
5749 and thus cause a leak.
5752 if (current_mixer_strip) {
5753 if (current_mixer_strip->get_parent() != 0) {
5754 global_hpacker.remove (*current_mixer_strip);
5756 delete current_mixer_strip;
5757 current_mixer_strip = 0;
5760 /* delete all trackviews */
5762 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5765 track_views.clear ();
5767 nudge_clock->set_session (0);
5769 editor_list_button.set_active(false);
5770 editor_list_button.set_sensitive(false);
5772 /* clear tempo/meter rulers */
5773 remove_metric_marks ();
5775 clear_marker_display ();
5777 stop_step_editing ();
5779 /* get rid of any existing editor mixer strip */
5781 WindowTitle title(Glib::get_application_name());
5782 title += _("Editor");
5784 set_title (title.get_string());
5786 SessionHandlePtr::session_going_away ();
5791 Editor::show_editor_list (bool yn)
5794 _the_notebook.show ();
5796 _the_notebook.hide ();
5801 Editor::change_region_layering_order (bool from_context_menu)
5803 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5805 if (!clicked_routeview) {
5806 if (layering_order_editor) {
5807 layering_order_editor->hide ();
5812 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5818 boost::shared_ptr<Playlist> pl = track->playlist();
5824 if (layering_order_editor == 0) {
5825 layering_order_editor = new RegionLayeringOrderEditor (*this);
5828 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5829 layering_order_editor->maybe_present ();
5833 Editor::update_region_layering_order_editor ()
5835 if (layering_order_editor && layering_order_editor->is_visible ()) {
5836 change_region_layering_order (true);
5841 Editor::setup_fade_images ()
5843 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5844 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5845 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5846 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5847 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5849 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5850 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5851 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5852 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5853 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5855 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5856 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5857 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5858 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5859 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5861 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5862 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5863 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5864 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5865 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5869 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5871 Editor::action_menu_item (std::string const & name)
5873 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5876 return *manage (a->create_menu_item ());
5880 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5882 EventBox* b = manage (new EventBox);
5883 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5884 Label* l = manage (new Label (name));
5888 _the_notebook.append_page (widget, *b);
5892 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5894 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5895 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5898 if (ev->type == GDK_2BUTTON_PRESS) {
5900 /* double-click on a notebook tab shrinks or expands the notebook */
5902 if (_notebook_shrunk) {
5903 if (pre_notebook_shrink_pane_width) {
5904 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5906 _notebook_shrunk = false;
5908 pre_notebook_shrink_pane_width = edit_pane.get_position();
5910 /* this expands the LHS of the edit pane to cover the notebook
5911 PAGE but leaves the tabs visible.
5913 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5914 _notebook_shrunk = true;
5922 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5924 using namespace Menu_Helpers;
5926 MenuList& items = _control_point_context_menu.items ();
5929 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5930 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5931 if (!can_remove_control_point (item)) {
5932 items.back().set_sensitive (false);
5935 _control_point_context_menu.popup (event->button.button, event->button.time);
5939 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5941 using namespace Menu_Helpers;
5943 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5948 /* We need to get the selection here and pass it to the operations, since
5949 popping up the menu will cause a region leave event which clears
5950 entered_regionview. */
5952 MidiRegionView& mrv = note->region_view();
5953 const RegionSelection rs = get_regions_from_selection_and_entered ();
5955 MenuList& items = _note_context_menu.items();
5958 items.push_back(MenuElem(_("Delete"),
5959 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5960 items.push_back(MenuElem(_("Edit..."),
5961 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5962 items.push_back(MenuElem(_("Legatize"),
5963 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5964 items.push_back(MenuElem(_("Quantize..."),
5965 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5966 items.push_back(MenuElem(_("Remove Overlap"),
5967 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5968 items.push_back(MenuElem(_("Transform..."),
5969 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5971 _note_context_menu.popup (event->button.button, event->button.time);
5975 Editor::zoom_vertical_modifier_released()
5977 _stepping_axis_view = 0;
5981 Editor::ui_parameter_changed (string parameter)
5983 if (parameter == "icon-set") {
5984 while (!_cursor_stack.empty()) {
5985 _cursor_stack.pop_back();
5987 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
5988 _cursor_stack.push_back(_cursors->grabber);
5989 } else if (parameter == "draggable-playhead") {
5990 if (_verbose_cursor) {
5991 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());