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 "ui_config.h"
129 #include "verbose_cursor.h"
134 using namespace ARDOUR;
135 using namespace ARDOUR_UI_UTILS;
138 using namespace Glib;
139 using namespace Gtkmm2ext;
140 using namespace Editing;
142 using PBD::internationalize;
144 using Gtkmm2ext::Keyboard;
146 double Editor::timebar_height = 15.0;
148 static const gchar *_snap_type_strings[] = {
182 static const gchar *_snap_mode_strings[] = {
189 static const gchar *_edit_point_strings[] = {
196 static const gchar *_edit_mode_strings[] = {
204 static const gchar *_zoom_focus_strings[] = {
214 #ifdef USE_RUBBERBAND
215 static const gchar *_rb_opt_strings[] = {
218 N_("Balanced multitimbral mixture"),
219 N_("Unpitched percussion with stable notes"),
220 N_("Crisp monophonic instrumental"),
221 N_("Unpitched solo percussion"),
222 N_("Resample without preserving pitch"),
227 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
230 pane_size_watcher (Paned* pane)
232 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
236 Quartz: impossible to access
238 so stop that by preventing it from ever getting too narrow. 35
239 pixels is basically a rough guess at the tab width.
244 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
246 gint pos = pane->get_position ();
248 if (pos > max_width_of_lhs) {
249 pane->set_position (max_width_of_lhs);
254 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
256 , _mouse_changed_selection (false)
257 /* time display buttons */
258 , minsec_label (_("Mins:Secs"))
259 , bbt_label (_("Bars:Beats"))
260 , timecode_label (_("Timecode"))
261 , samples_label (_("Samples"))
262 , tempo_label (_("Tempo"))
263 , meter_label (_("Meter"))
264 , mark_label (_("Location Markers"))
265 , range_mark_label (_("Range Markers"))
266 , transport_mark_label (_("Loop/Punch Ranges"))
267 , cd_mark_label (_("CD Markers"))
268 , videotl_label (_("Video Timeline"))
269 , edit_packer (4, 4, true)
271 /* the values here don't matter: layout widgets
272 reset them as needed.
275 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
276 , horizontal_adjustment (0.0, 0.0, 1e16)
277 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
279 , controls_layout (unused_adjustment, vertical_adjustment)
281 /* tool bar related */
283 , toolbar_selection_clock_table (2,3)
284 , _mouse_mode_tearoff (0)
285 , automation_mode_button (_("mode"))
289 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
290 , selection_op_cmd_depth (0)
291 , selection_op_history_it (0)
295 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
296 , meters_running(false)
297 , _pending_locate_request (false)
298 , _pending_initial_locate (false)
299 , _last_cut_copy_source_track (0)
301 , _region_selection_change_updates_region_list (true)
302 , _following_mixer_selection (false)
303 , _control_point_toggled_on_press (false)
304 , _stepping_axis_view (0)
305 , quantize_dialog (0)
306 , _main_menu_disabler (0)
310 /* we are a singleton */
312 PublicEditor::_instance = this;
316 selection = new Selection (this);
317 cut_buffer = new Selection (this);
318 _selection_memento = new SelectionMemento ();
319 selection_op_history.clear();
322 clicked_regionview = 0;
323 clicked_axisview = 0;
324 clicked_routeview = 0;
325 clicked_control_point = 0;
326 last_update_frame = 0;
329 _drags = new DragManager (this);
332 current_mixer_strip = 0;
335 snap_type_strings = I18N (_snap_type_strings);
336 snap_mode_strings = I18N (_snap_mode_strings);
337 zoom_focus_strings = I18N (_zoom_focus_strings);
338 edit_mode_strings = I18N (_edit_mode_strings);
339 edit_point_strings = I18N (_edit_point_strings);
340 #ifdef USE_RUBBERBAND
341 rb_opt_strings = I18N (_rb_opt_strings);
345 build_edit_mode_menu();
346 build_zoom_focus_menu();
347 build_track_count_menu();
348 build_snap_mode_menu();
349 build_snap_type_menu();
350 build_edit_point_menu();
352 snap_threshold = 5.0;
353 bbt_beat_subdivision = 4;
354 _visible_canvas_width = 0;
355 _visible_canvas_height = 0;
356 autoscroll_horizontal_allowed = false;
357 autoscroll_vertical_allowed = false;
362 current_interthread_info = 0;
363 _show_measures = true;
365 show_gain_after_trim = false;
367 have_pending_keyboard_selection = false;
368 _follow_playhead = true;
369 _stationary_playhead = false;
370 editor_ruler_menu = 0;
371 no_ruler_shown_update = false;
373 range_marker_menu = 0;
374 marker_menu_item = 0;
375 tempo_or_meter_marker_menu = 0;
376 transport_marker_menu = 0;
377 new_transport_marker_menu = 0;
378 editor_mixer_strip_width = Wide;
379 show_editor_mixer_when_tracks_arrive = false;
380 region_edit_menu_split_multichannel_item = 0;
381 region_edit_menu_split_item = 0;
384 mouse_mode = MouseObject;
385 current_stepping_trackview = 0;
387 entered_regionview = 0;
389 clear_entered_track = false;
392 button_release_can_deselect = true;
393 _dragging_playhead = false;
394 _dragging_edit_point = false;
395 select_new_marker = false;
397 layering_order_editor = 0;
398 no_save_visual = false;
400 within_track_canvas = false;
402 scrubbing_direction = 0;
406 location_marker_color = UIConfiguration::instance().color ("location marker");
407 location_range_color = UIConfiguration::instance().color ("location range");
408 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
409 location_loop_color = UIConfiguration::instance().color ("location loop");
410 location_punch_color = UIConfiguration::instance().color ("location punch");
412 zoom_focus = ZoomFocusPlayhead;
413 _edit_point = EditAtMouse;
414 _visible_track_count = -1;
416 samples_per_pixel = 2048; /* too early to use reset_zoom () */
418 timebar_height = std::max(12., ceil (15. * UIConfiguration::instance().get_ui_scale()));
419 TimeAxisView::setup_sizes ();
420 ArdourMarker::setup_sizes (timebar_height);
422 _scroll_callbacks = 0;
424 bbt_label.set_name ("EditorRulerLabel");
425 bbt_label.set_size_request (-1, (int)timebar_height);
426 bbt_label.set_alignment (1.0, 0.5);
427 bbt_label.set_padding (5,0);
429 bbt_label.set_no_show_all();
430 minsec_label.set_name ("EditorRulerLabel");
431 minsec_label.set_size_request (-1, (int)timebar_height);
432 minsec_label.set_alignment (1.0, 0.5);
433 minsec_label.set_padding (5,0);
434 minsec_label.hide ();
435 minsec_label.set_no_show_all();
436 timecode_label.set_name ("EditorRulerLabel");
437 timecode_label.set_size_request (-1, (int)timebar_height);
438 timecode_label.set_alignment (1.0, 0.5);
439 timecode_label.set_padding (5,0);
440 timecode_label.hide ();
441 timecode_label.set_no_show_all();
442 samples_label.set_name ("EditorRulerLabel");
443 samples_label.set_size_request (-1, (int)timebar_height);
444 samples_label.set_alignment (1.0, 0.5);
445 samples_label.set_padding (5,0);
446 samples_label.hide ();
447 samples_label.set_no_show_all();
449 tempo_label.set_name ("EditorRulerLabel");
450 tempo_label.set_size_request (-1, (int)timebar_height);
451 tempo_label.set_alignment (1.0, 0.5);
452 tempo_label.set_padding (5,0);
454 tempo_label.set_no_show_all();
456 meter_label.set_name ("EditorRulerLabel");
457 meter_label.set_size_request (-1, (int)timebar_height);
458 meter_label.set_alignment (1.0, 0.5);
459 meter_label.set_padding (5,0);
461 meter_label.set_no_show_all();
463 if (Profile->get_trx()) {
464 mark_label.set_text (_("Markers"));
466 mark_label.set_name ("EditorRulerLabel");
467 mark_label.set_size_request (-1, (int)timebar_height);
468 mark_label.set_alignment (1.0, 0.5);
469 mark_label.set_padding (5,0);
471 mark_label.set_no_show_all();
473 cd_mark_label.set_name ("EditorRulerLabel");
474 cd_mark_label.set_size_request (-1, (int)timebar_height);
475 cd_mark_label.set_alignment (1.0, 0.5);
476 cd_mark_label.set_padding (5,0);
477 cd_mark_label.hide();
478 cd_mark_label.set_no_show_all();
480 videotl_bar_height = 4;
481 videotl_label.set_name ("EditorRulerLabel");
482 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
483 videotl_label.set_alignment (1.0, 0.5);
484 videotl_label.set_padding (5,0);
485 videotl_label.hide();
486 videotl_label.set_no_show_all();
488 range_mark_label.set_name ("EditorRulerLabel");
489 range_mark_label.set_size_request (-1, (int)timebar_height);
490 range_mark_label.set_alignment (1.0, 0.5);
491 range_mark_label.set_padding (5,0);
492 range_mark_label.hide();
493 range_mark_label.set_no_show_all();
495 transport_mark_label.set_name ("EditorRulerLabel");
496 transport_mark_label.set_size_request (-1, (int)timebar_height);
497 transport_mark_label.set_alignment (1.0, 0.5);
498 transport_mark_label.set_padding (5,0);
499 transport_mark_label.hide();
500 transport_mark_label.set_no_show_all();
502 initialize_canvas ();
504 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
506 _summary = new EditorSummary (this);
508 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
509 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
511 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
513 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
514 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
516 edit_controls_vbox.set_spacing (0);
517 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
518 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
520 HBox* h = manage (new HBox);
521 _group_tabs = new EditorGroupTabs (this);
522 if (!ARDOUR::Profile->get_trx()) {
523 h->pack_start (*_group_tabs, PACK_SHRINK);
525 h->pack_start (edit_controls_vbox);
526 controls_layout.add (*h);
528 controls_layout.set_name ("EditControlsBase");
529 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
530 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
531 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
533 _cursors = new MouseCursors;
534 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
535 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
537 /* Push default cursor to ever-present bottom of cursor stack. */
538 push_canvas_cursor(_cursors->grabber);
540 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
542 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
543 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
544 pad_line_1->set_outline_color (0xFF0000FF);
550 edit_packer.set_col_spacings (0);
551 edit_packer.set_row_spacings (0);
552 edit_packer.set_homogeneous (false);
553 edit_packer.set_border_width (0);
554 edit_packer.set_name ("EditorWindow");
556 time_bars_event_box.add (time_bars_vbox);
557 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
558 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
560 /* labels for the time bars */
561 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
563 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
565 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
567 bottom_hbox.set_border_width (2);
568 bottom_hbox.set_spacing (3);
570 _route_groups = new EditorRouteGroups (this);
571 _routes = new EditorRoutes (this);
572 _regions = new EditorRegions (this);
573 _snapshots = new EditorSnapshots (this);
574 _locations = new EditorLocations (this);
576 /* these are static location signals */
578 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
579 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
580 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
582 add_notebook_page (_("Regions"), _regions->widget ());
583 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
584 add_notebook_page (_("Snapshots"), _snapshots->widget ());
585 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
586 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
588 _the_notebook.set_show_tabs (true);
589 _the_notebook.set_scrollable (true);
590 _the_notebook.popup_disable ();
591 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
592 _the_notebook.show_all ();
594 _notebook_shrunk = false;
596 editor_summary_pane.pack1(edit_packer);
598 Button* summary_arrows_left_left = manage (new Button);
599 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
600 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
601 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
603 Button* summary_arrows_left_right = manage (new Button);
604 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
605 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
606 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
608 VBox* summary_arrows_left = manage (new VBox);
609 summary_arrows_left->pack_start (*summary_arrows_left_left);
610 summary_arrows_left->pack_start (*summary_arrows_left_right);
612 Button* summary_arrows_right_up = manage (new Button);
613 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
614 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
615 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
617 Button* summary_arrows_right_down = manage (new Button);
618 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
619 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
620 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
622 VBox* summary_arrows_right = manage (new VBox);
623 summary_arrows_right->pack_start (*summary_arrows_right_up);
624 summary_arrows_right->pack_start (*summary_arrows_right_down);
626 Frame* summary_frame = manage (new Frame);
627 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
629 summary_frame->add (*_summary);
630 summary_frame->show ();
632 _summary_hbox.pack_start (*summary_arrows_left, false, false);
633 _summary_hbox.pack_start (*summary_frame, true, true);
634 _summary_hbox.pack_start (*summary_arrows_right, false, false);
636 if (!ARDOUR::Profile->get_trx()) {
637 editor_summary_pane.pack2 (_summary_hbox);
640 edit_pane.pack1 (editor_summary_pane, true, true);
641 if (!ARDOUR::Profile->get_trx()) {
642 edit_pane.pack2 (_the_notebook, false, true);
645 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
647 /* XXX: editor_summary_pane might need similar to the edit_pane */
649 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
651 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
652 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
654 top_hbox.pack_start (toolbar_frame);
656 HBox *hbox = manage (new HBox);
657 hbox->pack_start (edit_pane, true, true);
659 global_vpacker.pack_start (top_hbox, false, false);
660 global_vpacker.pack_start (*hbox, true, true);
662 global_hpacker.pack_start (global_vpacker, true, true);
664 set_name ("EditorWindow");
665 add_accel_group (ActionManager::ui_manager->get_accel_group());
667 status_bar_hpacker.show ();
669 vpacker.pack_end (status_bar_hpacker, false, false);
670 vpacker.pack_end (global_hpacker, true, true);
672 /* register actions now so that set_state() can find them and set toggles/checks etc */
675 /* when we start using our own keybinding system for the editor, this
676 * will be uncommented
682 set_zoom_focus (zoom_focus);
683 set_visible_track_count (_visible_track_count);
684 _snap_type = SnapToBeat;
685 set_snap_to (_snap_type);
686 _snap_mode = SnapOff;
687 set_snap_mode (_snap_mode);
688 set_mouse_mode (MouseObject, true);
689 pre_internal_snap_type = _snap_type;
690 pre_internal_snap_mode = _snap_mode;
691 internal_snap_type = _snap_type;
692 internal_snap_mode = _snap_mode;
693 set_edit_point_preference (EditAtMouse, true);
695 _playlist_selector = new PlaylistSelector();
696 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
698 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
702 nudge_forward_button.set_name ("nudge button");
703 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
705 nudge_backward_button.set_name ("nudge button");
706 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
708 fade_context_menu.set_name ("ArdourContextMenu");
710 /* icons, titles, WM stuff */
712 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
713 Glib::RefPtr<Gdk::Pixbuf> icon;
715 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
716 window_icons.push_back (icon);
718 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
719 window_icons.push_back (icon);
721 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
722 window_icons.push_back (icon);
724 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
725 window_icons.push_back (icon);
727 if (!window_icons.empty()) {
728 // set_icon_list (window_icons);
729 set_default_icon_list (window_icons);
732 WindowTitle title(Glib::get_application_name());
733 title += _("Editor");
734 set_title (title.get_string());
735 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
738 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
740 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
741 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
743 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
745 /* allow external control surfaces/protocols to do various things */
747 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
748 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
749 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
750 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
751 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
752 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
753 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
754 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
755 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
756 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
757 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
758 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
759 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
760 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
762 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
763 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
764 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
765 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
766 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
768 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
770 /* problematic: has to return a value and thus cannot be x-thread */
772 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
774 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
775 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
777 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
779 _ignore_region_action = false;
780 _last_region_menu_was_main = false;
781 _popup_region_menu_item = 0;
783 _ignore_follow_edits = false;
785 _show_marker_lines = false;
787 /* Button bindings */
789 button_bindings = new Bindings;
791 XMLNode* node = button_settings();
793 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
794 button_bindings->load (**i);
800 /* grab current parameter state */
801 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
802 UIConfiguration::instance().map_parameters (pc);
804 setup_fade_images ();
811 delete button_bindings;
813 delete _route_groups;
814 delete _track_canvas_viewport;
817 delete quantize_dialog;
823 delete _playlist_selector;
827 Editor::button_settings () const
829 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
830 XMLNode* node = find_named_node (*settings, X_("Buttons"));
833 node = new XMLNode (X_("Buttons"));
840 Editor::add_toplevel_menu (Container& cont)
842 vpacker.pack_start (cont, false, false);
847 Editor::add_transport_frame (Container& cont)
849 if(ARDOUR::Profile->get_mixbus()) {
850 global_vpacker.pack_start (cont, false, false);
851 global_vpacker.reorder_child (cont, 0);
854 vpacker.pack_start (cont, false, false);
859 Editor::get_smart_mode () const
861 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
865 Editor::catch_vanishing_regionview (RegionView *rv)
867 /* note: the selection will take care of the vanishing
868 audioregionview by itself.
871 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
875 if (clicked_regionview == rv) {
876 clicked_regionview = 0;
879 if (entered_regionview == rv) {
880 set_entered_regionview (0);
883 if (!_all_region_actions_sensitized) {
884 sensitize_all_region_actions (true);
889 Editor::set_entered_regionview (RegionView* rv)
891 if (rv == entered_regionview) {
895 if (entered_regionview) {
896 entered_regionview->exited ();
899 entered_regionview = rv;
901 if (entered_regionview != 0) {
902 entered_regionview->entered ();
905 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
906 /* This RegionView entry might have changed what region actions
907 are allowed, so sensitize them all in case a key is pressed.
909 sensitize_all_region_actions (true);
914 Editor::set_entered_track (TimeAxisView* tav)
917 entered_track->exited ();
923 entered_track->entered ();
928 Editor::show_window ()
930 if (!is_visible ()) {
934 /* XXX: this is a bit unfortunate; it would probably
935 be nicer if we could just call show () above rather
936 than needing the show_all ()
939 /* re-hide stuff if necessary */
940 editor_list_button_toggled ();
941 parameter_changed ("show-summary");
942 parameter_changed ("show-group-tabs");
943 parameter_changed ("show-zoom-tools");
945 /* now reset all audio_time_axis heights, because widgets might need
951 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
952 tv = (static_cast<TimeAxisView*>(*i));
956 if (current_mixer_strip) {
957 current_mixer_strip->hide_things ();
958 current_mixer_strip->parameter_changed ("mixer-element-visibility");
966 Editor::instant_save ()
968 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
973 _session->add_instant_xml(get_state());
975 Config->add_instant_xml(get_state());
980 Editor::control_vertical_zoom_in_all ()
982 tav_zoom_smooth (false, true);
986 Editor::control_vertical_zoom_out_all ()
988 tav_zoom_smooth (true, true);
992 Editor::control_vertical_zoom_in_selected ()
994 tav_zoom_smooth (false, false);
998 Editor::control_vertical_zoom_out_selected ()
1000 tav_zoom_smooth (true, false);
1004 Editor::control_view (uint32_t view)
1006 goto_visual_state (view);
1010 Editor::control_unselect ()
1012 selection->clear_tracks ();
1016 Editor::control_select (uint32_t rid, Selection::Operation op)
1018 /* handles the (static) signal from the ControlProtocol class that
1019 * requests setting the selected track to a given RID
1026 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1032 TimeAxisView* tav = axis_view_from_route (r);
1036 case Selection::Add:
1037 selection->add (tav);
1039 case Selection::Toggle:
1040 selection->toggle (tav);
1042 case Selection::Extend:
1044 case Selection::Set:
1045 selection->set (tav);
1049 selection->clear_tracks ();
1054 Editor::control_step_tracks_up ()
1056 scroll_tracks_up_line ();
1060 Editor::control_step_tracks_down ()
1062 scroll_tracks_down_line ();
1066 Editor::control_scroll (float fraction)
1068 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1074 double step = fraction * current_page_samples();
1077 _control_scroll_target is an optional<T>
1079 it acts like a pointer to an framepos_t, with
1080 a operator conversion to boolean to check
1081 that it has a value could possibly use
1082 playhead_cursor->current_frame to store the
1083 value and a boolean in the class to know
1084 when it's out of date
1087 if (!_control_scroll_target) {
1088 _control_scroll_target = _session->transport_frame();
1089 _dragging_playhead = true;
1092 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1093 *_control_scroll_target = 0;
1094 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1095 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1097 *_control_scroll_target += (framepos_t) trunc (step);
1100 /* move visuals, we'll catch up with it later */
1102 playhead_cursor->set_position (*_control_scroll_target);
1103 UpdateAllTransportClocks (*_control_scroll_target);
1105 if (*_control_scroll_target > (current_page_samples() / 2)) {
1106 /* try to center PH in window */
1107 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1113 Now we do a timeout to actually bring the session to the right place
1114 according to the playhead. This is to avoid reading disk buffers on every
1115 call to control_scroll, which is driven by ScrollTimeline and therefore
1116 probably by a control surface wheel which can generate lots of events.
1118 /* cancel the existing timeout */
1120 control_scroll_connection.disconnect ();
1122 /* add the next timeout */
1124 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1128 Editor::deferred_control_scroll (framepos_t /*target*/)
1130 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1131 // reset for next stream
1132 _control_scroll_target = boost::none;
1133 _dragging_playhead = false;
1138 Editor::access_action (std::string action_group, std::string action_item)
1144 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1147 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1155 Editor::on_realize ()
1157 Window::on_realize ();
1160 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1161 start_lock_event_timing ();
1164 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1168 Editor::start_lock_event_timing ()
1170 /* check if we should lock the GUI every 30 seconds */
1172 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1176 Editor::generic_event_handler (GdkEvent* ev)
1179 case GDK_BUTTON_PRESS:
1180 case GDK_BUTTON_RELEASE:
1181 case GDK_MOTION_NOTIFY:
1183 case GDK_KEY_RELEASE:
1184 gettimeofday (&last_event_time, 0);
1187 case GDK_LEAVE_NOTIFY:
1188 switch (ev->crossing.detail) {
1189 case GDK_NOTIFY_UNKNOWN:
1190 case GDK_NOTIFY_INFERIOR:
1191 case GDK_NOTIFY_ANCESTOR:
1193 case GDK_NOTIFY_VIRTUAL:
1194 case GDK_NOTIFY_NONLINEAR:
1195 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1196 /* leaving window, so reset focus, thus ending any and
1197 all text entry operations.
1212 Editor::lock_timeout_callback ()
1214 struct timeval now, delta;
1216 gettimeofday (&now, 0);
1218 timersub (&now, &last_event_time, &delta);
1220 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1222 /* don't call again. Returning false will effectively
1223 disconnect us from the timer callback.
1225 unlock() will call start_lock_event_timing() to get things
1235 Editor::map_position_change (framepos_t frame)
1237 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1239 if (_session == 0) {
1243 if (_follow_playhead) {
1244 center_screen (frame);
1247 playhead_cursor->set_position (frame);
1251 Editor::center_screen (framepos_t frame)
1253 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1255 /* if we're off the page, then scroll.
1258 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1259 center_screen_internal (frame, page);
1264 Editor::center_screen_internal (framepos_t frame, float page)
1269 frame -= (framepos_t) page;
1274 reset_x_origin (frame);
1279 Editor::update_title ()
1281 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1284 bool dirty = _session->dirty();
1286 string session_name;
1288 if (_session->snap_name() != _session->name()) {
1289 session_name = _session->snap_name();
1291 session_name = _session->name();
1295 session_name = "*" + session_name;
1298 WindowTitle title(session_name);
1299 title += Glib::get_application_name();
1300 set_title (title.get_string());
1302 /* ::session_going_away() will have taken care of it */
1307 Editor::set_session (Session *t)
1309 SessionHandlePtr::set_session (t);
1315 _playlist_selector->set_session (_session);
1316 nudge_clock->set_session (_session);
1317 _summary->set_session (_session);
1318 _group_tabs->set_session (_session);
1319 _route_groups->set_session (_session);
1320 _regions->set_session (_session);
1321 _snapshots->set_session (_session);
1322 _routes->set_session (_session);
1323 _locations->set_session (_session);
1325 if (rhythm_ferret) {
1326 rhythm_ferret->set_session (_session);
1329 if (analysis_window) {
1330 analysis_window->set_session (_session);
1334 sfbrowser->set_session (_session);
1337 compute_fixed_ruler_scale ();
1339 /* Make sure we have auto loop and auto punch ranges */
1341 Location* loc = _session->locations()->auto_loop_location();
1343 loc->set_name (_("Loop"));
1346 loc = _session->locations()->auto_punch_location();
1349 loc->set_name (_("Punch"));
1352 refresh_location_display ();
1354 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1355 the selected Marker; this needs the LocationMarker list to be available.
1357 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1358 set_state (*node, Stateful::loading_state_version);
1360 /* catch up with the playhead */
1362 _session->request_locate (playhead_cursor->current_frame ());
1363 _pending_initial_locate = true;
1367 /* These signals can all be emitted by a non-GUI thread. Therefore the
1368 handlers for them must not attempt to directly interact with the GUI,
1369 but use PBD::Signal<T>::connect() which accepts an event loop
1370 ("context") where the handler will be asked to run.
1373 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1374 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1375 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1376 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1377 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1378 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1379 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1380 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1381 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1382 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1383 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1384 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1385 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1387 playhead_cursor->show ();
1389 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1390 Config->map_parameters (pc);
1391 _session->config.map_parameters (pc);
1393 restore_ruler_visibility ();
1394 //tempo_map_changed (PropertyChange (0));
1395 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1397 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1398 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1401 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1402 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1405 switch (_snap_type) {
1406 case SnapToRegionStart:
1407 case SnapToRegionEnd:
1408 case SnapToRegionSync:
1409 case SnapToRegionBoundary:
1410 build_region_boundary_cache ();
1417 /* register for undo history */
1418 _session->register_with_memento_command_factory(id(), this);
1419 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1421 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1423 start_updating_meters ();
1427 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1429 if (a->get_name() == "RegionMenu") {
1430 /* When the main menu's region menu is opened, we setup the actions so that they look right
1431 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1432 so we resensitize all region actions when the entered regionview or the region selection
1433 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1434 happens after the region context menu is opened. So we set a flag here, too.
1438 sensitize_the_right_region_actions ();
1439 _last_region_menu_was_main = true;
1444 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1446 using namespace Menu_Helpers;
1448 void (Editor::*emf)(FadeShape);
1449 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1452 images = &_xfade_in_images;
1453 emf = &Editor::set_fade_in_shape;
1455 images = &_xfade_out_images;
1456 emf = &Editor::set_fade_out_shape;
1461 _("Linear (for highly correlated material)"),
1462 *(*images)[FadeLinear],
1463 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1467 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1471 _("Constant power"),
1472 *(*images)[FadeConstantPower],
1473 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1476 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1481 *(*images)[FadeSymmetric],
1482 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1486 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1491 *(*images)[FadeSlow],
1492 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1495 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1500 *(*images)[FadeFast],
1501 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1504 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1507 /** Pop up a context menu for when the user clicks on a start crossfade */
1509 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1511 using namespace Menu_Helpers;
1512 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1517 MenuList& items (xfade_in_context_menu.items());
1520 if (arv->audio_region()->fade_in_active()) {
1521 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1523 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1526 items.push_back (SeparatorElem());
1527 fill_xfade_menu (items, true);
1529 xfade_in_context_menu.popup (button, time);
1532 /** Pop up a context menu for when the user clicks on an end crossfade */
1534 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1536 using namespace Menu_Helpers;
1537 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1542 MenuList& items (xfade_out_context_menu.items());
1545 if (arv->audio_region()->fade_out_active()) {
1546 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1548 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1551 items.push_back (SeparatorElem());
1552 fill_xfade_menu (items, false);
1554 xfade_out_context_menu.popup (button, time);
1558 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1560 using namespace Menu_Helpers;
1561 Menu* (Editor::*build_menu_function)();
1564 switch (item_type) {
1566 case RegionViewName:
1567 case RegionViewNameHighlight:
1568 case LeftFrameHandle:
1569 case RightFrameHandle:
1570 if (with_selection) {
1571 build_menu_function = &Editor::build_track_selection_context_menu;
1573 build_menu_function = &Editor::build_track_region_context_menu;
1578 if (with_selection) {
1579 build_menu_function = &Editor::build_track_selection_context_menu;
1581 build_menu_function = &Editor::build_track_context_menu;
1586 if (clicked_routeview->track()) {
1587 build_menu_function = &Editor::build_track_context_menu;
1589 build_menu_function = &Editor::build_track_bus_context_menu;
1594 /* probably shouldn't happen but if it does, we don't care */
1598 menu = (this->*build_menu_function)();
1599 menu->set_name ("ArdourContextMenu");
1601 /* now handle specific situations */
1603 switch (item_type) {
1605 case RegionViewName:
1606 case RegionViewNameHighlight:
1607 case LeftFrameHandle:
1608 case RightFrameHandle:
1609 if (!with_selection) {
1610 if (region_edit_menu_split_item) {
1611 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1612 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1614 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1617 if (region_edit_menu_split_multichannel_item) {
1618 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1619 region_edit_menu_split_multichannel_item->set_sensitive (true);
1621 region_edit_menu_split_multichannel_item->set_sensitive (false);
1634 /* probably shouldn't happen but if it does, we don't care */
1638 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1640 /* Bounce to disk */
1642 using namespace Menu_Helpers;
1643 MenuList& edit_items = menu->items();
1645 edit_items.push_back (SeparatorElem());
1647 switch (clicked_routeview->audio_track()->freeze_state()) {
1648 case AudioTrack::NoFreeze:
1649 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1652 case AudioTrack::Frozen:
1653 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1656 case AudioTrack::UnFrozen:
1657 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1663 if (item_type == StreamItem && clicked_routeview) {
1664 clicked_routeview->build_underlay_menu(menu);
1667 /* When the region menu is opened, we setup the actions so that they look right
1670 sensitize_the_right_region_actions ();
1671 _last_region_menu_was_main = false;
1673 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1674 menu->popup (button, time);
1678 Editor::build_track_context_menu ()
1680 using namespace Menu_Helpers;
1682 MenuList& edit_items = track_context_menu.items();
1685 add_dstream_context_items (edit_items);
1686 return &track_context_menu;
1690 Editor::build_track_bus_context_menu ()
1692 using namespace Menu_Helpers;
1694 MenuList& edit_items = track_context_menu.items();
1697 add_bus_context_items (edit_items);
1698 return &track_context_menu;
1702 Editor::build_track_region_context_menu ()
1704 using namespace Menu_Helpers;
1705 MenuList& edit_items = track_region_context_menu.items();
1708 /* we've just cleared the track region context menu, so the menu that these
1709 two items were on will have disappeared; stop them dangling.
1711 region_edit_menu_split_item = 0;
1712 region_edit_menu_split_multichannel_item = 0;
1714 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1717 boost::shared_ptr<Track> tr;
1718 boost::shared_ptr<Playlist> pl;
1720 if ((tr = rtv->track())) {
1721 add_region_context_items (edit_items, tr);
1725 add_dstream_context_items (edit_items);
1727 return &track_region_context_menu;
1731 Editor::analyze_region_selection ()
1733 if (analysis_window == 0) {
1734 analysis_window = new AnalysisWindow();
1737 analysis_window->set_session(_session);
1739 analysis_window->show_all();
1742 analysis_window->set_regionmode();
1743 analysis_window->analyze();
1745 analysis_window->present();
1749 Editor::analyze_range_selection()
1751 if (analysis_window == 0) {
1752 analysis_window = new AnalysisWindow();
1755 analysis_window->set_session(_session);
1757 analysis_window->show_all();
1760 analysis_window->set_rangemode();
1761 analysis_window->analyze();
1763 analysis_window->present();
1767 Editor::build_track_selection_context_menu ()
1769 using namespace Menu_Helpers;
1770 MenuList& edit_items = track_selection_context_menu.items();
1771 edit_items.clear ();
1773 add_selection_context_items (edit_items);
1774 // edit_items.push_back (SeparatorElem());
1775 // add_dstream_context_items (edit_items);
1777 return &track_selection_context_menu;
1781 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1783 using namespace Menu_Helpers;
1785 /* OK, stick the region submenu at the top of the list, and then add
1789 RegionSelection rs = get_regions_from_selection_and_entered ();
1791 string::size_type pos = 0;
1792 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1794 /* we have to hack up the region name because "_" has a special
1795 meaning for menu titles.
1798 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1799 menu_item_name.replace (pos, 1, "__");
1803 if (_popup_region_menu_item == 0) {
1804 _popup_region_menu_item = new MenuItem (menu_item_name);
1805 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1806 _popup_region_menu_item->show ();
1808 _popup_region_menu_item->set_label (menu_item_name);
1811 /* No latering allowed in later is higher layering model */
1812 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1813 if (act && Config->get_layer_model() == LaterHigher) {
1814 act->set_sensitive (false);
1816 act->set_sensitive (true);
1819 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1821 edit_items.push_back (*_popup_region_menu_item);
1822 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1823 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1825 edit_items.push_back (SeparatorElem());
1828 /** Add context menu items relevant to selection ranges.
1829 * @param edit_items List to add the items to.
1832 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1834 using namespace Menu_Helpers;
1836 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1837 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1839 edit_items.push_back (SeparatorElem());
1840 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1842 edit_items.push_back (SeparatorElem());
1843 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1845 edit_items.push_back (SeparatorElem());
1847 edit_items.push_back (
1849 _("Move Range Start to Previous Region Boundary"),
1850 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1854 edit_items.push_back (
1856 _("Move Range Start to Next Region Boundary"),
1857 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1861 edit_items.push_back (
1863 _("Move Range End to Previous Region Boundary"),
1864 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1868 edit_items.push_back (
1870 _("Move Range End to Next Region Boundary"),
1871 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1875 edit_items.push_back (SeparatorElem());
1876 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1877 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1879 edit_items.push_back (SeparatorElem());
1880 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1882 edit_items.push_back (SeparatorElem());
1883 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1884 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1885 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1887 edit_items.push_back (SeparatorElem());
1888 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1890 edit_items.push_back (SeparatorElem());
1891 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1892 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1893 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1895 edit_items.push_back (SeparatorElem());
1896 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1897 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1898 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1899 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1900 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1901 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1902 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1908 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1910 using namespace Menu_Helpers;
1914 Menu *play_menu = manage (new Menu);
1915 MenuList& play_items = play_menu->items();
1916 play_menu->set_name ("ArdourContextMenu");
1918 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1919 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1920 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1921 play_items.push_back (SeparatorElem());
1922 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1924 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1928 Menu *select_menu = manage (new Menu);
1929 MenuList& select_items = select_menu->items();
1930 select_menu->set_name ("ArdourContextMenu");
1932 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1933 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1934 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1935 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1936 select_items.push_back (SeparatorElem());
1937 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1938 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1939 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
1940 select_items.push_back (SeparatorElem());
1941 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1942 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1943 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1944 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1945 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1946 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1947 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1949 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1953 Menu *cutnpaste_menu = manage (new Menu);
1954 MenuList& cutnpaste_items = cutnpaste_menu->items();
1955 cutnpaste_menu->set_name ("ArdourContextMenu");
1957 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1958 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1959 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1961 cutnpaste_items.push_back (SeparatorElem());
1963 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1964 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1966 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1968 /* Adding new material */
1970 edit_items.push_back (SeparatorElem());
1971 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1972 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1976 Menu *nudge_menu = manage (new Menu());
1977 MenuList& nudge_items = nudge_menu->items();
1978 nudge_menu->set_name ("ArdourContextMenu");
1980 edit_items.push_back (SeparatorElem());
1981 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1982 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1983 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1984 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1986 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1990 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1992 using namespace Menu_Helpers;
1996 Menu *play_menu = manage (new Menu);
1997 MenuList& play_items = play_menu->items();
1998 play_menu->set_name ("ArdourContextMenu");
2000 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2001 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2002 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2006 Menu *select_menu = manage (new Menu);
2007 MenuList& select_items = select_menu->items();
2008 select_menu->set_name ("ArdourContextMenu");
2010 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2011 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2012 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2013 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2014 select_items.push_back (SeparatorElem());
2015 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2016 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2017 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2018 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2020 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2024 Menu *cutnpaste_menu = manage (new Menu);
2025 MenuList& cutnpaste_items = cutnpaste_menu->items();
2026 cutnpaste_menu->set_name ("ArdourContextMenu");
2028 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2029 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2030 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2032 Menu *nudge_menu = manage (new Menu());
2033 MenuList& nudge_items = nudge_menu->items();
2034 nudge_menu->set_name ("ArdourContextMenu");
2036 edit_items.push_back (SeparatorElem());
2037 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2038 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2039 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2040 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2042 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2046 Editor::snap_type() const
2052 Editor::snap_mode() const
2058 Editor::set_snap_to (SnapType st)
2060 unsigned int snap_ind = (unsigned int)st;
2062 if (internal_editing()) {
2063 internal_snap_type = st;
2065 pre_internal_snap_type = st;
2070 if (snap_ind > snap_type_strings.size() - 1) {
2072 _snap_type = (SnapType)snap_ind;
2075 string str = snap_type_strings[snap_ind];
2077 if (str != snap_type_selector.get_text()) {
2078 snap_type_selector.set_text (str);
2083 switch (_snap_type) {
2084 case SnapToBeatDiv128:
2085 case SnapToBeatDiv64:
2086 case SnapToBeatDiv32:
2087 case SnapToBeatDiv28:
2088 case SnapToBeatDiv24:
2089 case SnapToBeatDiv20:
2090 case SnapToBeatDiv16:
2091 case SnapToBeatDiv14:
2092 case SnapToBeatDiv12:
2093 case SnapToBeatDiv10:
2094 case SnapToBeatDiv8:
2095 case SnapToBeatDiv7:
2096 case SnapToBeatDiv6:
2097 case SnapToBeatDiv5:
2098 case SnapToBeatDiv4:
2099 case SnapToBeatDiv3:
2100 case SnapToBeatDiv2: {
2101 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2102 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2104 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2105 current_bbt_points_begin, current_bbt_points_end);
2106 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2107 current_bbt_points_begin, current_bbt_points_end);
2108 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2112 case SnapToRegionStart:
2113 case SnapToRegionEnd:
2114 case SnapToRegionSync:
2115 case SnapToRegionBoundary:
2116 build_region_boundary_cache ();
2124 redisplay_tempo (false);
2126 SnapChanged (); /* EMIT SIGNAL */
2130 Editor::set_snap_mode (SnapMode mode)
2132 string str = snap_mode_strings[(int)mode];
2134 if (internal_editing()) {
2135 internal_snap_mode = mode;
2137 pre_internal_snap_mode = mode;
2142 if (str != snap_mode_selector.get_text ()) {
2143 snap_mode_selector.set_text (str);
2150 Editor::set_edit_point_preference (EditPoint ep, bool force)
2152 bool changed = (_edit_point != ep);
2155 if (Profile->get_mixbus())
2156 if (ep == EditAtSelectedMarker)
2157 ep = EditAtPlayhead;
2159 string str = edit_point_strings[(int)ep];
2160 if (str != edit_point_selector.get_text ()) {
2161 edit_point_selector.set_text (str);
2164 update_all_enter_cursors();
2166 if (!force && !changed) {
2170 const char* action=NULL;
2172 switch (_edit_point) {
2173 case EditAtPlayhead:
2174 action = "edit-at-playhead";
2176 case EditAtSelectedMarker:
2177 action = "edit-at-marker";
2180 action = "edit-at-mouse";
2184 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2186 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2190 bool in_track_canvas;
2192 if (!mouse_frame (foo, in_track_canvas)) {
2193 in_track_canvas = false;
2196 reset_canvas_action_sensitivity (in_track_canvas);
2202 Editor::set_state (const XMLNode& node, int /*version*/)
2204 const XMLProperty* prop;
2211 g.base_width = default_width;
2212 g.base_height = default_height;
2216 if ((geometry = find_named_node (node, "geometry")) != 0) {
2220 if ((prop = geometry->property("x_size")) == 0) {
2221 prop = geometry->property ("x-size");
2224 g.base_width = atoi(prop->value());
2226 if ((prop = geometry->property("y_size")) == 0) {
2227 prop = geometry->property ("y-size");
2230 g.base_height = atoi(prop->value());
2233 if ((prop = geometry->property ("x_pos")) == 0) {
2234 prop = geometry->property ("x-pos");
2237 x = atoi (prop->value());
2240 if ((prop = geometry->property ("y_pos")) == 0) {
2241 prop = geometry->property ("y-pos");
2244 y = atoi (prop->value());
2248 set_default_size (g.base_width, g.base_height);
2251 if (_session && (prop = node.property ("playhead"))) {
2253 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2255 playhead_cursor->set_position (pos);
2257 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2258 playhead_cursor->set_position (0);
2261 playhead_cursor->set_position (0);
2264 if ((prop = node.property ("mixer-width"))) {
2265 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2268 if ((prop = node.property ("zoom-focus"))) {
2269 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2272 if ((prop = node.property ("zoom"))) {
2273 /* older versions of ardour used floating point samples_per_pixel */
2274 double f = PBD::atof (prop->value());
2275 reset_zoom (llrintf (f));
2277 reset_zoom (samples_per_pixel);
2280 if ((prop = node.property ("visible-track-count"))) {
2281 set_visible_track_count (PBD::atoi (prop->value()));
2284 if ((prop = node.property ("snap-to"))) {
2285 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2288 if ((prop = node.property ("snap-mode"))) {
2289 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2292 if ((prop = node.property ("internal-snap-to"))) {
2293 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2296 if ((prop = node.property ("internal-snap-mode"))) {
2297 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2300 if ((prop = node.property ("pre-internal-snap-to"))) {
2301 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2304 if ((prop = node.property ("pre-internal-snap-mode"))) {
2305 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2308 if ((prop = node.property ("mouse-mode"))) {
2309 MouseMode m = str2mousemode(prop->value());
2310 set_mouse_mode (m, true);
2312 set_mouse_mode (MouseObject, true);
2315 if ((prop = node.property ("left-frame")) != 0) {
2317 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2321 reset_x_origin (pos);
2325 if ((prop = node.property ("y-origin")) != 0) {
2326 reset_y_origin (atof (prop->value ()));
2329 if ((prop = node.property ("join-object-range"))) {
2330 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2331 bool yn = string_is_affirmative (prop->value());
2333 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2334 tact->set_active (!yn);
2335 tact->set_active (yn);
2337 set_mouse_mode(mouse_mode, true);
2340 if ((prop = node.property ("edit-point"))) {
2341 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2344 if ((prop = node.property ("show-measures"))) {
2345 bool yn = string_is_affirmative (prop->value());
2346 _show_measures = yn;
2349 if ((prop = node.property ("follow-playhead"))) {
2350 bool yn = string_is_affirmative (prop->value());
2351 set_follow_playhead (yn);
2354 if ((prop = node.property ("stationary-playhead"))) {
2355 bool yn = string_is_affirmative (prop->value());
2356 set_stationary_playhead (yn);
2359 if ((prop = node.property ("region-list-sort-type"))) {
2360 RegionListSortType st;
2361 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2364 if ((prop = node.property ("show-editor-mixer"))) {
2366 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2369 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2370 bool yn = string_is_affirmative (prop->value());
2372 /* do it twice to force the change */
2374 tact->set_active (!yn);
2375 tact->set_active (yn);
2378 if ((prop = node.property ("show-editor-list"))) {
2380 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2383 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2384 bool yn = string_is_affirmative (prop->value());
2386 /* do it twice to force the change */
2388 tact->set_active (!yn);
2389 tact->set_active (yn);
2392 if ((prop = node.property (X_("editor-list-page")))) {
2393 _the_notebook.set_current_page (atoi (prop->value ()));
2396 if ((prop = node.property (X_("show-marker-lines")))) {
2397 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2399 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2400 bool yn = string_is_affirmative (prop->value ());
2402 tact->set_active (!yn);
2403 tact->set_active (yn);
2406 XMLNodeList children = node.children ();
2407 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2408 selection->set_state (**i, Stateful::current_state_version);
2409 _regions->set_state (**i);
2412 if ((prop = node.property ("maximised"))) {
2413 bool yn = string_is_affirmative (prop->value());
2414 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2416 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2417 bool fs = tact && tact->get_active();
2419 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2423 if ((prop = node.property ("nudge-clock-value"))) {
2425 sscanf (prop->value().c_str(), "%" PRId64, &f);
2426 nudge_clock->set (f);
2428 nudge_clock->set_mode (AudioClock::Timecode);
2429 nudge_clock->set (_session->frame_rate() * 5, true);
2434 * Not all properties may have been in XML, but
2435 * those that are linked to a private variable may need changing
2440 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2442 yn = _show_measures;
2443 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2444 /* do it twice to force the change */
2445 tact->set_active (!yn);
2446 tact->set_active (yn);
2449 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2450 yn = _follow_playhead;
2452 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2453 if (tact->get_active() != yn) {
2454 tact->set_active (yn);
2458 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2459 yn = _stationary_playhead;
2461 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2462 if (tact->get_active() != yn) {
2463 tact->set_active (yn);
2472 Editor::get_state ()
2474 XMLNode* node = new XMLNode ("Editor");
2477 id().print (buf, sizeof (buf));
2478 node->add_property ("id", buf);
2480 if (is_realized()) {
2481 Glib::RefPtr<Gdk::Window> win = get_window();
2483 int x, y, width, height;
2484 win->get_root_origin(x, y);
2485 win->get_size(width, height);
2487 XMLNode* geometry = new XMLNode ("geometry");
2489 snprintf(buf, sizeof(buf), "%d", width);
2490 geometry->add_property("x-size", string(buf));
2491 snprintf(buf, sizeof(buf), "%d", height);
2492 geometry->add_property("y-size", string(buf));
2493 snprintf(buf, sizeof(buf), "%d", x);
2494 geometry->add_property("x-pos", string(buf));
2495 snprintf(buf, sizeof(buf), "%d", y);
2496 geometry->add_property("y-pos", string(buf));
2497 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2498 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2499 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2500 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2501 geometry->add_property("edit-vertical-pane-pos", string(buf));
2503 node->add_child_nocopy (*geometry);
2506 maybe_add_mixer_strip_width (*node);
2508 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2510 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2511 node->add_property ("zoom", buf);
2512 node->add_property ("snap-to", enum_2_string (_snap_type));
2513 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2514 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2515 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2516 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2517 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2518 node->add_property ("edit-point", enum_2_string (_edit_point));
2519 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2520 node->add_property ("visible-track-count", buf);
2522 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2523 node->add_property ("playhead", buf);
2524 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2525 node->add_property ("left-frame", buf);
2526 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2527 node->add_property ("y-origin", buf);
2529 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2530 node->add_property ("maximised", _maximised ? "yes" : "no");
2531 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2532 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2533 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2534 node->add_property ("mouse-mode", enum2str(mouse_mode));
2535 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2537 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2539 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2540 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2543 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2545 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2546 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2549 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2550 node->add_property (X_("editor-list-page"), buf);
2552 if (button_bindings) {
2553 XMLNode* bb = new XMLNode (X_("Buttons"));
2554 button_bindings->save (*bb);
2555 node->add_child_nocopy (*bb);
2558 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2560 node->add_child_nocopy (selection->get_state ());
2561 node->add_child_nocopy (_regions->get_state ());
2563 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2564 node->add_property ("nudge-clock-value", buf);
2569 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2570 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2572 * @return pair: TimeAxisView that y is over, layer index.
2574 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2575 * in stacked or expanded region display mode, otherwise 0.
2577 std::pair<TimeAxisView *, double>
2578 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2580 if (!trackview_relative_offset) {
2581 y -= _trackview_group->canvas_origin().y;
2585 return std::make_pair ( (TimeAxisView *) 0, 0);
2588 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2590 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2597 return std::make_pair ( (TimeAxisView *) 0, 0);
2600 /** Snap a position to the grid, if appropriate, taking into account current
2601 * grid settings and also the state of any snap modifier keys that may be pressed.
2602 * @param start Position to snap.
2603 * @param event Event to get current key modifier information from, or 0.
2606 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2608 if (!_session || !event) {
2612 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2613 if (_snap_mode == SnapOff) {
2614 snap_to_internal (start, direction, for_mark);
2617 if (_snap_mode != SnapOff) {
2618 snap_to_internal (start, direction, for_mark);
2619 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2620 /* SnapOff, but we pressed the snap_delta modifier */
2621 snap_to_internal (start, direction, for_mark);
2627 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2629 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2633 snap_to_internal (start, direction, for_mark, ensure_snap);
2637 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2639 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2640 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2642 switch (_snap_type) {
2643 case SnapToTimecodeFrame:
2644 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2645 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2646 /* start is already on a whole timecode frame, do nothing */
2647 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2648 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2650 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2654 case SnapToTimecodeSeconds:
2655 if (_session->config.get_timecode_offset_negative()) {
2656 start += _session->config.get_timecode_offset ();
2658 start -= _session->config.get_timecode_offset ();
2660 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2661 (start % one_timecode_second == 0)) {
2662 /* start is already on a whole second, do nothing */
2663 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2664 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2666 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2669 if (_session->config.get_timecode_offset_negative()) {
2670 start -= _session->config.get_timecode_offset ();
2672 start += _session->config.get_timecode_offset ();
2676 case SnapToTimecodeMinutes:
2677 if (_session->config.get_timecode_offset_negative()) {
2678 start += _session->config.get_timecode_offset ();
2680 start -= _session->config.get_timecode_offset ();
2682 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2683 (start % one_timecode_minute == 0)) {
2684 /* start is already on a whole minute, do nothing */
2685 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2686 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2688 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2690 if (_session->config.get_timecode_offset_negative()) {
2691 start -= _session->config.get_timecode_offset ();
2693 start += _session->config.get_timecode_offset ();
2697 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2698 abort(); /*NOTREACHED*/
2703 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2705 const framepos_t one_second = _session->frame_rate();
2706 const framepos_t one_minute = _session->frame_rate() * 60;
2707 framepos_t presnap = start;
2711 switch (_snap_type) {
2712 case SnapToTimecodeFrame:
2713 case SnapToTimecodeSeconds:
2714 case SnapToTimecodeMinutes:
2715 return timecode_snap_to_internal (start, direction, for_mark);
2718 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2719 start % (one_second/75) == 0) {
2720 /* start is already on a whole CD frame, do nothing */
2721 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2722 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2724 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2729 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2730 start % one_second == 0) {
2731 /* start is already on a whole second, do nothing */
2732 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2733 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2735 start = (framepos_t) floor ((double) start / one_second) * one_second;
2740 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2741 start % one_minute == 0) {
2742 /* start is already on a whole minute, do nothing */
2743 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2744 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2746 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2751 start = _session->tempo_map().round_to_bar (start, direction);
2755 start = _session->tempo_map().round_to_beat (start, direction);
2758 case SnapToBeatDiv128:
2759 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2761 case SnapToBeatDiv64:
2762 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2764 case SnapToBeatDiv32:
2765 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2767 case SnapToBeatDiv28:
2768 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2770 case SnapToBeatDiv24:
2771 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2773 case SnapToBeatDiv20:
2774 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2776 case SnapToBeatDiv16:
2777 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2779 case SnapToBeatDiv14:
2780 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2782 case SnapToBeatDiv12:
2783 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2785 case SnapToBeatDiv10:
2786 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2788 case SnapToBeatDiv8:
2789 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2791 case SnapToBeatDiv7:
2792 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2794 case SnapToBeatDiv6:
2795 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2797 case SnapToBeatDiv5:
2798 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2800 case SnapToBeatDiv4:
2801 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2803 case SnapToBeatDiv3:
2804 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2806 case SnapToBeatDiv2:
2807 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2815 _session->locations()->marks_either_side (start, before, after);
2817 if (before == max_framepos && after == max_framepos) {
2818 /* No marks to snap to, so just don't snap */
2820 } else if (before == max_framepos) {
2822 } else if (after == max_framepos) {
2824 } else if (before != max_framepos && after != max_framepos) {
2825 /* have before and after */
2826 if ((start - before) < (after - start)) {
2835 case SnapToRegionStart:
2836 case SnapToRegionEnd:
2837 case SnapToRegionSync:
2838 case SnapToRegionBoundary:
2839 if (!region_boundary_cache.empty()) {
2841 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2842 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2844 if (direction > 0) {
2845 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2847 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2850 if (next != region_boundary_cache.begin ()) {
2855 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2856 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2858 if (start > (p + n) / 2) {
2867 switch (_snap_mode) {
2877 if (presnap > start) {
2878 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2882 } else if (presnap < start) {
2883 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2889 /* handled at entry */
2897 Editor::setup_toolbar ()
2899 HBox* mode_box = manage(new HBox);
2900 mode_box->set_border_width (2);
2901 mode_box->set_spacing(2);
2903 HBox* mouse_mode_box = manage (new HBox);
2904 HBox* mouse_mode_hbox = manage (new HBox);
2905 VBox* mouse_mode_vbox = manage (new VBox);
2906 Alignment* mouse_mode_align = manage (new Alignment);
2908 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2909 mouse_mode_size_group->add_widget (smart_mode_button);
2910 mouse_mode_size_group->add_widget (mouse_move_button);
2911 mouse_mode_size_group->add_widget (mouse_cut_button);
2912 mouse_mode_size_group->add_widget (mouse_select_button);
2913 mouse_mode_size_group->add_widget (mouse_timefx_button);
2914 mouse_mode_size_group->add_widget (mouse_audition_button);
2915 mouse_mode_size_group->add_widget (mouse_draw_button);
2916 mouse_mode_size_group->add_widget (mouse_content_button);
2918 mouse_mode_size_group->add_widget (zoom_in_button);
2919 mouse_mode_size_group->add_widget (zoom_out_button);
2920 mouse_mode_size_group->add_widget (zoom_preset_selector);
2921 mouse_mode_size_group->add_widget (zoom_out_full_button);
2922 mouse_mode_size_group->add_widget (zoom_focus_selector);
2924 mouse_mode_size_group->add_widget (tav_shrink_button);
2925 mouse_mode_size_group->add_widget (tav_expand_button);
2926 mouse_mode_size_group->add_widget (visible_tracks_selector);
2928 mouse_mode_size_group->add_widget (snap_type_selector);
2929 mouse_mode_size_group->add_widget (snap_mode_selector);
2931 mouse_mode_size_group->add_widget (edit_point_selector);
2932 mouse_mode_size_group->add_widget (edit_mode_selector);
2934 mouse_mode_size_group->add_widget (*nudge_clock);
2935 mouse_mode_size_group->add_widget (nudge_forward_button);
2936 mouse_mode_size_group->add_widget (nudge_backward_button);
2938 mouse_mode_hbox->set_spacing (2);
2940 if (!ARDOUR::Profile->get_trx()) {
2941 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2944 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2945 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2947 if (!ARDOUR::Profile->get_mixbus()) {
2948 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2951 if (!ARDOUR::Profile->get_trx()) {
2952 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2953 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2954 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2955 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2958 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2960 mouse_mode_align->add (*mouse_mode_vbox);
2961 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2963 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2965 edit_mode_selector.set_name ("mouse mode button");
2967 if (!ARDOUR::Profile->get_trx()) {
2968 mode_box->pack_start (edit_mode_selector, false, false);
2970 mode_box->pack_start (*mouse_mode_box, false, false);
2972 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2973 _mouse_mode_tearoff->set_name ("MouseModeBase");
2974 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2976 if (Profile->get_sae() || Profile->get_mixbus() ) {
2977 _mouse_mode_tearoff->set_can_be_torn_off (false);
2980 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2981 &_mouse_mode_tearoff->tearoff_window()));
2982 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2983 &_mouse_mode_tearoff->tearoff_window(), 1));
2984 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2985 &_mouse_mode_tearoff->tearoff_window()));
2986 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2987 &_mouse_mode_tearoff->tearoff_window(), 1));
2991 _zoom_box.set_spacing (2);
2992 _zoom_box.set_border_width (2);
2996 zoom_preset_selector.set_name ("zoom button");
2997 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2998 zoom_preset_selector.set_size_request (42, -1);
3000 zoom_in_button.set_name ("zoom button");
3001 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3002 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3003 zoom_in_button.set_related_action (act);
3005 zoom_out_button.set_name ("zoom button");
3006 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3007 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3008 zoom_out_button.set_related_action (act);
3010 zoom_out_full_button.set_name ("zoom button");
3011 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3012 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3013 zoom_out_full_button.set_related_action (act);
3015 zoom_focus_selector.set_name ("zoom button");
3017 if (ARDOUR::Profile->get_mixbus()) {
3018 _zoom_box.pack_start (zoom_preset_selector, false, false);
3019 } else if (ARDOUR::Profile->get_trx()) {
3020 mode_box->pack_start (zoom_out_button, false, false);
3021 mode_box->pack_start (zoom_in_button, false, false);
3023 _zoom_box.pack_start (zoom_out_button, false, false);
3024 _zoom_box.pack_start (zoom_in_button, false, false);
3025 _zoom_box.pack_start (zoom_out_full_button, false, false);
3026 _zoom_box.pack_start (zoom_focus_selector, false, false);
3029 /* Track zoom buttons */
3030 visible_tracks_selector.set_name ("zoom button");
3031 if (Profile->get_mixbus()) {
3032 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3033 visible_tracks_selector.set_size_request (42, -1);
3035 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3038 tav_expand_button.set_name ("zoom button");
3039 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3040 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3041 tav_expand_button.set_related_action (act);
3043 tav_shrink_button.set_name ("zoom button");
3044 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3045 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3046 tav_shrink_button.set_related_action (act);
3048 if (ARDOUR::Profile->get_mixbus()) {
3049 _zoom_box.pack_start (visible_tracks_selector);
3050 } else if (ARDOUR::Profile->get_trx()) {
3051 _zoom_box.pack_start (tav_shrink_button);
3052 _zoom_box.pack_start (tav_expand_button);
3054 _zoom_box.pack_start (visible_tracks_selector);
3055 _zoom_box.pack_start (tav_shrink_button);
3056 _zoom_box.pack_start (tav_expand_button);
3059 if (!ARDOUR::Profile->get_trx()) {
3060 _zoom_tearoff = manage (new TearOff (_zoom_box));
3062 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3063 &_zoom_tearoff->tearoff_window()));
3064 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3065 &_zoom_tearoff->tearoff_window(), 0));
3066 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3067 &_zoom_tearoff->tearoff_window()));
3068 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3069 &_zoom_tearoff->tearoff_window(), 0));
3072 if (Profile->get_sae() || Profile->get_mixbus() ) {
3073 _zoom_tearoff->set_can_be_torn_off (false);
3076 snap_box.set_spacing (2);
3077 snap_box.set_border_width (2);
3079 snap_type_selector.set_name ("mouse mode button");
3081 snap_mode_selector.set_name ("mouse mode button");
3083 edit_point_selector.set_name ("mouse mode button");
3085 snap_box.pack_start (snap_mode_selector, false, false);
3086 snap_box.pack_start (snap_type_selector, false, false);
3087 snap_box.pack_start (edit_point_selector, false, false);
3091 HBox *nudge_box = manage (new HBox);
3092 nudge_box->set_spacing (2);
3093 nudge_box->set_border_width (2);
3095 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3096 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3098 nudge_box->pack_start (nudge_backward_button, false, false);
3099 nudge_box->pack_start (nudge_forward_button, false, false);
3100 nudge_box->pack_start (*nudge_clock, false, false);
3103 /* Pack everything in... */
3105 HBox* hbox = manage (new HBox);
3106 hbox->set_spacing(2);
3108 _tools_tearoff = manage (new TearOff (*hbox));
3109 _tools_tearoff->set_name ("MouseModeBase");
3110 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3112 if (Profile->get_sae() || Profile->get_mixbus()) {
3113 _tools_tearoff->set_can_be_torn_off (false);
3116 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3117 &_tools_tearoff->tearoff_window()));
3118 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3119 &_tools_tearoff->tearoff_window(), 0));
3120 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3121 &_tools_tearoff->tearoff_window()));
3122 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3123 &_tools_tearoff->tearoff_window(), 0));
3125 toolbar_hbox.set_spacing (2);
3126 toolbar_hbox.set_border_width (1);
3128 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3129 if (!ARDOUR::Profile->get_trx()) {
3130 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3131 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3134 if (!ARDOUR::Profile->get_trx()) {
3135 hbox->pack_start (snap_box, false, false);
3136 hbox->pack_start (*nudge_box, false, false);
3138 hbox->pack_start (panic_box, false, false);
3142 toolbar_base.set_name ("ToolBarBase");
3143 toolbar_base.add (toolbar_hbox);
3145 _toolbar_viewport.add (toolbar_base);
3146 /* stick to the required height but allow width to vary if there's not enough room */
3147 _toolbar_viewport.set_size_request (1, -1);
3149 toolbar_frame.set_shadow_type (SHADOW_OUT);
3150 toolbar_frame.set_name ("BaseFrame");
3151 toolbar_frame.add (_toolbar_viewport);
3155 Editor::build_edit_point_menu ()
3157 using namespace Menu_Helpers;
3159 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3160 if(!Profile->get_mixbus())
3161 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3162 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3164 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3168 Editor::build_edit_mode_menu ()
3170 using namespace Menu_Helpers;
3172 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3173 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3174 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3175 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3177 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3181 Editor::build_snap_mode_menu ()
3183 using namespace Menu_Helpers;
3185 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3186 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3187 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3189 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3193 Editor::build_snap_type_menu ()
3195 using namespace Menu_Helpers;
3197 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3198 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3199 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3200 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3201 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3202 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3203 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3204 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3205 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3206 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3207 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3208 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3209 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3210 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3211 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3212 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3213 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3214 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3215 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3216 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3217 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3218 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3219 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3220 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3221 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3222 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3223 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3224 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3225 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3226 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3228 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3233 Editor::setup_tooltips ()
3235 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Grab mode)"));
3236 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Grab Mode (select/move objects)"));
3237 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split regions)"));
3238 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select time ranges)"));
3239 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3240 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3241 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3242 ARDOUR_UI::instance()->set_tip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3243 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3244 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3245 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3246 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3247 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3248 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3249 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3250 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3251 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3252 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3253 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3254 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3255 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3256 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3257 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3258 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3262 Editor::convert_drop_to_paths (
3263 vector<string>& paths,
3264 const RefPtr<Gdk::DragContext>& /*context*/,
3267 const SelectionData& data,
3271 if (_session == 0) {
3275 vector<string> uris = data.get_uris();
3279 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3280 are actually URI lists. So do it by hand.
3283 if (data.get_target() != "text/plain") {
3287 /* Parse the "uri-list" format that Nautilus provides,
3288 where each pathname is delimited by \r\n.
3290 THERE MAY BE NO NULL TERMINATING CHAR!!!
3293 string txt = data.get_text();
3297 p = (char *) malloc (txt.length() + 1);
3298 txt.copy (p, txt.length(), 0);
3299 p[txt.length()] = '\0';
3305 while (g_ascii_isspace (*p))
3309 while (*q && (*q != '\n') && (*q != '\r')) {
3316 while (q > p && g_ascii_isspace (*q))
3321 uris.push_back (string (p, q - p + 1));
3325 p = strchr (p, '\n');
3337 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3338 if ((*i).substr (0,7) == "file://") {
3339 paths.push_back (Glib::filename_from_uri (*i));
3347 Editor::new_tempo_section ()
3352 Editor::map_transport_state ()
3354 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3356 if (_session && _session->transport_stopped()) {
3357 have_pending_keyboard_selection = false;
3360 update_loop_range_view ();
3366 Editor::begin_selection_op_history ()
3368 selection_op_cmd_depth = 0;
3369 selection_op_history_it = 0;
3371 while(!selection_op_history.empty()) {
3372 delete selection_op_history.front();
3373 selection_op_history.pop_front();
3376 selection_undo_action->set_sensitive (false);
3377 selection_redo_action->set_sensitive (false);
3378 selection_op_history.push_front (&_selection_memento->get_state ());
3382 Editor::begin_reversible_selection_op (string name)
3385 //cerr << name << endl;
3386 /* begin/commit pairs can be nested */
3387 selection_op_cmd_depth++;
3392 Editor::commit_reversible_selection_op ()
3395 if (selection_op_cmd_depth == 1) {
3397 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3399 The user has undone some selection ops and then made a new one,
3400 making anything earlier in the list invalid.
3403 list<XMLNode *>::iterator it = selection_op_history.begin();
3404 list<XMLNode *>::iterator e_it = it;
3405 advance (e_it, selection_op_history_it);
3407 for ( ; it != e_it; ++it) {
3410 selection_op_history.erase (selection_op_history.begin(), e_it);
3413 selection_op_history.push_front (&_selection_memento->get_state ());
3414 selection_op_history_it = 0;
3416 selection_undo_action->set_sensitive (true);
3417 selection_redo_action->set_sensitive (false);
3420 if (selection_op_cmd_depth > 0) {
3421 selection_op_cmd_depth--;
3427 Editor::undo_selection_op ()
3430 selection_op_history_it++;
3432 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3433 if (n == selection_op_history_it) {
3434 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3435 selection_redo_action->set_sensitive (true);
3439 /* is there an earlier entry? */
3440 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3441 selection_undo_action->set_sensitive (false);
3447 Editor::redo_selection_op ()
3450 if (selection_op_history_it > 0) {
3451 selection_op_history_it--;
3454 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3455 if (n == selection_op_history_it) {
3456 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3457 selection_undo_action->set_sensitive (true);
3462 if (selection_op_history_it == 0) {
3463 selection_redo_action->set_sensitive (false);
3469 Editor::begin_reversible_command (string name)
3472 before.push_back (&_selection_memento->get_state ());
3473 _session->begin_reversible_command (name);
3478 Editor::begin_reversible_command (GQuark q)
3481 before.push_back (&_selection_memento->get_state ());
3482 _session->begin_reversible_command (q);
3487 Editor::abort_reversible_command ()
3490 while(!before.empty()) {
3491 delete before.front();
3494 _session->abort_reversible_command ();
3499 Editor::commit_reversible_command ()
3502 if (before.size() == 1) {
3503 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3504 redo_action->set_sensitive(false);
3505 undo_action->set_sensitive(true);
3506 begin_selection_op_history ();
3509 if (before.empty()) {
3510 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3515 _session->commit_reversible_command ();
3520 Editor::history_changed ()
3524 if (undo_action && _session) {
3525 if (_session->undo_depth() == 0) {
3526 label = S_("Command|Undo");
3528 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3530 undo_action->property_label() = label;
3533 if (redo_action && _session) {
3534 if (_session->redo_depth() == 0) {
3537 label = string_compose(_("Redo (%1)"), _session->next_redo());
3539 redo_action->property_label() = label;
3544 Editor::duplicate_range (bool with_dialog)
3548 RegionSelection rs = get_regions_from_selection_and_entered ();
3550 if ( selection->time.length() == 0 && rs.empty()) {
3556 ArdourDialog win (_("Duplicate"));
3557 Label label (_("Number of duplications:"));
3558 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3559 SpinButton spinner (adjustment, 0.0, 1);
3562 win.get_vbox()->set_spacing (12);
3563 win.get_vbox()->pack_start (hbox);
3564 hbox.set_border_width (6);
3565 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3567 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3568 place, visually. so do this by hand.
3571 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3572 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3573 spinner.grab_focus();
3579 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3580 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3581 win.set_default_response (RESPONSE_ACCEPT);
3583 spinner.grab_focus ();
3585 switch (win.run ()) {
3586 case RESPONSE_ACCEPT:
3592 times = adjustment.get_value();
3595 if ((current_mouse_mode() == Editing::MouseRange)) {
3596 if (selection->time.length()) {
3597 duplicate_selection (times);
3599 } else if (get_smart_mode()) {
3600 if (selection->time.length()) {
3601 duplicate_selection (times);
3603 duplicate_some_regions (rs, times);
3605 duplicate_some_regions (rs, times);
3610 Editor::set_edit_mode (EditMode m)
3612 Config->set_edit_mode (m);
3616 Editor::cycle_edit_mode ()
3618 switch (Config->get_edit_mode()) {
3620 if (Profile->get_sae()) {
3621 Config->set_edit_mode (Lock);
3623 Config->set_edit_mode (Ripple);
3628 Config->set_edit_mode (Lock);
3631 Config->set_edit_mode (Slide);
3637 Editor::edit_mode_selection_done ( EditMode m )
3639 Config->set_edit_mode ( m );
3643 Editor::snap_type_selection_done (SnapType snaptype)
3645 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3647 ract->set_active ();
3652 Editor::snap_mode_selection_done (SnapMode mode)
3654 RefPtr<RadioAction> ract = snap_mode_action (mode);
3657 ract->set_active (true);
3662 Editor::cycle_edit_point (bool with_marker)
3664 if(Profile->get_mixbus())
3665 with_marker = false;
3667 switch (_edit_point) {
3669 set_edit_point_preference (EditAtPlayhead);
3671 case EditAtPlayhead:
3673 set_edit_point_preference (EditAtSelectedMarker);
3675 set_edit_point_preference (EditAtMouse);
3678 case EditAtSelectedMarker:
3679 set_edit_point_preference (EditAtMouse);
3685 Editor::edit_point_selection_done (EditPoint ep)
3687 set_edit_point_preference ( ep );
3691 Editor::build_zoom_focus_menu ()
3693 using namespace Menu_Helpers;
3695 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3696 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3697 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3698 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3699 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3700 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3702 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3706 Editor::zoom_focus_selection_done ( ZoomFocus f )
3708 RefPtr<RadioAction> ract = zoom_focus_action (f);
3710 ract->set_active ();
3715 Editor::build_track_count_menu ()
3717 using namespace Menu_Helpers;
3719 if (!Profile->get_mixbus()) {
3720 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3721 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3722 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3723 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3724 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3725 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3726 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3727 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3728 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3729 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3730 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3731 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3732 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3734 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3735 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3736 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3737 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3738 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3739 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3740 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3741 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3742 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3743 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3745 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3746 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3747 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3748 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3749 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3750 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3751 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3752 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3753 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3754 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3755 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3760 Editor::set_zoom_preset (int64_t ms)
3763 temporal_zoom_session();
3767 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3768 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3772 Editor::set_visible_track_count (int32_t n)
3774 _visible_track_count = n;
3776 /* if the canvas hasn't really been allocated any size yet, just
3777 record the desired number of visible tracks and return. when canvas
3778 allocation happens, we will get called again and then we can do the
3782 if (_visible_canvas_height <= 1) {
3788 DisplaySuspender ds;
3790 if (_visible_track_count > 0) {
3791 h = trackviews_height() / _visible_track_count;
3792 std::ostringstream s;
3793 s << _visible_track_count;
3795 } else if (_visible_track_count == 0) {
3797 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3798 if ((*i)->marked_for_display()) {
3802 h = trackviews_height() / n;
3805 /* negative value means that the visible track count has
3806 been overridden by explicit track height changes.
3808 visible_tracks_selector.set_text (X_("*"));
3812 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3813 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3816 if (str != visible_tracks_selector.get_text()) {
3817 visible_tracks_selector.set_text (str);
3822 Editor::override_visible_track_count ()
3824 _visible_track_count = -1;
3825 visible_tracks_selector.set_text ( _("*") );
3829 Editor::edit_controls_button_release (GdkEventButton* ev)
3831 if (Keyboard::is_context_menu_event (ev)) {
3832 ARDOUR_UI::instance()->add_route (this);
3833 } else if (ev->button == 1) {
3834 selection->clear_tracks ();
3841 Editor::mouse_select_button_release (GdkEventButton* ev)
3843 /* this handles just right-clicks */
3845 if (ev->button != 3) {
3853 Editor::set_zoom_focus (ZoomFocus f)
3855 string str = zoom_focus_strings[(int)f];
3857 if (str != zoom_focus_selector.get_text()) {
3858 zoom_focus_selector.set_text (str);
3861 if (zoom_focus != f) {
3868 Editor::cycle_zoom_focus ()
3870 switch (zoom_focus) {
3872 set_zoom_focus (ZoomFocusRight);
3874 case ZoomFocusRight:
3875 set_zoom_focus (ZoomFocusCenter);
3877 case ZoomFocusCenter:
3878 set_zoom_focus (ZoomFocusPlayhead);
3880 case ZoomFocusPlayhead:
3881 set_zoom_focus (ZoomFocusMouse);
3883 case ZoomFocusMouse:
3884 set_zoom_focus (ZoomFocusEdit);
3887 set_zoom_focus (ZoomFocusLeft);
3893 Editor::ensure_float (Window& win)
3895 win.set_transient_for (*this);
3899 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3901 /* recover or initialize pane positions. do this here rather than earlier because
3902 we don't want the positions to change the child allocations, which they seem to do.
3908 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3917 XMLNode* geometry = find_named_node (*node, "geometry");
3919 if (which == static_cast<Paned*> (&edit_pane)) {
3921 if (done & Horizontal) {
3925 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3926 _notebook_shrunk = string_is_affirmative (prop->value ());
3929 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3930 /* initial allocation is 90% to canvas, 10% to notebook */
3931 pos = (int) floor (alloc.get_width() * 0.90f);
3932 snprintf (buf, sizeof(buf), "%d", pos);
3934 pos = atoi (prop->value());
3937 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3938 edit_pane.set_position (pos);
3941 done = (Pane) (done | Horizontal);
3943 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3945 if (done & Vertical) {
3949 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3950 /* initial allocation is 90% to canvas, 10% to summary */
3951 pos = (int) floor (alloc.get_height() * 0.90f);
3952 snprintf (buf, sizeof(buf), "%d", pos);
3955 pos = atoi (prop->value());
3958 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3959 editor_summary_pane.set_position (pos);
3962 done = (Pane) (done | Vertical);
3967 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3969 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3970 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3971 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3972 top_hbox.remove (toolbar_frame);
3977 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3979 if (toolbar_frame.get_parent() == 0) {
3980 top_hbox.pack_end (toolbar_frame);
3985 Editor::set_show_measures (bool yn)
3987 if (_show_measures != yn) {
3990 if ((_show_measures = yn) == true) {
3992 tempo_lines->show();
3995 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3996 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3998 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3999 draw_measures (begin, end);
4007 Editor::toggle_follow_playhead ()
4009 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
4011 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4012 set_follow_playhead (tact->get_active());
4016 /** @param yn true to follow playhead, otherwise false.
4017 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4020 Editor::set_follow_playhead (bool yn, bool catch_up)
4022 if (_follow_playhead != yn) {
4023 if ((_follow_playhead = yn) == true && catch_up) {
4025 reset_x_origin_to_follow_playhead ();
4032 Editor::toggle_stationary_playhead ()
4034 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4036 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4037 set_stationary_playhead (tact->get_active());
4042 Editor::set_stationary_playhead (bool yn)
4044 if (_stationary_playhead != yn) {
4045 if ((_stationary_playhead = yn) == true) {
4047 // FIXME need a 3.0 equivalent of this 2.X call
4048 // update_current_screen ();
4055 Editor::playlist_selector () const
4057 return *_playlist_selector;
4061 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4063 if (paste_count == 0) {
4064 /* don't bother calculating an offset that will be zero anyway */
4068 /* calculate basic unsnapped multi-paste offset */
4069 framecnt_t offset = paste_count * duration;
4071 /* snap offset so pos + offset is aligned to the grid */
4072 framepos_t offset_pos = pos + offset;
4073 snap_to(offset_pos, RoundUpMaybe);
4074 offset = offset_pos - pos;
4080 Editor::get_grid_beat_divisions(framepos_t position)
4082 switch (_snap_type) {
4083 case SnapToBeatDiv128: return 128;
4084 case SnapToBeatDiv64: return 64;
4085 case SnapToBeatDiv32: return 32;
4086 case SnapToBeatDiv28: return 28;
4087 case SnapToBeatDiv24: return 24;
4088 case SnapToBeatDiv20: return 20;
4089 case SnapToBeatDiv16: return 16;
4090 case SnapToBeatDiv14: return 14;
4091 case SnapToBeatDiv12: return 12;
4092 case SnapToBeatDiv10: return 10;
4093 case SnapToBeatDiv8: return 8;
4094 case SnapToBeatDiv7: return 7;
4095 case SnapToBeatDiv6: return 6;
4096 case SnapToBeatDiv5: return 5;
4097 case SnapToBeatDiv4: return 4;
4098 case SnapToBeatDiv3: return 3;
4099 case SnapToBeatDiv2: return 2;
4106 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4110 const unsigned divisions = get_grid_beat_divisions(position);
4112 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4115 switch (_snap_type) {
4117 return Evoral::Beats(1.0);
4120 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
4128 return Evoral::Beats();
4132 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4136 ret = nudge_clock->current_duration (pos);
4137 next = ret + 1; /* XXXX fix me */
4143 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4145 ArdourDialog dialog (_("Playlist Deletion"));
4146 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4147 "If it is kept, its audio files will not be cleaned.\n"
4148 "If it is deleted, audio files used by it alone will be cleaned."),
4151 dialog.set_position (WIN_POS_CENTER);
4152 dialog.get_vbox()->pack_start (label);
4156 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4157 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4158 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4160 switch (dialog.run ()) {
4161 case RESPONSE_ACCEPT:
4162 /* delete the playlist */
4166 case RESPONSE_REJECT:
4167 /* keep the playlist */
4179 Editor::audio_region_selection_covers (framepos_t where)
4181 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4182 if ((*a)->region()->covers (where)) {
4191 Editor::prepare_for_cleanup ()
4193 cut_buffer->clear_regions ();
4194 cut_buffer->clear_playlists ();
4196 selection->clear_regions ();
4197 selection->clear_playlists ();
4199 _regions->suspend_redisplay ();
4203 Editor::finish_cleanup ()
4205 _regions->resume_redisplay ();
4209 Editor::transport_loop_location()
4212 return _session->locations()->auto_loop_location();
4219 Editor::transport_punch_location()
4222 return _session->locations()->auto_punch_location();
4229 Editor::control_layout_scroll (GdkEventScroll* ev)
4231 /* Just forward to the normal canvas scroll method. The coordinate
4232 systems are different but since the canvas is always larger than the
4233 track headers, and aligned with the trackview area, this will work.
4235 In the not too distant future this layout is going away anyway and
4236 headers will be on the canvas.
4238 return canvas_scroll_event (ev, false);
4242 Editor::session_state_saved (string)
4245 _snapshots->redisplay ();
4249 Editor::update_tearoff_visibility()
4251 bool visible = UIConfiguration::instance().get_keep_tearoffs();
4252 _mouse_mode_tearoff->set_visible (visible);
4253 _tools_tearoff->set_visible (visible);
4254 if (_zoom_tearoff) {
4255 _zoom_tearoff->set_visible (visible);
4260 Editor::reattach_all_tearoffs ()
4262 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4263 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4264 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4268 Editor::maximise_editing_space ()
4280 Editor::restore_editing_space ()
4292 * Make new playlists for a given track and also any others that belong
4293 * to the same active route group with the `select' property.
4298 Editor::new_playlists (TimeAxisView* v)
4300 begin_reversible_command (_("new playlists"));
4301 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4302 _session->playlists->get (playlists);
4303 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4304 commit_reversible_command ();
4308 * Use a copy of the current playlist for a given track and also any others that belong
4309 * to the same active route group with the `select' property.
4314 Editor::copy_playlists (TimeAxisView* v)
4316 begin_reversible_command (_("copy playlists"));
4317 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4318 _session->playlists->get (playlists);
4319 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4320 commit_reversible_command ();
4323 /** Clear the current playlist for a given track and also any others that belong
4324 * to the same active route group with the `select' property.
4329 Editor::clear_playlists (TimeAxisView* v)
4331 begin_reversible_command (_("clear playlists"));
4332 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4333 _session->playlists->get (playlists);
4334 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4335 commit_reversible_command ();
4339 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4341 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4345 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4347 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4351 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4353 atv.clear_playlist ();
4357 Editor::on_key_press_event (GdkEventKey* ev)
4359 return key_press_focus_accelerator_handler (*this, ev);
4363 Editor::on_key_release_event (GdkEventKey* ev)
4365 return Gtk::Window::on_key_release_event (ev);
4366 // return key_press_focus_accelerator_handler (*this, ev);
4370 Editor::get_y_origin () const
4372 return vertical_adjustment.get_value ();
4375 /** Queue up a change to the viewport x origin.
4376 * @param frame New x origin.
4379 Editor::reset_x_origin (framepos_t frame)
4381 pending_visual_change.add (VisualChange::TimeOrigin);
4382 pending_visual_change.time_origin = frame;
4383 ensure_visual_change_idle_handler ();
4387 Editor::reset_y_origin (double y)
4389 pending_visual_change.add (VisualChange::YOrigin);
4390 pending_visual_change.y_origin = y;
4391 ensure_visual_change_idle_handler ();
4395 Editor::reset_zoom (framecnt_t spp)
4397 if (spp == samples_per_pixel) {
4401 pending_visual_change.add (VisualChange::ZoomLevel);
4402 pending_visual_change.samples_per_pixel = spp;
4403 ensure_visual_change_idle_handler ();
4407 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4409 reset_x_origin (frame);
4412 if (!no_save_visual) {
4413 undo_visual_stack.push_back (current_visual_state(false));
4417 Editor::VisualState::VisualState (bool with_tracks)
4418 : gui_state (with_tracks ? new GUIObjectState : 0)
4422 Editor::VisualState::~VisualState ()
4427 Editor::VisualState*
4428 Editor::current_visual_state (bool with_tracks)
4430 VisualState* vs = new VisualState (with_tracks);
4431 vs->y_position = vertical_adjustment.get_value();
4432 vs->samples_per_pixel = samples_per_pixel;
4433 vs->leftmost_frame = leftmost_frame;
4434 vs->zoom_focus = zoom_focus;
4437 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4444 Editor::undo_visual_state ()
4446 if (undo_visual_stack.empty()) {
4450 VisualState* vs = undo_visual_stack.back();
4451 undo_visual_stack.pop_back();
4454 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4457 use_visual_state (*vs);
4462 Editor::redo_visual_state ()
4464 if (redo_visual_stack.empty()) {
4468 VisualState* vs = redo_visual_stack.back();
4469 redo_visual_stack.pop_back();
4471 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4472 // why do we check here?
4473 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4476 use_visual_state (*vs);
4481 Editor::swap_visual_state ()
4483 if (undo_visual_stack.empty()) {
4484 redo_visual_state ();
4486 undo_visual_state ();
4491 Editor::use_visual_state (VisualState& vs)
4493 PBD::Unwinder<bool> nsv (no_save_visual, true);
4494 DisplaySuspender ds;
4496 vertical_adjustment.set_value (vs.y_position);
4498 set_zoom_focus (vs.zoom_focus);
4499 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4502 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4504 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4505 (*i)->clear_property_cache();
4506 (*i)->reset_visual_state ();
4510 _routes->update_visibility ();
4513 /** This is the core function that controls the zoom level of the canvas. It is called
4514 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4515 * @param spp new number of samples per pixel
4518 Editor::set_samples_per_pixel (framecnt_t spp)
4524 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4525 const framecnt_t lots_of_pixels = 4000;
4527 /* if the zoom level is greater than what you'd get trying to display 3
4528 * days of audio on a really big screen, then it's too big.
4531 if (spp * lots_of_pixels > three_days) {
4535 samples_per_pixel = spp;
4538 tempo_lines->tempo_map_changed();
4541 bool const showing_time_selection = selection->time.length() > 0;
4543 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4544 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4545 (*i)->reshow_selection (selection->time);
4549 ZoomChanged (); /* EMIT_SIGNAL */
4551 ArdourCanvas::GtkCanvasViewport* c;
4553 c = get_track_canvas();
4555 c->canvas()->zoomed ();
4558 if (playhead_cursor) {
4559 playhead_cursor->set_position (playhead_cursor->current_frame ());
4562 refresh_location_display();
4563 _summary->set_overlays_dirty ();
4565 update_marker_labels ();
4571 Editor::queue_visual_videotimeline_update ()
4574 * pending_visual_change.add (VisualChange::VideoTimeline);
4575 * or maybe even more specific: which videotimeline-image
4576 * currently it calls update_video_timeline() to update
4577 * _all outdated_ images on the video-timeline.
4578 * see 'exposeimg()' in video_image_frame.cc
4580 ensure_visual_change_idle_handler ();
4584 Editor::ensure_visual_change_idle_handler ()
4586 if (pending_visual_change.idle_handler_id < 0) {
4587 // see comment in add_to_idle_resize above.
4588 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4589 pending_visual_change.being_handled = false;
4594 Editor::_idle_visual_changer (void* arg)
4596 return static_cast<Editor*>(arg)->idle_visual_changer ();
4600 Editor::idle_visual_changer ()
4602 /* set_horizontal_position() below (and maybe other calls) call
4603 gtk_main_iteration(), so it's possible that a signal will be handled
4604 half-way through this method. If this signal wants an
4605 idle_visual_changer we must schedule another one after this one, so
4606 mark the idle_handler_id as -1 here to allow that. Also make a note
4607 that we are doing the visual change, so that changes in response to
4608 super-rapid-screen-update can be dropped if we are still processing
4612 pending_visual_change.idle_handler_id = -1;
4613 pending_visual_change.being_handled = true;
4615 VisualChange vc = pending_visual_change;
4617 pending_visual_change.pending = (VisualChange::Type) 0;
4619 visual_changer (vc);
4621 pending_visual_change.being_handled = false;
4623 return 0; /* this is always a one-shot call */
4627 Editor::visual_changer (const VisualChange& vc)
4629 double const last_time_origin = horizontal_position ();
4631 if (vc.pending & VisualChange::ZoomLevel) {
4632 set_samples_per_pixel (vc.samples_per_pixel);
4634 compute_fixed_ruler_scale ();
4636 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4637 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4639 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4640 current_bbt_points_begin, current_bbt_points_end);
4641 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4642 current_bbt_points_begin, current_bbt_points_end);
4643 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4645 update_video_timeline();
4648 if (vc.pending & VisualChange::TimeOrigin) {
4649 set_horizontal_position (vc.time_origin / samples_per_pixel);
4652 if (vc.pending & VisualChange::YOrigin) {
4653 vertical_adjustment.set_value (vc.y_origin);
4656 if (last_time_origin == horizontal_position ()) {
4657 /* changed signal not emitted */
4658 update_fixed_rulers ();
4659 redisplay_tempo (true);
4662 if (!(vc.pending & VisualChange::ZoomLevel)) {
4663 update_video_timeline();
4666 _summary->set_overlays_dirty ();
4669 struct EditorOrderTimeAxisSorter {
4670 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4671 return a->order () < b->order ();
4676 Editor::sort_track_selection (TrackViewList& sel)
4678 EditorOrderTimeAxisSorter cmp;
4683 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4686 framepos_t where = 0;
4687 EditPoint ep = _edit_point;
4689 if (Profile->get_mixbus())
4690 if (ep == EditAtSelectedMarker)
4691 ep = EditAtPlayhead;
4693 if (from_outside_canvas && (ep == EditAtMouse)) {
4694 ep = EditAtPlayhead;
4695 } else if (from_context_menu && (ep == EditAtMouse)) {
4696 return canvas_event_sample (&context_click_event, 0, 0);
4699 if (entered_marker) {
4700 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4701 return entered_marker->position();
4704 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4705 ep = EditAtSelectedMarker;
4708 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4709 ep = EditAtPlayhead;
4713 case EditAtPlayhead:
4714 if (_dragging_playhead) {
4715 if (!mouse_frame (where, ignored)) {
4716 /* XXX not right but what can we do ? */
4720 where = _session->audible_frame();
4722 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4725 case EditAtSelectedMarker:
4726 if (!selection->markers.empty()) {
4728 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4731 where = loc->start();
4735 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4743 if (!mouse_frame (where, ignored)) {
4744 /* XXX not right but what can we do ? */
4748 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4756 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4758 if (!_session) return;
4760 begin_reversible_command (cmd);
4764 if ((tll = transport_loop_location()) == 0) {
4765 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4766 XMLNode &before = _session->locations()->get_state();
4767 _session->locations()->add (loc, true);
4768 _session->set_auto_loop_location (loc);
4769 XMLNode &after = _session->locations()->get_state();
4770 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4772 XMLNode &before = tll->get_state();
4773 tll->set_hidden (false, this);
4774 tll->set (start, end);
4775 XMLNode &after = tll->get_state();
4776 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4779 commit_reversible_command ();
4783 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4785 if (!_session) return;
4787 begin_reversible_command (cmd);
4791 if ((tpl = transport_punch_location()) == 0) {
4792 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4793 XMLNode &before = _session->locations()->get_state();
4794 _session->locations()->add (loc, true);
4795 _session->set_auto_punch_location (loc);
4796 XMLNode &after = _session->locations()->get_state();
4797 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4799 XMLNode &before = tpl->get_state();
4800 tpl->set_hidden (false, this);
4801 tpl->set (start, end);
4802 XMLNode &after = tpl->get_state();
4803 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4806 commit_reversible_command ();
4809 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4810 * @param rs List to which found regions are added.
4811 * @param where Time to look at.
4812 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4815 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4817 const TrackViewList* tracks;
4820 tracks = &track_views;
4825 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4827 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4830 boost::shared_ptr<Track> tr;
4831 boost::shared_ptr<Playlist> pl;
4833 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4835 boost::shared_ptr<RegionList> regions = pl->regions_at (
4836 (framepos_t) floor ( (double) where * tr->speed()));
4838 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4839 RegionView* rv = rtv->view()->find_view (*i);
4850 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4852 const TrackViewList* tracks;
4855 tracks = &track_views;
4860 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4861 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4863 boost::shared_ptr<Track> tr;
4864 boost::shared_ptr<Playlist> pl;
4866 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4868 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4869 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4871 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4873 RegionView* rv = rtv->view()->find_view (*i);
4884 /** Get regions using the following method:
4886 * Make a region list using:
4887 * (a) any selected regions
4888 * (b) the intersection of any selected tracks and the edit point(*)
4889 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4891 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4893 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4897 Editor::get_regions_from_selection_and_edit_point ()
4899 RegionSelection regions;
4901 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4902 regions.add (entered_regionview);
4904 regions = selection->regions;
4907 if ( regions.empty() ) {
4908 TrackViewList tracks = selection->tracks;
4910 if (!tracks.empty()) {
4911 /* no region selected or entered, but some selected tracks:
4912 * act on all regions on the selected tracks at the edit point
4914 framepos_t const where = get_preferred_edit_position ();
4915 get_regions_at(regions, where, tracks);
4922 /** Get regions using the following method:
4924 * Make a region list using:
4925 * (a) any selected regions
4926 * (b) the intersection of any selected tracks and the edit point(*)
4927 * (c) if neither exists, then whatever region is under the mouse
4929 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4931 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4934 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4936 RegionSelection regions;
4938 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4939 regions.add (entered_regionview);
4941 regions = selection->regions;
4944 if ( regions.empty() ) {
4945 TrackViewList tracks = selection->tracks;
4947 if (!tracks.empty()) {
4948 /* no region selected or entered, but some selected tracks:
4949 * act on all regions on the selected tracks at the edit point
4951 get_regions_at(regions, pos, tracks);
4958 /** Start with regions that are selected, or the entered regionview if none are selected.
4959 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4960 * of the regions that we started with.
4964 Editor::get_regions_from_selection_and_entered ()
4966 RegionSelection regions = selection->regions;
4968 if (regions.empty() && entered_regionview) {
4969 regions.add (entered_regionview);
4976 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4978 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4979 RouteTimeAxisView* rtav;
4981 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4982 boost::shared_ptr<Playlist> pl;
4983 std::vector<boost::shared_ptr<Region> > results;
4984 boost::shared_ptr<Track> tr;
4986 if ((tr = rtav->track()) == 0) {
4991 if ((pl = (tr->playlist())) != 0) {
4992 boost::shared_ptr<Region> r = pl->region_by_id (id);
4994 RegionView* rv = rtav->view()->find_view (r);
4996 regions.push_back (rv);
5005 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5008 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5009 MidiTimeAxisView* mtav;
5011 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5013 mtav->get_per_region_note_selection (selection);
5020 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5022 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5024 RouteTimeAxisView* tatv;
5026 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5028 boost::shared_ptr<Playlist> pl;
5029 vector<boost::shared_ptr<Region> > results;
5031 boost::shared_ptr<Track> tr;
5033 if ((tr = tatv->track()) == 0) {
5038 if ((pl = (tr->playlist())) != 0) {
5039 if (src_comparison) {
5040 pl->get_source_equivalent_regions (region, results);
5042 pl->get_region_list_equivalent_regions (region, results);
5046 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5047 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5048 regions.push_back (marv);
5057 Editor::show_rhythm_ferret ()
5059 if (rhythm_ferret == 0) {
5060 rhythm_ferret = new RhythmFerret(*this);
5063 rhythm_ferret->set_session (_session);
5064 rhythm_ferret->show ();
5065 rhythm_ferret->present ();
5069 Editor::first_idle ()
5071 MessageDialog* dialog = 0;
5073 if (track_views.size() > 1) {
5074 dialog = new MessageDialog (
5076 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5080 ARDOUR_UI::instance()->flush_pending ();
5083 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5087 // first idle adds route children (automation tracks), so we need to redisplay here
5088 _routes->redisplay ();
5092 if (_session->undo_depth() == 0) {
5093 undo_action->set_sensitive(false);
5095 redo_action->set_sensitive(false);
5096 begin_selection_op_history ();
5102 Editor::_idle_resize (gpointer arg)
5104 return ((Editor*)arg)->idle_resize ();
5108 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5110 if (resize_idle_id < 0) {
5111 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5112 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5113 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5115 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5116 _pending_resize_amount = 0;
5119 /* make a note of the smallest resulting height, so that we can clamp the
5120 lower limit at TimeAxisView::hSmall */
5122 int32_t min_resulting = INT32_MAX;
5124 _pending_resize_amount += h;
5125 _pending_resize_view = view;
5127 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5129 if (selection->tracks.contains (_pending_resize_view)) {
5130 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5131 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5135 if (min_resulting < 0) {
5140 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5141 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5145 /** Handle pending resizing of tracks */
5147 Editor::idle_resize ()
5149 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5151 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5152 selection->tracks.contains (_pending_resize_view)) {
5154 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5155 if (*i != _pending_resize_view) {
5156 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5161 _pending_resize_amount = 0;
5162 _group_tabs->set_dirty ();
5163 resize_idle_id = -1;
5171 ENSURE_GUI_THREAD (*this, &Editor::located);
5174 playhead_cursor->set_position (_session->audible_frame ());
5175 if (_follow_playhead && !_pending_initial_locate) {
5176 reset_x_origin_to_follow_playhead ();
5180 _pending_locate_request = false;
5181 _pending_initial_locate = false;
5185 Editor::region_view_added (RegionView * rv)
5187 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5188 if (rv->region ()->id () == (*pr)) {
5189 selection->add (rv);
5190 selection->regions.pending.erase (pr);
5195 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5197 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5198 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5199 if (rv->region()->id () == (*rnote).first) {
5200 mrv->select_notes ((*rnote).second);
5201 selection->pending_midi_note_selection.erase(rnote);
5207 _summary->set_background_dirty ();
5211 Editor::region_view_removed ()
5213 _summary->set_background_dirty ();
5217 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5219 TrackViewList::const_iterator j = track_views.begin ();
5220 while (j != track_views.end()) {
5221 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5222 if (rtv && rtv->route() == r) {
5233 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5237 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5238 TimeAxisView* tv = axis_view_from_route (*i);
5248 Editor::suspend_route_redisplay ()
5251 _routes->suspend_redisplay();
5256 Editor::resume_route_redisplay ()
5259 _routes->redisplay(); // queue redisplay
5260 _routes->resume_redisplay();
5265 Editor::add_routes (RouteList& routes)
5267 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5269 RouteTimeAxisView *rtv;
5270 list<RouteTimeAxisView*> new_views;
5271 TrackViewList new_selection;
5272 bool from_scratch = (track_views.size() == 0);
5274 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5275 boost::shared_ptr<Route> route = (*x);
5277 if (route->is_auditioner() || route->is_monitor()) {
5281 DataType dt = route->input()->default_type();
5283 if (dt == ARDOUR::DataType::AUDIO) {
5284 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5285 rtv->set_route (route);
5286 } else if (dt == ARDOUR::DataType::MIDI) {
5287 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5288 rtv->set_route (route);
5290 throw unknown_type();
5293 new_views.push_back (rtv);
5294 track_views.push_back (rtv);
5295 new_selection.push_back (rtv);
5297 rtv->effective_gain_display ();
5299 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5300 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5303 if (new_views.size() > 0) {
5304 _routes->routes_added (new_views);
5305 _summary->routes_added (new_views);
5308 if (!from_scratch) {
5309 selection->tracks.clear();
5310 selection->add (new_selection);
5311 begin_selection_op_history();
5314 if (show_editor_mixer_when_tracks_arrive) {
5315 show_editor_mixer (true);
5318 editor_list_button.set_sensitive (true);
5322 Editor::timeaxisview_deleted (TimeAxisView *tv)
5324 if (tv == entered_track) {
5328 if (_session && _session->deletion_in_progress()) {
5329 /* the situation is under control */
5333 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5335 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5337 _routes->route_removed (tv);
5339 TimeAxisView::Children c = tv->get_child_list ();
5340 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5341 if (entered_track == i->get()) {
5346 /* remove it from the list of track views */
5348 TrackViewList::iterator i;
5350 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5351 i = track_views.erase (i);
5354 /* update whatever the current mixer strip is displaying, if revelant */
5356 boost::shared_ptr<Route> route;
5359 route = rtav->route ();
5362 if (current_mixer_strip && current_mixer_strip->route() == route) {
5364 TimeAxisView* next_tv;
5366 if (track_views.empty()) {
5368 } else if (i == track_views.end()) {
5369 next_tv = track_views.front();
5376 set_selected_mixer_strip (*next_tv);
5378 /* make the editor mixer strip go away setting the
5379 * button to inactive (which also unticks the menu option)
5382 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5388 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5390 if (apply_to_selection) {
5391 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5393 TrackSelection::iterator j = i;
5396 hide_track_in_display (*i, false);
5401 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5403 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5404 // this will hide the mixer strip
5405 set_selected_mixer_strip (*tv);
5408 _routes->hide_track_in_display (*tv);
5413 Editor::sync_track_view_list_and_routes ()
5415 track_views = TrackViewList (_routes->views ());
5417 _summary->set_background_dirty();
5418 _group_tabs->set_dirty ();
5420 return false; // do not call again (until needed)
5424 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5426 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5431 /** Find a RouteTimeAxisView by the ID of its route */
5433 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5435 RouteTimeAxisView* v;
5437 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5438 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5439 if(v->route()->id() == id) {
5449 Editor::fit_route_group (RouteGroup *g)
5451 TrackViewList ts = axis_views_from_routes (g->route_list ());
5456 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5458 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5461 _session->cancel_audition ();
5465 if (_session->is_auditioning()) {
5466 _session->cancel_audition ();
5467 if (r == last_audition_region) {
5472 _session->audition_region (r);
5473 last_audition_region = r;
5478 Editor::hide_a_region (boost::shared_ptr<Region> r)
5480 r->set_hidden (true);
5484 Editor::show_a_region (boost::shared_ptr<Region> r)
5486 r->set_hidden (false);
5490 Editor::audition_region_from_region_list ()
5492 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5496 Editor::hide_region_from_region_list ()
5498 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5502 Editor::show_region_in_region_list ()
5504 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5508 Editor::step_edit_status_change (bool yn)
5511 start_step_editing ();
5513 stop_step_editing ();
5518 Editor::start_step_editing ()
5520 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5524 Editor::stop_step_editing ()
5526 step_edit_connection.disconnect ();
5530 Editor::check_step_edit ()
5532 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5533 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5535 mtv->check_step_edit ();
5539 return true; // do it again, till we stop
5543 Editor::scroll_press (Direction dir)
5545 ++_scroll_callbacks;
5547 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5548 /* delay the first auto-repeat */
5554 scroll_backward (1);
5562 scroll_up_one_track ();
5566 scroll_down_one_track ();
5570 /* do hacky auto-repeat */
5571 if (!_scroll_connection.connected ()) {
5573 _scroll_connection = Glib::signal_timeout().connect (
5574 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5577 _scroll_callbacks = 0;
5584 Editor::scroll_release ()
5586 _scroll_connection.disconnect ();
5589 /** Queue a change for the Editor viewport x origin to follow the playhead */
5591 Editor::reset_x_origin_to_follow_playhead ()
5593 framepos_t const frame = playhead_cursor->current_frame ();
5595 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5597 if (_session->transport_speed() < 0) {
5599 if (frame > (current_page_samples() / 2)) {
5600 center_screen (frame-(current_page_samples()/2));
5602 center_screen (current_page_samples()/2);
5609 if (frame < leftmost_frame) {
5611 if (_session->transport_rolling()) {
5612 /* rolling; end up with the playhead at the right of the page */
5613 l = frame - current_page_samples ();
5615 /* not rolling: end up with the playhead 1/4 of the way along the page */
5616 l = frame - current_page_samples() / 4;
5620 if (_session->transport_rolling()) {
5621 /* rolling: end up with the playhead on the left of the page */
5624 /* not rolling: end up with the playhead 3/4 of the way along the page */
5625 l = frame - 3 * current_page_samples() / 4;
5633 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5639 Editor::super_rapid_screen_update ()
5641 if (!_session || !_session->engine().running()) {
5645 /* METERING / MIXER STRIPS */
5647 /* update track meters, if required */
5648 if (is_mapped() && meters_running) {
5649 RouteTimeAxisView* rtv;
5650 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5651 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5652 rtv->fast_update ();
5657 /* and any current mixer strip */
5658 if (current_mixer_strip) {
5659 current_mixer_strip->fast_update ();
5662 /* PLAYHEAD AND VIEWPORT */
5664 framepos_t const frame = _session->audible_frame();
5666 /* There are a few reasons why we might not update the playhead / viewport stuff:
5668 * 1. we don't update things when there's a pending locate request, otherwise
5669 * when the editor requests a locate there is a chance that this method
5670 * will move the playhead before the locate request is processed, causing
5672 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5673 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5676 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5678 last_update_frame = frame;
5680 if (!_dragging_playhead) {
5681 playhead_cursor->set_position (frame);
5684 if (!_stationary_playhead) {
5686 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5687 /* We only do this if we aren't already
5688 handling a visual change (ie if
5689 pending_visual_change.being_handled is
5690 false) so that these requests don't stack
5691 up there are too many of them to handle in
5694 reset_x_origin_to_follow_playhead ();
5699 if (!_dragging_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5700 framepos_t const frame = playhead_cursor->current_frame ();
5701 double target = ((double)frame - (double)current_page_samples()/3.0);
5702 if (target <= 0.0) {
5705 // compare to EditorCursor::set_position()
5706 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5707 double const new_pos = sample_to_pixel_unrounded (target);
5708 if (rint (new_pos) != rint (old_pos)) {
5709 reset_x_origin (pixel_to_sample (floor (new_pos)));
5720 Editor::session_going_away ()
5722 _have_idled = false;
5724 _session_connections.drop_connections ();
5726 super_rapid_screen_update_connection.disconnect ();
5728 selection->clear ();
5729 cut_buffer->clear ();
5731 clicked_regionview = 0;
5732 clicked_axisview = 0;
5733 clicked_routeview = 0;
5734 entered_regionview = 0;
5736 last_update_frame = 0;
5739 playhead_cursor->hide ();
5741 /* rip everything out of the list displays */
5745 _route_groups->clear ();
5747 /* do this first so that deleting a track doesn't reset cms to null
5748 and thus cause a leak.
5751 if (current_mixer_strip) {
5752 if (current_mixer_strip->get_parent() != 0) {
5753 global_hpacker.remove (*current_mixer_strip);
5755 delete current_mixer_strip;
5756 current_mixer_strip = 0;
5759 /* delete all trackviews */
5761 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5764 track_views.clear ();
5766 nudge_clock->set_session (0);
5768 editor_list_button.set_active(false);
5769 editor_list_button.set_sensitive(false);
5771 /* clear tempo/meter rulers */
5772 remove_metric_marks ();
5774 clear_marker_display ();
5776 stop_step_editing ();
5778 /* get rid of any existing editor mixer strip */
5780 WindowTitle title(Glib::get_application_name());
5781 title += _("Editor");
5783 set_title (title.get_string());
5785 SessionHandlePtr::session_going_away ();
5790 Editor::show_editor_list (bool yn)
5793 _the_notebook.show ();
5795 _the_notebook.hide ();
5800 Editor::change_region_layering_order (bool from_context_menu)
5802 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5804 if (!clicked_routeview) {
5805 if (layering_order_editor) {
5806 layering_order_editor->hide ();
5811 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5817 boost::shared_ptr<Playlist> pl = track->playlist();
5823 if (layering_order_editor == 0) {
5824 layering_order_editor = new RegionLayeringOrderEditor (*this);
5827 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5828 layering_order_editor->maybe_present ();
5832 Editor::update_region_layering_order_editor ()
5834 if (layering_order_editor && layering_order_editor->is_visible ()) {
5835 change_region_layering_order (true);
5840 Editor::setup_fade_images ()
5842 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5843 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5844 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5845 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5846 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5848 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5849 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5850 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5851 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5852 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5854 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5855 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5856 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5857 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5858 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5860 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5861 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5862 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5863 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5864 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5868 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5870 Editor::action_menu_item (std::string const & name)
5872 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5875 return *manage (a->create_menu_item ());
5879 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5881 EventBox* b = manage (new EventBox);
5882 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5883 Label* l = manage (new Label (name));
5887 _the_notebook.append_page (widget, *b);
5891 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5893 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5894 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5897 if (ev->type == GDK_2BUTTON_PRESS) {
5899 /* double-click on a notebook tab shrinks or expands the notebook */
5901 if (_notebook_shrunk) {
5902 if (pre_notebook_shrink_pane_width) {
5903 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5905 _notebook_shrunk = false;
5907 pre_notebook_shrink_pane_width = edit_pane.get_position();
5909 /* this expands the LHS of the edit pane to cover the notebook
5910 PAGE but leaves the tabs visible.
5912 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5913 _notebook_shrunk = true;
5921 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5923 using namespace Menu_Helpers;
5925 MenuList& items = _control_point_context_menu.items ();
5928 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5929 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5930 if (!can_remove_control_point (item)) {
5931 items.back().set_sensitive (false);
5934 _control_point_context_menu.popup (event->button.button, event->button.time);
5938 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5940 using namespace Menu_Helpers;
5942 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5947 /* We need to get the selection here and pass it to the operations, since
5948 popping up the menu will cause a region leave event which clears
5949 entered_regionview. */
5951 MidiRegionView& mrv = note->region_view();
5952 const RegionSelection rs = get_regions_from_selection_and_entered ();
5954 MenuList& items = _note_context_menu.items();
5957 items.push_back(MenuElem(_("Delete"),
5958 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5959 items.push_back(MenuElem(_("Edit..."),
5960 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5961 items.push_back(MenuElem(_("Legatize"),
5962 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5963 items.push_back(MenuElem(_("Quantize..."),
5964 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5965 items.push_back(MenuElem(_("Remove Overlap"),
5966 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5967 items.push_back(MenuElem(_("Transform..."),
5968 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5970 _note_context_menu.popup (event->button.button, event->button.time);
5974 Editor::zoom_vertical_modifier_released()
5976 _stepping_axis_view = 0;
5980 Editor::ui_parameter_changed (string parameter)
5982 if (parameter == "icon-set") {
5983 while (!_cursor_stack.empty()) {
5984 _cursor_stack.pop_back();
5986 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
5987 _cursor_stack.push_back(_cursors->grabber);
5988 } else if (parameter == "draggable-playhead") {
5989 if (_verbose_cursor) {
5990 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());