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::snap_to_no_magnets (framepos_t& start, RoundMode direction, bool for_mark)
2659 if (!_session || _snap_mode == SnapOff) {
2663 snap_to_internal (start, direction, for_mark, true);
2667 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2669 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2670 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2672 switch (_snap_type) {
2673 case SnapToTimecodeFrame:
2674 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2675 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2676 /* start is already on a whole timecode frame, do nothing */
2677 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2678 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2680 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2684 case SnapToTimecodeSeconds:
2685 if (_session->config.get_timecode_offset_negative()) {
2686 start += _session->config.get_timecode_offset ();
2688 start -= _session->config.get_timecode_offset ();
2690 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2691 (start % one_timecode_second == 0)) {
2692 /* start is already on a whole second, do nothing */
2693 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2694 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2696 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2699 if (_session->config.get_timecode_offset_negative()) {
2700 start -= _session->config.get_timecode_offset ();
2702 start += _session->config.get_timecode_offset ();
2706 case SnapToTimecodeMinutes:
2707 if (_session->config.get_timecode_offset_negative()) {
2708 start += _session->config.get_timecode_offset ();
2710 start -= _session->config.get_timecode_offset ();
2712 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2713 (start % one_timecode_minute == 0)) {
2714 /* start is already on a whole minute, do nothing */
2715 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2716 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2718 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2720 if (_session->config.get_timecode_offset_negative()) {
2721 start -= _session->config.get_timecode_offset ();
2723 start += _session->config.get_timecode_offset ();
2727 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2728 abort(); /*NOTREACHED*/
2733 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool no_magnets)
2735 const framepos_t one_second = _session->frame_rate();
2736 const framepos_t one_minute = _session->frame_rate() * 60;
2737 framepos_t presnap = start;
2741 switch (_snap_type) {
2742 case SnapToTimecodeFrame:
2743 case SnapToTimecodeSeconds:
2744 case SnapToTimecodeMinutes:
2745 return timecode_snap_to_internal (start, direction, for_mark);
2748 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2749 start % (one_second/75) == 0) {
2750 /* start is already on a whole CD frame, do nothing */
2751 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2752 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2754 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2759 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2760 start % one_second == 0) {
2761 /* start is already on a whole second, do nothing */
2762 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2763 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2765 start = (framepos_t) floor ((double) start / one_second) * one_second;
2770 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2771 start % one_minute == 0) {
2772 /* start is already on a whole minute, do nothing */
2773 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2774 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2776 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2781 start = _session->tempo_map().round_to_bar (start, direction);
2785 start = _session->tempo_map().round_to_beat (start, direction);
2788 case SnapToBeatDiv128:
2789 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2791 case SnapToBeatDiv64:
2792 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2794 case SnapToBeatDiv32:
2795 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2797 case SnapToBeatDiv28:
2798 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2800 case SnapToBeatDiv24:
2801 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2803 case SnapToBeatDiv20:
2804 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2806 case SnapToBeatDiv16:
2807 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2809 case SnapToBeatDiv14:
2810 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2812 case SnapToBeatDiv12:
2813 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2815 case SnapToBeatDiv10:
2816 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2818 case SnapToBeatDiv8:
2819 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2821 case SnapToBeatDiv7:
2822 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2824 case SnapToBeatDiv6:
2825 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2827 case SnapToBeatDiv5:
2828 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2830 case SnapToBeatDiv4:
2831 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2833 case SnapToBeatDiv3:
2834 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2836 case SnapToBeatDiv2:
2837 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2845 _session->locations()->marks_either_side (start, before, after);
2847 if (before == max_framepos && after == max_framepos) {
2848 /* No marks to snap to, so just don't snap */
2850 } else if (before == max_framepos) {
2852 } else if (after == max_framepos) {
2854 } else if (before != max_framepos && after != max_framepos) {
2855 /* have before and after */
2856 if ((start - before) < (after - start)) {
2865 case SnapToRegionStart:
2866 case SnapToRegionEnd:
2867 case SnapToRegionSync:
2868 case SnapToRegionBoundary:
2869 if (!region_boundary_cache.empty()) {
2871 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2872 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2874 if (direction > 0) {
2875 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2877 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2880 if (next != region_boundary_cache.begin ()) {
2885 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2886 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2888 if (start > (p + n) / 2) {
2897 switch (_snap_mode) {
2907 if (presnap > start) {
2908 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2912 } else if (presnap < start) {
2913 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2919 /* handled at entry */
2927 Editor::setup_toolbar ()
2929 HBox* mode_box = manage(new HBox);
2930 mode_box->set_border_width (2);
2931 mode_box->set_spacing(2);
2933 HBox* mouse_mode_box = manage (new HBox);
2934 HBox* mouse_mode_hbox = manage (new HBox);
2935 VBox* mouse_mode_vbox = manage (new VBox);
2936 Alignment* mouse_mode_align = manage (new Alignment);
2938 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2939 mouse_mode_size_group->add_widget (smart_mode_button);
2940 mouse_mode_size_group->add_widget (mouse_move_button);
2941 mouse_mode_size_group->add_widget (mouse_cut_button);
2942 mouse_mode_size_group->add_widget (mouse_select_button);
2943 mouse_mode_size_group->add_widget (mouse_timefx_button);
2944 mouse_mode_size_group->add_widget (mouse_audition_button);
2945 mouse_mode_size_group->add_widget (mouse_draw_button);
2946 mouse_mode_size_group->add_widget (mouse_content_button);
2948 mouse_mode_size_group->add_widget (zoom_in_button);
2949 mouse_mode_size_group->add_widget (zoom_out_button);
2950 mouse_mode_size_group->add_widget (zoom_preset_selector);
2951 mouse_mode_size_group->add_widget (zoom_out_full_button);
2952 mouse_mode_size_group->add_widget (zoom_focus_selector);
2954 mouse_mode_size_group->add_widget (tav_shrink_button);
2955 mouse_mode_size_group->add_widget (tav_expand_button);
2956 mouse_mode_size_group->add_widget (visible_tracks_selector);
2958 mouse_mode_size_group->add_widget (snap_type_selector);
2959 mouse_mode_size_group->add_widget (snap_delta_selector);
2960 mouse_mode_size_group->add_widget (snap_mode_selector);
2962 mouse_mode_size_group->add_widget (edit_point_selector);
2963 mouse_mode_size_group->add_widget (edit_mode_selector);
2965 mouse_mode_size_group->add_widget (*nudge_clock);
2966 mouse_mode_size_group->add_widget (nudge_forward_button);
2967 mouse_mode_size_group->add_widget (nudge_backward_button);
2969 mouse_mode_hbox->set_spacing (2);
2971 if (!ARDOUR::Profile->get_trx()) {
2972 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2975 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2976 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2978 if (!ARDOUR::Profile->get_mixbus()) {
2979 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2982 if (!ARDOUR::Profile->get_trx()) {
2983 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2984 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2985 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2986 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2989 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2991 mouse_mode_align->add (*mouse_mode_vbox);
2992 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2994 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2996 edit_mode_selector.set_name ("mouse mode button");
2998 if (!ARDOUR::Profile->get_trx()) {
2999 mode_box->pack_start (edit_mode_selector, false, false);
3001 mode_box->pack_start (*mouse_mode_box, false, false);
3003 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
3004 _mouse_mode_tearoff->set_name ("MouseModeBase");
3005 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
3007 if (Profile->get_sae() || Profile->get_mixbus() ) {
3008 _mouse_mode_tearoff->set_can_be_torn_off (false);
3011 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3012 &_mouse_mode_tearoff->tearoff_window()));
3013 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3014 &_mouse_mode_tearoff->tearoff_window(), 1));
3015 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3016 &_mouse_mode_tearoff->tearoff_window()));
3017 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3018 &_mouse_mode_tearoff->tearoff_window(), 1));
3022 _zoom_box.set_spacing (2);
3023 _zoom_box.set_border_width (2);
3027 zoom_preset_selector.set_name ("zoom button");
3028 zoom_preset_selector.set_image(::get_icon ("time_exp"));
3029 zoom_preset_selector.set_size_request (42, -1);
3031 zoom_in_button.set_name ("zoom button");
3032 zoom_in_button.set_image(::get_icon ("zoom_in"));
3033 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3034 zoom_in_button.set_related_action (act);
3036 zoom_out_button.set_name ("zoom button");
3037 zoom_out_button.set_image(::get_icon ("zoom_out"));
3038 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3039 zoom_out_button.set_related_action (act);
3041 zoom_out_full_button.set_name ("zoom button");
3042 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
3043 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3044 zoom_out_full_button.set_related_action (act);
3046 zoom_focus_selector.set_name ("zoom button");
3048 if (ARDOUR::Profile->get_mixbus()) {
3049 _zoom_box.pack_start (zoom_preset_selector, false, false);
3050 } else if (ARDOUR::Profile->get_trx()) {
3051 mode_box->pack_start (zoom_out_button, false, false);
3052 mode_box->pack_start (zoom_in_button, false, false);
3054 _zoom_box.pack_start (zoom_out_button, false, false);
3055 _zoom_box.pack_start (zoom_in_button, false, false);
3056 _zoom_box.pack_start (zoom_out_full_button, false, false);
3057 _zoom_box.pack_start (zoom_focus_selector, false, false);
3060 /* Track zoom buttons */
3061 visible_tracks_selector.set_name ("zoom button");
3062 if (Profile->get_mixbus()) {
3063 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3064 visible_tracks_selector.set_size_request (42, -1);
3066 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3069 tav_expand_button.set_name ("zoom button");
3070 tav_expand_button.set_image(::get_icon ("tav_exp"));
3071 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3072 tav_expand_button.set_related_action (act);
3074 tav_shrink_button.set_name ("zoom button");
3075 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
3076 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3077 tav_shrink_button.set_related_action (act);
3079 if (ARDOUR::Profile->get_mixbus()) {
3080 _zoom_box.pack_start (visible_tracks_selector);
3081 } else if (ARDOUR::Profile->get_trx()) {
3082 _zoom_box.pack_start (tav_shrink_button);
3083 _zoom_box.pack_start (tav_expand_button);
3085 _zoom_box.pack_start (visible_tracks_selector);
3086 _zoom_box.pack_start (tav_shrink_button);
3087 _zoom_box.pack_start (tav_expand_button);
3090 if (!ARDOUR::Profile->get_trx()) {
3091 _zoom_tearoff = manage (new TearOff (_zoom_box));
3093 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3094 &_zoom_tearoff->tearoff_window()));
3095 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3096 &_zoom_tearoff->tearoff_window(), 0));
3097 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3098 &_zoom_tearoff->tearoff_window()));
3099 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3100 &_zoom_tearoff->tearoff_window(), 0));
3103 if (Profile->get_sae() || Profile->get_mixbus() ) {
3104 _zoom_tearoff->set_can_be_torn_off (false);
3107 snap_box.set_spacing (2);
3108 snap_box.set_border_width (2);
3110 snap_type_selector.set_name ("mouse mode button");
3112 snap_delta_selector.set_name ("mouse mode button");
3113 snap_mode_selector.set_name ("mouse mode button");
3115 edit_point_selector.set_name ("mouse mode button");
3117 snap_box.pack_start (snap_delta_selector, false, false);
3118 snap_box.pack_start (snap_mode_selector, false, false);
3119 snap_box.pack_start (snap_type_selector, false, false);
3120 snap_box.pack_start (edit_point_selector, false, false);
3124 HBox *nudge_box = manage (new HBox);
3125 nudge_box->set_spacing (2);
3126 nudge_box->set_border_width (2);
3128 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3129 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3131 nudge_box->pack_start (nudge_backward_button, false, false);
3132 nudge_box->pack_start (nudge_forward_button, false, false);
3133 nudge_box->pack_start (*nudge_clock, false, false);
3136 /* Pack everything in... */
3138 HBox* hbox = manage (new HBox);
3139 hbox->set_spacing(2);
3141 _tools_tearoff = manage (new TearOff (*hbox));
3142 _tools_tearoff->set_name ("MouseModeBase");
3143 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3145 if (Profile->get_sae() || Profile->get_mixbus()) {
3146 _tools_tearoff->set_can_be_torn_off (false);
3149 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3150 &_tools_tearoff->tearoff_window()));
3151 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3152 &_tools_tearoff->tearoff_window(), 0));
3153 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3154 &_tools_tearoff->tearoff_window()));
3155 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3156 &_tools_tearoff->tearoff_window(), 0));
3158 toolbar_hbox.set_spacing (2);
3159 toolbar_hbox.set_border_width (1);
3161 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3162 if (!ARDOUR::Profile->get_trx()) {
3163 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3164 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3167 if (!ARDOUR::Profile->get_trx()) {
3168 hbox->pack_start (snap_box, false, false);
3169 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3170 hbox->pack_start (*nudge_box, false, false);
3172 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3175 hbox->pack_start (panic_box, false, false);
3179 toolbar_base.set_name ("ToolBarBase");
3180 toolbar_base.add (toolbar_hbox);
3182 _toolbar_viewport.add (toolbar_base);
3183 /* stick to the required height but allow width to vary if there's not enough room */
3184 _toolbar_viewport.set_size_request (1, -1);
3186 toolbar_frame.set_shadow_type (SHADOW_OUT);
3187 toolbar_frame.set_name ("BaseFrame");
3188 toolbar_frame.add (_toolbar_viewport);
3192 Editor::build_edit_point_menu ()
3194 using namespace Menu_Helpers;
3196 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3197 if(!Profile->get_mixbus())
3198 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3199 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3201 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3205 Editor::build_edit_mode_menu ()
3207 using namespace Menu_Helpers;
3209 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3210 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3211 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3212 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3214 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3218 Editor::build_snap_delta_menu ()
3220 using namespace Menu_Helpers;
3222 snap_delta_selector.AddMenuElem (MenuElem ( snap_delta_strings[(int)SnapAbsolute], sigc::bind (sigc::mem_fun(*this, &Editor::snap_delta_selection_done), (SnapDelta) SnapAbsolute)));
3223 snap_delta_selector.AddMenuElem (MenuElem ( snap_delta_strings[(int)SnapRelative], sigc::bind (sigc::mem_fun(*this, &Editor::snap_delta_selection_done), (SnapDelta) SnapRelative)));
3225 set_size_request_to_display_given_text (snap_delta_selector, snap_delta_strings, COMBO_TRIANGLE_WIDTH, 2);
3229 Editor::build_snap_mode_menu ()
3231 using namespace Menu_Helpers;
3233 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3234 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3235 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3237 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3241 Editor::build_snap_type_menu ()
3243 using namespace Menu_Helpers;
3245 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3246 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3247 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3248 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3249 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3250 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3251 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3252 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3253 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3254 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3255 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3256 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3257 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3258 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3259 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3260 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3261 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3262 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3263 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3264 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3265 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3266 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3267 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3268 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3269 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3270 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3271 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3272 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3273 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3274 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3276 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3281 Editor::setup_tooltips ()
3283 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Grab mode)"));
3284 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Grab Mode (select/move objects)"));
3285 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split regions)"));
3286 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select time ranges)"));
3287 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3288 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3289 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3290 ARDOUR_UI::instance()->set_tip (mouse_content_button, _("Internal Edit Mode (edit notes and gain curves inside regions)"));
3291 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3292 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3293 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3294 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3295 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3296 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3297 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3298 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3299 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3300 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3301 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3302 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3303 ARDOUR_UI::instance()->set_tip (snap_delta_selector, _("Relative Snap Mode"));
3304 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3305 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3306 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3307 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3311 Editor::convert_drop_to_paths (
3312 vector<string>& paths,
3313 const RefPtr<Gdk::DragContext>& /*context*/,
3316 const SelectionData& data,
3320 if (_session == 0) {
3324 vector<string> uris = data.get_uris();
3328 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3329 are actually URI lists. So do it by hand.
3332 if (data.get_target() != "text/plain") {
3336 /* Parse the "uri-list" format that Nautilus provides,
3337 where each pathname is delimited by \r\n.
3339 THERE MAY BE NO NULL TERMINATING CHAR!!!
3342 string txt = data.get_text();
3346 p = (char *) malloc (txt.length() + 1);
3347 txt.copy (p, txt.length(), 0);
3348 p[txt.length()] = '\0';
3354 while (g_ascii_isspace (*p))
3358 while (*q && (*q != '\n') && (*q != '\r')) {
3365 while (q > p && g_ascii_isspace (*q))
3370 uris.push_back (string (p, q - p + 1));
3374 p = strchr (p, '\n');
3386 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3387 if ((*i).substr (0,7) == "file://") {
3388 paths.push_back (Glib::filename_from_uri (*i));
3396 Editor::new_tempo_section ()
3401 Editor::map_transport_state ()
3403 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3405 if (_session && _session->transport_stopped()) {
3406 have_pending_keyboard_selection = false;
3409 update_loop_range_view ();
3415 Editor::begin_selection_op_history ()
3417 selection_op_cmd_depth = 0;
3418 selection_op_history_it = 0;
3420 while(!selection_op_history.empty()) {
3421 delete selection_op_history.front();
3422 selection_op_history.pop_front();
3425 selection_undo_action->set_sensitive (false);
3426 selection_redo_action->set_sensitive (false);
3427 selection_op_history.push_front (&_selection_memento->get_state ());
3431 Editor::begin_reversible_selection_op (string name)
3434 //cerr << name << endl;
3435 /* begin/commit pairs can be nested */
3436 selection_op_cmd_depth++;
3441 Editor::commit_reversible_selection_op ()
3444 if (selection_op_cmd_depth == 1) {
3446 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3448 The user has undone some selection ops and then made a new one,
3449 making anything earlier in the list invalid.
3452 list<XMLNode *>::iterator it = selection_op_history.begin();
3453 list<XMLNode *>::iterator e_it = it;
3454 advance (e_it, selection_op_history_it);
3456 for ( ; it != e_it; ++it) {
3459 selection_op_history.erase (selection_op_history.begin(), e_it);
3462 selection_op_history.push_front (&_selection_memento->get_state ());
3463 selection_op_history_it = 0;
3465 selection_undo_action->set_sensitive (true);
3466 selection_redo_action->set_sensitive (false);
3469 if (selection_op_cmd_depth > 0) {
3470 selection_op_cmd_depth--;
3476 Editor::undo_selection_op ()
3479 selection_op_history_it++;
3481 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3482 if (n == selection_op_history_it) {
3483 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3484 selection_redo_action->set_sensitive (true);
3488 /* is there an earlier entry? */
3489 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3490 selection_undo_action->set_sensitive (false);
3496 Editor::redo_selection_op ()
3499 if (selection_op_history_it > 0) {
3500 selection_op_history_it--;
3503 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3504 if (n == selection_op_history_it) {
3505 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3506 selection_undo_action->set_sensitive (true);
3511 if (selection_op_history_it == 0) {
3512 selection_redo_action->set_sensitive (false);
3518 Editor::begin_reversible_command (string name)
3521 before.push_back (&_selection_memento->get_state ());
3522 _session->begin_reversible_command (name);
3527 Editor::begin_reversible_command (GQuark q)
3530 before.push_back (&_selection_memento->get_state ());
3531 _session->begin_reversible_command (q);
3536 Editor::abort_reversible_command ()
3539 while(!before.empty()) {
3540 delete before.front();
3543 _session->abort_reversible_command ();
3548 Editor::commit_reversible_command ()
3551 if (before.size() == 1) {
3552 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3553 redo_action->set_sensitive(false);
3554 undo_action->set_sensitive(true);
3555 begin_selection_op_history ();
3558 if (before.empty()) {
3559 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3564 _session->commit_reversible_command ();
3569 Editor::history_changed ()
3573 if (undo_action && _session) {
3574 if (_session->undo_depth() == 0) {
3575 label = S_("Command|Undo");
3577 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3579 undo_action->property_label() = label;
3582 if (redo_action && _session) {
3583 if (_session->redo_depth() == 0) {
3586 label = string_compose(_("Redo (%1)"), _session->next_redo());
3588 redo_action->property_label() = label;
3593 Editor::duplicate_range (bool with_dialog)
3597 RegionSelection rs = get_regions_from_selection_and_entered ();
3599 if ( selection->time.length() == 0 && rs.empty()) {
3605 ArdourDialog win (_("Duplicate"));
3606 Label label (_("Number of duplications:"));
3607 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3608 SpinButton spinner (adjustment, 0.0, 1);
3611 win.get_vbox()->set_spacing (12);
3612 win.get_vbox()->pack_start (hbox);
3613 hbox.set_border_width (6);
3614 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3616 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3617 place, visually. so do this by hand.
3620 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3621 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3622 spinner.grab_focus();
3628 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3629 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3630 win.set_default_response (RESPONSE_ACCEPT);
3632 spinner.grab_focus ();
3634 switch (win.run ()) {
3635 case RESPONSE_ACCEPT:
3641 times = adjustment.get_value();
3644 if ((current_mouse_mode() == Editing::MouseRange)) {
3645 if (selection->time.length()) {
3646 duplicate_selection (times);
3648 } else if (get_smart_mode()) {
3649 if (selection->time.length()) {
3650 duplicate_selection (times);
3652 duplicate_some_regions (rs, times);
3654 duplicate_some_regions (rs, times);
3659 Editor::set_edit_mode (EditMode m)
3661 Config->set_edit_mode (m);
3665 Editor::cycle_edit_mode ()
3667 switch (Config->get_edit_mode()) {
3669 if (Profile->get_sae()) {
3670 Config->set_edit_mode (Lock);
3672 Config->set_edit_mode (Ripple);
3677 Config->set_edit_mode (Lock);
3680 Config->set_edit_mode (Slide);
3686 Editor::edit_mode_selection_done ( EditMode m )
3688 Config->set_edit_mode ( m );
3692 Editor::snap_type_selection_done (SnapType snaptype)
3694 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3696 ract->set_active ();
3701 Editor::snap_delta_selection_done (SnapDelta delta)
3703 RefPtr<RadioAction> ract = snap_delta_action (delta);
3706 ract->set_active (true);
3711 Editor::snap_mode_selection_done (SnapMode mode)
3713 RefPtr<RadioAction> ract = snap_mode_action (mode);
3716 ract->set_active (true);
3721 Editor::cycle_edit_point (bool with_marker)
3723 if(Profile->get_mixbus())
3724 with_marker = false;
3726 switch (_edit_point) {
3728 set_edit_point_preference (EditAtPlayhead);
3730 case EditAtPlayhead:
3732 set_edit_point_preference (EditAtSelectedMarker);
3734 set_edit_point_preference (EditAtMouse);
3737 case EditAtSelectedMarker:
3738 set_edit_point_preference (EditAtMouse);
3744 Editor::edit_point_selection_done (EditPoint ep)
3746 set_edit_point_preference ( ep );
3750 Editor::build_zoom_focus_menu ()
3752 using namespace Menu_Helpers;
3754 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3755 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3756 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3757 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3758 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3759 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3761 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3765 Editor::zoom_focus_selection_done ( ZoomFocus f )
3767 RefPtr<RadioAction> ract = zoom_focus_action (f);
3769 ract->set_active ();
3774 Editor::build_track_count_menu ()
3776 using namespace Menu_Helpers;
3778 if (!Profile->get_mixbus()) {
3779 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3780 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3781 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3782 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3783 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3784 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3785 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3786 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3787 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3788 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3789 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3790 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3791 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3793 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3794 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3795 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3796 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3797 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3798 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3799 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3800 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3801 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3802 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3804 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3805 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3806 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3807 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3808 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3809 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3810 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3811 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3812 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3813 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3814 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3819 Editor::set_zoom_preset (int64_t ms)
3822 temporal_zoom_session();
3826 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3827 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3831 Editor::set_visible_track_count (int32_t n)
3833 _visible_track_count = n;
3835 /* if the canvas hasn't really been allocated any size yet, just
3836 record the desired number of visible tracks and return. when canvas
3837 allocation happens, we will get called again and then we can do the
3841 if (_visible_canvas_height <= 1) {
3847 DisplaySuspender ds;
3849 if (_visible_track_count > 0) {
3850 h = trackviews_height() / _visible_track_count;
3851 std::ostringstream s;
3852 s << _visible_track_count;
3854 } else if (_visible_track_count == 0) {
3856 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3857 if ((*i)->marked_for_display()) {
3861 h = trackviews_height() / n;
3864 /* negative value means that the visible track count has
3865 been overridden by explicit track height changes.
3867 visible_tracks_selector.set_text (X_("*"));
3871 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3872 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3875 if (str != visible_tracks_selector.get_text()) {
3876 visible_tracks_selector.set_text (str);
3881 Editor::override_visible_track_count ()
3883 _visible_track_count = -1;
3884 visible_tracks_selector.set_text ( _("*") );
3888 Editor::edit_controls_button_release (GdkEventButton* ev)
3890 if (Keyboard::is_context_menu_event (ev)) {
3891 ARDOUR_UI::instance()->add_route (this);
3892 } else if (ev->button == 1) {
3893 selection->clear_tracks ();
3900 Editor::mouse_select_button_release (GdkEventButton* ev)
3902 /* this handles just right-clicks */
3904 if (ev->button != 3) {
3912 Editor::set_zoom_focus (ZoomFocus f)
3914 string str = zoom_focus_strings[(int)f];
3916 if (str != zoom_focus_selector.get_text()) {
3917 zoom_focus_selector.set_text (str);
3920 if (zoom_focus != f) {
3927 Editor::cycle_zoom_focus ()
3929 switch (zoom_focus) {
3931 set_zoom_focus (ZoomFocusRight);
3933 case ZoomFocusRight:
3934 set_zoom_focus (ZoomFocusCenter);
3936 case ZoomFocusCenter:
3937 set_zoom_focus (ZoomFocusPlayhead);
3939 case ZoomFocusPlayhead:
3940 set_zoom_focus (ZoomFocusMouse);
3942 case ZoomFocusMouse:
3943 set_zoom_focus (ZoomFocusEdit);
3946 set_zoom_focus (ZoomFocusLeft);
3952 Editor::ensure_float (Window& win)
3954 win.set_transient_for (*this);
3958 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3960 /* recover or initialize pane positions. do this here rather than earlier because
3961 we don't want the positions to change the child allocations, which they seem to do.
3967 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3976 XMLNode* geometry = find_named_node (*node, "geometry");
3978 if (which == static_cast<Paned*> (&edit_pane)) {
3980 if (done & Horizontal) {
3984 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3985 _notebook_shrunk = string_is_affirmative (prop->value ());
3988 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3989 /* initial allocation is 90% to canvas, 10% to notebook */
3990 pos = (int) floor (alloc.get_width() * 0.90f);
3991 snprintf (buf, sizeof(buf), "%d", pos);
3993 pos = atoi (prop->value());
3996 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3997 edit_pane.set_position (pos);
4000 done = (Pane) (done | Horizontal);
4002 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
4004 if (done & Vertical) {
4008 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
4009 /* initial allocation is 90% to canvas, 10% to summary */
4010 pos = (int) floor (alloc.get_height() * 0.90f);
4011 snprintf (buf, sizeof(buf), "%d", pos);
4014 pos = atoi (prop->value());
4017 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
4018 editor_summary_pane.set_position (pos);
4021 done = (Pane) (done | Vertical);
4026 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
4028 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
4029 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
4030 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
4031 top_hbox.remove (toolbar_frame);
4036 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
4038 if (toolbar_frame.get_parent() == 0) {
4039 top_hbox.pack_end (toolbar_frame);
4044 Editor::set_show_measures (bool yn)
4046 if (_show_measures != yn) {
4049 if ((_show_measures = yn) == true) {
4051 tempo_lines->show();
4054 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
4055 ARDOUR::TempoMap::BBTPointList::const_iterator end;
4057 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
4058 draw_measures (begin, end);
4066 Editor::toggle_follow_playhead ()
4068 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
4070 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4071 set_follow_playhead (tact->get_active());
4075 /** @param yn true to follow playhead, otherwise false.
4076 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4079 Editor::set_follow_playhead (bool yn, bool catch_up)
4081 if (_follow_playhead != yn) {
4082 if ((_follow_playhead = yn) == true && catch_up) {
4084 reset_x_origin_to_follow_playhead ();
4091 Editor::toggle_stationary_playhead ()
4093 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4095 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4096 set_stationary_playhead (tact->get_active());
4101 Editor::set_stationary_playhead (bool yn)
4103 if (_stationary_playhead != yn) {
4104 if ((_stationary_playhead = yn) == true) {
4106 // FIXME need a 3.0 equivalent of this 2.X call
4107 // update_current_screen ();
4114 Editor::playlist_selector () const
4116 return *_playlist_selector;
4120 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4122 if (paste_count == 0) {
4123 /* don't bother calculating an offset that will be zero anyway */
4127 /* calculate basic unsnapped multi-paste offset */
4128 framecnt_t offset = paste_count * duration;
4130 /* snap offset so pos + offset is aligned to the grid */
4131 framepos_t offset_pos = pos + offset;
4132 snap_to(offset_pos, RoundUpMaybe);
4133 offset = offset_pos - pos;
4139 Editor::get_grid_beat_divisions(framepos_t position)
4141 switch (_snap_type) {
4142 case SnapToBeatDiv128: return 128;
4143 case SnapToBeatDiv64: return 64;
4144 case SnapToBeatDiv32: return 32;
4145 case SnapToBeatDiv28: return 28;
4146 case SnapToBeatDiv24: return 24;
4147 case SnapToBeatDiv20: return 20;
4148 case SnapToBeatDiv16: return 16;
4149 case SnapToBeatDiv14: return 14;
4150 case SnapToBeatDiv12: return 12;
4151 case SnapToBeatDiv10: return 10;
4152 case SnapToBeatDiv8: return 8;
4153 case SnapToBeatDiv7: return 7;
4154 case SnapToBeatDiv6: return 6;
4155 case SnapToBeatDiv5: return 5;
4156 case SnapToBeatDiv4: return 4;
4157 case SnapToBeatDiv3: return 3;
4158 case SnapToBeatDiv2: return 2;
4165 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4169 const unsigned divisions = get_grid_beat_divisions(position);
4171 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4174 switch (_snap_type) {
4176 return Evoral::Beats(1.0);
4179 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
4187 return Evoral::Beats();
4191 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4195 ret = nudge_clock->current_duration (pos);
4196 next = ret + 1; /* XXXX fix me */
4202 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4204 ArdourDialog dialog (_("Playlist Deletion"));
4205 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4206 "If it is kept, its audio files will not be cleaned.\n"
4207 "If it is deleted, audio files used by it alone will be cleaned."),
4210 dialog.set_position (WIN_POS_CENTER);
4211 dialog.get_vbox()->pack_start (label);
4215 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4216 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4217 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4219 switch (dialog.run ()) {
4220 case RESPONSE_ACCEPT:
4221 /* delete the playlist */
4225 case RESPONSE_REJECT:
4226 /* keep the playlist */
4238 Editor::audio_region_selection_covers (framepos_t where)
4240 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4241 if ((*a)->region()->covers (where)) {
4250 Editor::prepare_for_cleanup ()
4252 cut_buffer->clear_regions ();
4253 cut_buffer->clear_playlists ();
4255 selection->clear_regions ();
4256 selection->clear_playlists ();
4258 _regions->suspend_redisplay ();
4262 Editor::finish_cleanup ()
4264 _regions->resume_redisplay ();
4268 Editor::transport_loop_location()
4271 return _session->locations()->auto_loop_location();
4278 Editor::transport_punch_location()
4281 return _session->locations()->auto_punch_location();
4288 Editor::control_layout_scroll (GdkEventScroll* ev)
4290 /* Just forward to the normal canvas scroll method. The coordinate
4291 systems are different but since the canvas is always larger than the
4292 track headers, and aligned with the trackview area, this will work.
4294 In the not too distant future this layout is going away anyway and
4295 headers will be on the canvas.
4297 return canvas_scroll_event (ev, false);
4301 Editor::session_state_saved (string)
4304 _snapshots->redisplay ();
4308 Editor::update_tearoff_visibility()
4310 bool visible = ARDOUR_UI::config()->get_keep_tearoffs();
4311 _mouse_mode_tearoff->set_visible (visible);
4312 _tools_tearoff->set_visible (visible);
4313 if (_zoom_tearoff) {
4314 _zoom_tearoff->set_visible (visible);
4319 Editor::reattach_all_tearoffs ()
4321 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4322 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4323 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4327 Editor::maximise_editing_space ()
4339 Editor::restore_editing_space ()
4351 * Make new playlists for a given track and also any others that belong
4352 * to the same active route group with the `select' property.
4357 Editor::new_playlists (TimeAxisView* v)
4359 begin_reversible_command (_("new playlists"));
4360 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4361 _session->playlists->get (playlists);
4362 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4363 commit_reversible_command ();
4367 * Use a copy of the current playlist for a given track and also any others that belong
4368 * to the same active route group with the `select' property.
4373 Editor::copy_playlists (TimeAxisView* v)
4375 begin_reversible_command (_("copy playlists"));
4376 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4377 _session->playlists->get (playlists);
4378 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4379 commit_reversible_command ();
4382 /** Clear the current playlist for a given track and also any others that belong
4383 * to the same active route group with the `select' property.
4388 Editor::clear_playlists (TimeAxisView* v)
4390 begin_reversible_command (_("clear playlists"));
4391 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4392 _session->playlists->get (playlists);
4393 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4394 commit_reversible_command ();
4398 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4400 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4404 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4406 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4410 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4412 atv.clear_playlist ();
4416 Editor::on_key_press_event (GdkEventKey* ev)
4418 return key_press_focus_accelerator_handler (*this, ev);
4422 Editor::on_key_release_event (GdkEventKey* ev)
4424 return Gtk::Window::on_key_release_event (ev);
4425 // return key_press_focus_accelerator_handler (*this, ev);
4429 Editor::get_y_origin () const
4431 return vertical_adjustment.get_value ();
4434 /** Queue up a change to the viewport x origin.
4435 * @param frame New x origin.
4438 Editor::reset_x_origin (framepos_t frame)
4440 pending_visual_change.add (VisualChange::TimeOrigin);
4441 pending_visual_change.time_origin = frame;
4442 ensure_visual_change_idle_handler ();
4446 Editor::reset_y_origin (double y)
4448 pending_visual_change.add (VisualChange::YOrigin);
4449 pending_visual_change.y_origin = y;
4450 ensure_visual_change_idle_handler ();
4454 Editor::reset_zoom (framecnt_t spp)
4456 if (spp == samples_per_pixel) {
4460 pending_visual_change.add (VisualChange::ZoomLevel);
4461 pending_visual_change.samples_per_pixel = spp;
4462 ensure_visual_change_idle_handler ();
4466 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4468 reset_x_origin (frame);
4471 if (!no_save_visual) {
4472 undo_visual_stack.push_back (current_visual_state(false));
4476 Editor::VisualState::VisualState (bool with_tracks)
4477 : gui_state (with_tracks ? new GUIObjectState : 0)
4481 Editor::VisualState::~VisualState ()
4486 Editor::VisualState*
4487 Editor::current_visual_state (bool with_tracks)
4489 VisualState* vs = new VisualState (with_tracks);
4490 vs->y_position = vertical_adjustment.get_value();
4491 vs->samples_per_pixel = samples_per_pixel;
4492 vs->leftmost_frame = leftmost_frame;
4493 vs->zoom_focus = zoom_focus;
4496 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4503 Editor::undo_visual_state ()
4505 if (undo_visual_stack.empty()) {
4509 VisualState* vs = undo_visual_stack.back();
4510 undo_visual_stack.pop_back();
4513 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4516 use_visual_state (*vs);
4521 Editor::redo_visual_state ()
4523 if (redo_visual_stack.empty()) {
4527 VisualState* vs = redo_visual_stack.back();
4528 redo_visual_stack.pop_back();
4530 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4531 // why do we check here?
4532 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4535 use_visual_state (*vs);
4540 Editor::swap_visual_state ()
4542 if (undo_visual_stack.empty()) {
4543 redo_visual_state ();
4545 undo_visual_state ();
4550 Editor::use_visual_state (VisualState& vs)
4552 PBD::Unwinder<bool> nsv (no_save_visual, true);
4553 DisplaySuspender ds;
4555 vertical_adjustment.set_value (vs.y_position);
4557 set_zoom_focus (vs.zoom_focus);
4558 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4561 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4563 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4564 (*i)->clear_property_cache();
4565 (*i)->reset_visual_state ();
4569 _routes->update_visibility ();
4572 /** This is the core function that controls the zoom level of the canvas. It is called
4573 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4574 * @param spp new number of samples per pixel
4577 Editor::set_samples_per_pixel (framecnt_t spp)
4583 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4584 const framecnt_t lots_of_pixels = 4000;
4586 /* if the zoom level is greater than what you'd get trying to display 3
4587 * days of audio on a really big screen, then it's too big.
4590 if (spp * lots_of_pixels > three_days) {
4594 samples_per_pixel = spp;
4597 tempo_lines->tempo_map_changed();
4600 bool const showing_time_selection = selection->time.length() > 0;
4602 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4603 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4604 (*i)->reshow_selection (selection->time);
4608 ZoomChanged (); /* EMIT_SIGNAL */
4610 ArdourCanvas::GtkCanvasViewport* c;
4612 c = get_track_canvas();
4614 c->canvas()->zoomed ();
4617 if (playhead_cursor) {
4618 playhead_cursor->set_position (playhead_cursor->current_frame ());
4621 refresh_location_display();
4622 _summary->set_overlays_dirty ();
4624 update_marker_labels ();
4630 Editor::queue_visual_videotimeline_update ()
4633 * pending_visual_change.add (VisualChange::VideoTimeline);
4634 * or maybe even more specific: which videotimeline-image
4635 * currently it calls update_video_timeline() to update
4636 * _all outdated_ images on the video-timeline.
4637 * see 'exposeimg()' in video_image_frame.cc
4639 ensure_visual_change_idle_handler ();
4643 Editor::ensure_visual_change_idle_handler ()
4645 if (pending_visual_change.idle_handler_id < 0) {
4646 // see comment in add_to_idle_resize above.
4647 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4648 pending_visual_change.being_handled = false;
4653 Editor::_idle_visual_changer (void* arg)
4655 return static_cast<Editor*>(arg)->idle_visual_changer ();
4659 Editor::idle_visual_changer ()
4661 /* set_horizontal_position() below (and maybe other calls) call
4662 gtk_main_iteration(), so it's possible that a signal will be handled
4663 half-way through this method. If this signal wants an
4664 idle_visual_changer we must schedule another one after this one, so
4665 mark the idle_handler_id as -1 here to allow that. Also make a note
4666 that we are doing the visual change, so that changes in response to
4667 super-rapid-screen-update can be dropped if we are still processing
4671 pending_visual_change.idle_handler_id = -1;
4672 pending_visual_change.being_handled = true;
4674 VisualChange vc = pending_visual_change;
4676 pending_visual_change.pending = (VisualChange::Type) 0;
4678 visual_changer (vc);
4680 pending_visual_change.being_handled = false;
4682 return 0; /* this is always a one-shot call */
4686 Editor::visual_changer (const VisualChange& vc)
4688 double const last_time_origin = horizontal_position ();
4690 if (vc.pending & VisualChange::ZoomLevel) {
4691 set_samples_per_pixel (vc.samples_per_pixel);
4693 compute_fixed_ruler_scale ();
4695 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4696 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4698 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4699 current_bbt_points_begin, current_bbt_points_end);
4700 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4701 current_bbt_points_begin, current_bbt_points_end);
4702 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4704 update_video_timeline();
4707 if (vc.pending & VisualChange::TimeOrigin) {
4708 set_horizontal_position (vc.time_origin / samples_per_pixel);
4711 if (vc.pending & VisualChange::YOrigin) {
4712 vertical_adjustment.set_value (vc.y_origin);
4715 if (last_time_origin == horizontal_position ()) {
4716 /* changed signal not emitted */
4717 update_fixed_rulers ();
4718 redisplay_tempo (true);
4721 if (!(vc.pending & VisualChange::ZoomLevel)) {
4722 update_video_timeline();
4725 _summary->set_overlays_dirty ();
4728 struct EditorOrderTimeAxisSorter {
4729 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4730 return a->order () < b->order ();
4735 Editor::sort_track_selection (TrackViewList& sel)
4737 EditorOrderTimeAxisSorter cmp;
4742 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4745 framepos_t where = 0;
4746 EditPoint ep = _edit_point;
4748 if (Profile->get_mixbus())
4749 if (ep == EditAtSelectedMarker)
4750 ep = EditAtPlayhead;
4752 if (from_outside_canvas && (ep == EditAtMouse)) {
4753 ep = EditAtPlayhead;
4754 } else if (from_context_menu && (ep == EditAtMouse)) {
4755 return canvas_event_sample (&context_click_event, 0, 0);
4758 if (entered_marker) {
4759 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4760 return entered_marker->position();
4763 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4764 ep = EditAtSelectedMarker;
4767 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4768 ep = EditAtPlayhead;
4772 case EditAtPlayhead:
4773 if (_dragging_playhead) {
4774 if (!mouse_frame (where, ignored)) {
4775 /* XXX not right but what can we do ? */
4779 where = _session->audible_frame();
4781 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4784 case EditAtSelectedMarker:
4785 if (!selection->markers.empty()) {
4787 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4790 where = loc->start();
4794 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4802 if (!mouse_frame (where, ignored)) {
4803 /* XXX not right but what can we do ? */
4807 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4815 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4817 if (!_session) return;
4819 begin_reversible_command (cmd);
4823 if ((tll = transport_loop_location()) == 0) {
4824 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4825 XMLNode &before = _session->locations()->get_state();
4826 _session->locations()->add (loc, true);
4827 _session->set_auto_loop_location (loc);
4828 XMLNode &after = _session->locations()->get_state();
4829 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4831 XMLNode &before = tll->get_state();
4832 tll->set_hidden (false, this);
4833 tll->set (start, end);
4834 XMLNode &after = tll->get_state();
4835 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4838 commit_reversible_command ();
4842 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4844 if (!_session) return;
4846 begin_reversible_command (cmd);
4850 if ((tpl = transport_punch_location()) == 0) {
4851 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4852 XMLNode &before = _session->locations()->get_state();
4853 _session->locations()->add (loc, true);
4854 _session->set_auto_punch_location (loc);
4855 XMLNode &after = _session->locations()->get_state();
4856 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4858 XMLNode &before = tpl->get_state();
4859 tpl->set_hidden (false, this);
4860 tpl->set (start, end);
4861 XMLNode &after = tpl->get_state();
4862 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4865 commit_reversible_command ();
4868 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4869 * @param rs List to which found regions are added.
4870 * @param where Time to look at.
4871 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4874 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4876 const TrackViewList* tracks;
4879 tracks = &track_views;
4884 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4886 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4889 boost::shared_ptr<Track> tr;
4890 boost::shared_ptr<Playlist> pl;
4892 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4894 boost::shared_ptr<RegionList> regions = pl->regions_at (
4895 (framepos_t) floor ( (double) where * tr->speed()));
4897 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4898 RegionView* rv = rtv->view()->find_view (*i);
4909 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4911 const TrackViewList* tracks;
4914 tracks = &track_views;
4919 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4920 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4922 boost::shared_ptr<Track> tr;
4923 boost::shared_ptr<Playlist> pl;
4925 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4927 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4928 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4930 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4932 RegionView* rv = rtv->view()->find_view (*i);
4943 /** Get regions using the following method:
4945 * Make a region list using:
4946 * (a) any selected regions
4947 * (b) the intersection of any selected tracks and the edit point(*)
4948 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4950 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4952 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4956 Editor::get_regions_from_selection_and_edit_point ()
4958 RegionSelection regions;
4960 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4961 regions.add (entered_regionview);
4963 regions = selection->regions;
4966 if ( regions.empty() ) {
4967 TrackViewList tracks = selection->tracks;
4969 if (!tracks.empty()) {
4970 /* no region selected or entered, but some selected tracks:
4971 * act on all regions on the selected tracks at the edit point
4973 framepos_t const where = get_preferred_edit_position ();
4974 get_regions_at(regions, where, tracks);
4981 /** Get regions using the following method:
4983 * Make a region list using:
4984 * (a) any selected regions
4985 * (b) the intersection of any selected tracks and the edit point(*)
4986 * (c) if neither exists, then whatever region is under the mouse
4988 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4990 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4993 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4995 RegionSelection regions;
4997 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4998 regions.add (entered_regionview);
5000 regions = selection->regions;
5003 if ( regions.empty() ) {
5004 TrackViewList tracks = selection->tracks;
5006 if (!tracks.empty()) {
5007 /* no region selected or entered, but some selected tracks:
5008 * act on all regions on the selected tracks at the edit point
5010 get_regions_at(regions, pos, tracks);
5017 /** Start with regions that are selected, or the entered regionview if none are selected.
5018 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
5019 * of the regions that we started with.
5023 Editor::get_regions_from_selection_and_entered ()
5025 RegionSelection regions = selection->regions;
5027 if (regions.empty() && entered_regionview) {
5028 regions.add (entered_regionview);
5035 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
5037 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5038 RouteTimeAxisView* rtav;
5040 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5041 boost::shared_ptr<Playlist> pl;
5042 std::vector<boost::shared_ptr<Region> > results;
5043 boost::shared_ptr<Track> tr;
5045 if ((tr = rtav->track()) == 0) {
5050 if ((pl = (tr->playlist())) != 0) {
5051 boost::shared_ptr<Region> r = pl->region_by_id (id);
5053 RegionView* rv = rtav->view()->find_view (r);
5055 regions.push_back (rv);
5064 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5067 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5068 MidiTimeAxisView* mtav;
5070 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5072 mtav->get_per_region_note_selection (selection);
5079 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5081 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5083 RouteTimeAxisView* tatv;
5085 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5087 boost::shared_ptr<Playlist> pl;
5088 vector<boost::shared_ptr<Region> > results;
5090 boost::shared_ptr<Track> tr;
5092 if ((tr = tatv->track()) == 0) {
5097 if ((pl = (tr->playlist())) != 0) {
5098 if (src_comparison) {
5099 pl->get_source_equivalent_regions (region, results);
5101 pl->get_region_list_equivalent_regions (region, results);
5105 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5106 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5107 regions.push_back (marv);
5116 Editor::show_rhythm_ferret ()
5118 if (rhythm_ferret == 0) {
5119 rhythm_ferret = new RhythmFerret(*this);
5122 rhythm_ferret->set_session (_session);
5123 rhythm_ferret->show ();
5124 rhythm_ferret->present ();
5128 Editor::first_idle ()
5130 MessageDialog* dialog = 0;
5132 if (track_views.size() > 1) {
5133 dialog = new MessageDialog (
5135 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5139 ARDOUR_UI::instance()->flush_pending ();
5142 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5146 // first idle adds route children (automation tracks), so we need to redisplay here
5147 _routes->redisplay ();
5151 if (_session->undo_depth() == 0) {
5152 undo_action->set_sensitive(false);
5154 redo_action->set_sensitive(false);
5155 begin_selection_op_history ();
5161 Editor::_idle_resize (gpointer arg)
5163 return ((Editor*)arg)->idle_resize ();
5167 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5169 if (resize_idle_id < 0) {
5170 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5171 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5172 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5174 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5175 _pending_resize_amount = 0;
5178 /* make a note of the smallest resulting height, so that we can clamp the
5179 lower limit at TimeAxisView::hSmall */
5181 int32_t min_resulting = INT32_MAX;
5183 _pending_resize_amount += h;
5184 _pending_resize_view = view;
5186 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5188 if (selection->tracks.contains (_pending_resize_view)) {
5189 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5190 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5194 if (min_resulting < 0) {
5199 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5200 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5204 /** Handle pending resizing of tracks */
5206 Editor::idle_resize ()
5208 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5210 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5211 selection->tracks.contains (_pending_resize_view)) {
5213 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5214 if (*i != _pending_resize_view) {
5215 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5220 _pending_resize_amount = 0;
5221 _group_tabs->set_dirty ();
5222 resize_idle_id = -1;
5230 ENSURE_GUI_THREAD (*this, &Editor::located);
5233 playhead_cursor->set_position (_session->audible_frame ());
5234 if (_follow_playhead && !_pending_initial_locate) {
5235 reset_x_origin_to_follow_playhead ();
5239 _pending_locate_request = false;
5240 _pending_initial_locate = false;
5244 Editor::region_view_added (RegionView * rv)
5246 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5247 if (rv->region ()->id () == (*pr)) {
5248 selection->add (rv);
5249 selection->regions.pending.erase (pr);
5254 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5256 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5257 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5258 if (rv->region()->id () == (*rnote).first) {
5259 mrv->select_notes ((*rnote).second);
5260 selection->pending_midi_note_selection.erase(rnote);
5266 _summary->set_background_dirty ();
5270 Editor::region_view_removed ()
5272 _summary->set_background_dirty ();
5276 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5278 TrackViewList::const_iterator j = track_views.begin ();
5279 while (j != track_views.end()) {
5280 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5281 if (rtv && rtv->route() == r) {
5292 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5296 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5297 TimeAxisView* tv = axis_view_from_route (*i);
5307 Editor::suspend_route_redisplay ()
5310 _routes->suspend_redisplay();
5315 Editor::resume_route_redisplay ()
5318 _routes->redisplay(); // queue redisplay
5319 _routes->resume_redisplay();
5324 Editor::add_routes (RouteList& routes)
5326 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5328 RouteTimeAxisView *rtv;
5329 list<RouteTimeAxisView*> new_views;
5330 TrackViewList new_selection;
5331 bool from_scratch = (track_views.size() == 0);
5333 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5334 boost::shared_ptr<Route> route = (*x);
5336 if (route->is_auditioner() || route->is_monitor()) {
5340 DataType dt = route->input()->default_type();
5342 if (dt == ARDOUR::DataType::AUDIO) {
5343 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5344 rtv->set_route (route);
5345 } else if (dt == ARDOUR::DataType::MIDI) {
5346 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5347 rtv->set_route (route);
5349 throw unknown_type();
5352 new_views.push_back (rtv);
5353 track_views.push_back (rtv);
5354 new_selection.push_back (rtv);
5356 rtv->effective_gain_display ();
5358 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5359 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5362 if (new_views.size() > 0) {
5363 _routes->routes_added (new_views);
5364 _summary->routes_added (new_views);
5367 if (!from_scratch) {
5368 selection->tracks.clear();
5369 selection->add (new_selection);
5370 begin_selection_op_history();
5373 if (show_editor_mixer_when_tracks_arrive) {
5374 show_editor_mixer (true);
5377 editor_list_button.set_sensitive (true);
5381 Editor::timeaxisview_deleted (TimeAxisView *tv)
5383 if (tv == entered_track) {
5387 if (_session && _session->deletion_in_progress()) {
5388 /* the situation is under control */
5392 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5394 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5396 _routes->route_removed (tv);
5398 TimeAxisView::Children c = tv->get_child_list ();
5399 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5400 if (entered_track == i->get()) {
5405 /* remove it from the list of track views */
5407 TrackViewList::iterator i;
5409 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5410 i = track_views.erase (i);
5413 /* update whatever the current mixer strip is displaying, if revelant */
5415 boost::shared_ptr<Route> route;
5418 route = rtav->route ();
5421 if (current_mixer_strip && current_mixer_strip->route() == route) {
5423 TimeAxisView* next_tv;
5425 if (track_views.empty()) {
5427 } else if (i == track_views.end()) {
5428 next_tv = track_views.front();
5435 set_selected_mixer_strip (*next_tv);
5437 /* make the editor mixer strip go away setting the
5438 * button to inactive (which also unticks the menu option)
5441 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5447 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5449 if (apply_to_selection) {
5450 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5452 TrackSelection::iterator j = i;
5455 hide_track_in_display (*i, false);
5460 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5462 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5463 // this will hide the mixer strip
5464 set_selected_mixer_strip (*tv);
5467 _routes->hide_track_in_display (*tv);
5472 Editor::sync_track_view_list_and_routes ()
5474 track_views = TrackViewList (_routes->views ());
5476 _summary->set_dirty ();
5477 _group_tabs->set_dirty ();
5479 return false; // do not call again (until needed)
5483 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5485 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5490 /** Find a RouteTimeAxisView by the ID of its route */
5492 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5494 RouteTimeAxisView* v;
5496 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5497 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5498 if(v->route()->id() == id) {
5508 Editor::fit_route_group (RouteGroup *g)
5510 TrackViewList ts = axis_views_from_routes (g->route_list ());
5515 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5517 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5520 _session->cancel_audition ();
5524 if (_session->is_auditioning()) {
5525 _session->cancel_audition ();
5526 if (r == last_audition_region) {
5531 _session->audition_region (r);
5532 last_audition_region = r;
5537 Editor::hide_a_region (boost::shared_ptr<Region> r)
5539 r->set_hidden (true);
5543 Editor::show_a_region (boost::shared_ptr<Region> r)
5545 r->set_hidden (false);
5549 Editor::audition_region_from_region_list ()
5551 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5555 Editor::hide_region_from_region_list ()
5557 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5561 Editor::show_region_in_region_list ()
5563 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5567 Editor::step_edit_status_change (bool yn)
5570 start_step_editing ();
5572 stop_step_editing ();
5577 Editor::start_step_editing ()
5579 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5583 Editor::stop_step_editing ()
5585 step_edit_connection.disconnect ();
5589 Editor::check_step_edit ()
5591 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5592 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5594 mtv->check_step_edit ();
5598 return true; // do it again, till we stop
5602 Editor::scroll_press (Direction dir)
5604 ++_scroll_callbacks;
5606 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5607 /* delay the first auto-repeat */
5613 scroll_backward (1);
5621 scroll_up_one_track ();
5625 scroll_down_one_track ();
5629 /* do hacky auto-repeat */
5630 if (!_scroll_connection.connected ()) {
5632 _scroll_connection = Glib::signal_timeout().connect (
5633 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5636 _scroll_callbacks = 0;
5643 Editor::scroll_release ()
5645 _scroll_connection.disconnect ();
5648 /** Queue a change for the Editor viewport x origin to follow the playhead */
5650 Editor::reset_x_origin_to_follow_playhead ()
5652 framepos_t const frame = playhead_cursor->current_frame ();
5654 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5656 if (_session->transport_speed() < 0) {
5658 if (frame > (current_page_samples() / 2)) {
5659 center_screen (frame-(current_page_samples()/2));
5661 center_screen (current_page_samples()/2);
5668 if (frame < leftmost_frame) {
5670 if (_session->transport_rolling()) {
5671 /* rolling; end up with the playhead at the right of the page */
5672 l = frame - current_page_samples ();
5674 /* not rolling: end up with the playhead 1/4 of the way along the page */
5675 l = frame - current_page_samples() / 4;
5679 if (_session->transport_rolling()) {
5680 /* rolling: end up with the playhead on the left of the page */
5683 /* not rolling: end up with the playhead 3/4 of the way along the page */
5684 l = frame - 3 * current_page_samples() / 4;
5692 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5698 Editor::super_rapid_screen_update ()
5700 if (!_session || !_session->engine().running()) {
5704 /* METERING / MIXER STRIPS */
5706 /* update track meters, if required */
5707 if (is_mapped() && meters_running) {
5708 RouteTimeAxisView* rtv;
5709 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5710 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5711 rtv->fast_update ();
5716 /* and any current mixer strip */
5717 if (current_mixer_strip) {
5718 current_mixer_strip->fast_update ();
5721 /* PLAYHEAD AND VIEWPORT */
5723 framepos_t const frame = _session->audible_frame();
5725 /* There are a few reasons why we might not update the playhead / viewport stuff:
5727 * 1. we don't update things when there's a pending locate request, otherwise
5728 * when the editor requests a locate there is a chance that this method
5729 * will move the playhead before the locate request is processed, causing
5731 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5732 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5735 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5737 last_update_frame = frame;
5739 if (!_dragging_playhead) {
5740 playhead_cursor->set_position (frame);
5743 if (!_stationary_playhead) {
5745 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5746 /* We only do this if we aren't already
5747 handling a visual change (ie if
5748 pending_visual_change.being_handled is
5749 false) so that these requests don't stack
5750 up there are too many of them to handle in
5753 reset_x_origin_to_follow_playhead ();
5758 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5762 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5763 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5764 if (target <= 0.0) {
5767 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5768 target = (target * 0.15) + (current * 0.85);
5774 set_horizontal_position (current);
5783 Editor::session_going_away ()
5785 _have_idled = false;
5787 _session_connections.drop_connections ();
5789 super_rapid_screen_update_connection.disconnect ();
5791 selection->clear ();
5792 cut_buffer->clear ();
5794 clicked_regionview = 0;
5795 clicked_axisview = 0;
5796 clicked_routeview = 0;
5797 entered_regionview = 0;
5799 last_update_frame = 0;
5802 playhead_cursor->hide ();
5804 /* rip everything out of the list displays */
5808 _route_groups->clear ();
5810 /* do this first so that deleting a track doesn't reset cms to null
5811 and thus cause a leak.
5814 if (current_mixer_strip) {
5815 if (current_mixer_strip->get_parent() != 0) {
5816 global_hpacker.remove (*current_mixer_strip);
5818 delete current_mixer_strip;
5819 current_mixer_strip = 0;
5822 /* delete all trackviews */
5824 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5827 track_views.clear ();
5829 nudge_clock->set_session (0);
5831 editor_list_button.set_active(false);
5832 editor_list_button.set_sensitive(false);
5834 /* clear tempo/meter rulers */
5835 remove_metric_marks ();
5837 clear_marker_display ();
5839 stop_step_editing ();
5841 /* get rid of any existing editor mixer strip */
5843 WindowTitle title(Glib::get_application_name());
5844 title += _("Editor");
5846 set_title (title.get_string());
5848 SessionHandlePtr::session_going_away ();
5853 Editor::show_editor_list (bool yn)
5856 _the_notebook.show ();
5858 _the_notebook.hide ();
5863 Editor::change_region_layering_order (bool from_context_menu)
5865 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5867 if (!clicked_routeview) {
5868 if (layering_order_editor) {
5869 layering_order_editor->hide ();
5874 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5880 boost::shared_ptr<Playlist> pl = track->playlist();
5886 if (layering_order_editor == 0) {
5887 layering_order_editor = new RegionLayeringOrderEditor (*this);
5890 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5891 layering_order_editor->maybe_present ();
5895 Editor::update_region_layering_order_editor ()
5897 if (layering_order_editor && layering_order_editor->is_visible ()) {
5898 change_region_layering_order (true);
5903 Editor::setup_fade_images ()
5905 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5906 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5907 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5908 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5909 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5911 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5912 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5913 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5914 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5915 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5917 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5918 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5919 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5920 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5921 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5923 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5924 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5925 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5926 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5927 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5931 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5933 Editor::action_menu_item (std::string const & name)
5935 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5938 return *manage (a->create_menu_item ());
5942 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5944 EventBox* b = manage (new EventBox);
5945 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5946 Label* l = manage (new Label (name));
5950 _the_notebook.append_page (widget, *b);
5954 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5956 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5957 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5960 if (ev->type == GDK_2BUTTON_PRESS) {
5962 /* double-click on a notebook tab shrinks or expands the notebook */
5964 if (_notebook_shrunk) {
5965 if (pre_notebook_shrink_pane_width) {
5966 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5968 _notebook_shrunk = false;
5970 pre_notebook_shrink_pane_width = edit_pane.get_position();
5972 /* this expands the LHS of the edit pane to cover the notebook
5973 PAGE but leaves the tabs visible.
5975 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5976 _notebook_shrunk = true;
5984 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5986 using namespace Menu_Helpers;
5988 MenuList& items = _control_point_context_menu.items ();
5991 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5992 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5993 if (!can_remove_control_point (item)) {
5994 items.back().set_sensitive (false);
5997 _control_point_context_menu.popup (event->button.button, event->button.time);
6001 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6003 using namespace Menu_Helpers;
6005 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6010 /* We need to get the selection here and pass it to the operations, since
6011 popping up the menu will cause a region leave event which clears
6012 entered_regionview. */
6014 MidiRegionView& mrv = note->region_view();
6015 const RegionSelection rs = get_regions_from_selection_and_entered ();
6017 MenuList& items = _note_context_menu.items();
6020 items.push_back(MenuElem(_("Delete"),
6021 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6022 items.push_back(MenuElem(_("Edit..."),
6023 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6024 items.push_back(MenuElem(_("Legatize"),
6025 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6026 items.push_back(MenuElem(_("Quantize..."),
6027 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6028 items.push_back(MenuElem(_("Remove Overlap"),
6029 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6030 items.push_back(MenuElem(_("Transform..."),
6031 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6033 _note_context_menu.popup (event->button.button, event->button.time);
6037 Editor::zoom_vertical_modifier_released()
6039 _stepping_axis_view = 0;
6043 Editor::ui_parameter_changed (string parameter)
6045 if (parameter == "icon-set") {
6046 while (!_cursor_stack.empty()) {
6047 _cursor_stack.pop_back();
6049 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
6050 _cursor_stack.push_back(_cursors->grabber);
6051 } else if (parameter == "draggable-playhead") {
6052 if (_verbose_cursor) {
6053 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());