2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include "gtkmm2ext/tearoff.h"
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/audio_track.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/audioregion.h"
71 #include "ardour/lmath.h"
72 #include "ardour/location.h"
73 #include "ardour/profile.h"
74 #include "ardour/route_group.h"
75 #include "ardour/session_playlists.h"
76 #include "ardour/tempo.h"
77 #include "ardour/utils.h"
79 #include "canvas/debug.h"
80 #include "canvas/text.h"
82 #include "control_protocol/control_protocol.h"
85 #include "analysis_window.h"
86 #include "audio_clock.h"
87 #include "audio_region_view.h"
88 #include "audio_streamview.h"
89 #include "audio_time_axis.h"
90 #include "automation_time_axis.h"
91 #include "bundle_manager.h"
92 #include "crossfade_edit.h"
96 #include "editor_cursors.h"
97 #include "editor_drag.h"
98 #include "editor_group_tabs.h"
99 #include "editor_locations.h"
100 #include "editor_regions.h"
101 #include "editor_route_groups.h"
102 #include "editor_routes.h"
103 #include "editor_snapshots.h"
104 #include "editor_summary.h"
105 #include "global_port_matrix.h"
106 #include "gui_object.h"
107 #include "gui_thread.h"
108 #include "keyboard.h"
110 #include "midi_region_view.h"
111 #include "midi_time_axis.h"
112 #include "mixer_strip.h"
113 #include "mixer_ui.h"
114 #include "mouse_cursors.h"
115 #include "note_base.h"
116 #include "playlist_selector.h"
117 #include "public_editor.h"
118 #include "region_layering_order_editor.h"
119 #include "rgb_macros.h"
120 #include "rhythm_ferret.h"
121 #include "selection.h"
123 #include "tempo_lines.h"
124 #include "time_axis_view.h"
127 #include "verbose_cursor.h"
132 using namespace ARDOUR;
133 using namespace ARDOUR_UI_UTILS;
136 using namespace Glib;
137 using namespace Gtkmm2ext;
138 using namespace Editing;
140 using PBD::internationalize;
142 using Gtkmm2ext::Keyboard;
144 double Editor::timebar_height = 15.0;
146 static const gchar *_snap_type_strings[] = {
180 static const gchar *_snap_delta_strings[] = {
186 static const gchar *_snap_mode_strings[] = {
193 static const gchar *_edit_point_strings[] = {
200 static const gchar *_edit_mode_strings[] = {
208 static const gchar *_zoom_focus_strings[] = {
218 #ifdef USE_RUBBERBAND
219 static const gchar *_rb_opt_strings[] = {
222 N_("Balanced multitimbral mixture"),
223 N_("Unpitched percussion with stable notes"),
224 N_("Crisp monophonic instrumental"),
225 N_("Unpitched solo percussion"),
226 N_("Resample without preserving pitch"),
231 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
234 pane_size_watcher (Paned* pane)
236 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
240 Quartz: impossible to access
242 so stop that by preventing it from ever getting too narrow. 35
243 pixels is basically a rough guess at the tab width.
248 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
250 gint pos = pane->get_position ();
252 if (pos > max_width_of_lhs) {
253 pane->set_position (max_width_of_lhs);
258 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
260 , _mouse_changed_selection (false)
261 /* time display buttons */
262 , minsec_label (_("Mins:Secs"))
263 , bbt_label (_("Bars:Beats"))
264 , timecode_label (_("Timecode"))
265 , samples_label (_("Samples"))
266 , tempo_label (_("Tempo"))
267 , meter_label (_("Meter"))
268 , mark_label (_("Location Markers"))
269 , range_mark_label (_("Range Markers"))
270 , transport_mark_label (_("Loop/Punch Ranges"))
271 , cd_mark_label (_("CD Markers"))
272 , videotl_label (_("Video Timeline"))
273 , edit_packer (4, 4, true)
275 /* the values here don't matter: layout widgets
276 reset them as needed.
279 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
280 , horizontal_adjustment (0.0, 0.0, 1e16)
281 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
283 , controls_layout (unused_adjustment, vertical_adjustment)
285 /* tool bar related */
287 , toolbar_selection_clock_table (2,3)
288 , _mouse_mode_tearoff (0)
289 , automation_mode_button (_("mode"))
293 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
294 , selection_op_cmd_depth (0)
295 , selection_op_history_it (0)
299 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
300 , meters_running(false)
301 , _pending_locate_request (false)
302 , _pending_initial_locate (false)
303 , _last_cut_copy_source_track (0)
305 , _region_selection_change_updates_region_list (true)
306 , _following_mixer_selection (false)
307 , _control_point_toggled_on_press (false)
308 , _stepping_axis_view (0)
312 /* we are a singleton */
314 PublicEditor::_instance = this;
318 selection = new Selection (this);
319 cut_buffer = new Selection (this);
320 _selection_memento = new SelectionMemento ();
321 selection_op_history.clear();
324 clicked_regionview = 0;
325 clicked_axisview = 0;
326 clicked_routeview = 0;
327 clicked_control_point = 0;
328 last_update_frame = 0;
331 _drags = new DragManager (this);
334 current_mixer_strip = 0;
337 snap_type_strings = I18N (_snap_type_strings);
338 snap_delta_strings = I18N (_snap_delta_strings);
339 snap_mode_strings = I18N (_snap_mode_strings);
340 zoom_focus_strings = I18N (_zoom_focus_strings);
341 edit_mode_strings = I18N (_edit_mode_strings);
342 edit_point_strings = I18N (_edit_point_strings);
343 #ifdef USE_RUBBERBAND
344 rb_opt_strings = I18N (_rb_opt_strings);
348 build_edit_mode_menu();
349 build_zoom_focus_menu();
350 build_track_count_menu();
351 build_snap_delta_menu();
352 build_snap_mode_menu();
353 build_snap_type_menu();
354 build_edit_point_menu();
356 snap_threshold = 5.0;
357 bbt_beat_subdivision = 4;
358 _visible_canvas_width = 0;
359 _visible_canvas_height = 0;
360 autoscroll_horizontal_allowed = false;
361 autoscroll_vertical_allowed = false;
366 current_interthread_info = 0;
367 _show_measures = true;
369 show_gain_after_trim = false;
371 have_pending_keyboard_selection = false;
372 _follow_playhead = true;
373 _stationary_playhead = false;
374 editor_ruler_menu = 0;
375 no_ruler_shown_update = false;
377 range_marker_menu = 0;
378 marker_menu_item = 0;
379 tempo_or_meter_marker_menu = 0;
380 transport_marker_menu = 0;
381 new_transport_marker_menu = 0;
382 editor_mixer_strip_width = Wide;
383 show_editor_mixer_when_tracks_arrive = false;
384 region_edit_menu_split_multichannel_item = 0;
385 region_edit_menu_split_item = 0;
388 current_stepping_trackview = 0;
390 entered_regionview = 0;
392 clear_entered_track = false;
395 button_release_can_deselect = true;
396 _dragging_playhead = false;
397 _dragging_edit_point = false;
398 select_new_marker = false;
400 layering_order_editor = 0;
401 no_save_visual = false;
403 within_track_canvas = false;
405 scrubbing_direction = 0;
409 location_marker_color = ARDOUR_UI::config()->color ("location marker");
410 location_range_color = ARDOUR_UI::config()->color ("location range");
411 location_cd_marker_color = ARDOUR_UI::config()->color ("location cd marker");
412 location_loop_color = ARDOUR_UI::config()->color ("location loop");
413 location_punch_color = ARDOUR_UI::config()->color ("location punch");
415 zoom_focus = ZoomFocusPlayhead;
416 _edit_point = EditAtMouse;
417 _visible_track_count = -1;
419 samples_per_pixel = 2048; /* too early to use reset_zoom () */
421 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
422 TimeAxisView::setup_sizes ();
423 Marker::setup_sizes (timebar_height);
425 _scroll_callbacks = 0;
427 bbt_label.set_name ("EditorRulerLabel");
428 bbt_label.set_size_request (-1, (int)timebar_height);
429 bbt_label.set_alignment (1.0, 0.5);
430 bbt_label.set_padding (5,0);
432 bbt_label.set_no_show_all();
433 minsec_label.set_name ("EditorRulerLabel");
434 minsec_label.set_size_request (-1, (int)timebar_height);
435 minsec_label.set_alignment (1.0, 0.5);
436 minsec_label.set_padding (5,0);
437 minsec_label.hide ();
438 minsec_label.set_no_show_all();
439 timecode_label.set_name ("EditorRulerLabel");
440 timecode_label.set_size_request (-1, (int)timebar_height);
441 timecode_label.set_alignment (1.0, 0.5);
442 timecode_label.set_padding (5,0);
443 timecode_label.hide ();
444 timecode_label.set_no_show_all();
445 samples_label.set_name ("EditorRulerLabel");
446 samples_label.set_size_request (-1, (int)timebar_height);
447 samples_label.set_alignment (1.0, 0.5);
448 samples_label.set_padding (5,0);
449 samples_label.hide ();
450 samples_label.set_no_show_all();
452 tempo_label.set_name ("EditorRulerLabel");
453 tempo_label.set_size_request (-1, (int)timebar_height);
454 tempo_label.set_alignment (1.0, 0.5);
455 tempo_label.set_padding (5,0);
457 tempo_label.set_no_show_all();
459 meter_label.set_name ("EditorRulerLabel");
460 meter_label.set_size_request (-1, (int)timebar_height);
461 meter_label.set_alignment (1.0, 0.5);
462 meter_label.set_padding (5,0);
464 meter_label.set_no_show_all();
466 if (Profile->get_trx()) {
467 mark_label.set_text (_("Markers"));
469 mark_label.set_name ("EditorRulerLabel");
470 mark_label.set_size_request (-1, (int)timebar_height);
471 mark_label.set_alignment (1.0, 0.5);
472 mark_label.set_padding (5,0);
474 mark_label.set_no_show_all();
476 cd_mark_label.set_name ("EditorRulerLabel");
477 cd_mark_label.set_size_request (-1, (int)timebar_height);
478 cd_mark_label.set_alignment (1.0, 0.5);
479 cd_mark_label.set_padding (5,0);
480 cd_mark_label.hide();
481 cd_mark_label.set_no_show_all();
483 videotl_bar_height = 4;
484 videotl_label.set_name ("EditorRulerLabel");
485 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
486 videotl_label.set_alignment (1.0, 0.5);
487 videotl_label.set_padding (5,0);
488 videotl_label.hide();
489 videotl_label.set_no_show_all();
491 range_mark_label.set_name ("EditorRulerLabel");
492 range_mark_label.set_size_request (-1, (int)timebar_height);
493 range_mark_label.set_alignment (1.0, 0.5);
494 range_mark_label.set_padding (5,0);
495 range_mark_label.hide();
496 range_mark_label.set_no_show_all();
498 transport_mark_label.set_name ("EditorRulerLabel");
499 transport_mark_label.set_size_request (-1, (int)timebar_height);
500 transport_mark_label.set_alignment (1.0, 0.5);
501 transport_mark_label.set_padding (5,0);
502 transport_mark_label.hide();
503 transport_mark_label.set_no_show_all();
505 initialize_canvas ();
507 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
509 _summary = new EditorSummary (this);
511 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
512 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
514 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
516 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
517 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
519 edit_controls_vbox.set_spacing (0);
520 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
521 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
523 HBox* h = manage (new HBox);
524 _group_tabs = new EditorGroupTabs (this);
525 if (!ARDOUR::Profile->get_trx()) {
526 h->pack_start (*_group_tabs, PACK_SHRINK);
528 h->pack_start (edit_controls_vbox);
529 controls_layout.add (*h);
531 controls_layout.set_name ("EditControlsBase");
532 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
533 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
534 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
536 _cursors = new MouseCursors;
537 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
538 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
540 /* Push default cursor to ever-present bottom of cursor stack. */
541 push_canvas_cursor(_cursors->grabber);
543 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
545 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
546 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
547 pad_line_1->set_outline_color (0xFF0000FF);
553 edit_packer.set_col_spacings (0);
554 edit_packer.set_row_spacings (0);
555 edit_packer.set_homogeneous (false);
556 edit_packer.set_border_width (0);
557 edit_packer.set_name ("EditorWindow");
559 time_bars_event_box.add (time_bars_vbox);
560 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
561 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
563 /* labels for the time bars */
564 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
566 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
568 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
570 bottom_hbox.set_border_width (2);
571 bottom_hbox.set_spacing (3);
573 _route_groups = new EditorRouteGroups (this);
574 _routes = new EditorRoutes (this);
575 _regions = new EditorRegions (this);
576 _snapshots = new EditorSnapshots (this);
577 _locations = new EditorLocations (this);
579 /* these are static location signals */
581 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
582 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
583 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
585 add_notebook_page (_("Regions"), _regions->widget ());
586 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
587 add_notebook_page (_("Snapshots"), _snapshots->widget ());
588 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
589 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
591 _the_notebook.set_show_tabs (true);
592 _the_notebook.set_scrollable (true);
593 _the_notebook.popup_disable ();
594 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
595 _the_notebook.show_all ();
597 _notebook_shrunk = false;
599 editor_summary_pane.pack1(edit_packer);
601 Button* summary_arrows_left_left = manage (new Button);
602 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
603 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
604 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
606 Button* summary_arrows_left_right = manage (new Button);
607 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
608 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
609 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
611 VBox* summary_arrows_left = manage (new VBox);
612 summary_arrows_left->pack_start (*summary_arrows_left_left);
613 summary_arrows_left->pack_start (*summary_arrows_left_right);
615 Button* summary_arrows_right_up = manage (new Button);
616 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
617 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
618 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
620 Button* summary_arrows_right_down = manage (new Button);
621 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
622 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
623 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
625 VBox* summary_arrows_right = manage (new VBox);
626 summary_arrows_right->pack_start (*summary_arrows_right_up);
627 summary_arrows_right->pack_start (*summary_arrows_right_down);
629 Frame* summary_frame = manage (new Frame);
630 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
632 summary_frame->add (*_summary);
633 summary_frame->show ();
635 _summary_hbox.pack_start (*summary_arrows_left, false, false);
636 _summary_hbox.pack_start (*summary_frame, true, true);
637 _summary_hbox.pack_start (*summary_arrows_right, false, false);
639 if (!ARDOUR::Profile->get_trx()) {
640 editor_summary_pane.pack2 (_summary_hbox);
643 edit_pane.pack1 (editor_summary_pane, true, true);
644 if (!ARDOUR::Profile->get_trx()) {
645 edit_pane.pack2 (_the_notebook, false, true);
648 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
650 /* XXX: editor_summary_pane might need similar to the edit_pane */
652 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
654 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
655 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
657 top_hbox.pack_start (toolbar_frame);
659 HBox *hbox = manage (new HBox);
660 hbox->pack_start (edit_pane, true, true);
662 global_vpacker.pack_start (top_hbox, false, false);
663 global_vpacker.pack_start (*hbox, true, true);
665 global_hpacker.pack_start (global_vpacker, true, true);
667 set_name ("EditorWindow");
668 add_accel_group (ActionManager::ui_manager->get_accel_group());
670 status_bar_hpacker.show ();
672 vpacker.pack_end (status_bar_hpacker, false, false);
673 vpacker.pack_end (global_hpacker, true, true);
675 /* register actions now so that set_state() can find them and set toggles/checks etc */
678 /* when we start using our own keybinding system for the editor, this
679 * will be uncommented
685 set_zoom_focus (zoom_focus);
686 set_visible_track_count (_visible_track_count);
687 _snap_type = SnapToBeat;
688 set_snap_to (_snap_type);
689 _snap_delta = SnapAbsolute;
690 set_snap_delta (_snap_delta);
691 _snap_mode = SnapOff;
692 set_snap_mode (_snap_mode);
693 set_mouse_mode (MouseObject, true);
694 pre_internal_snap_type = _snap_type;
695 pre_internal_snap_mode = _snap_mode;
696 internal_snap_type = _snap_type;
697 internal_snap_mode = _snap_mode;
698 set_edit_point_preference (EditAtMouse, true);
700 _playlist_selector = new PlaylistSelector();
701 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
703 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
707 nudge_forward_button.set_name ("nudge button");
708 nudge_forward_button.set_image(::get_icon("nudge_right"));
710 nudge_backward_button.set_name ("nudge button");
711 nudge_backward_button.set_image(::get_icon("nudge_left"));
713 fade_context_menu.set_name ("ArdourContextMenu");
715 /* icons, titles, WM stuff */
717 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
718 Glib::RefPtr<Gdk::Pixbuf> icon;
720 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
721 window_icons.push_back (icon);
723 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
724 window_icons.push_back (icon);
726 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
727 window_icons.push_back (icon);
729 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
730 window_icons.push_back (icon);
732 if (!window_icons.empty()) {
733 // set_icon_list (window_icons);
734 set_default_icon_list (window_icons);
737 WindowTitle title(Glib::get_application_name());
738 title += _("Editor");
739 set_title (title.get_string());
740 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
743 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
745 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
746 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
748 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
750 /* allow external control surfaces/protocols to do various things */
752 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
753 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
754 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
755 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
756 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
757 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
758 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
759 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
760 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
761 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
762 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
763 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
764 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
765 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
767 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
768 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
769 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
770 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
771 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
773 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
775 /* problematic: has to return a value and thus cannot be x-thread */
777 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
779 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
780 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
782 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
784 _ignore_region_action = false;
785 _last_region_menu_was_main = false;
786 _popup_region_menu_item = 0;
788 _ignore_follow_edits = false;
790 _show_marker_lines = false;
792 /* Button bindings */
794 button_bindings = new Bindings;
796 XMLNode* node = button_settings();
798 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
799 button_bindings->load (**i);
805 /* grab current parameter state */
806 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
807 ARDOUR_UI::config()->map_parameters (pc);
809 setup_fade_images ();
816 delete button_bindings;
818 delete _route_groups;
819 delete _track_canvas_viewport;
825 Editor::button_settings () const
827 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
828 XMLNode* node = find_named_node (*settings, X_("Buttons"));
831 node = new XMLNode (X_("Buttons"));
838 Editor::add_toplevel_menu (Container& cont)
840 vpacker.pack_start (cont, false, false);
845 Editor::add_transport_frame (Container& cont)
847 if(ARDOUR::Profile->get_mixbus()) {
848 global_vpacker.pack_start (cont, false, false);
849 global_vpacker.reorder_child (cont, 0);
852 vpacker.pack_start (cont, false, false);
857 Editor::get_smart_mode () const
859 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
863 Editor::catch_vanishing_regionview (RegionView *rv)
865 /* note: the selection will take care of the vanishing
866 audioregionview by itself.
869 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
873 if (clicked_regionview == rv) {
874 clicked_regionview = 0;
877 if (entered_regionview == rv) {
878 set_entered_regionview (0);
881 if (!_all_region_actions_sensitized) {
882 sensitize_all_region_actions (true);
887 Editor::set_entered_regionview (RegionView* rv)
889 if (rv == entered_regionview) {
893 if (entered_regionview) {
894 entered_regionview->exited ();
897 entered_regionview = rv;
899 if (entered_regionview != 0) {
900 entered_regionview->entered ();
903 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
904 /* This RegionView entry might have changed what region actions
905 are allowed, so sensitize them all in case a key is pressed.
907 sensitize_all_region_actions (true);
912 Editor::set_entered_track (TimeAxisView* tav)
915 entered_track->exited ();
921 entered_track->entered ();
926 Editor::show_window ()
928 if (!is_visible ()) {
932 /* XXX: this is a bit unfortunate; it would probably
933 be nicer if we could just call show () above rather
934 than needing the show_all ()
937 /* re-hide stuff if necessary */
938 editor_list_button_toggled ();
939 parameter_changed ("show-summary");
940 parameter_changed ("show-group-tabs");
941 parameter_changed ("show-zoom-tools");
943 /* now reset all audio_time_axis heights, because widgets might need
949 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
950 tv = (static_cast<TimeAxisView*>(*i));
954 if (current_mixer_strip) {
955 current_mixer_strip->hide_things ();
956 current_mixer_strip->parameter_changed ("mixer-element-visibility");
964 Editor::instant_save ()
966 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
971 _session->add_instant_xml(get_state());
973 Config->add_instant_xml(get_state());
978 Editor::control_vertical_zoom_in_all ()
980 tav_zoom_smooth (false, true);
984 Editor::control_vertical_zoom_out_all ()
986 tav_zoom_smooth (true, true);
990 Editor::control_vertical_zoom_in_selected ()
992 tav_zoom_smooth (false, false);
996 Editor::control_vertical_zoom_out_selected ()
998 tav_zoom_smooth (true, false);
1002 Editor::control_view (uint32_t view)
1004 goto_visual_state (view);
1008 Editor::control_unselect ()
1010 selection->clear_tracks ();
1014 Editor::control_select (uint32_t rid, Selection::Operation op)
1016 /* handles the (static) signal from the ControlProtocol class that
1017 * requests setting the selected track to a given RID
1024 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1030 TimeAxisView* tav = axis_view_from_route (r);
1034 case Selection::Add:
1035 selection->add (tav);
1037 case Selection::Toggle:
1038 selection->toggle (tav);
1040 case Selection::Extend:
1042 case Selection::Set:
1043 selection->set (tav);
1047 selection->clear_tracks ();
1052 Editor::control_step_tracks_up ()
1054 scroll_tracks_up_line ();
1058 Editor::control_step_tracks_down ()
1060 scroll_tracks_down_line ();
1064 Editor::control_scroll (float fraction)
1066 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1072 double step = fraction * current_page_samples();
1075 _control_scroll_target is an optional<T>
1077 it acts like a pointer to an framepos_t, with
1078 a operator conversion to boolean to check
1079 that it has a value could possibly use
1080 playhead_cursor->current_frame to store the
1081 value and a boolean in the class to know
1082 when it's out of date
1085 if (!_control_scroll_target) {
1086 _control_scroll_target = _session->transport_frame();
1087 _dragging_playhead = true;
1090 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1091 *_control_scroll_target = 0;
1092 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1093 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1095 *_control_scroll_target += (framepos_t) trunc (step);
1098 /* move visuals, we'll catch up with it later */
1100 playhead_cursor->set_position (*_control_scroll_target);
1101 UpdateAllTransportClocks (*_control_scroll_target);
1103 if (*_control_scroll_target > (current_page_samples() / 2)) {
1104 /* try to center PH in window */
1105 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1111 Now we do a timeout to actually bring the session to the right place
1112 according to the playhead. This is to avoid reading disk buffers on every
1113 call to control_scroll, which is driven by ScrollTimeline and therefore
1114 probably by a control surface wheel which can generate lots of events.
1116 /* cancel the existing timeout */
1118 control_scroll_connection.disconnect ();
1120 /* add the next timeout */
1122 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1126 Editor::deferred_control_scroll (framepos_t /*target*/)
1128 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1129 // reset for next stream
1130 _control_scroll_target = boost::none;
1131 _dragging_playhead = false;
1136 Editor::access_action (std::string action_group, std::string action_item)
1142 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1145 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1153 Editor::on_realize ()
1155 Window::on_realize ();
1158 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1159 start_lock_event_timing ();
1162 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1166 Editor::start_lock_event_timing ()
1168 /* check if we should lock the GUI every 30 seconds */
1170 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1174 Editor::generic_event_handler (GdkEvent* ev)
1177 case GDK_BUTTON_PRESS:
1178 case GDK_BUTTON_RELEASE:
1179 case GDK_MOTION_NOTIFY:
1181 case GDK_KEY_RELEASE:
1182 gettimeofday (&last_event_time, 0);
1185 case GDK_LEAVE_NOTIFY:
1186 switch (ev->crossing.detail) {
1187 case GDK_NOTIFY_UNKNOWN:
1188 case GDK_NOTIFY_INFERIOR:
1189 case GDK_NOTIFY_ANCESTOR:
1191 case GDK_NOTIFY_VIRTUAL:
1192 case GDK_NOTIFY_NONLINEAR:
1193 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1194 /* leaving window, so reset focus, thus ending any and
1195 all text entry operations.
1210 Editor::lock_timeout_callback ()
1212 struct timeval now, delta;
1214 gettimeofday (&now, 0);
1216 timersub (&now, &last_event_time, &delta);
1218 if (delta.tv_sec > (time_t) ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1220 /* don't call again. Returning false will effectively
1221 disconnect us from the timer callback.
1223 unlock() will call start_lock_event_timing() to get things
1233 Editor::map_position_change (framepos_t frame)
1235 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1237 if (_session == 0) {
1241 if (_follow_playhead) {
1242 center_screen (frame);
1245 playhead_cursor->set_position (frame);
1249 Editor::center_screen (framepos_t frame)
1251 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1253 /* if we're off the page, then scroll.
1256 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1257 center_screen_internal (frame, page);
1262 Editor::center_screen_internal (framepos_t frame, float page)
1267 frame -= (framepos_t) page;
1272 reset_x_origin (frame);
1277 Editor::update_title ()
1279 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1282 bool dirty = _session->dirty();
1284 string session_name;
1286 if (_session->snap_name() != _session->name()) {
1287 session_name = _session->snap_name();
1289 session_name = _session->name();
1293 session_name = "*" + session_name;
1296 WindowTitle title(session_name);
1297 title += Glib::get_application_name();
1298 set_title (title.get_string());
1300 /* ::session_going_away() will have taken care of it */
1305 Editor::set_session (Session *t)
1307 SessionHandlePtr::set_session (t);
1313 _playlist_selector->set_session (_session);
1314 nudge_clock->set_session (_session);
1315 _summary->set_session (_session);
1316 _group_tabs->set_session (_session);
1317 _route_groups->set_session (_session);
1318 _regions->set_session (_session);
1319 _snapshots->set_session (_session);
1320 _routes->set_session (_session);
1321 _locations->set_session (_session);
1323 if (rhythm_ferret) {
1324 rhythm_ferret->set_session (_session);
1327 if (analysis_window) {
1328 analysis_window->set_session (_session);
1332 sfbrowser->set_session (_session);
1335 compute_fixed_ruler_scale ();
1337 /* Make sure we have auto loop and auto punch ranges */
1339 Location* loc = _session->locations()->auto_loop_location();
1341 loc->set_name (_("Loop"));
1344 loc = _session->locations()->auto_punch_location();
1347 loc->set_name (_("Punch"));
1350 refresh_location_display ();
1352 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1353 the selected Marker; this needs the LocationMarker list to be available.
1355 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1356 set_state (*node, Stateful::loading_state_version);
1358 /* catch up with the playhead */
1360 _session->request_locate (playhead_cursor->current_frame ());
1361 _pending_initial_locate = true;
1365 /* These signals can all be emitted by a non-GUI thread. Therefore the
1366 handlers for them must not attempt to directly interact with the GUI,
1367 but use PBD::Signal<T>::connect() which accepts an event loop
1368 ("context") where the handler will be asked to run.
1371 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1372 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1373 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1374 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1375 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1376 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1377 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1378 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1379 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1380 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1381 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1382 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1383 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1385 playhead_cursor->show ();
1387 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1388 Config->map_parameters (pc);
1389 _session->config.map_parameters (pc);
1391 restore_ruler_visibility ();
1392 //tempo_map_changed (PropertyChange (0));
1393 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1395 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1396 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1399 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1400 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1403 switch (_snap_type) {
1404 case SnapToRegionStart:
1405 case SnapToRegionEnd:
1406 case SnapToRegionSync:
1407 case SnapToRegionBoundary:
1408 build_region_boundary_cache ();
1415 /* register for undo history */
1416 _session->register_with_memento_command_factory(id(), this);
1417 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1419 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1421 start_updating_meters ();
1425 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1427 if (a->get_name() == "RegionMenu") {
1428 /* When the main menu's region menu is opened, we setup the actions so that they look right
1429 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1430 so we resensitize all region actions when the entered regionview or the region selection
1431 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1432 happens after the region context menu is opened. So we set a flag here, too.
1436 sensitize_the_right_region_actions ();
1437 _last_region_menu_was_main = true;
1442 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1444 using namespace Menu_Helpers;
1446 void (Editor::*emf)(FadeShape);
1447 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1450 images = &_xfade_in_images;
1451 emf = &Editor::set_fade_in_shape;
1453 images = &_xfade_out_images;
1454 emf = &Editor::set_fade_out_shape;
1459 _("Linear (for highly correlated material)"),
1460 *(*images)[FadeLinear],
1461 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1465 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1469 _("Constant power"),
1470 *(*images)[FadeConstantPower],
1471 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1474 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1479 *(*images)[FadeSymmetric],
1480 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1484 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1489 *(*images)[FadeSlow],
1490 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1493 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1498 *(*images)[FadeFast],
1499 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1502 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1505 /** Pop up a context menu for when the user clicks on a start crossfade */
1507 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1509 using namespace Menu_Helpers;
1510 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1515 MenuList& items (xfade_in_context_menu.items());
1518 if (arv->audio_region()->fade_in_active()) {
1519 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1521 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1524 items.push_back (SeparatorElem());
1525 fill_xfade_menu (items, true);
1527 xfade_in_context_menu.popup (button, time);
1530 /** Pop up a context menu for when the user clicks on an end crossfade */
1532 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1534 using namespace Menu_Helpers;
1535 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1540 MenuList& items (xfade_out_context_menu.items());
1543 if (arv->audio_region()->fade_out_active()) {
1544 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1546 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1549 items.push_back (SeparatorElem());
1550 fill_xfade_menu (items, false);
1552 xfade_out_context_menu.popup (button, time);
1556 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1558 using namespace Menu_Helpers;
1559 Menu* (Editor::*build_menu_function)();
1562 switch (item_type) {
1564 case RegionViewName:
1565 case RegionViewNameHighlight:
1566 case LeftFrameHandle:
1567 case RightFrameHandle:
1568 if (with_selection) {
1569 build_menu_function = &Editor::build_track_selection_context_menu;
1571 build_menu_function = &Editor::build_track_region_context_menu;
1576 if (with_selection) {
1577 build_menu_function = &Editor::build_track_selection_context_menu;
1579 build_menu_function = &Editor::build_track_context_menu;
1584 if (clicked_routeview->track()) {
1585 build_menu_function = &Editor::build_track_context_menu;
1587 build_menu_function = &Editor::build_track_bus_context_menu;
1592 /* probably shouldn't happen but if it does, we don't care */
1596 menu = (this->*build_menu_function)();
1597 menu->set_name ("ArdourContextMenu");
1599 /* now handle specific situations */
1601 switch (item_type) {
1603 case RegionViewName:
1604 case RegionViewNameHighlight:
1605 case LeftFrameHandle:
1606 case RightFrameHandle:
1607 if (!with_selection) {
1608 if (region_edit_menu_split_item) {
1609 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1610 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1612 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1615 if (region_edit_menu_split_multichannel_item) {
1616 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1617 region_edit_menu_split_multichannel_item->set_sensitive (true);
1619 region_edit_menu_split_multichannel_item->set_sensitive (false);
1632 /* probably shouldn't happen but if it does, we don't care */
1636 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1638 /* Bounce to disk */
1640 using namespace Menu_Helpers;
1641 MenuList& edit_items = menu->items();
1643 edit_items.push_back (SeparatorElem());
1645 switch (clicked_routeview->audio_track()->freeze_state()) {
1646 case AudioTrack::NoFreeze:
1647 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1650 case AudioTrack::Frozen:
1651 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1654 case AudioTrack::UnFrozen:
1655 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1661 if (item_type == StreamItem && clicked_routeview) {
1662 clicked_routeview->build_underlay_menu(menu);
1665 /* When the region menu is opened, we setup the actions so that they look right
1668 sensitize_the_right_region_actions ();
1669 _last_region_menu_was_main = false;
1671 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1672 menu->popup (button, time);
1676 Editor::build_track_context_menu ()
1678 using namespace Menu_Helpers;
1680 MenuList& edit_items = track_context_menu.items();
1683 add_dstream_context_items (edit_items);
1684 return &track_context_menu;
1688 Editor::build_track_bus_context_menu ()
1690 using namespace Menu_Helpers;
1692 MenuList& edit_items = track_context_menu.items();
1695 add_bus_context_items (edit_items);
1696 return &track_context_menu;
1700 Editor::build_track_region_context_menu ()
1702 using namespace Menu_Helpers;
1703 MenuList& edit_items = track_region_context_menu.items();
1706 /* we've just cleared the track region context menu, so the menu that these
1707 two items were on will have disappeared; stop them dangling.
1709 region_edit_menu_split_item = 0;
1710 region_edit_menu_split_multichannel_item = 0;
1712 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1715 boost::shared_ptr<Track> tr;
1716 boost::shared_ptr<Playlist> pl;
1718 if ((tr = rtv->track())) {
1719 add_region_context_items (edit_items, tr);
1723 add_dstream_context_items (edit_items);
1725 return &track_region_context_menu;
1729 Editor::analyze_region_selection ()
1731 if (analysis_window == 0) {
1732 analysis_window = new AnalysisWindow();
1735 analysis_window->set_session(_session);
1737 analysis_window->show_all();
1740 analysis_window->set_regionmode();
1741 analysis_window->analyze();
1743 analysis_window->present();
1747 Editor::analyze_range_selection()
1749 if (analysis_window == 0) {
1750 analysis_window = new AnalysisWindow();
1753 analysis_window->set_session(_session);
1755 analysis_window->show_all();
1758 analysis_window->set_rangemode();
1759 analysis_window->analyze();
1761 analysis_window->present();
1765 Editor::build_track_selection_context_menu ()
1767 using namespace Menu_Helpers;
1768 MenuList& edit_items = track_selection_context_menu.items();
1769 edit_items.clear ();
1771 add_selection_context_items (edit_items);
1772 // edit_items.push_back (SeparatorElem());
1773 // add_dstream_context_items (edit_items);
1775 return &track_selection_context_menu;
1779 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1781 using namespace Menu_Helpers;
1783 /* OK, stick the region submenu at the top of the list, and then add
1787 RegionSelection rs = get_regions_from_selection_and_entered ();
1789 string::size_type pos = 0;
1790 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1792 /* we have to hack up the region name because "_" has a special
1793 meaning for menu titles.
1796 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1797 menu_item_name.replace (pos, 1, "__");
1801 if (_popup_region_menu_item == 0) {
1802 _popup_region_menu_item = new MenuItem (menu_item_name);
1803 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1804 _popup_region_menu_item->show ();
1806 _popup_region_menu_item->set_label (menu_item_name);
1809 /* No latering allowed in later is higher layering model */
1810 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1811 if (act && Config->get_layer_model() == LaterHigher) {
1812 act->set_sensitive (false);
1814 act->set_sensitive (true);
1817 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1819 edit_items.push_back (*_popup_region_menu_item);
1820 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1821 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1823 edit_items.push_back (SeparatorElem());
1826 /** Add context menu items relevant to selection ranges.
1827 * @param edit_items List to add the items to.
1830 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1832 using namespace Menu_Helpers;
1834 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1835 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1837 edit_items.push_back (SeparatorElem());
1838 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1840 edit_items.push_back (SeparatorElem());
1841 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1843 edit_items.push_back (SeparatorElem());
1845 edit_items.push_back (
1847 _("Move Range Start to Previous Region Boundary"),
1848 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1852 edit_items.push_back (
1854 _("Move Range Start to Next Region Boundary"),
1855 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1859 edit_items.push_back (
1861 _("Move Range End to Previous Region Boundary"),
1862 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1866 edit_items.push_back (
1868 _("Move Range End to Next Region Boundary"),
1869 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1873 edit_items.push_back (SeparatorElem());
1874 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1875 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1877 edit_items.push_back (SeparatorElem());
1878 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1880 edit_items.push_back (SeparatorElem());
1881 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1882 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1883 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1885 edit_items.push_back (SeparatorElem());
1886 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1888 edit_items.push_back (SeparatorElem());
1889 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1890 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1891 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1893 edit_items.push_back (SeparatorElem());
1894 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1895 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1896 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1897 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1898 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1899 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1900 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1906 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1908 using namespace Menu_Helpers;
1912 Menu *play_menu = manage (new Menu);
1913 MenuList& play_items = play_menu->items();
1914 play_menu->set_name ("ArdourContextMenu");
1916 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1917 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1918 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1919 play_items.push_back (SeparatorElem());
1920 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1922 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1926 Menu *select_menu = manage (new Menu);
1927 MenuList& select_items = select_menu->items();
1928 select_menu->set_name ("ArdourContextMenu");
1930 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1931 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1932 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1933 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1934 select_items.push_back (SeparatorElem());
1935 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1936 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1937 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
1938 select_items.push_back (SeparatorElem());
1939 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1940 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1941 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1942 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1943 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1944 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1945 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1947 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1951 Menu *cutnpaste_menu = manage (new Menu);
1952 MenuList& cutnpaste_items = cutnpaste_menu->items();
1953 cutnpaste_menu->set_name ("ArdourContextMenu");
1955 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1956 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1957 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1959 cutnpaste_items.push_back (SeparatorElem());
1961 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1962 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1964 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1966 /* Adding new material */
1968 edit_items.push_back (SeparatorElem());
1969 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1970 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1974 Menu *nudge_menu = manage (new Menu());
1975 MenuList& nudge_items = nudge_menu->items();
1976 nudge_menu->set_name ("ArdourContextMenu");
1978 edit_items.push_back (SeparatorElem());
1979 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1980 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1981 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1982 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1984 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1988 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1990 using namespace Menu_Helpers;
1994 Menu *play_menu = manage (new Menu);
1995 MenuList& play_items = play_menu->items();
1996 play_menu->set_name ("ArdourContextMenu");
1998 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1999 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2000 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2004 Menu *select_menu = manage (new Menu);
2005 MenuList& select_items = select_menu->items();
2006 select_menu->set_name ("ArdourContextMenu");
2008 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2009 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2010 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2011 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2012 select_items.push_back (SeparatorElem());
2013 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2014 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2015 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2016 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2018 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2022 Menu *cutnpaste_menu = manage (new Menu);
2023 MenuList& cutnpaste_items = cutnpaste_menu->items();
2024 cutnpaste_menu->set_name ("ArdourContextMenu");
2026 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2027 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2028 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2030 Menu *nudge_menu = manage (new Menu());
2031 MenuList& nudge_items = nudge_menu->items();
2032 nudge_menu->set_name ("ArdourContextMenu");
2034 edit_items.push_back (SeparatorElem());
2035 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2036 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2037 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2038 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2040 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2044 Editor::snap_type() const
2050 Editor::snap_delta() const
2056 Editor::snap_mode() const
2062 Editor::set_snap_to (SnapType st)
2064 unsigned int snap_ind = (unsigned int)st;
2066 if (internal_editing()) {
2067 internal_snap_type = st;
2069 pre_internal_snap_type = st;
2074 if (snap_ind > snap_type_strings.size() - 1) {
2076 _snap_type = (SnapType)snap_ind;
2079 string str = snap_type_strings[snap_ind];
2081 if (str != snap_type_selector.get_text()) {
2082 snap_type_selector.set_text (str);
2087 switch (_snap_type) {
2088 case SnapToBeatDiv128:
2089 case SnapToBeatDiv64:
2090 case SnapToBeatDiv32:
2091 case SnapToBeatDiv28:
2092 case SnapToBeatDiv24:
2093 case SnapToBeatDiv20:
2094 case SnapToBeatDiv16:
2095 case SnapToBeatDiv14:
2096 case SnapToBeatDiv12:
2097 case SnapToBeatDiv10:
2098 case SnapToBeatDiv8:
2099 case SnapToBeatDiv7:
2100 case SnapToBeatDiv6:
2101 case SnapToBeatDiv5:
2102 case SnapToBeatDiv4:
2103 case SnapToBeatDiv3:
2104 case SnapToBeatDiv2: {
2105 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2106 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2108 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2109 current_bbt_points_begin, current_bbt_points_end);
2110 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2111 current_bbt_points_begin, current_bbt_points_end);
2112 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2116 case SnapToRegionStart:
2117 case SnapToRegionEnd:
2118 case SnapToRegionSync:
2119 case SnapToRegionBoundary:
2120 build_region_boundary_cache ();
2128 redisplay_tempo (false);
2130 SnapChanged (); /* EMIT SIGNAL */
2134 Editor::set_snap_delta (SnapDelta delta)
2136 string str = snap_delta_strings[(int)delta];
2138 _snap_delta = delta;
2140 if (str != snap_delta_selector.get_text ()) {
2141 snap_delta_selector.set_text (str);
2148 Editor::set_snap_mode (SnapMode mode)
2150 string str = snap_mode_strings[(int)mode];
2152 if (internal_editing()) {
2153 internal_snap_mode = mode;
2155 pre_internal_snap_mode = mode;
2160 if (str != snap_mode_selector.get_text ()) {
2161 snap_mode_selector.set_text (str);
2168 Editor::set_edit_point_preference (EditPoint ep, bool force)
2170 bool changed = (_edit_point != ep);
2173 if (Profile->get_mixbus())
2174 if (ep == EditAtSelectedMarker)
2175 ep = EditAtPlayhead;
2177 string str = edit_point_strings[(int)ep];
2178 if (str != edit_point_selector.get_text ()) {
2179 edit_point_selector.set_text (str);
2182 update_all_enter_cursors();
2184 if (!force && !changed) {
2188 const char* action=NULL;
2190 switch (_edit_point) {
2191 case EditAtPlayhead:
2192 action = "edit-at-playhead";
2194 case EditAtSelectedMarker:
2195 action = "edit-at-marker";
2198 action = "edit-at-mouse";
2202 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2204 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2208 bool in_track_canvas;
2210 if (!mouse_frame (foo, in_track_canvas)) {
2211 in_track_canvas = false;
2214 reset_canvas_action_sensitivity (in_track_canvas);
2220 Editor::set_state (const XMLNode& node, int /*version*/)
2222 const XMLProperty* prop;
2229 g.base_width = default_width;
2230 g.base_height = default_height;
2234 if ((geometry = find_named_node (node, "geometry")) != 0) {
2238 if ((prop = geometry->property("x_size")) == 0) {
2239 prop = geometry->property ("x-size");
2242 g.base_width = atoi(prop->value());
2244 if ((prop = geometry->property("y_size")) == 0) {
2245 prop = geometry->property ("y-size");
2248 g.base_height = atoi(prop->value());
2251 if ((prop = geometry->property ("x_pos")) == 0) {
2252 prop = geometry->property ("x-pos");
2255 x = atoi (prop->value());
2258 if ((prop = geometry->property ("y_pos")) == 0) {
2259 prop = geometry->property ("y-pos");
2262 y = atoi (prop->value());
2266 set_default_size (g.base_width, g.base_height);
2269 if (_session && (prop = node.property ("playhead"))) {
2271 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2273 playhead_cursor->set_position (pos);
2275 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2276 playhead_cursor->set_position (0);
2279 playhead_cursor->set_position (0);
2282 if ((prop = node.property ("mixer-width"))) {
2283 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2286 if ((prop = node.property ("zoom-focus"))) {
2287 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2290 if ((prop = node.property ("zoom"))) {
2291 /* older versions of ardour used floating point samples_per_pixel */
2292 double f = PBD::atof (prop->value());
2293 reset_zoom (llrintf (f));
2295 reset_zoom (samples_per_pixel);
2298 if ((prop = node.property ("visible-track-count"))) {
2299 set_visible_track_count (PBD::atoi (prop->value()));
2302 if ((prop = node.property ("snap-to"))) {
2303 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2306 if ((prop = node.property ("snap-delta"))) {
2307 snap_delta_selection_done((SnapDelta) string_2_enum (prop->value(), _snap_delta));
2310 if ((prop = node.property ("snap-mode"))) {
2311 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2314 if ((prop = node.property ("internal-snap-to"))) {
2315 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2318 if ((prop = node.property ("internal-snap-mode"))) {
2319 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2322 if ((prop = node.property ("pre-internal-snap-to"))) {
2323 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2326 if ((prop = node.property ("pre-internal-snap-mode"))) {
2327 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2330 if ((prop = node.property ("mouse-mode"))) {
2331 MouseMode m = str2mousemode(prop->value());
2332 set_mouse_mode (m, true);
2334 set_mouse_mode (MouseObject, true);
2337 if ((prop = node.property ("left-frame")) != 0) {
2339 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2343 reset_x_origin (pos);
2347 if ((prop = node.property ("y-origin")) != 0) {
2348 reset_y_origin (atof (prop->value ()));
2351 if ((prop = node.property ("join-object-range"))) {
2352 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2353 bool yn = string_is_affirmative (prop->value());
2355 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2356 tact->set_active (!yn);
2357 tact->set_active (yn);
2359 set_mouse_mode(mouse_mode, true);
2362 if ((prop = node.property ("edit-point"))) {
2363 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2366 if ((prop = node.property ("show-measures"))) {
2367 bool yn = string_is_affirmative (prop->value());
2368 _show_measures = yn;
2371 if ((prop = node.property ("follow-playhead"))) {
2372 bool yn = string_is_affirmative (prop->value());
2373 set_follow_playhead (yn);
2376 if ((prop = node.property ("stationary-playhead"))) {
2377 bool yn = string_is_affirmative (prop->value());
2378 set_stationary_playhead (yn);
2381 if ((prop = node.property ("region-list-sort-type"))) {
2382 RegionListSortType st;
2383 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2386 if ((prop = node.property ("show-editor-mixer"))) {
2388 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2391 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2392 bool yn = string_is_affirmative (prop->value());
2394 /* do it twice to force the change */
2396 tact->set_active (!yn);
2397 tact->set_active (yn);
2400 if ((prop = node.property ("show-editor-list"))) {
2402 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2405 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2406 bool yn = string_is_affirmative (prop->value());
2408 /* do it twice to force the change */
2410 tact->set_active (!yn);
2411 tact->set_active (yn);
2414 if ((prop = node.property (X_("editor-list-page")))) {
2415 _the_notebook.set_current_page (atoi (prop->value ()));
2418 if ((prop = node.property (X_("show-marker-lines")))) {
2419 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2421 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2422 bool yn = string_is_affirmative (prop->value ());
2424 tact->set_active (!yn);
2425 tact->set_active (yn);
2428 XMLNodeList children = node.children ();
2429 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2430 selection->set_state (**i, Stateful::current_state_version);
2431 _regions->set_state (**i);
2434 if ((prop = node.property ("maximised"))) {
2435 bool yn = string_is_affirmative (prop->value());
2436 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2438 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2439 bool fs = tact && tact->get_active();
2441 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2445 if ((prop = node.property ("nudge-clock-value"))) {
2447 sscanf (prop->value().c_str(), "%" PRId64, &f);
2448 nudge_clock->set (f);
2450 nudge_clock->set_mode (AudioClock::Timecode);
2451 nudge_clock->set (_session->frame_rate() * 5, true);
2456 * Not all properties may have been in XML, but
2457 * those that are linked to a private variable may need changing
2462 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2464 yn = _show_measures;
2465 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2466 /* do it twice to force the change */
2467 tact->set_active (!yn);
2468 tact->set_active (yn);
2471 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2472 yn = _follow_playhead;
2474 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2475 if (tact->get_active() != yn) {
2476 tact->set_active (yn);
2480 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2481 yn = _stationary_playhead;
2483 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2484 if (tact->get_active() != yn) {
2485 tact->set_active (yn);
2494 Editor::get_state ()
2496 XMLNode* node = new XMLNode ("Editor");
2499 id().print (buf, sizeof (buf));
2500 node->add_property ("id", buf);
2502 if (is_realized()) {
2503 Glib::RefPtr<Gdk::Window> win = get_window();
2505 int x, y, width, height;
2506 win->get_root_origin(x, y);
2507 win->get_size(width, height);
2509 XMLNode* geometry = new XMLNode ("geometry");
2511 snprintf(buf, sizeof(buf), "%d", width);
2512 geometry->add_property("x-size", string(buf));
2513 snprintf(buf, sizeof(buf), "%d", height);
2514 geometry->add_property("y-size", string(buf));
2515 snprintf(buf, sizeof(buf), "%d", x);
2516 geometry->add_property("x-pos", string(buf));
2517 snprintf(buf, sizeof(buf), "%d", y);
2518 geometry->add_property("y-pos", string(buf));
2519 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2520 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2521 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2522 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2523 geometry->add_property("edit-vertical-pane-pos", string(buf));
2525 node->add_child_nocopy (*geometry);
2528 maybe_add_mixer_strip_width (*node);
2530 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2532 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2533 node->add_property ("zoom", buf);
2534 node->add_property ("snap-to", enum_2_string (_snap_type));
2535 node->add_property ("snap-delta", enum_2_string (_snap_delta));
2536 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2537 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2538 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2539 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2540 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2541 node->add_property ("edit-point", enum_2_string (_edit_point));
2542 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2543 node->add_property ("visible-track-count", buf);
2545 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2546 node->add_property ("playhead", buf);
2547 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2548 node->add_property ("left-frame", buf);
2549 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2550 node->add_property ("y-origin", buf);
2552 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2553 node->add_property ("maximised", _maximised ? "yes" : "no");
2554 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2555 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2556 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2557 node->add_property ("mouse-mode", enum2str(mouse_mode));
2558 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2560 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2562 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2563 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2566 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2568 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2569 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2572 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2573 node->add_property (X_("editor-list-page"), buf);
2575 if (button_bindings) {
2576 XMLNode* bb = new XMLNode (X_("Buttons"));
2577 button_bindings->save (*bb);
2578 node->add_child_nocopy (*bb);
2581 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2583 node->add_child_nocopy (selection->get_state ());
2584 node->add_child_nocopy (_regions->get_state ());
2586 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2587 node->add_property ("nudge-clock-value", buf);
2592 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2593 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2595 * @return pair: TimeAxisView that y is over, layer index.
2597 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2598 * in stacked or expanded region display mode, otherwise 0.
2600 std::pair<TimeAxisView *, double>
2601 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2603 if (!trackview_relative_offset) {
2604 y -= _trackview_group->canvas_origin().y;
2608 return std::make_pair ( (TimeAxisView *) 0, 0);
2611 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2613 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2620 return std::make_pair ( (TimeAxisView *) 0, 0);
2623 /** Snap a position to the grid, if appropriate, taking into account current
2624 * grid settings and also the state of any snap modifier keys that may be pressed.
2625 * @param start Position to snap.
2626 * @param event Event to get current key modifier information from, or 0.
2629 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2631 if (!_session || !event) {
2635 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2636 if (_snap_mode == SnapOff) {
2637 snap_to_internal (start, direction, for_mark);
2640 if (_snap_mode != SnapOff) {
2641 snap_to_internal (start, direction, for_mark);
2647 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark)
2649 if (!_session || _snap_mode == SnapOff) {
2653 snap_to_internal (start, direction, for_mark);
2657 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2659 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2660 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2662 switch (_snap_type) {
2663 case SnapToTimecodeFrame:
2664 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2665 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2666 /* start is already on a whole timecode frame, do nothing */
2667 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2668 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2670 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2674 case SnapToTimecodeSeconds:
2675 if (_session->config.get_timecode_offset_negative()) {
2676 start += _session->config.get_timecode_offset ();
2678 start -= _session->config.get_timecode_offset ();
2680 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2681 (start % one_timecode_second == 0)) {
2682 /* start is already on a whole second, do nothing */
2683 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2684 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2686 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2689 if (_session->config.get_timecode_offset_negative()) {
2690 start -= _session->config.get_timecode_offset ();
2692 start += _session->config.get_timecode_offset ();
2696 case SnapToTimecodeMinutes:
2697 if (_session->config.get_timecode_offset_negative()) {
2698 start += _session->config.get_timecode_offset ();
2700 start -= _session->config.get_timecode_offset ();
2702 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2703 (start % one_timecode_minute == 0)) {
2704 /* start is already on a whole minute, do nothing */
2705 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2706 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2708 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2710 if (_session->config.get_timecode_offset_negative()) {
2711 start -= _session->config.get_timecode_offset ();
2713 start += _session->config.get_timecode_offset ();
2717 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2718 abort(); /*NOTREACHED*/
2723 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark)
2725 const framepos_t one_second = _session->frame_rate();
2726 const framepos_t one_minute = _session->frame_rate() * 60;
2727 framepos_t presnap = start;
2731 switch (_snap_type) {
2732 case SnapToTimecodeFrame:
2733 case SnapToTimecodeSeconds:
2734 case SnapToTimecodeMinutes:
2735 return timecode_snap_to_internal (start, direction, for_mark);
2738 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2739 start % (one_second/75) == 0) {
2740 /* start is already on a whole CD frame, do nothing */
2741 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2742 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2744 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2749 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2750 start % one_second == 0) {
2751 /* start is already on a whole second, do nothing */
2752 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2753 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2755 start = (framepos_t) floor ((double) start / one_second) * one_second;
2760 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2761 start % one_minute == 0) {
2762 /* start is already on a whole minute, do nothing */
2763 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2764 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2766 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2771 start = _session->tempo_map().round_to_bar (start, direction);
2775 start = _session->tempo_map().round_to_beat (start, direction);
2778 case SnapToBeatDiv128:
2779 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2781 case SnapToBeatDiv64:
2782 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2784 case SnapToBeatDiv32:
2785 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2787 case SnapToBeatDiv28:
2788 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2790 case SnapToBeatDiv24:
2791 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2793 case SnapToBeatDiv20:
2794 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2796 case SnapToBeatDiv16:
2797 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2799 case SnapToBeatDiv14:
2800 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2802 case SnapToBeatDiv12:
2803 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2805 case SnapToBeatDiv10:
2806 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2808 case SnapToBeatDiv8:
2809 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2811 case SnapToBeatDiv7:
2812 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2814 case SnapToBeatDiv6:
2815 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2817 case SnapToBeatDiv5:
2818 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2820 case SnapToBeatDiv4:
2821 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2823 case SnapToBeatDiv3:
2824 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2826 case SnapToBeatDiv2:
2827 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2835 _session->locations()->marks_either_side (start, before, after);
2837 if (before == max_framepos && after == max_framepos) {
2838 /* No marks to snap to, so just don't snap */
2840 } else if (before == max_framepos) {
2842 } else if (after == max_framepos) {
2844 } else if (before != max_framepos && after != max_framepos) {
2845 /* have before and after */
2846 if ((start - before) < (after - start)) {
2855 case SnapToRegionStart:
2856 case SnapToRegionEnd:
2857 case SnapToRegionSync:
2858 case SnapToRegionBoundary:
2859 if (!region_boundary_cache.empty()) {
2861 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2862 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2864 if (direction > 0) {
2865 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2867 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2870 if (next != region_boundary_cache.begin ()) {
2875 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2876 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2878 if (start > (p + n) / 2) {
2887 switch (_snap_mode) {
2893 if (presnap > start) {
2894 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2898 } else if (presnap < start) {
2899 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2905 /* handled at entry */
2913 Editor::setup_toolbar ()
2915 HBox* mode_box = manage(new HBox);
2916 mode_box->set_border_width (2);
2917 mode_box->set_spacing(2);
2919 HBox* mouse_mode_box = manage (new HBox);
2920 HBox* mouse_mode_hbox = manage (new HBox);
2921 VBox* mouse_mode_vbox = manage (new VBox);
2922 Alignment* mouse_mode_align = manage (new Alignment);
2924 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2925 mouse_mode_size_group->add_widget (smart_mode_button);
2926 mouse_mode_size_group->add_widget (mouse_move_button);
2927 mouse_mode_size_group->add_widget (mouse_cut_button);
2928 mouse_mode_size_group->add_widget (mouse_select_button);
2929 mouse_mode_size_group->add_widget (mouse_timefx_button);
2930 mouse_mode_size_group->add_widget (mouse_audition_button);
2931 mouse_mode_size_group->add_widget (mouse_draw_button);
2932 mouse_mode_size_group->add_widget (mouse_content_button);
2934 mouse_mode_size_group->add_widget (zoom_in_button);
2935 mouse_mode_size_group->add_widget (zoom_out_button);
2936 mouse_mode_size_group->add_widget (zoom_preset_selector);
2937 mouse_mode_size_group->add_widget (zoom_out_full_button);
2938 mouse_mode_size_group->add_widget (zoom_focus_selector);
2940 mouse_mode_size_group->add_widget (tav_shrink_button);
2941 mouse_mode_size_group->add_widget (tav_expand_button);
2942 mouse_mode_size_group->add_widget (visible_tracks_selector);
2944 mouse_mode_size_group->add_widget (snap_type_selector);
2945 mouse_mode_size_group->add_widget (snap_delta_selector);
2946 mouse_mode_size_group->add_widget (snap_mode_selector);
2948 mouse_mode_size_group->add_widget (edit_point_selector);
2949 mouse_mode_size_group->add_widget (edit_mode_selector);
2951 mouse_mode_size_group->add_widget (*nudge_clock);
2952 mouse_mode_size_group->add_widget (nudge_forward_button);
2953 mouse_mode_size_group->add_widget (nudge_backward_button);
2955 mouse_mode_hbox->set_spacing (2);
2957 if (!ARDOUR::Profile->get_trx()) {
2958 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2961 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2962 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2964 if (!ARDOUR::Profile->get_mixbus()) {
2965 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2968 if (!ARDOUR::Profile->get_trx()) {
2969 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2970 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2971 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2972 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2975 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2977 mouse_mode_align->add (*mouse_mode_vbox);
2978 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2980 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2982 edit_mode_selector.set_name ("mouse mode button");
2984 if (!ARDOUR::Profile->get_trx()) {
2985 mode_box->pack_start (edit_mode_selector, false, false);
2987 mode_box->pack_start (*mouse_mode_box, false, false);
2989 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2990 _mouse_mode_tearoff->set_name ("MouseModeBase");
2991 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2993 if (Profile->get_sae() || Profile->get_mixbus() ) {
2994 _mouse_mode_tearoff->set_can_be_torn_off (false);
2997 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2998 &_mouse_mode_tearoff->tearoff_window()));
2999 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3000 &_mouse_mode_tearoff->tearoff_window(), 1));
3001 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3002 &_mouse_mode_tearoff->tearoff_window()));
3003 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3004 &_mouse_mode_tearoff->tearoff_window(), 1));
3008 _zoom_box.set_spacing (2);
3009 _zoom_box.set_border_width (2);
3013 zoom_preset_selector.set_name ("zoom button");
3014 zoom_preset_selector.set_image(::get_icon ("time_exp"));
3015 zoom_preset_selector.set_size_request (42, -1);
3017 zoom_in_button.set_name ("zoom button");
3018 zoom_in_button.set_image(::get_icon ("zoom_in"));
3019 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3020 zoom_in_button.set_related_action (act);
3022 zoom_out_button.set_name ("zoom button");
3023 zoom_out_button.set_image(::get_icon ("zoom_out"));
3024 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3025 zoom_out_button.set_related_action (act);
3027 zoom_out_full_button.set_name ("zoom button");
3028 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
3029 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3030 zoom_out_full_button.set_related_action (act);
3032 zoom_focus_selector.set_name ("zoom button");
3034 if (ARDOUR::Profile->get_mixbus()) {
3035 _zoom_box.pack_start (zoom_preset_selector, false, false);
3036 } else if (ARDOUR::Profile->get_trx()) {
3037 mode_box->pack_start (zoom_out_button, false, false);
3038 mode_box->pack_start (zoom_in_button, false, false);
3040 _zoom_box.pack_start (zoom_out_button, false, false);
3041 _zoom_box.pack_start (zoom_in_button, false, false);
3042 _zoom_box.pack_start (zoom_out_full_button, false, false);
3043 _zoom_box.pack_start (zoom_focus_selector, false, false);
3046 /* Track zoom buttons */
3047 visible_tracks_selector.set_name ("zoom button");
3048 if (Profile->get_mixbus()) {
3049 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3050 visible_tracks_selector.set_size_request (42, -1);
3052 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3055 tav_expand_button.set_name ("zoom button");
3056 tav_expand_button.set_image(::get_icon ("tav_exp"));
3057 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3058 tav_expand_button.set_related_action (act);
3060 tav_shrink_button.set_name ("zoom button");
3061 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
3062 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3063 tav_shrink_button.set_related_action (act);
3065 if (ARDOUR::Profile->get_mixbus()) {
3066 _zoom_box.pack_start (visible_tracks_selector);
3067 } else if (ARDOUR::Profile->get_trx()) {
3068 _zoom_box.pack_start (tav_shrink_button);
3069 _zoom_box.pack_start (tav_expand_button);
3071 _zoom_box.pack_start (visible_tracks_selector);
3072 _zoom_box.pack_start (tav_shrink_button);
3073 _zoom_box.pack_start (tav_expand_button);
3076 if (!ARDOUR::Profile->get_trx()) {
3077 _zoom_tearoff = manage (new TearOff (_zoom_box));
3079 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3080 &_zoom_tearoff->tearoff_window()));
3081 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3082 &_zoom_tearoff->tearoff_window(), 0));
3083 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3084 &_zoom_tearoff->tearoff_window()));
3085 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3086 &_zoom_tearoff->tearoff_window(), 0));
3089 if (Profile->get_sae() || Profile->get_mixbus() ) {
3090 _zoom_tearoff->set_can_be_torn_off (false);
3093 snap_box.set_spacing (2);
3094 snap_box.set_border_width (2);
3096 snap_type_selector.set_name ("mouse mode button");
3098 snap_delta_selector.set_name ("mouse mode button");
3099 snap_mode_selector.set_name ("mouse mode button");
3101 edit_point_selector.set_name ("mouse mode button");
3103 snap_box.pack_start (snap_delta_selector, false, false);
3104 snap_box.pack_start (snap_mode_selector, false, false);
3105 snap_box.pack_start (snap_type_selector, false, false);
3106 snap_box.pack_start (edit_point_selector, false, false);
3110 HBox *nudge_box = manage (new HBox);
3111 nudge_box->set_spacing (2);
3112 nudge_box->set_border_width (2);
3114 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3115 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3117 nudge_box->pack_start (nudge_backward_button, false, false);
3118 nudge_box->pack_start (nudge_forward_button, false, false);
3119 nudge_box->pack_start (*nudge_clock, false, false);
3122 /* Pack everything in... */
3124 HBox* hbox = manage (new HBox);
3125 hbox->set_spacing(2);
3127 _tools_tearoff = manage (new TearOff (*hbox));
3128 _tools_tearoff->set_name ("MouseModeBase");
3129 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3131 if (Profile->get_sae() || Profile->get_mixbus()) {
3132 _tools_tearoff->set_can_be_torn_off (false);
3135 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3136 &_tools_tearoff->tearoff_window()));
3137 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3138 &_tools_tearoff->tearoff_window(), 0));
3139 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3140 &_tools_tearoff->tearoff_window()));
3141 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3142 &_tools_tearoff->tearoff_window(), 0));
3144 toolbar_hbox.set_spacing (2);
3145 toolbar_hbox.set_border_width (1);
3147 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3148 if (!ARDOUR::Profile->get_trx()) {
3149 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3150 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3153 if (!ARDOUR::Profile->get_trx()) {
3154 hbox->pack_start (snap_box, false, false);
3155 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3156 hbox->pack_start (*nudge_box, false, false);
3158 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3161 hbox->pack_start (panic_box, false, false);
3165 toolbar_base.set_name ("ToolBarBase");
3166 toolbar_base.add (toolbar_hbox);
3168 _toolbar_viewport.add (toolbar_base);
3169 /* stick to the required height but allow width to vary if there's not enough room */
3170 _toolbar_viewport.set_size_request (1, -1);
3172 toolbar_frame.set_shadow_type (SHADOW_OUT);
3173 toolbar_frame.set_name ("BaseFrame");
3174 toolbar_frame.add (_toolbar_viewport);
3178 Editor::build_edit_point_menu ()
3180 using namespace Menu_Helpers;
3182 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3183 if(!Profile->get_mixbus())
3184 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3185 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3187 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3191 Editor::build_edit_mode_menu ()
3193 using namespace Menu_Helpers;
3195 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3196 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3197 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3198 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3200 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3204 Editor::build_snap_delta_menu ()
3206 using namespace Menu_Helpers;
3208 snap_delta_selector.AddMenuElem (MenuElem ( snap_delta_strings[(int)SnapAbsolute], sigc::bind (sigc::mem_fun(*this, &Editor::snap_delta_selection_done), (SnapDelta) SnapAbsolute)));
3209 snap_delta_selector.AddMenuElem (MenuElem ( snap_delta_strings[(int)SnapRelative], sigc::bind (sigc::mem_fun(*this, &Editor::snap_delta_selection_done), (SnapDelta) SnapRelative)));
3211 set_size_request_to_display_given_text (snap_delta_selector, snap_delta_strings, COMBO_TRIANGLE_WIDTH, 2);
3215 Editor::build_snap_mode_menu ()
3217 using namespace Menu_Helpers;
3219 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3220 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3221 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3223 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3227 Editor::build_snap_type_menu ()
3229 using namespace Menu_Helpers;
3231 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3232 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3233 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3234 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3235 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3236 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3237 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3238 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3239 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3240 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3241 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3242 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3243 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3244 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3245 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3246 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3247 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3248 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3249 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3250 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3251 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3252 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3253 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3254 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3255 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3256 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3257 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3258 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3259 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3260 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3262 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3267 Editor::setup_tooltips ()
3269 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Grab mode)"));
3270 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Grab Mode (select/move objects)"));
3271 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split regions)"));
3272 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select time ranges)"));
3273 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3274 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3275 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3276 ARDOUR_UI::instance()->set_tip (mouse_content_button, _("Internal Edit Mode (edit notes and gain curves inside regions)"));
3277 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3278 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3279 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3280 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3281 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3282 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3283 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3284 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3285 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3286 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3287 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3288 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3289 ARDOUR_UI::instance()->set_tip (snap_delta_selector, _("Relative Snap Mode"));
3290 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3291 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3292 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3293 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3297 Editor::convert_drop_to_paths (
3298 vector<string>& paths,
3299 const RefPtr<Gdk::DragContext>& /*context*/,
3302 const SelectionData& data,
3306 if (_session == 0) {
3310 vector<string> uris = data.get_uris();
3314 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3315 are actually URI lists. So do it by hand.
3318 if (data.get_target() != "text/plain") {
3322 /* Parse the "uri-list" format that Nautilus provides,
3323 where each pathname is delimited by \r\n.
3325 THERE MAY BE NO NULL TERMINATING CHAR!!!
3328 string txt = data.get_text();
3332 p = (char *) malloc (txt.length() + 1);
3333 txt.copy (p, txt.length(), 0);
3334 p[txt.length()] = '\0';
3340 while (g_ascii_isspace (*p))
3344 while (*q && (*q != '\n') && (*q != '\r')) {
3351 while (q > p && g_ascii_isspace (*q))
3356 uris.push_back (string (p, q - p + 1));
3360 p = strchr (p, '\n');
3372 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3373 if ((*i).substr (0,7) == "file://") {
3374 paths.push_back (Glib::filename_from_uri (*i));
3382 Editor::new_tempo_section ()
3387 Editor::map_transport_state ()
3389 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3391 if (_session && _session->transport_stopped()) {
3392 have_pending_keyboard_selection = false;
3395 update_loop_range_view ();
3401 Editor::begin_selection_op_history ()
3403 selection_op_cmd_depth = 0;
3404 selection_op_history_it = 0;
3406 while(!selection_op_history.empty()) {
3407 delete selection_op_history.front();
3408 selection_op_history.pop_front();
3411 selection_undo_action->set_sensitive (false);
3412 selection_redo_action->set_sensitive (false);
3413 selection_op_history.push_front (&_selection_memento->get_state ());
3417 Editor::begin_reversible_selection_op (string name)
3420 //cerr << name << endl;
3421 /* begin/commit pairs can be nested */
3422 selection_op_cmd_depth++;
3427 Editor::commit_reversible_selection_op ()
3430 if (selection_op_cmd_depth == 1) {
3432 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3434 The user has undone some selection ops and then made a new one,
3435 making anything earlier in the list invalid.
3438 list<XMLNode *>::iterator it = selection_op_history.begin();
3439 list<XMLNode *>::iterator e_it = it;
3440 advance (e_it, selection_op_history_it);
3442 for ( ; it != e_it; ++it) {
3445 selection_op_history.erase (selection_op_history.begin(), e_it);
3448 selection_op_history.push_front (&_selection_memento->get_state ());
3449 selection_op_history_it = 0;
3451 selection_undo_action->set_sensitive (true);
3452 selection_redo_action->set_sensitive (false);
3455 if (selection_op_cmd_depth > 0) {
3456 selection_op_cmd_depth--;
3462 Editor::undo_selection_op ()
3465 selection_op_history_it++;
3467 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3468 if (n == selection_op_history_it) {
3469 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3470 selection_redo_action->set_sensitive (true);
3474 /* is there an earlier entry? */
3475 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3476 selection_undo_action->set_sensitive (false);
3482 Editor::redo_selection_op ()
3485 if (selection_op_history_it > 0) {
3486 selection_op_history_it--;
3489 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3490 if (n == selection_op_history_it) {
3491 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3492 selection_undo_action->set_sensitive (true);
3497 if (selection_op_history_it == 0) {
3498 selection_redo_action->set_sensitive (false);
3504 Editor::begin_reversible_command (string name)
3507 before.push_back (&_selection_memento->get_state ());
3508 _session->begin_reversible_command (name);
3513 Editor::begin_reversible_command (GQuark q)
3516 before.push_back (&_selection_memento->get_state ());
3517 _session->begin_reversible_command (q);
3522 Editor::abort_reversible_command ()
3525 while(!before.empty()) {
3526 delete before.front();
3529 _session->abort_reversible_command ();
3534 Editor::commit_reversible_command ()
3537 if (before.size() == 1) {
3538 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3539 redo_action->set_sensitive(false);
3540 undo_action->set_sensitive(true);
3541 begin_selection_op_history ();
3544 if (before.empty()) {
3545 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3550 _session->commit_reversible_command ();
3555 Editor::history_changed ()
3559 if (undo_action && _session) {
3560 if (_session->undo_depth() == 0) {
3561 label = S_("Command|Undo");
3563 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3565 undo_action->property_label() = label;
3568 if (redo_action && _session) {
3569 if (_session->redo_depth() == 0) {
3572 label = string_compose(_("Redo (%1)"), _session->next_redo());
3574 redo_action->property_label() = label;
3579 Editor::duplicate_range (bool with_dialog)
3583 RegionSelection rs = get_regions_from_selection_and_entered ();
3585 if ( selection->time.length() == 0 && rs.empty()) {
3591 ArdourDialog win (_("Duplicate"));
3592 Label label (_("Number of duplications:"));
3593 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3594 SpinButton spinner (adjustment, 0.0, 1);
3597 win.get_vbox()->set_spacing (12);
3598 win.get_vbox()->pack_start (hbox);
3599 hbox.set_border_width (6);
3600 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3602 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3603 place, visually. so do this by hand.
3606 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3607 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3608 spinner.grab_focus();
3614 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3615 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3616 win.set_default_response (RESPONSE_ACCEPT);
3618 spinner.grab_focus ();
3620 switch (win.run ()) {
3621 case RESPONSE_ACCEPT:
3627 times = adjustment.get_value();
3630 if ((current_mouse_mode() == Editing::MouseRange)) {
3631 if (selection->time.length()) {
3632 duplicate_selection (times);
3634 } else if (get_smart_mode()) {
3635 if (selection->time.length()) {
3636 duplicate_selection (times);
3638 duplicate_some_regions (rs, times);
3640 duplicate_some_regions (rs, times);
3645 Editor::set_edit_mode (EditMode m)
3647 Config->set_edit_mode (m);
3651 Editor::cycle_edit_mode ()
3653 switch (Config->get_edit_mode()) {
3655 if (Profile->get_sae()) {
3656 Config->set_edit_mode (Lock);
3658 Config->set_edit_mode (Ripple);
3663 Config->set_edit_mode (Lock);
3666 Config->set_edit_mode (Slide);
3672 Editor::edit_mode_selection_done ( EditMode m )
3674 Config->set_edit_mode ( m );
3678 Editor::snap_type_selection_done (SnapType snaptype)
3680 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3682 ract->set_active ();
3687 Editor::snap_delta_selection_done (SnapDelta delta)
3689 RefPtr<RadioAction> ract = snap_delta_action (delta);
3692 ract->set_active (true);
3697 Editor::snap_mode_selection_done (SnapMode mode)
3699 RefPtr<RadioAction> ract = snap_mode_action (mode);
3702 ract->set_active (true);
3707 Editor::cycle_edit_point (bool with_marker)
3709 if(Profile->get_mixbus())
3710 with_marker = false;
3712 switch (_edit_point) {
3714 set_edit_point_preference (EditAtPlayhead);
3716 case EditAtPlayhead:
3718 set_edit_point_preference (EditAtSelectedMarker);
3720 set_edit_point_preference (EditAtMouse);
3723 case EditAtSelectedMarker:
3724 set_edit_point_preference (EditAtMouse);
3730 Editor::edit_point_selection_done (EditPoint ep)
3732 set_edit_point_preference ( ep );
3736 Editor::build_zoom_focus_menu ()
3738 using namespace Menu_Helpers;
3740 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3741 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3742 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3743 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3744 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3745 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3747 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3751 Editor::zoom_focus_selection_done ( ZoomFocus f )
3753 RefPtr<RadioAction> ract = zoom_focus_action (f);
3755 ract->set_active ();
3760 Editor::build_track_count_menu ()
3762 using namespace Menu_Helpers;
3764 if (!Profile->get_mixbus()) {
3765 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3766 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3767 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3768 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3769 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3770 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3771 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3772 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3773 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3774 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3775 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3776 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3777 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3779 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3780 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3781 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3782 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3783 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3784 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3785 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3786 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3787 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3788 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3790 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3791 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3792 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3793 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3794 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3795 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3796 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3797 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3798 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3799 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3800 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3805 Editor::set_zoom_preset (int64_t ms)
3808 temporal_zoom_session();
3812 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3813 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3817 Editor::set_visible_track_count (int32_t n)
3819 _visible_track_count = n;
3821 /* if the canvas hasn't really been allocated any size yet, just
3822 record the desired number of visible tracks and return. when canvas
3823 allocation happens, we will get called again and then we can do the
3827 if (_visible_canvas_height <= 1) {
3833 DisplaySuspender ds;
3835 if (_visible_track_count > 0) {
3836 h = trackviews_height() / _visible_track_count;
3837 std::ostringstream s;
3838 s << _visible_track_count;
3840 } else if (_visible_track_count == 0) {
3842 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3843 if ((*i)->marked_for_display()) {
3847 h = trackviews_height() / n;
3850 /* negative value means that the visible track count has
3851 been overridden by explicit track height changes.
3853 visible_tracks_selector.set_text (X_("*"));
3857 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3858 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3861 if (str != visible_tracks_selector.get_text()) {
3862 visible_tracks_selector.set_text (str);
3867 Editor::override_visible_track_count ()
3869 _visible_track_count = -1;
3870 visible_tracks_selector.set_text ( _("*") );
3874 Editor::edit_controls_button_release (GdkEventButton* ev)
3876 if (Keyboard::is_context_menu_event (ev)) {
3877 ARDOUR_UI::instance()->add_route (this);
3878 } else if (ev->button == 1) {
3879 selection->clear_tracks ();
3886 Editor::mouse_select_button_release (GdkEventButton* ev)
3888 /* this handles just right-clicks */
3890 if (ev->button != 3) {
3898 Editor::set_zoom_focus (ZoomFocus f)
3900 string str = zoom_focus_strings[(int)f];
3902 if (str != zoom_focus_selector.get_text()) {
3903 zoom_focus_selector.set_text (str);
3906 if (zoom_focus != f) {
3913 Editor::cycle_zoom_focus ()
3915 switch (zoom_focus) {
3917 set_zoom_focus (ZoomFocusRight);
3919 case ZoomFocusRight:
3920 set_zoom_focus (ZoomFocusCenter);
3922 case ZoomFocusCenter:
3923 set_zoom_focus (ZoomFocusPlayhead);
3925 case ZoomFocusPlayhead:
3926 set_zoom_focus (ZoomFocusMouse);
3928 case ZoomFocusMouse:
3929 set_zoom_focus (ZoomFocusEdit);
3932 set_zoom_focus (ZoomFocusLeft);
3938 Editor::ensure_float (Window& win)
3940 win.set_transient_for (*this);
3944 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3946 /* recover or initialize pane positions. do this here rather than earlier because
3947 we don't want the positions to change the child allocations, which they seem to do.
3953 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3962 XMLNode* geometry = find_named_node (*node, "geometry");
3964 if (which == static_cast<Paned*> (&edit_pane)) {
3966 if (done & Horizontal) {
3970 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3971 _notebook_shrunk = string_is_affirmative (prop->value ());
3974 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3975 /* initial allocation is 90% to canvas, 10% to notebook */
3976 pos = (int) floor (alloc.get_width() * 0.90f);
3977 snprintf (buf, sizeof(buf), "%d", pos);
3979 pos = atoi (prop->value());
3982 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3983 edit_pane.set_position (pos);
3986 done = (Pane) (done | Horizontal);
3988 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3990 if (done & Vertical) {
3994 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3995 /* initial allocation is 90% to canvas, 10% to summary */
3996 pos = (int) floor (alloc.get_height() * 0.90f);
3997 snprintf (buf, sizeof(buf), "%d", pos);
4000 pos = atoi (prop->value());
4003 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
4004 editor_summary_pane.set_position (pos);
4007 done = (Pane) (done | Vertical);
4012 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
4014 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
4015 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
4016 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
4017 top_hbox.remove (toolbar_frame);
4022 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
4024 if (toolbar_frame.get_parent() == 0) {
4025 top_hbox.pack_end (toolbar_frame);
4030 Editor::set_show_measures (bool yn)
4032 if (_show_measures != yn) {
4035 if ((_show_measures = yn) == true) {
4037 tempo_lines->show();
4040 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
4041 ARDOUR::TempoMap::BBTPointList::const_iterator end;
4043 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
4044 draw_measures (begin, end);
4052 Editor::toggle_follow_playhead ()
4054 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
4056 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4057 set_follow_playhead (tact->get_active());
4061 /** @param yn true to follow playhead, otherwise false.
4062 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4065 Editor::set_follow_playhead (bool yn, bool catch_up)
4067 if (_follow_playhead != yn) {
4068 if ((_follow_playhead = yn) == true && catch_up) {
4070 reset_x_origin_to_follow_playhead ();
4077 Editor::toggle_stationary_playhead ()
4079 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4081 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4082 set_stationary_playhead (tact->get_active());
4087 Editor::set_stationary_playhead (bool yn)
4089 if (_stationary_playhead != yn) {
4090 if ((_stationary_playhead = yn) == true) {
4092 // FIXME need a 3.0 equivalent of this 2.X call
4093 // update_current_screen ();
4100 Editor::playlist_selector () const
4102 return *_playlist_selector;
4106 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4108 if (paste_count == 0) {
4109 /* don't bother calculating an offset that will be zero anyway */
4113 /* calculate basic unsnapped multi-paste offset */
4114 framecnt_t offset = paste_count * duration;
4116 /* snap offset so pos + offset is aligned to the grid */
4117 framepos_t offset_pos = pos + offset;
4118 snap_to(offset_pos, RoundUpMaybe);
4119 offset = offset_pos - pos;
4125 Editor::get_grid_beat_divisions(framepos_t position)
4127 switch (_snap_type) {
4128 case SnapToBeatDiv128: return 128;
4129 case SnapToBeatDiv64: return 64;
4130 case SnapToBeatDiv32: return 32;
4131 case SnapToBeatDiv28: return 28;
4132 case SnapToBeatDiv24: return 24;
4133 case SnapToBeatDiv20: return 20;
4134 case SnapToBeatDiv16: return 16;
4135 case SnapToBeatDiv14: return 14;
4136 case SnapToBeatDiv12: return 12;
4137 case SnapToBeatDiv10: return 10;
4138 case SnapToBeatDiv8: return 8;
4139 case SnapToBeatDiv7: return 7;
4140 case SnapToBeatDiv6: return 6;
4141 case SnapToBeatDiv5: return 5;
4142 case SnapToBeatDiv4: return 4;
4143 case SnapToBeatDiv3: return 3;
4144 case SnapToBeatDiv2: return 2;
4151 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4155 const unsigned divisions = get_grid_beat_divisions(position);
4157 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4160 switch (_snap_type) {
4162 return Evoral::Beats(1.0);
4165 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
4173 return Evoral::Beats();
4177 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4181 ret = nudge_clock->current_duration (pos);
4182 next = ret + 1; /* XXXX fix me */
4188 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4190 ArdourDialog dialog (_("Playlist Deletion"));
4191 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4192 "If it is kept, its audio files will not be cleaned.\n"
4193 "If it is deleted, audio files used by it alone will be cleaned."),
4196 dialog.set_position (WIN_POS_CENTER);
4197 dialog.get_vbox()->pack_start (label);
4201 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4202 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4203 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4205 switch (dialog.run ()) {
4206 case RESPONSE_ACCEPT:
4207 /* delete the playlist */
4211 case RESPONSE_REJECT:
4212 /* keep the playlist */
4224 Editor::audio_region_selection_covers (framepos_t where)
4226 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4227 if ((*a)->region()->covers (where)) {
4236 Editor::prepare_for_cleanup ()
4238 cut_buffer->clear_regions ();
4239 cut_buffer->clear_playlists ();
4241 selection->clear_regions ();
4242 selection->clear_playlists ();
4244 _regions->suspend_redisplay ();
4248 Editor::finish_cleanup ()
4250 _regions->resume_redisplay ();
4254 Editor::transport_loop_location()
4257 return _session->locations()->auto_loop_location();
4264 Editor::transport_punch_location()
4267 return _session->locations()->auto_punch_location();
4274 Editor::control_layout_scroll (GdkEventScroll* ev)
4276 /* Just forward to the normal canvas scroll method. The coordinate
4277 systems are different but since the canvas is always larger than the
4278 track headers, and aligned with the trackview area, this will work.
4280 In the not too distant future this layout is going away anyway and
4281 headers will be on the canvas.
4283 return canvas_scroll_event (ev, false);
4287 Editor::session_state_saved (string)
4290 _snapshots->redisplay ();
4294 Editor::update_tearoff_visibility()
4296 bool visible = ARDOUR_UI::config()->get_keep_tearoffs();
4297 _mouse_mode_tearoff->set_visible (visible);
4298 _tools_tearoff->set_visible (visible);
4299 if (_zoom_tearoff) {
4300 _zoom_tearoff->set_visible (visible);
4305 Editor::reattach_all_tearoffs ()
4307 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4308 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4309 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4313 Editor::maximise_editing_space ()
4325 Editor::restore_editing_space ()
4337 * Make new playlists for a given track and also any others that belong
4338 * to the same active route group with the `select' property.
4343 Editor::new_playlists (TimeAxisView* v)
4345 begin_reversible_command (_("new playlists"));
4346 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4347 _session->playlists->get (playlists);
4348 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4349 commit_reversible_command ();
4353 * Use a copy of the current playlist for a given track and also any others that belong
4354 * to the same active route group with the `select' property.
4359 Editor::copy_playlists (TimeAxisView* v)
4361 begin_reversible_command (_("copy playlists"));
4362 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4363 _session->playlists->get (playlists);
4364 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4365 commit_reversible_command ();
4368 /** Clear the current playlist for a given track and also any others that belong
4369 * to the same active route group with the `select' property.
4374 Editor::clear_playlists (TimeAxisView* v)
4376 begin_reversible_command (_("clear playlists"));
4377 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4378 _session->playlists->get (playlists);
4379 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4380 commit_reversible_command ();
4384 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4386 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4390 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4392 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4396 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4398 atv.clear_playlist ();
4402 Editor::on_key_press_event (GdkEventKey* ev)
4404 return key_press_focus_accelerator_handler (*this, ev);
4408 Editor::on_key_release_event (GdkEventKey* ev)
4410 return Gtk::Window::on_key_release_event (ev);
4411 // return key_press_focus_accelerator_handler (*this, ev);
4415 Editor::get_y_origin () const
4417 return vertical_adjustment.get_value ();
4420 /** Queue up a change to the viewport x origin.
4421 * @param frame New x origin.
4424 Editor::reset_x_origin (framepos_t frame)
4426 pending_visual_change.add (VisualChange::TimeOrigin);
4427 pending_visual_change.time_origin = frame;
4428 ensure_visual_change_idle_handler ();
4432 Editor::reset_y_origin (double y)
4434 pending_visual_change.add (VisualChange::YOrigin);
4435 pending_visual_change.y_origin = y;
4436 ensure_visual_change_idle_handler ();
4440 Editor::reset_zoom (framecnt_t spp)
4442 if (spp == samples_per_pixel) {
4446 pending_visual_change.add (VisualChange::ZoomLevel);
4447 pending_visual_change.samples_per_pixel = spp;
4448 ensure_visual_change_idle_handler ();
4452 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4454 reset_x_origin (frame);
4457 if (!no_save_visual) {
4458 undo_visual_stack.push_back (current_visual_state(false));
4462 Editor::VisualState::VisualState (bool with_tracks)
4463 : gui_state (with_tracks ? new GUIObjectState : 0)
4467 Editor::VisualState::~VisualState ()
4472 Editor::VisualState*
4473 Editor::current_visual_state (bool with_tracks)
4475 VisualState* vs = new VisualState (with_tracks);
4476 vs->y_position = vertical_adjustment.get_value();
4477 vs->samples_per_pixel = samples_per_pixel;
4478 vs->leftmost_frame = leftmost_frame;
4479 vs->zoom_focus = zoom_focus;
4482 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4489 Editor::undo_visual_state ()
4491 if (undo_visual_stack.empty()) {
4495 VisualState* vs = undo_visual_stack.back();
4496 undo_visual_stack.pop_back();
4499 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4502 use_visual_state (*vs);
4507 Editor::redo_visual_state ()
4509 if (redo_visual_stack.empty()) {
4513 VisualState* vs = redo_visual_stack.back();
4514 redo_visual_stack.pop_back();
4516 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4517 // why do we check here?
4518 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4521 use_visual_state (*vs);
4526 Editor::swap_visual_state ()
4528 if (undo_visual_stack.empty()) {
4529 redo_visual_state ();
4531 undo_visual_state ();
4536 Editor::use_visual_state (VisualState& vs)
4538 PBD::Unwinder<bool> nsv (no_save_visual, true);
4539 DisplaySuspender ds;
4541 vertical_adjustment.set_value (vs.y_position);
4543 set_zoom_focus (vs.zoom_focus);
4544 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4547 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4549 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4550 (*i)->clear_property_cache();
4551 (*i)->reset_visual_state ();
4555 _routes->update_visibility ();
4558 /** This is the core function that controls the zoom level of the canvas. It is called
4559 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4560 * @param spp new number of samples per pixel
4563 Editor::set_samples_per_pixel (framecnt_t spp)
4569 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4570 const framecnt_t lots_of_pixels = 4000;
4572 /* if the zoom level is greater than what you'd get trying to display 3
4573 * days of audio on a really big screen, then it's too big.
4576 if (spp * lots_of_pixels > three_days) {
4580 samples_per_pixel = spp;
4583 tempo_lines->tempo_map_changed();
4586 bool const showing_time_selection = selection->time.length() > 0;
4588 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4589 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4590 (*i)->reshow_selection (selection->time);
4594 ZoomChanged (); /* EMIT_SIGNAL */
4596 ArdourCanvas::GtkCanvasViewport* c;
4598 c = get_track_canvas();
4600 c->canvas()->zoomed ();
4603 if (playhead_cursor) {
4604 playhead_cursor->set_position (playhead_cursor->current_frame ());
4607 refresh_location_display();
4608 _summary->set_overlays_dirty ();
4610 update_marker_labels ();
4616 Editor::queue_visual_videotimeline_update ()
4619 * pending_visual_change.add (VisualChange::VideoTimeline);
4620 * or maybe even more specific: which videotimeline-image
4621 * currently it calls update_video_timeline() to update
4622 * _all outdated_ images on the video-timeline.
4623 * see 'exposeimg()' in video_image_frame.cc
4625 ensure_visual_change_idle_handler ();
4629 Editor::ensure_visual_change_idle_handler ()
4631 if (pending_visual_change.idle_handler_id < 0) {
4632 // see comment in add_to_idle_resize above.
4633 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4634 pending_visual_change.being_handled = false;
4639 Editor::_idle_visual_changer (void* arg)
4641 return static_cast<Editor*>(arg)->idle_visual_changer ();
4645 Editor::idle_visual_changer ()
4647 /* set_horizontal_position() below (and maybe other calls) call
4648 gtk_main_iteration(), so it's possible that a signal will be handled
4649 half-way through this method. If this signal wants an
4650 idle_visual_changer we must schedule another one after this one, so
4651 mark the idle_handler_id as -1 here to allow that. Also make a note
4652 that we are doing the visual change, so that changes in response to
4653 super-rapid-screen-update can be dropped if we are still processing
4657 pending_visual_change.idle_handler_id = -1;
4658 pending_visual_change.being_handled = true;
4660 VisualChange vc = pending_visual_change;
4662 pending_visual_change.pending = (VisualChange::Type) 0;
4664 visual_changer (vc);
4666 pending_visual_change.being_handled = false;
4668 return 0; /* this is always a one-shot call */
4672 Editor::visual_changer (const VisualChange& vc)
4674 double const last_time_origin = horizontal_position ();
4676 if (vc.pending & VisualChange::ZoomLevel) {
4677 set_samples_per_pixel (vc.samples_per_pixel);
4679 compute_fixed_ruler_scale ();
4681 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4682 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4684 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4685 current_bbt_points_begin, current_bbt_points_end);
4686 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4687 current_bbt_points_begin, current_bbt_points_end);
4688 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4690 update_video_timeline();
4693 if (vc.pending & VisualChange::TimeOrigin) {
4694 set_horizontal_position (vc.time_origin / samples_per_pixel);
4697 if (vc.pending & VisualChange::YOrigin) {
4698 vertical_adjustment.set_value (vc.y_origin);
4701 if (last_time_origin == horizontal_position ()) {
4702 /* changed signal not emitted */
4703 update_fixed_rulers ();
4704 redisplay_tempo (true);
4707 if (!(vc.pending & VisualChange::ZoomLevel)) {
4708 update_video_timeline();
4711 _summary->set_overlays_dirty ();
4714 struct EditorOrderTimeAxisSorter {
4715 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4716 return a->order () < b->order ();
4721 Editor::sort_track_selection (TrackViewList& sel)
4723 EditorOrderTimeAxisSorter cmp;
4728 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4731 framepos_t where = 0;
4732 EditPoint ep = _edit_point;
4734 if (Profile->get_mixbus())
4735 if (ep == EditAtSelectedMarker)
4736 ep = EditAtPlayhead;
4738 if (from_outside_canvas && (ep == EditAtMouse)) {
4739 ep = EditAtPlayhead;
4740 } else if (from_context_menu && (ep == EditAtMouse)) {
4741 return canvas_event_sample (&context_click_event, 0, 0);
4744 if (entered_marker) {
4745 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4746 return entered_marker->position();
4749 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4750 ep = EditAtSelectedMarker;
4753 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4754 ep = EditAtPlayhead;
4758 case EditAtPlayhead:
4759 if (_dragging_playhead) {
4760 if (!mouse_frame (where, ignored)) {
4761 /* XXX not right but what can we do ? */
4765 where = _session->audible_frame();
4767 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4770 case EditAtSelectedMarker:
4771 if (!selection->markers.empty()) {
4773 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4776 where = loc->start();
4780 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4788 if (!mouse_frame (where, ignored)) {
4789 /* XXX not right but what can we do ? */
4793 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4801 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4803 if (!_session) return;
4805 begin_reversible_command (cmd);
4809 if ((tll = transport_loop_location()) == 0) {
4810 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4811 XMLNode &before = _session->locations()->get_state();
4812 _session->locations()->add (loc, true);
4813 _session->set_auto_loop_location (loc);
4814 XMLNode &after = _session->locations()->get_state();
4815 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4817 XMLNode &before = tll->get_state();
4818 tll->set_hidden (false, this);
4819 tll->set (start, end);
4820 XMLNode &after = tll->get_state();
4821 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4824 commit_reversible_command ();
4828 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4830 if (!_session) return;
4832 begin_reversible_command (cmd);
4836 if ((tpl = transport_punch_location()) == 0) {
4837 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4838 XMLNode &before = _session->locations()->get_state();
4839 _session->locations()->add (loc, true);
4840 _session->set_auto_punch_location (loc);
4841 XMLNode &after = _session->locations()->get_state();
4842 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4844 XMLNode &before = tpl->get_state();
4845 tpl->set_hidden (false, this);
4846 tpl->set (start, end);
4847 XMLNode &after = tpl->get_state();
4848 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4851 commit_reversible_command ();
4854 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4855 * @param rs List to which found regions are added.
4856 * @param where Time to look at.
4857 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4860 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4862 const TrackViewList* tracks;
4865 tracks = &track_views;
4870 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4872 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4875 boost::shared_ptr<Track> tr;
4876 boost::shared_ptr<Playlist> pl;
4878 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4880 boost::shared_ptr<RegionList> regions = pl->regions_at (
4881 (framepos_t) floor ( (double) where * tr->speed()));
4883 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4884 RegionView* rv = rtv->view()->find_view (*i);
4895 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4897 const TrackViewList* tracks;
4900 tracks = &track_views;
4905 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4906 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4908 boost::shared_ptr<Track> tr;
4909 boost::shared_ptr<Playlist> pl;
4911 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4913 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4914 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4916 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4918 RegionView* rv = rtv->view()->find_view (*i);
4929 /** Get regions using the following method:
4931 * Make a region list using:
4932 * (a) any selected regions
4933 * (b) the intersection of any selected tracks and the edit point(*)
4934 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4936 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4938 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4942 Editor::get_regions_from_selection_and_edit_point ()
4944 RegionSelection regions;
4946 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4947 regions.add (entered_regionview);
4949 regions = selection->regions;
4952 if ( regions.empty() ) {
4953 TrackViewList tracks = selection->tracks;
4955 if (!tracks.empty()) {
4956 /* no region selected or entered, but some selected tracks:
4957 * act on all regions on the selected tracks at the edit point
4959 framepos_t const where = get_preferred_edit_position ();
4960 get_regions_at(regions, where, tracks);
4967 /** Get regions using the following method:
4969 * Make a region list using:
4970 * (a) any selected regions
4971 * (b) the intersection of any selected tracks and the edit point(*)
4972 * (c) if neither exists, then whatever region is under the mouse
4974 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4976 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4979 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4981 RegionSelection regions;
4983 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4984 regions.add (entered_regionview);
4986 regions = selection->regions;
4989 if ( regions.empty() ) {
4990 TrackViewList tracks = selection->tracks;
4992 if (!tracks.empty()) {
4993 /* no region selected or entered, but some selected tracks:
4994 * act on all regions on the selected tracks at the edit point
4996 get_regions_at(regions, pos, tracks);
5003 /** Start with regions that are selected, or the entered regionview if none are selected.
5004 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
5005 * of the regions that we started with.
5009 Editor::get_regions_from_selection_and_entered ()
5011 RegionSelection regions = selection->regions;
5013 if (regions.empty() && entered_regionview) {
5014 regions.add (entered_regionview);
5021 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
5023 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5024 RouteTimeAxisView* rtav;
5026 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5027 boost::shared_ptr<Playlist> pl;
5028 std::vector<boost::shared_ptr<Region> > results;
5029 boost::shared_ptr<Track> tr;
5031 if ((tr = rtav->track()) == 0) {
5036 if ((pl = (tr->playlist())) != 0) {
5037 boost::shared_ptr<Region> r = pl->region_by_id (id);
5039 RegionView* rv = rtav->view()->find_view (r);
5041 regions.push_back (rv);
5050 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5053 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5054 MidiTimeAxisView* mtav;
5056 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5058 mtav->get_per_region_note_selection (selection);
5065 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5067 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5069 RouteTimeAxisView* tatv;
5071 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5073 boost::shared_ptr<Playlist> pl;
5074 vector<boost::shared_ptr<Region> > results;
5076 boost::shared_ptr<Track> tr;
5078 if ((tr = tatv->track()) == 0) {
5083 if ((pl = (tr->playlist())) != 0) {
5084 if (src_comparison) {
5085 pl->get_source_equivalent_regions (region, results);
5087 pl->get_region_list_equivalent_regions (region, results);
5091 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5092 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5093 regions.push_back (marv);
5102 Editor::show_rhythm_ferret ()
5104 if (rhythm_ferret == 0) {
5105 rhythm_ferret = new RhythmFerret(*this);
5108 rhythm_ferret->set_session (_session);
5109 rhythm_ferret->show ();
5110 rhythm_ferret->present ();
5114 Editor::first_idle ()
5116 MessageDialog* dialog = 0;
5118 if (track_views.size() > 1) {
5119 dialog = new MessageDialog (
5121 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5125 ARDOUR_UI::instance()->flush_pending ();
5128 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5132 // first idle adds route children (automation tracks), so we need to redisplay here
5133 _routes->redisplay ();
5137 if (_session->undo_depth() == 0) {
5138 undo_action->set_sensitive(false);
5140 redo_action->set_sensitive(false);
5141 begin_selection_op_history ();
5147 Editor::_idle_resize (gpointer arg)
5149 return ((Editor*)arg)->idle_resize ();
5153 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5155 if (resize_idle_id < 0) {
5156 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5157 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5158 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5160 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5161 _pending_resize_amount = 0;
5164 /* make a note of the smallest resulting height, so that we can clamp the
5165 lower limit at TimeAxisView::hSmall */
5167 int32_t min_resulting = INT32_MAX;
5169 _pending_resize_amount += h;
5170 _pending_resize_view = view;
5172 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5174 if (selection->tracks.contains (_pending_resize_view)) {
5175 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5176 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5180 if (min_resulting < 0) {
5185 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5186 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5190 /** Handle pending resizing of tracks */
5192 Editor::idle_resize ()
5194 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5196 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5197 selection->tracks.contains (_pending_resize_view)) {
5199 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5200 if (*i != _pending_resize_view) {
5201 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5206 _pending_resize_amount = 0;
5207 _group_tabs->set_dirty ();
5208 resize_idle_id = -1;
5216 ENSURE_GUI_THREAD (*this, &Editor::located);
5219 playhead_cursor->set_position (_session->audible_frame ());
5220 if (_follow_playhead && !_pending_initial_locate) {
5221 reset_x_origin_to_follow_playhead ();
5225 _pending_locate_request = false;
5226 _pending_initial_locate = false;
5230 Editor::region_view_added (RegionView * rv)
5232 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5233 if (rv->region ()->id () == (*pr)) {
5234 selection->add (rv);
5235 selection->regions.pending.erase (pr);
5240 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5242 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5243 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5244 if (rv->region()->id () == (*rnote).first) {
5245 mrv->select_notes ((*rnote).second);
5246 selection->pending_midi_note_selection.erase(rnote);
5252 _summary->set_background_dirty ();
5256 Editor::region_view_removed ()
5258 _summary->set_background_dirty ();
5262 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5264 TrackViewList::const_iterator j = track_views.begin ();
5265 while (j != track_views.end()) {
5266 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5267 if (rtv && rtv->route() == r) {
5278 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5282 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5283 TimeAxisView* tv = axis_view_from_route (*i);
5293 Editor::suspend_route_redisplay ()
5296 _routes->suspend_redisplay();
5301 Editor::resume_route_redisplay ()
5304 _routes->redisplay(); // queue redisplay
5305 _routes->resume_redisplay();
5310 Editor::add_routes (RouteList& routes)
5312 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5314 RouteTimeAxisView *rtv;
5315 list<RouteTimeAxisView*> new_views;
5316 TrackViewList new_selection;
5317 bool from_scratch = (track_views.size() == 0);
5319 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5320 boost::shared_ptr<Route> route = (*x);
5322 if (route->is_auditioner() || route->is_monitor()) {
5326 DataType dt = route->input()->default_type();
5328 if (dt == ARDOUR::DataType::AUDIO) {
5329 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5330 rtv->set_route (route);
5331 } else if (dt == ARDOUR::DataType::MIDI) {
5332 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5333 rtv->set_route (route);
5335 throw unknown_type();
5338 new_views.push_back (rtv);
5339 track_views.push_back (rtv);
5340 new_selection.push_back (rtv);
5342 rtv->effective_gain_display ();
5344 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5345 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5348 if (new_views.size() > 0) {
5349 _routes->routes_added (new_views);
5350 _summary->routes_added (new_views);
5353 if (!from_scratch) {
5354 selection->tracks.clear();
5355 selection->add (new_selection);
5356 begin_selection_op_history();
5359 if (show_editor_mixer_when_tracks_arrive) {
5360 show_editor_mixer (true);
5363 editor_list_button.set_sensitive (true);
5367 Editor::timeaxisview_deleted (TimeAxisView *tv)
5369 if (tv == entered_track) {
5373 if (_session && _session->deletion_in_progress()) {
5374 /* the situation is under control */
5378 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5380 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5382 _routes->route_removed (tv);
5384 TimeAxisView::Children c = tv->get_child_list ();
5385 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5386 if (entered_track == i->get()) {
5391 /* remove it from the list of track views */
5393 TrackViewList::iterator i;
5395 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5396 i = track_views.erase (i);
5399 /* update whatever the current mixer strip is displaying, if revelant */
5401 boost::shared_ptr<Route> route;
5404 route = rtav->route ();
5407 if (current_mixer_strip && current_mixer_strip->route() == route) {
5409 TimeAxisView* next_tv;
5411 if (track_views.empty()) {
5413 } else if (i == track_views.end()) {
5414 next_tv = track_views.front();
5421 set_selected_mixer_strip (*next_tv);
5423 /* make the editor mixer strip go away setting the
5424 * button to inactive (which also unticks the menu option)
5427 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5433 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5435 if (apply_to_selection) {
5436 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5438 TrackSelection::iterator j = i;
5441 hide_track_in_display (*i, false);
5446 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5448 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5449 // this will hide the mixer strip
5450 set_selected_mixer_strip (*tv);
5453 _routes->hide_track_in_display (*tv);
5458 Editor::sync_track_view_list_and_routes ()
5460 track_views = TrackViewList (_routes->views ());
5462 _summary->set_dirty ();
5463 _group_tabs->set_dirty ();
5465 return false; // do not call again (until needed)
5469 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5471 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5476 /** Find a RouteTimeAxisView by the ID of its route */
5478 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5480 RouteTimeAxisView* v;
5482 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5483 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5484 if(v->route()->id() == id) {
5494 Editor::fit_route_group (RouteGroup *g)
5496 TrackViewList ts = axis_views_from_routes (g->route_list ());
5501 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5503 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5506 _session->cancel_audition ();
5510 if (_session->is_auditioning()) {
5511 _session->cancel_audition ();
5512 if (r == last_audition_region) {
5517 _session->audition_region (r);
5518 last_audition_region = r;
5523 Editor::hide_a_region (boost::shared_ptr<Region> r)
5525 r->set_hidden (true);
5529 Editor::show_a_region (boost::shared_ptr<Region> r)
5531 r->set_hidden (false);
5535 Editor::audition_region_from_region_list ()
5537 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5541 Editor::hide_region_from_region_list ()
5543 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5547 Editor::show_region_in_region_list ()
5549 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5553 Editor::step_edit_status_change (bool yn)
5556 start_step_editing ();
5558 stop_step_editing ();
5563 Editor::start_step_editing ()
5565 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5569 Editor::stop_step_editing ()
5571 step_edit_connection.disconnect ();
5575 Editor::check_step_edit ()
5577 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5578 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5580 mtv->check_step_edit ();
5584 return true; // do it again, till we stop
5588 Editor::scroll_press (Direction dir)
5590 ++_scroll_callbacks;
5592 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5593 /* delay the first auto-repeat */
5599 scroll_backward (1);
5607 scroll_up_one_track ();
5611 scroll_down_one_track ();
5615 /* do hacky auto-repeat */
5616 if (!_scroll_connection.connected ()) {
5618 _scroll_connection = Glib::signal_timeout().connect (
5619 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5622 _scroll_callbacks = 0;
5629 Editor::scroll_release ()
5631 _scroll_connection.disconnect ();
5634 /** Queue a change for the Editor viewport x origin to follow the playhead */
5636 Editor::reset_x_origin_to_follow_playhead ()
5638 framepos_t const frame = playhead_cursor->current_frame ();
5640 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5642 if (_session->transport_speed() < 0) {
5644 if (frame > (current_page_samples() / 2)) {
5645 center_screen (frame-(current_page_samples()/2));
5647 center_screen (current_page_samples()/2);
5654 if (frame < leftmost_frame) {
5656 if (_session->transport_rolling()) {
5657 /* rolling; end up with the playhead at the right of the page */
5658 l = frame - current_page_samples ();
5660 /* not rolling: end up with the playhead 1/4 of the way along the page */
5661 l = frame - current_page_samples() / 4;
5665 if (_session->transport_rolling()) {
5666 /* rolling: end up with the playhead on the left of the page */
5669 /* not rolling: end up with the playhead 3/4 of the way along the page */
5670 l = frame - 3 * current_page_samples() / 4;
5678 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5684 Editor::super_rapid_screen_update ()
5686 if (!_session || !_session->engine().running()) {
5690 /* METERING / MIXER STRIPS */
5692 /* update track meters, if required */
5693 if (is_mapped() && meters_running) {
5694 RouteTimeAxisView* rtv;
5695 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5696 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5697 rtv->fast_update ();
5702 /* and any current mixer strip */
5703 if (current_mixer_strip) {
5704 current_mixer_strip->fast_update ();
5707 /* PLAYHEAD AND VIEWPORT */
5709 framepos_t const frame = _session->audible_frame();
5711 /* There are a few reasons why we might not update the playhead / viewport stuff:
5713 * 1. we don't update things when there's a pending locate request, otherwise
5714 * when the editor requests a locate there is a chance that this method
5715 * will move the playhead before the locate request is processed, causing
5717 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5718 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5721 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5723 last_update_frame = frame;
5725 if (!_dragging_playhead) {
5726 playhead_cursor->set_position (frame);
5729 if (!_stationary_playhead) {
5731 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5732 /* We only do this if we aren't already
5733 handling a visual change (ie if
5734 pending_visual_change.being_handled is
5735 false) so that these requests don't stack
5736 up there are too many of them to handle in
5739 reset_x_origin_to_follow_playhead ();
5744 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5748 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5749 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5750 if (target <= 0.0) {
5753 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5754 target = (target * 0.15) + (current * 0.85);
5760 set_horizontal_position (current);
5769 Editor::session_going_away ()
5771 _have_idled = false;
5773 _session_connections.drop_connections ();
5775 super_rapid_screen_update_connection.disconnect ();
5777 selection->clear ();
5778 cut_buffer->clear ();
5780 clicked_regionview = 0;
5781 clicked_axisview = 0;
5782 clicked_routeview = 0;
5783 entered_regionview = 0;
5785 last_update_frame = 0;
5788 playhead_cursor->hide ();
5790 /* rip everything out of the list displays */
5794 _route_groups->clear ();
5796 /* do this first so that deleting a track doesn't reset cms to null
5797 and thus cause a leak.
5800 if (current_mixer_strip) {
5801 if (current_mixer_strip->get_parent() != 0) {
5802 global_hpacker.remove (*current_mixer_strip);
5804 delete current_mixer_strip;
5805 current_mixer_strip = 0;
5808 /* delete all trackviews */
5810 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5813 track_views.clear ();
5815 nudge_clock->set_session (0);
5817 editor_list_button.set_active(false);
5818 editor_list_button.set_sensitive(false);
5820 /* clear tempo/meter rulers */
5821 remove_metric_marks ();
5823 clear_marker_display ();
5825 stop_step_editing ();
5827 /* get rid of any existing editor mixer strip */
5829 WindowTitle title(Glib::get_application_name());
5830 title += _("Editor");
5832 set_title (title.get_string());
5834 SessionHandlePtr::session_going_away ();
5839 Editor::show_editor_list (bool yn)
5842 _the_notebook.show ();
5844 _the_notebook.hide ();
5849 Editor::change_region_layering_order (bool from_context_menu)
5851 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5853 if (!clicked_routeview) {
5854 if (layering_order_editor) {
5855 layering_order_editor->hide ();
5860 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5866 boost::shared_ptr<Playlist> pl = track->playlist();
5872 if (layering_order_editor == 0) {
5873 layering_order_editor = new RegionLayeringOrderEditor (*this);
5876 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5877 layering_order_editor->maybe_present ();
5881 Editor::update_region_layering_order_editor ()
5883 if (layering_order_editor && layering_order_editor->is_visible ()) {
5884 change_region_layering_order (true);
5889 Editor::setup_fade_images ()
5891 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5892 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5893 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5894 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5895 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5897 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5898 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5899 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5900 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5901 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5903 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5904 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5905 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5906 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5907 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5909 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5910 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5911 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5912 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5913 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5917 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5919 Editor::action_menu_item (std::string const & name)
5921 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5924 return *manage (a->create_menu_item ());
5928 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5930 EventBox* b = manage (new EventBox);
5931 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5932 Label* l = manage (new Label (name));
5936 _the_notebook.append_page (widget, *b);
5940 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5942 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5943 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5946 if (ev->type == GDK_2BUTTON_PRESS) {
5948 /* double-click on a notebook tab shrinks or expands the notebook */
5950 if (_notebook_shrunk) {
5951 if (pre_notebook_shrink_pane_width) {
5952 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5954 _notebook_shrunk = false;
5956 pre_notebook_shrink_pane_width = edit_pane.get_position();
5958 /* this expands the LHS of the edit pane to cover the notebook
5959 PAGE but leaves the tabs visible.
5961 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5962 _notebook_shrunk = true;
5970 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5972 using namespace Menu_Helpers;
5974 MenuList& items = _control_point_context_menu.items ();
5977 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5978 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5979 if (!can_remove_control_point (item)) {
5980 items.back().set_sensitive (false);
5983 _control_point_context_menu.popup (event->button.button, event->button.time);
5987 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5989 using namespace Menu_Helpers;
5991 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5996 /* We need to get the selection here and pass it to the operations, since
5997 popping up the menu will cause a region leave event which clears
5998 entered_regionview. */
6000 MidiRegionView& mrv = note->region_view();
6001 const RegionSelection rs = get_regions_from_selection_and_entered ();
6003 MenuList& items = _note_context_menu.items();
6006 items.push_back(MenuElem(_("Delete"),
6007 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6008 items.push_back(MenuElem(_("Edit..."),
6009 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6010 items.push_back(MenuElem(_("Legatize"),
6011 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6012 items.push_back(MenuElem(_("Quantize..."),
6013 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6014 items.push_back(MenuElem(_("Remove Overlap"),
6015 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6016 items.push_back(MenuElem(_("Transform..."),
6017 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6019 _note_context_menu.popup (event->button.button, event->button.time);
6023 Editor::zoom_vertical_modifier_released()
6025 _stepping_axis_view = 0;
6029 Editor::ui_parameter_changed (string parameter)
6031 if (parameter == "icon-set") {
6032 while (!_cursor_stack.empty()) {
6033 _cursor_stack.pop_back();
6035 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
6036 _cursor_stack.push_back(_cursors->grabber);
6037 } else if (parameter == "draggable-playhead") {
6038 if (_verbose_cursor) {
6039 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());