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/location.h"
72 #include "ardour/profile.h"
73 #include "ardour/route_group.h"
74 #include "ardour/session_playlists.h"
75 #include "ardour/tempo.h"
76 #include "ardour/utils.h"
78 #include "canvas/debug.h"
79 #include "canvas/text.h"
81 #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_time_axis.h"
111 #include "mixer_strip.h"
112 #include "mixer_ui.h"
113 #include "mouse_cursors.h"
114 #include "playlist_selector.h"
115 #include "public_editor.h"
116 #include "region_layering_order_editor.h"
117 #include "rgb_macros.h"
118 #include "rhythm_ferret.h"
119 #include "selection.h"
121 #include "tempo_lines.h"
122 #include "time_axis_view.h"
124 #include "verbose_cursor.h"
129 using namespace ARDOUR;
130 using namespace ARDOUR_UI_UTILS;
133 using namespace Glib;
134 using namespace Gtkmm2ext;
135 using namespace Editing;
137 using PBD::internationalize;
139 using Gtkmm2ext::Keyboard;
141 const double Editor::timebar_height = 15.0;
143 static const gchar *_snap_type_strings[] = {
177 static const gchar *_snap_mode_strings[] = {
184 static const gchar *_edit_point_strings[] = {
191 static const gchar *_edit_mode_strings[] = {
199 static const gchar *_zoom_focus_strings[] = {
209 #ifdef USE_RUBBERBAND
210 static const gchar *_rb_opt_strings[] = {
213 N_("Balanced multitimbral mixture"),
214 N_("Unpitched percussion with stable notes"),
215 N_("Crisp monophonic instrumental"),
216 N_("Unpitched solo percussion"),
217 N_("Resample without preserving pitch"),
222 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
225 pane_size_watcher (Paned* pane)
227 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
231 Quartz: impossible to access
233 so stop that by preventing it from ever getting too narrow. 35
234 pixels is basically a rough guess at the tab width.
239 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
241 gint pos = pane->get_position ();
243 if (pos > max_width_of_lhs) {
244 pane->set_position (max_width_of_lhs);
249 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
251 /* time display buttons */
252 , minsec_label (_("Mins:Secs"))
253 , bbt_label (_("Bars:Beats"))
254 , timecode_label (_("Timecode"))
255 , samples_label (_("Samples"))
256 , tempo_label (_("Tempo"))
257 , meter_label (_("Meter"))
258 , mark_label (_("Location Markers"))
259 , range_mark_label (_("Range Markers"))
260 , transport_mark_label (_("Loop/Punch Ranges"))
261 , cd_mark_label (_("CD Markers"))
262 , videotl_label (_("Video Timeline"))
263 , edit_packer (4, 4, true)
265 /* the values here don't matter: layout widgets
266 reset them as needed.
269 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
270 , horizontal_adjustment (0.0, 0.0, 1e16)
271 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
273 , controls_layout (unused_adjustment, vertical_adjustment)
275 /* tool bar related */
277 , toolbar_selection_clock_table (2,3)
278 , _mouse_mode_tearoff (0)
279 , automation_mode_button (_("mode"))
283 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
287 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
288 , meters_running(false)
289 , _pending_locate_request (false)
290 , _pending_initial_locate (false)
291 , _last_cut_copy_source_track (0)
293 , _region_selection_change_updates_region_list (true)
294 , _following_mixer_selection (false)
295 , _control_point_toggled_on_press (false)
296 , _stepping_axis_view (0)
300 /* we are a singleton */
302 PublicEditor::_instance = this;
306 selection = new Selection (this);
307 cut_buffer = new Selection (this);
309 clicked_regionview = 0;
310 clicked_axisview = 0;
311 clicked_routeview = 0;
312 clicked_control_point = 0;
313 last_update_frame = 0;
314 pre_press_cursor = 0;
317 _drags = new DragManager (this);
320 current_mixer_strip = 0;
323 snap_type_strings = I18N (_snap_type_strings);
324 snap_mode_strings = I18N (_snap_mode_strings);
325 zoom_focus_strings = I18N (_zoom_focus_strings);
326 edit_mode_strings = I18N (_edit_mode_strings);
327 edit_point_strings = I18N (_edit_point_strings);
328 #ifdef USE_RUBBERBAND
329 rb_opt_strings = I18N (_rb_opt_strings);
333 build_edit_mode_menu();
334 build_zoom_focus_menu();
335 build_track_count_menu();
336 build_snap_mode_menu();
337 build_snap_type_menu();
338 build_edit_point_menu();
340 snap_threshold = 5.0;
341 bbt_beat_subdivision = 4;
342 _visible_canvas_width = 0;
343 _visible_canvas_height = 0;
344 autoscroll_horizontal_allowed = false;
345 autoscroll_vertical_allowed = false;
350 current_interthread_info = 0;
351 _show_measures = true;
353 show_gain_after_trim = false;
355 have_pending_keyboard_selection = false;
356 _follow_playhead = true;
357 _stationary_playhead = false;
358 editor_ruler_menu = 0;
359 no_ruler_shown_update = false;
361 range_marker_menu = 0;
362 marker_menu_item = 0;
363 tempo_or_meter_marker_menu = 0;
364 transport_marker_menu = 0;
365 new_transport_marker_menu = 0;
366 editor_mixer_strip_width = Wide;
367 show_editor_mixer_when_tracks_arrive = false;
368 region_edit_menu_split_multichannel_item = 0;
369 region_edit_menu_split_item = 0;
372 current_stepping_trackview = 0;
374 entered_regionview = 0;
376 clear_entered_track = false;
379 button_release_can_deselect = true;
380 _dragging_playhead = false;
381 _dragging_edit_point = false;
382 select_new_marker = false;
384 layering_order_editor = 0;
385 no_save_visual = false;
387 within_track_canvas = false;
389 scrubbing_direction = 0;
393 location_marker_color = ARDOUR_UI::config()->color ("LocationMarker");
394 location_range_color = ARDOUR_UI::config()->color ("LocationRange");
395 location_cd_marker_color = ARDOUR_UI::config()->color ("LocationCDMarker");
396 location_loop_color = ARDOUR_UI::config()->color ("LocationLoop");
397 location_punch_color = ARDOUR_UI::config()->color ("LocationPunch");
399 zoom_focus = ZoomFocusLeft;
400 _edit_point = EditAtMouse;
401 _internal_editing = false;
402 current_canvas_cursor = 0;
403 _visible_track_count = -1;
405 samples_per_pixel = 2048; /* too early to use reset_zoom () */
407 _scroll_callbacks = 0;
409 bbt_label.set_name ("EditorRulerLabel");
410 bbt_label.set_size_request (-1, (int)timebar_height);
411 bbt_label.set_alignment (1.0, 0.5);
412 bbt_label.set_padding (5,0);
414 bbt_label.set_no_show_all();
415 minsec_label.set_name ("EditorRulerLabel");
416 minsec_label.set_size_request (-1, (int)timebar_height);
417 minsec_label.set_alignment (1.0, 0.5);
418 minsec_label.set_padding (5,0);
419 minsec_label.hide ();
420 minsec_label.set_no_show_all();
421 timecode_label.set_name ("EditorRulerLabel");
422 timecode_label.set_size_request (-1, (int)timebar_height);
423 timecode_label.set_alignment (1.0, 0.5);
424 timecode_label.set_padding (5,0);
425 timecode_label.hide ();
426 timecode_label.set_no_show_all();
427 samples_label.set_name ("EditorRulerLabel");
428 samples_label.set_size_request (-1, (int)timebar_height);
429 samples_label.set_alignment (1.0, 0.5);
430 samples_label.set_padding (5,0);
431 samples_label.hide ();
432 samples_label.set_no_show_all();
434 tempo_label.set_name ("EditorRulerLabel");
435 tempo_label.set_size_request (-1, (int)timebar_height);
436 tempo_label.set_alignment (1.0, 0.5);
437 tempo_label.set_padding (5,0);
439 tempo_label.set_no_show_all();
441 meter_label.set_name ("EditorRulerLabel");
442 meter_label.set_size_request (-1, (int)timebar_height);
443 meter_label.set_alignment (1.0, 0.5);
444 meter_label.set_padding (5,0);
446 meter_label.set_no_show_all();
448 if (Profile->get_trx()) {
449 mark_label.set_text (_("Markers"));
451 mark_label.set_name ("EditorRulerLabel");
452 mark_label.set_size_request (-1, (int)timebar_height);
453 mark_label.set_alignment (1.0, 0.5);
454 mark_label.set_padding (5,0);
456 mark_label.set_no_show_all();
458 cd_mark_label.set_name ("EditorRulerLabel");
459 cd_mark_label.set_size_request (-1, (int)timebar_height);
460 cd_mark_label.set_alignment (1.0, 0.5);
461 cd_mark_label.set_padding (5,0);
462 cd_mark_label.hide();
463 cd_mark_label.set_no_show_all();
465 videotl_bar_height = 4;
466 videotl_label.set_name ("EditorRulerLabel");
467 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
468 videotl_label.set_alignment (1.0, 0.5);
469 videotl_label.set_padding (5,0);
470 videotl_label.hide();
471 videotl_label.set_no_show_all();
473 range_mark_label.set_name ("EditorRulerLabel");
474 range_mark_label.set_size_request (-1, (int)timebar_height);
475 range_mark_label.set_alignment (1.0, 0.5);
476 range_mark_label.set_padding (5,0);
477 range_mark_label.hide();
478 range_mark_label.set_no_show_all();
480 transport_mark_label.set_name ("EditorRulerLabel");
481 transport_mark_label.set_size_request (-1, (int)timebar_height);
482 transport_mark_label.set_alignment (1.0, 0.5);
483 transport_mark_label.set_padding (5,0);
484 transport_mark_label.hide();
485 transport_mark_label.set_no_show_all();
487 initialize_canvas ();
489 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
491 _summary = new EditorSummary (this);
493 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
494 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
496 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
498 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
499 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
501 edit_controls_vbox.set_spacing (0);
502 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
503 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
505 HBox* h = manage (new HBox);
506 _group_tabs = new EditorGroupTabs (this);
507 if (!ARDOUR::Profile->get_trx()) {
508 h->pack_start (*_group_tabs, PACK_SHRINK);
510 h->pack_start (edit_controls_vbox);
511 controls_layout.add (*h);
513 controls_layout.set_name ("EditControlsBase");
514 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
515 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
516 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
518 _cursors = new MouseCursors;
519 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
520 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
522 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
524 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
525 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
526 pad_line_1->set_outline_color (0xFF0000FF);
532 edit_packer.set_col_spacings (0);
533 edit_packer.set_row_spacings (0);
534 edit_packer.set_homogeneous (false);
535 edit_packer.set_border_width (0);
536 edit_packer.set_name ("EditorWindow");
538 time_bars_event_box.add (time_bars_vbox);
539 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
540 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
542 /* labels for the time bars */
543 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
545 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
547 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
549 bottom_hbox.set_border_width (2);
550 bottom_hbox.set_spacing (3);
552 _route_groups = new EditorRouteGroups (this);
553 _routes = new EditorRoutes (this);
554 _regions = new EditorRegions (this);
555 _snapshots = new EditorSnapshots (this);
556 _locations = new EditorLocations (this);
558 /* these are static location signals */
560 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
561 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
562 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
564 add_notebook_page (_("Regions"), _regions->widget ());
565 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
566 add_notebook_page (_("Snapshots"), _snapshots->widget ());
567 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
568 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
570 _the_notebook.set_show_tabs (true);
571 _the_notebook.set_scrollable (true);
572 _the_notebook.popup_disable ();
573 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
574 _the_notebook.show_all ();
576 _notebook_shrunk = false;
578 editor_summary_pane.pack1(edit_packer);
580 Button* summary_arrows_left_left = manage (new Button);
581 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
582 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
583 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
585 Button* summary_arrows_left_right = manage (new Button);
586 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
587 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
588 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
590 VBox* summary_arrows_left = manage (new VBox);
591 summary_arrows_left->pack_start (*summary_arrows_left_left);
592 summary_arrows_left->pack_start (*summary_arrows_left_right);
594 Button* summary_arrows_right_up = manage (new Button);
595 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
596 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
597 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
599 Button* summary_arrows_right_down = manage (new Button);
600 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
601 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
602 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
604 VBox* summary_arrows_right = manage (new VBox);
605 summary_arrows_right->pack_start (*summary_arrows_right_up);
606 summary_arrows_right->pack_start (*summary_arrows_right_down);
608 Frame* summary_frame = manage (new Frame);
609 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
611 summary_frame->add (*_summary);
612 summary_frame->show ();
614 _summary_hbox.pack_start (*summary_arrows_left, false, false);
615 _summary_hbox.pack_start (*summary_frame, true, true);
616 _summary_hbox.pack_start (*summary_arrows_right, false, false);
618 if (!ARDOUR::Profile->get_trx()) {
619 editor_summary_pane.pack2 (_summary_hbox);
622 edit_pane.pack1 (editor_summary_pane, true, true);
623 if (!ARDOUR::Profile->get_trx()) {
624 edit_pane.pack2 (_the_notebook, false, true);
627 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
629 /* XXX: editor_summary_pane might need similar to the edit_pane */
631 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
633 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
634 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
636 top_hbox.pack_start (toolbar_frame);
638 HBox *hbox = manage (new HBox);
639 hbox->pack_start (edit_pane, true, true);
641 global_vpacker.pack_start (top_hbox, false, false);
642 global_vpacker.pack_start (*hbox, true, true);
644 global_hpacker.pack_start (global_vpacker, true, true);
646 set_name ("EditorWindow");
647 add_accel_group (ActionManager::ui_manager->get_accel_group());
649 status_bar_hpacker.show ();
651 vpacker.pack_end (status_bar_hpacker, false, false);
652 vpacker.pack_end (global_hpacker, true, true);
654 /* register actions now so that set_state() can find them and set toggles/checks etc */
657 /* when we start using our own keybinding system for the editor, this
658 * will be uncommented
664 set_zoom_focus (zoom_focus);
665 set_visible_track_count (_visible_track_count);
666 _snap_type = SnapToBeat;
667 set_snap_to (_snap_type);
668 _snap_mode = SnapOff;
669 set_snap_mode (_snap_mode);
670 set_mouse_mode (MouseObject, true);
671 pre_internal_mouse_mode = MouseObject;
672 pre_internal_snap_type = _snap_type;
673 pre_internal_snap_mode = _snap_mode;
674 internal_snap_type = _snap_type;
675 internal_snap_mode = _snap_mode;
676 set_edit_point_preference (EditAtMouse, true);
678 _playlist_selector = new PlaylistSelector();
679 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
681 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
685 nudge_forward_button.set_name ("nudge button");
686 nudge_forward_button.set_image(::get_icon("nudge_right"));
688 nudge_backward_button.set_name ("nudge button");
689 nudge_backward_button.set_image(::get_icon("nudge_left"));
691 fade_context_menu.set_name ("ArdourContextMenu");
693 /* icons, titles, WM stuff */
695 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
696 Glib::RefPtr<Gdk::Pixbuf> icon;
698 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
699 window_icons.push_back (icon);
701 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
702 window_icons.push_back (icon);
704 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
705 window_icons.push_back (icon);
707 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
708 window_icons.push_back (icon);
710 if (!window_icons.empty()) {
711 // set_icon_list (window_icons);
712 set_default_icon_list (window_icons);
715 WindowTitle title(Glib::get_application_name());
716 title += _("Editor");
717 set_title (title.get_string());
718 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
721 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
723 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
724 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
726 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
728 /* allow external control surfaces/protocols to do various things */
730 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
731 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
732 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
733 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
734 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
735 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
736 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
737 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
738 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
739 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
740 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
741 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
742 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
743 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
745 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
746 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
747 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
748 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
749 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
751 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
753 /* problematic: has to return a value and thus cannot be x-thread */
755 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
757 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
758 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
760 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
762 _ignore_region_action = false;
763 _last_region_menu_was_main = false;
764 _popup_region_menu_item = 0;
766 _ignore_follow_edits = false;
768 _show_marker_lines = false;
770 /* Button bindings */
772 button_bindings = new Bindings;
774 XMLNode* node = button_settings();
776 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
777 button_bindings->load (**i);
783 /* grab current parameter state */
784 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
785 ARDOUR_UI::config()->map_parameters (pc);
787 setup_fade_images ();
794 delete button_bindings;
796 delete _route_groups;
797 delete _track_canvas_viewport;
803 Editor::button_settings () const
805 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
806 XMLNode* node = find_named_node (*settings, X_("Buttons"));
809 node = new XMLNode (X_("Buttons"));
816 Editor::add_toplevel_menu (Container& cont)
818 vpacker.pack_start (cont, false, false);
823 Editor::add_transport_frame (Container& cont)
825 if(ARDOUR::Profile->get_mixbus()) {
826 global_vpacker.pack_start (cont, false, false);
827 global_vpacker.reorder_child (cont, 0);
830 vpacker.pack_start (cont, false, false);
835 Editor::get_smart_mode () const
837 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
841 Editor::catch_vanishing_regionview (RegionView *rv)
843 /* note: the selection will take care of the vanishing
844 audioregionview by itself.
847 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
851 if (clicked_regionview == rv) {
852 clicked_regionview = 0;
855 if (entered_regionview == rv) {
856 set_entered_regionview (0);
859 if (!_all_region_actions_sensitized) {
860 sensitize_all_region_actions (true);
865 Editor::set_entered_regionview (RegionView* rv)
867 if (rv == entered_regionview) {
871 if (entered_regionview) {
872 entered_regionview->exited ();
875 entered_regionview = rv;
877 if (entered_regionview != 0) {
878 entered_regionview->entered (internal_editing ());
881 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
882 /* This RegionView entry might have changed what region actions
883 are allowed, so sensitize them all in case a key is pressed.
885 sensitize_all_region_actions (true);
890 Editor::set_entered_track (TimeAxisView* tav)
893 entered_track->exited ();
899 entered_track->entered ();
904 Editor::show_window ()
906 if (!is_visible ()) {
910 /* XXX: this is a bit unfortunate; it would probably
911 be nicer if we could just call show () above rather
912 than needing the show_all ()
915 /* re-hide stuff if necessary */
916 editor_list_button_toggled ();
917 parameter_changed ("show-summary");
918 parameter_changed ("show-group-tabs");
919 parameter_changed ("show-zoom-tools");
921 /* now reset all audio_time_axis heights, because widgets might need
927 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
928 tv = (static_cast<TimeAxisView*>(*i));
932 if (current_mixer_strip) {
933 current_mixer_strip->hide_things ();
934 current_mixer_strip->parameter_changed ("mixer-element-visibility");
942 Editor::instant_save ()
944 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
949 _session->add_instant_xml(get_state());
951 Config->add_instant_xml(get_state());
956 Editor::control_vertical_zoom_in_all ()
958 tav_zoom_smooth (false, true);
962 Editor::control_vertical_zoom_out_all ()
964 tav_zoom_smooth (true, true);
968 Editor::control_vertical_zoom_in_selected ()
970 tav_zoom_smooth (false, false);
974 Editor::control_vertical_zoom_out_selected ()
976 tav_zoom_smooth (true, false);
980 Editor::control_view (uint32_t view)
982 goto_visual_state (view);
986 Editor::control_unselect ()
988 selection->clear_tracks ();
992 Editor::control_select (uint32_t rid, Selection::Operation op)
994 /* handles the (static) signal from the ControlProtocol class that
995 * requests setting the selected track to a given RID
1002 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1008 TimeAxisView* tav = axis_view_from_route (r);
1012 case Selection::Add:
1013 selection->add (tav);
1015 case Selection::Toggle:
1016 selection->toggle (tav);
1018 case Selection::Extend:
1020 case Selection::Set:
1021 selection->set (tav);
1025 selection->clear_tracks ();
1030 Editor::control_step_tracks_up ()
1032 scroll_tracks_up_line ();
1036 Editor::control_step_tracks_down ()
1038 scroll_tracks_down_line ();
1042 Editor::control_scroll (float fraction)
1044 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1050 double step = fraction * current_page_samples();
1053 _control_scroll_target is an optional<T>
1055 it acts like a pointer to an framepos_t, with
1056 a operator conversion to boolean to check
1057 that it has a value could possibly use
1058 playhead_cursor->current_frame to store the
1059 value and a boolean in the class to know
1060 when it's out of date
1063 if (!_control_scroll_target) {
1064 _control_scroll_target = _session->transport_frame();
1065 _dragging_playhead = true;
1068 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1069 *_control_scroll_target = 0;
1070 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1071 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1073 *_control_scroll_target += (framepos_t) trunc (step);
1076 /* move visuals, we'll catch up with it later */
1078 playhead_cursor->set_position (*_control_scroll_target);
1079 UpdateAllTransportClocks (*_control_scroll_target);
1081 if (*_control_scroll_target > (current_page_samples() / 2)) {
1082 /* try to center PH in window */
1083 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1089 Now we do a timeout to actually bring the session to the right place
1090 according to the playhead. This is to avoid reading disk buffers on every
1091 call to control_scroll, which is driven by ScrollTimeline and therefore
1092 probably by a control surface wheel which can generate lots of events.
1094 /* cancel the existing timeout */
1096 control_scroll_connection.disconnect ();
1098 /* add the next timeout */
1100 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1104 Editor::deferred_control_scroll (framepos_t /*target*/)
1106 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1107 // reset for next stream
1108 _control_scroll_target = boost::none;
1109 _dragging_playhead = false;
1114 Editor::access_action (std::string action_group, std::string action_item)
1120 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1123 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1131 Editor::on_realize ()
1133 Window::on_realize ();
1136 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1137 start_lock_event_timing ();
1140 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1144 Editor::start_lock_event_timing ()
1146 /* check if we should lock the GUI every 30 seconds */
1148 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1152 Editor::generic_event_handler (GdkEvent* ev)
1155 case GDK_BUTTON_PRESS:
1156 case GDK_BUTTON_RELEASE:
1157 case GDK_MOTION_NOTIFY:
1159 case GDK_KEY_RELEASE:
1160 gettimeofday (&last_event_time, 0);
1163 case GDK_LEAVE_NOTIFY:
1164 switch (ev->crossing.detail) {
1165 case GDK_NOTIFY_UNKNOWN:
1166 case GDK_NOTIFY_INFERIOR:
1167 case GDK_NOTIFY_ANCESTOR:
1169 case GDK_NOTIFY_VIRTUAL:
1170 case GDK_NOTIFY_NONLINEAR:
1171 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1172 /* leaving window, so reset focus, thus ending any and
1173 all text entry operations.
1188 Editor::lock_timeout_callback ()
1190 struct timeval now, delta;
1192 gettimeofday (&now, 0);
1194 timersub (&now, &last_event_time, &delta);
1196 if (delta.tv_sec > (time_t) ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1198 /* don't call again. Returning false will effectively
1199 disconnect us from the timer callback.
1201 unlock() will call start_lock_event_timing() to get things
1211 Editor::map_position_change (framepos_t frame)
1213 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1215 if (_session == 0) {
1219 if (_follow_playhead) {
1220 center_screen (frame);
1223 playhead_cursor->set_position (frame);
1227 Editor::center_screen (framepos_t frame)
1229 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1231 /* if we're off the page, then scroll.
1234 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1235 center_screen_internal (frame, page);
1240 Editor::center_screen_internal (framepos_t frame, float page)
1245 frame -= (framepos_t) page;
1250 reset_x_origin (frame);
1255 Editor::update_title ()
1257 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1260 bool dirty = _session->dirty();
1262 string session_name;
1264 if (_session->snap_name() != _session->name()) {
1265 session_name = _session->snap_name();
1267 session_name = _session->name();
1271 session_name = "*" + session_name;
1274 WindowTitle title(session_name);
1275 title += Glib::get_application_name();
1276 set_title (title.get_string());
1278 /* ::session_going_away() will have taken care of it */
1283 Editor::set_session (Session *t)
1285 SessionHandlePtr::set_session (t);
1291 _playlist_selector->set_session (_session);
1292 nudge_clock->set_session (_session);
1293 _summary->set_session (_session);
1294 _group_tabs->set_session (_session);
1295 _route_groups->set_session (_session);
1296 _regions->set_session (_session);
1297 _snapshots->set_session (_session);
1298 _routes->set_session (_session);
1299 _locations->set_session (_session);
1301 if (rhythm_ferret) {
1302 rhythm_ferret->set_session (_session);
1305 if (analysis_window) {
1306 analysis_window->set_session (_session);
1310 sfbrowser->set_session (_session);
1313 compute_fixed_ruler_scale ();
1315 /* Make sure we have auto loop and auto punch ranges */
1317 Location* loc = _session->locations()->auto_loop_location();
1319 loc->set_name (_("Loop"));
1322 loc = _session->locations()->auto_punch_location();
1325 loc->set_name (_("Punch"));
1328 refresh_location_display ();
1330 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1331 the selected Marker; this needs the LocationMarker list to be available.
1333 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1334 set_state (*node, Stateful::loading_state_version);
1336 /* catch up with the playhead */
1338 _session->request_locate (playhead_cursor->current_frame ());
1339 _pending_initial_locate = true;
1343 /* These signals can all be emitted by a non-GUI thread. Therefore the
1344 handlers for them must not attempt to directly interact with the GUI,
1345 but use PBD::Signal<T>::connect() which accepts an event loop
1346 ("context") where the handler will be asked to run.
1349 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1350 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1351 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1352 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1353 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1354 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1355 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1356 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1357 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1358 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1359 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1360 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1361 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1363 playhead_cursor->show ();
1365 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1366 Config->map_parameters (pc);
1367 _session->config.map_parameters (pc);
1369 restore_ruler_visibility ();
1370 //tempo_map_changed (PropertyChange (0));
1371 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1373 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1374 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1377 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1378 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1381 switch (_snap_type) {
1382 case SnapToRegionStart:
1383 case SnapToRegionEnd:
1384 case SnapToRegionSync:
1385 case SnapToRegionBoundary:
1386 build_region_boundary_cache ();
1393 /* register for undo history */
1394 _session->register_with_memento_command_factory(id(), this);
1396 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1398 start_updating_meters ();
1402 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1404 if (a->get_name() == "RegionMenu") {
1405 /* When the main menu's region menu is opened, we setup the actions so that they look right
1406 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1407 so we resensitize all region actions when the entered regionview or the region selection
1408 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1409 happens after the region context menu is opened. So we set a flag here, too.
1413 sensitize_the_right_region_actions ();
1414 _last_region_menu_was_main = true;
1419 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1421 using namespace Menu_Helpers;
1423 void (Editor::*emf)(FadeShape);
1424 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1427 images = &_xfade_in_images;
1428 emf = &Editor::set_fade_in_shape;
1430 images = &_xfade_out_images;
1431 emf = &Editor::set_fade_out_shape;
1436 _("Linear (for highly correlated material)"),
1437 *(*images)[FadeLinear],
1438 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1442 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1446 _("Constant power"),
1447 *(*images)[FadeConstantPower],
1448 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1451 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1456 *(*images)[FadeSymmetric],
1457 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1461 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1466 *(*images)[FadeSlow],
1467 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1470 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1475 *(*images)[FadeFast],
1476 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1479 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1482 /** Pop up a context menu for when the user clicks on a start crossfade */
1484 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1486 using namespace Menu_Helpers;
1487 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1490 MenuList& items (xfade_in_context_menu.items());
1493 if (arv->audio_region()->fade_in_active()) {
1494 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1496 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1499 items.push_back (SeparatorElem());
1500 fill_xfade_menu (items, true);
1502 xfade_in_context_menu.popup (button, time);
1505 /** Pop up a context menu for when the user clicks on an end crossfade */
1507 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1509 using namespace Menu_Helpers;
1510 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1513 MenuList& items (xfade_out_context_menu.items());
1516 if (arv->audio_region()->fade_out_active()) {
1517 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1519 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1522 items.push_back (SeparatorElem());
1523 fill_xfade_menu (items, false);
1525 xfade_out_context_menu.popup (button, time);
1529 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1531 using namespace Menu_Helpers;
1532 Menu* (Editor::*build_menu_function)();
1535 switch (item_type) {
1537 case RegionViewName:
1538 case RegionViewNameHighlight:
1539 case LeftFrameHandle:
1540 case RightFrameHandle:
1541 if (with_selection) {
1542 build_menu_function = &Editor::build_track_selection_context_menu;
1544 build_menu_function = &Editor::build_track_region_context_menu;
1549 if (with_selection) {
1550 build_menu_function = &Editor::build_track_selection_context_menu;
1552 build_menu_function = &Editor::build_track_context_menu;
1557 if (clicked_routeview->track()) {
1558 build_menu_function = &Editor::build_track_context_menu;
1560 build_menu_function = &Editor::build_track_bus_context_menu;
1565 /* probably shouldn't happen but if it does, we don't care */
1569 menu = (this->*build_menu_function)();
1570 menu->set_name ("ArdourContextMenu");
1572 /* now handle specific situations */
1574 switch (item_type) {
1576 case RegionViewName:
1577 case RegionViewNameHighlight:
1578 case LeftFrameHandle:
1579 case RightFrameHandle:
1580 if (!with_selection) {
1581 if (region_edit_menu_split_item) {
1582 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1583 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1585 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1588 if (region_edit_menu_split_multichannel_item) {
1589 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1590 region_edit_menu_split_multichannel_item->set_sensitive (true);
1592 region_edit_menu_split_multichannel_item->set_sensitive (false);
1605 /* probably shouldn't happen but if it does, we don't care */
1609 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1611 /* Bounce to disk */
1613 using namespace Menu_Helpers;
1614 MenuList& edit_items = menu->items();
1616 edit_items.push_back (SeparatorElem());
1618 switch (clicked_routeview->audio_track()->freeze_state()) {
1619 case AudioTrack::NoFreeze:
1620 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1623 case AudioTrack::Frozen:
1624 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1627 case AudioTrack::UnFrozen:
1628 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1634 if (item_type == StreamItem && clicked_routeview) {
1635 clicked_routeview->build_underlay_menu(menu);
1638 /* When the region menu is opened, we setup the actions so that they look right
1641 sensitize_the_right_region_actions ();
1642 _last_region_menu_was_main = false;
1644 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1645 menu->popup (button, time);
1649 Editor::build_track_context_menu ()
1651 using namespace Menu_Helpers;
1653 MenuList& edit_items = track_context_menu.items();
1656 add_dstream_context_items (edit_items);
1657 return &track_context_menu;
1661 Editor::build_track_bus_context_menu ()
1663 using namespace Menu_Helpers;
1665 MenuList& edit_items = track_context_menu.items();
1668 add_bus_context_items (edit_items);
1669 return &track_context_menu;
1673 Editor::build_track_region_context_menu ()
1675 using namespace Menu_Helpers;
1676 MenuList& edit_items = track_region_context_menu.items();
1679 /* we've just cleared the track region context menu, so the menu that these
1680 two items were on will have disappeared; stop them dangling.
1682 region_edit_menu_split_item = 0;
1683 region_edit_menu_split_multichannel_item = 0;
1685 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1688 boost::shared_ptr<Track> tr;
1689 boost::shared_ptr<Playlist> pl;
1691 if ((tr = rtv->track())) {
1692 add_region_context_items (edit_items, tr);
1696 add_dstream_context_items (edit_items);
1698 return &track_region_context_menu;
1702 Editor::analyze_region_selection ()
1704 if (analysis_window == 0) {
1705 analysis_window = new AnalysisWindow();
1708 analysis_window->set_session(_session);
1710 analysis_window->show_all();
1713 analysis_window->set_regionmode();
1714 analysis_window->analyze();
1716 analysis_window->present();
1720 Editor::analyze_range_selection()
1722 if (analysis_window == 0) {
1723 analysis_window = new AnalysisWindow();
1726 analysis_window->set_session(_session);
1728 analysis_window->show_all();
1731 analysis_window->set_rangemode();
1732 analysis_window->analyze();
1734 analysis_window->present();
1738 Editor::build_track_selection_context_menu ()
1740 using namespace Menu_Helpers;
1741 MenuList& edit_items = track_selection_context_menu.items();
1742 edit_items.clear ();
1744 add_selection_context_items (edit_items);
1745 // edit_items.push_back (SeparatorElem());
1746 // add_dstream_context_items (edit_items);
1748 return &track_selection_context_menu;
1752 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1754 using namespace Menu_Helpers;
1756 /* OK, stick the region submenu at the top of the list, and then add
1760 RegionSelection rs = get_regions_from_selection_and_entered ();
1762 string::size_type pos = 0;
1763 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1765 /* we have to hack up the region name because "_" has a special
1766 meaning for menu titles.
1769 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1770 menu_item_name.replace (pos, 1, "__");
1774 if (_popup_region_menu_item == 0) {
1775 _popup_region_menu_item = new MenuItem (menu_item_name);
1776 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1777 _popup_region_menu_item->show ();
1779 _popup_region_menu_item->set_label (menu_item_name);
1782 const framepos_t position = get_preferred_edit_position (false, true);
1784 edit_items.push_back (*_popup_region_menu_item);
1785 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1786 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1788 edit_items.push_back (SeparatorElem());
1791 /** Add context menu items relevant to selection ranges.
1792 * @param edit_items List to add the items to.
1795 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1797 using namespace Menu_Helpers;
1799 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1800 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1802 edit_items.push_back (SeparatorElem());
1803 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1805 edit_items.push_back (SeparatorElem());
1806 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1808 edit_items.push_back (SeparatorElem());
1810 edit_items.push_back (
1812 _("Move Range Start to Previous Region Boundary"),
1813 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1817 edit_items.push_back (
1819 _("Move Range Start to Next Region Boundary"),
1820 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1824 edit_items.push_back (
1826 _("Move Range End to Previous Region Boundary"),
1827 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1831 edit_items.push_back (
1833 _("Move Range End to Next Region Boundary"),
1834 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1838 edit_items.push_back (SeparatorElem());
1839 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1840 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1842 edit_items.push_back (SeparatorElem());
1843 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1845 edit_items.push_back (SeparatorElem());
1846 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1847 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1848 edit_items.push_back (MenuElem (_("Set Session Start/End from Range"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1850 edit_items.push_back (SeparatorElem());
1851 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1853 edit_items.push_back (SeparatorElem());
1854 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1855 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1856 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1858 edit_items.push_back (SeparatorElem());
1859 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1860 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1861 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1862 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1863 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1864 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1865 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1871 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1873 using namespace Menu_Helpers;
1877 Menu *play_menu = manage (new Menu);
1878 MenuList& play_items = play_menu->items();
1879 play_menu->set_name ("ArdourContextMenu");
1881 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1882 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1883 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1884 play_items.push_back (SeparatorElem());
1885 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1887 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1891 Menu *select_menu = manage (new Menu);
1892 MenuList& select_items = select_menu->items();
1893 select_menu->set_name ("ArdourContextMenu");
1895 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1896 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1897 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1898 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1899 select_items.push_back (SeparatorElem());
1900 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1901 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1902 select_items.push_back (SeparatorElem());
1903 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1904 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1905 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1906 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1907 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1908 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1909 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1911 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1915 Menu *cutnpaste_menu = manage (new Menu);
1916 MenuList& cutnpaste_items = cutnpaste_menu->items();
1917 cutnpaste_menu->set_name ("ArdourContextMenu");
1919 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1920 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1921 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1923 cutnpaste_items.push_back (SeparatorElem());
1925 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1926 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1928 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1930 /* Adding new material */
1932 edit_items.push_back (SeparatorElem());
1933 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1934 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1938 Menu *nudge_menu = manage (new Menu());
1939 MenuList& nudge_items = nudge_menu->items();
1940 nudge_menu->set_name ("ArdourContextMenu");
1942 edit_items.push_back (SeparatorElem());
1943 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1944 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1945 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1946 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1948 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1952 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1954 using namespace Menu_Helpers;
1958 Menu *play_menu = manage (new Menu);
1959 MenuList& play_items = play_menu->items();
1960 play_menu->set_name ("ArdourContextMenu");
1962 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1963 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1964 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1968 Menu *select_menu = manage (new Menu);
1969 MenuList& select_items = select_menu->items();
1970 select_menu->set_name ("ArdourContextMenu");
1972 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1973 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1974 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1975 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1976 select_items.push_back (SeparatorElem());
1977 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1978 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1979 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1980 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1982 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1986 Menu *cutnpaste_menu = manage (new Menu);
1987 MenuList& cutnpaste_items = cutnpaste_menu->items();
1988 cutnpaste_menu->set_name ("ArdourContextMenu");
1990 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1991 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1992 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1994 Menu *nudge_menu = manage (new Menu());
1995 MenuList& nudge_items = nudge_menu->items();
1996 nudge_menu->set_name ("ArdourContextMenu");
1998 edit_items.push_back (SeparatorElem());
1999 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2000 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2001 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2002 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2004 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2008 Editor::snap_type() const
2014 Editor::snap_mode() const
2020 Editor::set_snap_to (SnapType st)
2022 unsigned int snap_ind = (unsigned int)st;
2026 if (snap_ind > snap_type_strings.size() - 1) {
2028 _snap_type = (SnapType)snap_ind;
2031 string str = snap_type_strings[snap_ind];
2033 if (str != snap_type_selector.get_text()) {
2034 snap_type_selector.set_text (str);
2039 switch (_snap_type) {
2040 case SnapToBeatDiv128:
2041 case SnapToBeatDiv64:
2042 case SnapToBeatDiv32:
2043 case SnapToBeatDiv28:
2044 case SnapToBeatDiv24:
2045 case SnapToBeatDiv20:
2046 case SnapToBeatDiv16:
2047 case SnapToBeatDiv14:
2048 case SnapToBeatDiv12:
2049 case SnapToBeatDiv10:
2050 case SnapToBeatDiv8:
2051 case SnapToBeatDiv7:
2052 case SnapToBeatDiv6:
2053 case SnapToBeatDiv5:
2054 case SnapToBeatDiv4:
2055 case SnapToBeatDiv3:
2056 case SnapToBeatDiv2: {
2057 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2058 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2060 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2061 current_bbt_points_begin, current_bbt_points_end);
2062 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2063 current_bbt_points_begin, current_bbt_points_end);
2064 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2068 case SnapToRegionStart:
2069 case SnapToRegionEnd:
2070 case SnapToRegionSync:
2071 case SnapToRegionBoundary:
2072 build_region_boundary_cache ();
2080 SnapChanged (); /* EMIT SIGNAL */
2084 Editor::set_snap_mode (SnapMode mode)
2086 string str = snap_mode_strings[(int)mode];
2088 if (_internal_editing) {
2089 internal_snap_mode = mode;
2091 pre_internal_snap_mode = mode;
2096 if (str != snap_mode_selector.get_text ()) {
2097 snap_mode_selector.set_text (str);
2103 Editor::set_edit_point_preference (EditPoint ep, bool force)
2105 bool changed = (_edit_point != ep);
2108 if (Profile->get_mixbus())
2109 if (ep == EditAtSelectedMarker)
2110 ep = EditAtPlayhead;
2112 string str = edit_point_strings[(int)ep];
2113 if (str != edit_point_selector.get_text ()) {
2114 edit_point_selector.set_text (str);
2117 reset_canvas_cursor ();
2119 if (!force && !changed) {
2123 const char* action=NULL;
2125 switch (_edit_point) {
2126 case EditAtPlayhead:
2127 action = "edit-at-playhead";
2129 case EditAtSelectedMarker:
2130 action = "edit-at-marker";
2133 action = "edit-at-mouse";
2137 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2139 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2143 bool in_track_canvas;
2145 if (!mouse_frame (foo, in_track_canvas)) {
2146 in_track_canvas = false;
2149 reset_canvas_action_sensitivity (in_track_canvas);
2155 Editor::set_state (const XMLNode& node, int /*version*/)
2157 const XMLProperty* prop;
2164 g.base_width = default_width;
2165 g.base_height = default_height;
2169 if ((geometry = find_named_node (node, "geometry")) != 0) {
2173 if ((prop = geometry->property("x_size")) == 0) {
2174 prop = geometry->property ("x-size");
2177 g.base_width = atoi(prop->value());
2179 if ((prop = geometry->property("y_size")) == 0) {
2180 prop = geometry->property ("y-size");
2183 g.base_height = atoi(prop->value());
2186 if ((prop = geometry->property ("x_pos")) == 0) {
2187 prop = geometry->property ("x-pos");
2190 x = atoi (prop->value());
2193 if ((prop = geometry->property ("y_pos")) == 0) {
2194 prop = geometry->property ("y-pos");
2197 y = atoi (prop->value());
2201 set_default_size (g.base_width, g.base_height);
2204 if (_session && (prop = node.property ("playhead"))) {
2206 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2208 playhead_cursor->set_position (pos);
2210 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2211 playhead_cursor->set_position (0);
2214 playhead_cursor->set_position (0);
2217 if ((prop = node.property ("mixer-width"))) {
2218 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2221 if ((prop = node.property ("zoom-focus"))) {
2222 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2225 if ((prop = node.property ("zoom"))) {
2226 /* older versions of ardour used floating point samples_per_pixel */
2227 double f = PBD::atof (prop->value());
2228 reset_zoom (llrintf (f));
2230 reset_zoom (samples_per_pixel);
2233 if ((prop = node.property ("visible-track-count"))) {
2234 set_visible_track_count (PBD::atoi (prop->value()));
2237 if ((prop = node.property ("snap-to"))) {
2238 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2241 if ((prop = node.property ("snap-mode"))) {
2242 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2245 if ((prop = node.property ("internal-snap-to"))) {
2246 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2249 if ((prop = node.property ("internal-snap-mode"))) {
2250 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2253 if ((prop = node.property ("pre-internal-snap-to"))) {
2254 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2258 if ((prop = node.property ("pre-internal-snap-mode"))) {
2259 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2262 if ((prop = node.property ("mouse-mode"))) {
2263 MouseMode m = str2mousemode(prop->value());
2264 set_mouse_mode (m, true);
2266 set_mouse_mode (MouseObject, true);
2269 if ((prop = node.property ("left-frame")) != 0) {
2271 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2275 reset_x_origin (pos);
2279 if ((prop = node.property ("y-origin")) != 0) {
2280 reset_y_origin (atof (prop->value ()));
2283 if ((prop = node.property ("internal-edit"))) {
2284 bool yn = string_is_affirmative (prop->value());
2285 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2287 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2288 tact->set_active (!yn);
2289 tact->set_active (yn);
2293 if ((prop = node.property ("join-object-range"))) {
2294 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2295 bool yn = string_is_affirmative (prop->value());
2297 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2298 tact->set_active (!yn);
2299 tact->set_active (yn);
2301 set_mouse_mode(mouse_mode, true);
2304 if ((prop = node.property ("edit-point"))) {
2305 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2308 if ((prop = node.property ("show-measures"))) {
2309 bool yn = string_is_affirmative (prop->value());
2310 _show_measures = yn;
2311 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2313 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2314 /* do it twice to force the change */
2315 tact->set_active (!yn);
2316 tact->set_active (yn);
2320 if ((prop = node.property ("follow-playhead"))) {
2321 bool yn = string_is_affirmative (prop->value());
2322 set_follow_playhead (yn);
2323 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2325 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2326 if (tact->get_active() != yn) {
2327 tact->set_active (yn);
2332 if ((prop = node.property ("stationary-playhead"))) {
2333 bool yn = string_is_affirmative (prop->value());
2334 set_stationary_playhead (yn);
2335 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2337 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2338 if (tact->get_active() != yn) {
2339 tact->set_active (yn);
2344 if ((prop = node.property ("region-list-sort-type"))) {
2345 RegionListSortType st;
2346 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2349 if ((prop = node.property ("show-editor-mixer"))) {
2351 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2354 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2355 bool yn = string_is_affirmative (prop->value());
2357 /* do it twice to force the change */
2359 tact->set_active (!yn);
2360 tact->set_active (yn);
2363 if ((prop = node.property ("show-editor-list"))) {
2365 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2368 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2369 bool yn = string_is_affirmative (prop->value());
2371 /* do it twice to force the change */
2373 tact->set_active (!yn);
2374 tact->set_active (yn);
2377 if ((prop = node.property (X_("editor-list-page")))) {
2378 _the_notebook.set_current_page (atoi (prop->value ()));
2381 if ((prop = node.property (X_("show-marker-lines")))) {
2382 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2384 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2385 bool yn = string_is_affirmative (prop->value ());
2387 tact->set_active (!yn);
2388 tact->set_active (yn);
2391 XMLNodeList children = node.children ();
2392 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2393 selection->set_state (**i, Stateful::current_state_version);
2394 _regions->set_state (**i);
2397 if ((prop = node.property ("maximised"))) {
2398 bool yn = string_is_affirmative (prop->value());
2399 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2401 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2402 bool fs = tact && tact->get_active();
2404 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2408 if ((prop = node.property ("nudge-clock-value"))) {
2410 sscanf (prop->value().c_str(), "%" PRId64, &f);
2411 nudge_clock->set (f);
2413 nudge_clock->set_mode (AudioClock::Timecode);
2414 nudge_clock->set (_session->frame_rate() * 5, true);
2421 Editor::get_state ()
2423 XMLNode* node = new XMLNode ("Editor");
2426 id().print (buf, sizeof (buf));
2427 node->add_property ("id", buf);
2429 if (is_realized()) {
2430 Glib::RefPtr<Gdk::Window> win = get_window();
2432 int x, y, width, height;
2433 win->get_root_origin(x, y);
2434 win->get_size(width, height);
2436 XMLNode* geometry = new XMLNode ("geometry");
2438 snprintf(buf, sizeof(buf), "%d", width);
2439 geometry->add_property("x-size", string(buf));
2440 snprintf(buf, sizeof(buf), "%d", height);
2441 geometry->add_property("y-size", string(buf));
2442 snprintf(buf, sizeof(buf), "%d", x);
2443 geometry->add_property("x-pos", string(buf));
2444 snprintf(buf, sizeof(buf), "%d", y);
2445 geometry->add_property("y-pos", string(buf));
2446 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2447 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2448 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2449 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2450 geometry->add_property("edit-vertical-pane-pos", string(buf));
2452 node->add_child_nocopy (*geometry);
2455 maybe_add_mixer_strip_width (*node);
2457 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2459 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2460 node->add_property ("zoom", buf);
2461 node->add_property ("snap-to", enum_2_string (_snap_type));
2462 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2463 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2464 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2465 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2466 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2467 node->add_property ("edit-point", enum_2_string (_edit_point));
2468 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2469 node->add_property ("visible-track-count", buf);
2471 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2472 node->add_property ("playhead", buf);
2473 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2474 node->add_property ("left-frame", buf);
2475 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2476 node->add_property ("y-origin", buf);
2478 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2479 node->add_property ("maximised", _maximised ? "yes" : "no");
2480 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2481 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2482 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2483 node->add_property ("mouse-mode", enum2str(mouse_mode));
2484 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2485 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2487 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2489 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2490 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2493 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2495 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2496 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2499 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2500 node->add_property (X_("editor-list-page"), buf);
2502 if (button_bindings) {
2503 XMLNode* bb = new XMLNode (X_("Buttons"));
2504 button_bindings->save (*bb);
2505 node->add_child_nocopy (*bb);
2508 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2510 node->add_child_nocopy (selection->get_state ());
2511 node->add_child_nocopy (_regions->get_state ());
2513 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2514 node->add_property ("nudge-clock-value", buf);
2519 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2520 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2522 * @return pair: TimeAxisView that y is over, layer index.
2524 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2525 * in stacked or expanded region display mode, otherwise 0.
2527 std::pair<TimeAxisView *, double>
2528 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2530 if (!trackview_relative_offset) {
2531 y -= _trackview_group->canvas_origin().y;
2535 return std::make_pair ( (TimeAxisView *) 0, 0);
2538 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2540 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2547 return std::make_pair ( (TimeAxisView *) 0, 0);
2550 /** Snap a position to the grid, if appropriate, taking into account current
2551 * grid settings and also the state of any snap modifier keys that may be pressed.
2552 * @param start Position to snap.
2553 * @param event Event to get current key modifier information from, or 0.
2556 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2558 if (!_session || !event) {
2562 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2563 if (_snap_mode == SnapOff) {
2564 snap_to_internal (start, direction, for_mark);
2567 if (_snap_mode != SnapOff) {
2568 snap_to_internal (start, direction, for_mark);
2574 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark)
2576 if (!_session || _snap_mode == SnapOff) {
2580 snap_to_internal (start, direction, for_mark);
2584 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2586 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2587 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2589 switch (_snap_type) {
2590 case SnapToTimecodeFrame:
2591 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2592 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2593 /* start is already on a whole timecode frame, do nothing */
2594 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2595 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2597 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2601 case SnapToTimecodeSeconds:
2602 if (_session->config.get_timecode_offset_negative()) {
2603 start += _session->config.get_timecode_offset ();
2605 start -= _session->config.get_timecode_offset ();
2607 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2608 (start % one_timecode_second == 0)) {
2609 /* start is already on a whole second, do nothing */
2610 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2611 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2613 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2616 if (_session->config.get_timecode_offset_negative()) {
2617 start -= _session->config.get_timecode_offset ();
2619 start += _session->config.get_timecode_offset ();
2623 case SnapToTimecodeMinutes:
2624 if (_session->config.get_timecode_offset_negative()) {
2625 start += _session->config.get_timecode_offset ();
2627 start -= _session->config.get_timecode_offset ();
2629 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2630 (start % one_timecode_minute == 0)) {
2631 /* start is already on a whole minute, do nothing */
2632 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2633 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2635 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2637 if (_session->config.get_timecode_offset_negative()) {
2638 start -= _session->config.get_timecode_offset ();
2640 start += _session->config.get_timecode_offset ();
2644 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2645 abort(); /*NOTREACHED*/
2650 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark)
2652 const framepos_t one_second = _session->frame_rate();
2653 const framepos_t one_minute = _session->frame_rate() * 60;
2654 framepos_t presnap = start;
2658 switch (_snap_type) {
2659 case SnapToTimecodeFrame:
2660 case SnapToTimecodeSeconds:
2661 case SnapToTimecodeMinutes:
2662 return timecode_snap_to_internal (start, direction, for_mark);
2665 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2666 start % (one_second/75) == 0) {
2667 /* start is already on a whole CD frame, do nothing */
2668 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2669 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2671 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2676 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2677 start % one_second == 0) {
2678 /* start is already on a whole second, do nothing */
2679 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2680 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2682 start = (framepos_t) floor ((double) start / one_second) * one_second;
2687 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2688 start % one_minute == 0) {
2689 /* start is already on a whole minute, do nothing */
2690 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2691 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2693 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2698 start = _session->tempo_map().round_to_bar (start, direction);
2702 start = _session->tempo_map().round_to_beat (start, direction);
2705 case SnapToBeatDiv128:
2706 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2708 case SnapToBeatDiv64:
2709 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2711 case SnapToBeatDiv32:
2712 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2714 case SnapToBeatDiv28:
2715 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2717 case SnapToBeatDiv24:
2718 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2720 case SnapToBeatDiv20:
2721 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2723 case SnapToBeatDiv16:
2724 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2726 case SnapToBeatDiv14:
2727 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2729 case SnapToBeatDiv12:
2730 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2732 case SnapToBeatDiv10:
2733 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2735 case SnapToBeatDiv8:
2736 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2738 case SnapToBeatDiv7:
2739 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2741 case SnapToBeatDiv6:
2742 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2744 case SnapToBeatDiv5:
2745 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2747 case SnapToBeatDiv4:
2748 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2750 case SnapToBeatDiv3:
2751 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2753 case SnapToBeatDiv2:
2754 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2762 _session->locations()->marks_either_side (start, before, after);
2764 if (before == max_framepos && after == max_framepos) {
2765 /* No marks to snap to, so just don't snap */
2767 } else if (before == max_framepos) {
2769 } else if (after == max_framepos) {
2771 } else if (before != max_framepos && after != max_framepos) {
2772 /* have before and after */
2773 if ((start - before) < (after - start)) {
2782 case SnapToRegionStart:
2783 case SnapToRegionEnd:
2784 case SnapToRegionSync:
2785 case SnapToRegionBoundary:
2786 if (!region_boundary_cache.empty()) {
2788 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2789 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2791 if (direction > 0) {
2792 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2794 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2797 if (next != region_boundary_cache.begin ()) {
2802 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2803 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2805 if (start > (p + n) / 2) {
2814 switch (_snap_mode) {
2820 if (presnap > start) {
2821 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2825 } else if (presnap < start) {
2826 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2832 /* handled at entry */
2840 Editor::setup_toolbar ()
2842 HBox* mode_box = manage(new HBox);
2843 mode_box->set_border_width (2);
2844 mode_box->set_spacing(2);
2846 HBox* mouse_mode_box = manage (new HBox);
2847 HBox* mouse_mode_hbox = manage (new HBox);
2848 VBox* mouse_mode_vbox = manage (new VBox);
2849 Alignment* mouse_mode_align = manage (new Alignment);
2851 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2852 mouse_mode_size_group->add_widget (smart_mode_button);
2853 mouse_mode_size_group->add_widget (mouse_move_button);
2854 mouse_mode_size_group->add_widget (mouse_cut_button);
2855 mouse_mode_size_group->add_widget (mouse_select_button);
2856 mouse_mode_size_group->add_widget (mouse_timefx_button);
2857 mouse_mode_size_group->add_widget (mouse_audition_button);
2858 mouse_mode_size_group->add_widget (mouse_draw_button);
2859 mouse_mode_size_group->add_widget (internal_edit_button);
2861 mouse_mode_size_group->add_widget (zoom_in_button);
2862 mouse_mode_size_group->add_widget (zoom_out_button);
2863 mouse_mode_size_group->add_widget (zoom_preset_selector);
2864 mouse_mode_size_group->add_widget (zoom_out_full_button);
2865 mouse_mode_size_group->add_widget (zoom_focus_selector);
2867 mouse_mode_size_group->add_widget (tav_shrink_button);
2868 mouse_mode_size_group->add_widget (tav_expand_button);
2869 mouse_mode_size_group->add_widget (visible_tracks_selector);
2871 mouse_mode_size_group->add_widget (snap_type_selector);
2872 mouse_mode_size_group->add_widget (snap_mode_selector);
2874 mouse_mode_size_group->add_widget (edit_point_selector);
2875 mouse_mode_size_group->add_widget (edit_mode_selector);
2877 mouse_mode_size_group->add_widget (*nudge_clock);
2878 mouse_mode_size_group->add_widget (nudge_forward_button);
2879 mouse_mode_size_group->add_widget (nudge_backward_button);
2881 mouse_mode_hbox->set_spacing (2);
2883 if (!ARDOUR::Profile->get_trx()) {
2884 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2887 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2888 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2890 if (!ARDOUR::Profile->get_mixbus()) {
2891 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2894 if (!ARDOUR::Profile->get_trx()) {
2895 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2896 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2897 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2898 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 0);
2901 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2903 mouse_mode_align->add (*mouse_mode_vbox);
2904 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2906 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2908 edit_mode_selector.set_name ("mouse mode button");
2910 if (!ARDOUR::Profile->get_trx()) {
2911 mode_box->pack_start (edit_mode_selector, false, false);
2913 mode_box->pack_start (*mouse_mode_box, false, false);
2915 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2916 _mouse_mode_tearoff->set_name ("MouseModeBase");
2917 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2919 if (Profile->get_sae() || Profile->get_mixbus() ) {
2920 _mouse_mode_tearoff->set_can_be_torn_off (false);
2923 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2924 &_mouse_mode_tearoff->tearoff_window()));
2925 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2926 &_mouse_mode_tearoff->tearoff_window(), 1));
2927 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2928 &_mouse_mode_tearoff->tearoff_window()));
2929 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2930 &_mouse_mode_tearoff->tearoff_window(), 1));
2934 _zoom_box.set_spacing (2);
2935 _zoom_box.set_border_width (2);
2939 zoom_preset_selector.set_name ("zoom button");
2940 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2941 zoom_preset_selector.set_size_request (42, -1);
2943 zoom_in_button.set_name ("zoom button");
2944 zoom_in_button.set_image(::get_icon ("zoom_in"));
2945 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2946 zoom_in_button.set_related_action (act);
2948 zoom_out_button.set_name ("zoom button");
2949 zoom_out_button.set_image(::get_icon ("zoom_out"));
2950 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2951 zoom_out_button.set_related_action (act);
2953 zoom_out_full_button.set_name ("zoom button");
2954 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2955 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2956 zoom_out_full_button.set_related_action (act);
2958 zoom_focus_selector.set_name ("zoom button");
2960 if (ARDOUR::Profile->get_mixbus()) {
2961 _zoom_box.pack_start (zoom_preset_selector, false, false);
2962 } else if (ARDOUR::Profile->get_trx()) {
2963 mode_box->pack_start (zoom_out_button, false, false);
2964 mode_box->pack_start (zoom_in_button, false, false);
2966 _zoom_box.pack_start (zoom_out_button, false, false);
2967 _zoom_box.pack_start (zoom_in_button, false, false);
2968 _zoom_box.pack_start (zoom_out_full_button, false, false);
2969 _zoom_box.pack_start (zoom_focus_selector, false, false);
2972 /* Track zoom buttons */
2973 visible_tracks_selector.set_name ("zoom button");
2974 if (Profile->get_mixbus()) {
2975 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2976 visible_tracks_selector.set_size_request (42, -1);
2978 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2981 tav_expand_button.set_name ("zoom button");
2982 tav_expand_button.set_image(::get_icon ("tav_exp"));
2983 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2984 tav_expand_button.set_related_action (act);
2986 tav_shrink_button.set_name ("zoom button");
2987 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2988 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2989 tav_shrink_button.set_related_action (act);
2991 if (ARDOUR::Profile->get_mixbus()) {
2992 _zoom_box.pack_start (visible_tracks_selector);
2993 } else if (ARDOUR::Profile->get_trx()) {
2994 _zoom_box.pack_start (tav_shrink_button);
2995 _zoom_box.pack_start (tav_expand_button);
2997 _zoom_box.pack_start (visible_tracks_selector);
2998 _zoom_box.pack_start (tav_shrink_button);
2999 _zoom_box.pack_start (tav_expand_button);
3002 if (!ARDOUR::Profile->get_trx()) {
3003 _zoom_tearoff = manage (new TearOff (_zoom_box));
3005 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3006 &_zoom_tearoff->tearoff_window()));
3007 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3008 &_zoom_tearoff->tearoff_window(), 0));
3009 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3010 &_zoom_tearoff->tearoff_window()));
3011 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3012 &_zoom_tearoff->tearoff_window(), 0));
3015 if (Profile->get_sae() || Profile->get_mixbus() ) {
3016 _zoom_tearoff->set_can_be_torn_off (false);
3019 snap_box.set_spacing (2);
3020 snap_box.set_border_width (2);
3022 snap_type_selector.set_name ("mouse mode button");
3024 snap_mode_selector.set_name ("mouse mode button");
3026 edit_point_selector.set_name ("mouse mode button");
3028 snap_box.pack_start (snap_mode_selector, false, false);
3029 snap_box.pack_start (snap_type_selector, false, false);
3030 snap_box.pack_start (edit_point_selector, false, false);
3034 HBox *nudge_box = manage (new HBox);
3035 nudge_box->set_spacing (2);
3036 nudge_box->set_border_width (2);
3038 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3039 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3041 nudge_box->pack_start (nudge_backward_button, false, false);
3042 nudge_box->pack_start (nudge_forward_button, false, false);
3043 nudge_box->pack_start (*nudge_clock, false, false);
3046 /* Pack everything in... */
3048 HBox* hbox = manage (new HBox);
3049 hbox->set_spacing(2);
3051 _tools_tearoff = manage (new TearOff (*hbox));
3052 _tools_tearoff->set_name ("MouseModeBase");
3053 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3055 if (Profile->get_sae() || Profile->get_mixbus()) {
3056 _tools_tearoff->set_can_be_torn_off (false);
3059 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3060 &_tools_tearoff->tearoff_window()));
3061 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3062 &_tools_tearoff->tearoff_window(), 0));
3063 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3064 &_tools_tearoff->tearoff_window()));
3065 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3066 &_tools_tearoff->tearoff_window(), 0));
3068 toolbar_hbox.set_spacing (2);
3069 toolbar_hbox.set_border_width (1);
3071 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3072 if (!ARDOUR::Profile->get_trx()) {
3073 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3074 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3077 if (!ARDOUR::Profile->get_trx()) {
3078 hbox->pack_start (snap_box, false, false);
3079 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3080 hbox->pack_start (*nudge_box, false, false);
3082 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3085 hbox->pack_start (panic_box, false, false);
3089 toolbar_base.set_name ("ToolBarBase");
3090 toolbar_base.add (toolbar_hbox);
3092 _toolbar_viewport.add (toolbar_base);
3093 /* stick to the required height but allow width to vary if there's not enough room */
3094 _toolbar_viewport.set_size_request (1, -1);
3096 toolbar_frame.set_shadow_type (SHADOW_OUT);
3097 toolbar_frame.set_name ("BaseFrame");
3098 toolbar_frame.add (_toolbar_viewport);
3102 Editor::build_edit_point_menu ()
3104 using namespace Menu_Helpers;
3106 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3107 if(!Profile->get_mixbus())
3108 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3109 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3111 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3115 Editor::build_edit_mode_menu ()
3117 using namespace Menu_Helpers;
3119 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3120 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3121 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3122 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3124 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3128 Editor::build_snap_mode_menu ()
3130 using namespace Menu_Helpers;
3132 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3133 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3134 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3136 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3140 Editor::build_snap_type_menu ()
3142 using namespace Menu_Helpers;
3144 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3145 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3146 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3147 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3148 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3149 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3150 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3151 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3152 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3153 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3154 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3155 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3156 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3157 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3158 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3159 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3160 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3161 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3162 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3163 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3164 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3165 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3166 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3167 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3168 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3169 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3170 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3171 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3172 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3173 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3175 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3180 Editor::setup_tooltips ()
3182 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3183 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3184 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3185 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3186 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit Gain/Notes/Automation"));
3187 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3188 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3189 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3190 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3191 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3192 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3193 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3194 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3195 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3196 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3197 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3198 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3199 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3200 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3201 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3202 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3203 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3204 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3205 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3209 Editor::convert_drop_to_paths (
3210 vector<string>& paths,
3211 const RefPtr<Gdk::DragContext>& /*context*/,
3214 const SelectionData& data,
3218 if (_session == 0) {
3222 vector<string> uris = data.get_uris();
3226 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3227 are actually URI lists. So do it by hand.
3230 if (data.get_target() != "text/plain") {
3234 /* Parse the "uri-list" format that Nautilus provides,
3235 where each pathname is delimited by \r\n.
3237 THERE MAY BE NO NULL TERMINATING CHAR!!!
3240 string txt = data.get_text();
3244 p = (char *) malloc (txt.length() + 1);
3245 txt.copy (p, txt.length(), 0);
3246 p[txt.length()] = '\0';
3252 while (g_ascii_isspace (*p))
3256 while (*q && (*q != '\n') && (*q != '\r')) {
3263 while (q > p && g_ascii_isspace (*q))
3268 uris.push_back (string (p, q - p + 1));
3272 p = strchr (p, '\n');
3284 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3285 if ((*i).substr (0,7) == "file://") {
3286 paths.push_back (Glib::filename_from_uri (*i));
3294 Editor::new_tempo_section ()
3299 Editor::map_transport_state ()
3301 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3303 if (_session && _session->transport_stopped()) {
3304 have_pending_keyboard_selection = false;
3307 update_loop_range_view ();
3313 Editor::begin_reversible_command (string name)
3316 _session->begin_reversible_command (name);
3321 Editor::begin_reversible_command (GQuark q)
3324 _session->begin_reversible_command (q);
3329 Editor::commit_reversible_command ()
3332 _session->commit_reversible_command ();
3337 Editor::history_changed ()
3341 if (undo_action && _session) {
3342 if (_session->undo_depth() == 0) {
3343 label = S_("Command|Undo");
3345 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3347 undo_action->property_label() = label;
3350 if (redo_action && _session) {
3351 if (_session->redo_depth() == 0) {
3354 label = string_compose(_("Redo (%1)"), _session->next_redo());
3356 redo_action->property_label() = label;
3361 Editor::duplicate_range (bool with_dialog)
3365 RegionSelection rs = get_regions_from_selection_and_entered ();
3367 if ( selection->time.length() == 0 && rs.empty()) {
3373 ArdourDialog win (_("Duplicate"));
3374 Label label (_("Number of duplications:"));
3375 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3376 SpinButton spinner (adjustment, 0.0, 1);
3379 win.get_vbox()->set_spacing (12);
3380 win.get_vbox()->pack_start (hbox);
3381 hbox.set_border_width (6);
3382 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3384 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3385 place, visually. so do this by hand.
3388 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3389 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3390 spinner.grab_focus();
3396 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3397 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3398 win.set_default_response (RESPONSE_ACCEPT);
3400 spinner.grab_focus ();
3402 switch (win.run ()) {
3403 case RESPONSE_ACCEPT:
3409 times = adjustment.get_value();
3412 if ((current_mouse_mode() == Editing::MouseRange)) {
3413 if (selection->time.length()) {
3414 duplicate_selection (times);
3416 } else if (get_smart_mode()) {
3417 if (selection->time.length()) {
3418 duplicate_selection (times);
3420 duplicate_some_regions (rs, times);
3422 duplicate_some_regions (rs, times);
3427 Editor::set_edit_mode (EditMode m)
3429 Config->set_edit_mode (m);
3433 Editor::cycle_edit_mode ()
3435 switch (Config->get_edit_mode()) {
3437 if (Profile->get_sae()) {
3438 Config->set_edit_mode (Lock);
3440 Config->set_edit_mode (Ripple);
3445 Config->set_edit_mode (Lock);
3448 Config->set_edit_mode (Slide);
3454 Editor::edit_mode_selection_done ( EditMode m )
3456 Config->set_edit_mode ( m );
3460 Editor::snap_type_selection_done (SnapType snaptype)
3462 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3464 ract->set_active ();
3469 Editor::snap_mode_selection_done (SnapMode mode)
3471 RefPtr<RadioAction> ract = snap_mode_action (mode);
3474 ract->set_active (true);
3479 Editor::cycle_edit_point (bool with_marker)
3481 if(Profile->get_mixbus())
3482 with_marker = false;
3484 switch (_edit_point) {
3486 set_edit_point_preference (EditAtPlayhead);
3488 case EditAtPlayhead:
3490 set_edit_point_preference (EditAtSelectedMarker);
3492 set_edit_point_preference (EditAtMouse);
3495 case EditAtSelectedMarker:
3496 set_edit_point_preference (EditAtMouse);
3502 Editor::edit_point_selection_done (EditPoint ep)
3504 set_edit_point_preference ( ep );
3508 Editor::build_zoom_focus_menu ()
3510 using namespace Menu_Helpers;
3512 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3513 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3514 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3515 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3516 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3517 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3519 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3523 Editor::zoom_focus_selection_done ( ZoomFocus f )
3525 RefPtr<RadioAction> ract = zoom_focus_action (f);
3527 ract->set_active ();
3532 Editor::build_track_count_menu ()
3534 using namespace Menu_Helpers;
3536 if (!Profile->get_mixbus()) {
3537 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3538 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3539 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3540 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3541 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3542 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3543 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3544 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3545 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3546 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3547 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3548 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3549 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3551 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3552 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3553 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3554 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3555 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3556 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3557 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3558 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3559 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3560 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3562 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3563 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3564 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3565 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3566 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3567 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3568 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3569 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3570 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3571 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3572 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3577 Editor::set_zoom_preset (int64_t ms)
3580 temporal_zoom_session();
3584 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3585 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3589 Editor::set_visible_track_count (int32_t n)
3591 _visible_track_count = n;
3593 /* if the canvas hasn't really been allocated any size yet, just
3594 record the desired number of visible tracks and return. when canvas
3595 allocation happens, we will get called again and then we can do the
3599 if (_visible_canvas_height <= 1) {
3606 if (_visible_track_count > 0) {
3607 h = trackviews_height() / _visible_track_count;
3608 std::ostringstream s;
3609 s << _visible_track_count;
3611 } else if (_visible_track_count == 0) {
3613 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3614 if ((*i)->marked_for_display()) {
3618 h = trackviews_height() / n;
3621 /* negative value means that the visible track count has
3622 been overridden by explicit track height changes.
3624 visible_tracks_selector.set_text (X_("*"));
3628 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3629 (*i)->set_height (h);
3632 if (str != visible_tracks_selector.get_text()) {
3633 visible_tracks_selector.set_text (str);
3638 Editor::override_visible_track_count ()
3640 _visible_track_count = -1;
3641 visible_tracks_selector.set_text ( _("*") );
3645 Editor::edit_controls_button_release (GdkEventButton* ev)
3647 if (Keyboard::is_context_menu_event (ev)) {
3648 ARDOUR_UI::instance()->add_route (this);
3649 } else if (ev->button == 1) {
3650 selection->clear_tracks ();
3657 Editor::mouse_select_button_release (GdkEventButton* ev)
3659 /* this handles just right-clicks */
3661 if (ev->button != 3) {
3669 Editor::set_zoom_focus (ZoomFocus f)
3671 string str = zoom_focus_strings[(int)f];
3673 if (str != zoom_focus_selector.get_text()) {
3674 zoom_focus_selector.set_text (str);
3677 if (zoom_focus != f) {
3684 Editor::cycle_zoom_focus ()
3686 switch (zoom_focus) {
3688 set_zoom_focus (ZoomFocusRight);
3690 case ZoomFocusRight:
3691 set_zoom_focus (ZoomFocusCenter);
3693 case ZoomFocusCenter:
3694 set_zoom_focus (ZoomFocusPlayhead);
3696 case ZoomFocusPlayhead:
3697 set_zoom_focus (ZoomFocusMouse);
3699 case ZoomFocusMouse:
3700 set_zoom_focus (ZoomFocusEdit);
3703 set_zoom_focus (ZoomFocusLeft);
3709 Editor::ensure_float (Window& win)
3711 win.set_transient_for (*this);
3715 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3717 /* recover or initialize pane positions. do this here rather than earlier because
3718 we don't want the positions to change the child allocations, which they seem to do.
3724 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3733 XMLNode* geometry = find_named_node (*node, "geometry");
3735 if (which == static_cast<Paned*> (&edit_pane)) {
3737 if (done & Horizontal) {
3741 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3742 _notebook_shrunk = string_is_affirmative (prop->value ());
3745 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3746 /* initial allocation is 90% to canvas, 10% to notebook */
3747 pos = (int) floor (alloc.get_width() * 0.90f);
3748 snprintf (buf, sizeof(buf), "%d", pos);
3750 pos = atoi (prop->value());
3753 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3754 edit_pane.set_position (pos);
3757 done = (Pane) (done | Horizontal);
3759 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3761 if (done & Vertical) {
3765 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3766 /* initial allocation is 90% to canvas, 10% to summary */
3767 pos = (int) floor (alloc.get_height() * 0.90f);
3768 snprintf (buf, sizeof(buf), "%d", pos);
3771 pos = atoi (prop->value());
3774 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3775 editor_summary_pane.set_position (pos);
3778 done = (Pane) (done | Vertical);
3783 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3785 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3786 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3787 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3788 top_hbox.remove (toolbar_frame);
3793 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3795 if (toolbar_frame.get_parent() == 0) {
3796 top_hbox.pack_end (toolbar_frame);
3801 Editor::set_show_measures (bool yn)
3803 if (_show_measures != yn) {
3806 if ((_show_measures = yn) == true) {
3808 tempo_lines->show();
3811 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3812 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3814 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3815 draw_measures (begin, end);
3823 Editor::toggle_follow_playhead ()
3825 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3827 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3828 set_follow_playhead (tact->get_active());
3832 /** @param yn true to follow playhead, otherwise false.
3833 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3836 Editor::set_follow_playhead (bool yn, bool catch_up)
3838 if (_follow_playhead != yn) {
3839 if ((_follow_playhead = yn) == true && catch_up) {
3841 reset_x_origin_to_follow_playhead ();
3848 Editor::toggle_stationary_playhead ()
3850 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3852 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3853 set_stationary_playhead (tact->get_active());
3858 Editor::set_stationary_playhead (bool yn)
3860 if (_stationary_playhead != yn) {
3861 if ((_stationary_playhead = yn) == true) {
3863 // FIXME need a 3.0 equivalent of this 2.X call
3864 // update_current_screen ();
3871 Editor::playlist_selector () const
3873 return *_playlist_selector;
3877 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3879 if (paste_count == 0) {
3880 /* don't bother calculating an offset that will be zero anyway */
3884 /* calculate basic unsnapped multi-paste offset */
3885 framecnt_t offset = paste_count * duration;
3887 /* snap offset so pos + offset is aligned to the grid */
3888 framepos_t offset_pos = pos + offset;
3889 snap_to(offset_pos, RoundUpMaybe);
3890 offset = offset_pos - pos;
3896 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3900 switch (_snap_type) {
3902 return Evoral::MusicalTime(1.0);
3905 case SnapToBeatDiv128:
3906 return Evoral::MusicalTime(1.0/128.0);
3908 case SnapToBeatDiv64:
3909 return Evoral::MusicalTime(1.0/64.0);
3911 case SnapToBeatDiv32:
3912 return Evoral::MusicalTime(1.0/32.0);
3914 case SnapToBeatDiv28:
3915 return Evoral::MusicalTime(1.0/28.0);
3917 case SnapToBeatDiv24:
3918 return Evoral::MusicalTime(1.0/24.0);
3920 case SnapToBeatDiv20:
3921 return Evoral::MusicalTime(1.0/20.0);
3923 case SnapToBeatDiv16:
3924 return Evoral::MusicalTime(1.0/16.0);
3926 case SnapToBeatDiv14:
3927 return Evoral::MusicalTime(1.0/14.0);
3929 case SnapToBeatDiv12:
3930 return Evoral::MusicalTime(1.0/12.0);
3932 case SnapToBeatDiv10:
3933 return Evoral::MusicalTime(1.0/10.0);
3935 case SnapToBeatDiv8:
3936 return Evoral::MusicalTime(1.0/8.0);
3938 case SnapToBeatDiv7:
3939 return Evoral::MusicalTime(1.0/7.0);
3941 case SnapToBeatDiv6:
3942 return Evoral::MusicalTime(1.0/6.0);
3944 case SnapToBeatDiv5:
3945 return Evoral::MusicalTime(1.0/5.0);
3947 case SnapToBeatDiv4:
3948 return Evoral::MusicalTime(1.0/4.0);
3950 case SnapToBeatDiv3:
3951 return Evoral::MusicalTime(1.0/3.0);
3953 case SnapToBeatDiv2:
3954 return Evoral::MusicalTime(1.0/2.0);
3959 return Evoral::MusicalTime(_session->tempo_map().meter_at (position).divisions_per_bar());
3964 case SnapToTimecodeFrame:
3965 case SnapToTimecodeSeconds:
3966 case SnapToTimecodeMinutes:
3969 case SnapToRegionStart:
3970 case SnapToRegionEnd:
3971 case SnapToRegionSync:
3972 case SnapToRegionBoundary:
3978 return Evoral::MusicalTime();
3982 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3986 ret = nudge_clock->current_duration (pos);
3987 next = ret + 1; /* XXXX fix me */
3993 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3995 ArdourDialog dialog (_("Playlist Deletion"));
3996 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3997 "If it is kept, its audio files will not be cleaned.\n"
3998 "If it is deleted, audio files used by it alone will be cleaned."),
4001 dialog.set_position (WIN_POS_CENTER);
4002 dialog.get_vbox()->pack_start (label);
4006 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4007 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4008 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4010 switch (dialog.run ()) {
4011 case RESPONSE_ACCEPT:
4012 /* delete the playlist */
4016 case RESPONSE_REJECT:
4017 /* keep the playlist */
4029 Editor::audio_region_selection_covers (framepos_t where)
4031 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4032 if ((*a)->region()->covers (where)) {
4041 Editor::prepare_for_cleanup ()
4043 cut_buffer->clear_regions ();
4044 cut_buffer->clear_playlists ();
4046 selection->clear_regions ();
4047 selection->clear_playlists ();
4049 _regions->suspend_redisplay ();
4053 Editor::finish_cleanup ()
4055 _regions->resume_redisplay ();
4059 Editor::transport_loop_location()
4062 return _session->locations()->auto_loop_location();
4069 Editor::transport_punch_location()
4072 return _session->locations()->auto_punch_location();
4079 Editor::control_layout_scroll (GdkEventScroll* ev)
4081 /* Just forward to the normal canvas scroll method. The coordinate
4082 systems are different but since the canvas is always larger than the
4083 track headers, and aligned with the trackview area, this will work.
4085 In the not too distant future this layout is going away anyway and
4086 headers will be on the canvas.
4088 return canvas_scroll_event (ev, false);
4092 Editor::session_state_saved (string)
4095 _snapshots->redisplay ();
4099 Editor::update_tearoff_visibility()
4101 bool visible = Config->get_keep_tearoffs();
4102 _mouse_mode_tearoff->set_visible (visible);
4103 _tools_tearoff->set_visible (visible);
4104 if (_zoom_tearoff) {
4105 _zoom_tearoff->set_visible (visible);
4110 Editor::reattach_all_tearoffs ()
4112 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4113 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4114 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4118 Editor::maximise_editing_space ()
4130 Editor::restore_editing_space ()
4142 * Make new playlists for a given track and also any others that belong
4143 * to the same active route group with the `select' property.
4148 Editor::new_playlists (TimeAxisView* v)
4150 begin_reversible_command (_("new playlists"));
4151 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4152 _session->playlists->get (playlists);
4153 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4154 commit_reversible_command ();
4158 * Use a copy of the current playlist for a given track and also any others that belong
4159 * to the same active route group with the `select' property.
4164 Editor::copy_playlists (TimeAxisView* v)
4166 begin_reversible_command (_("copy playlists"));
4167 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4168 _session->playlists->get (playlists);
4169 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4170 commit_reversible_command ();
4173 /** Clear the current playlist for a given track and also any others that belong
4174 * to the same active route group with the `select' property.
4179 Editor::clear_playlists (TimeAxisView* v)
4181 begin_reversible_command (_("clear playlists"));
4182 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4183 _session->playlists->get (playlists);
4184 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4185 commit_reversible_command ();
4189 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4191 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4195 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4197 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4201 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4203 atv.clear_playlist ();
4207 Editor::on_key_press_event (GdkEventKey* ev)
4209 return key_press_focus_accelerator_handler (*this, ev);
4213 Editor::on_key_release_event (GdkEventKey* ev)
4215 return Gtk::Window::on_key_release_event (ev);
4216 // return key_press_focus_accelerator_handler (*this, ev);
4219 /** Queue up a change to the viewport x origin.
4220 * @param frame New x origin.
4223 Editor::reset_x_origin (framepos_t frame)
4225 pending_visual_change.add (VisualChange::TimeOrigin);
4226 pending_visual_change.time_origin = frame;
4227 ensure_visual_change_idle_handler ();
4231 Editor::reset_y_origin (double y)
4233 pending_visual_change.add (VisualChange::YOrigin);
4234 pending_visual_change.y_origin = y;
4235 ensure_visual_change_idle_handler ();
4239 Editor::reset_zoom (framecnt_t spp)
4241 if (spp == samples_per_pixel) {
4245 pending_visual_change.add (VisualChange::ZoomLevel);
4246 pending_visual_change.samples_per_pixel = spp;
4247 ensure_visual_change_idle_handler ();
4251 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4253 reset_x_origin (frame);
4256 if (!no_save_visual) {
4257 undo_visual_stack.push_back (current_visual_state(false));
4261 Editor::VisualState::VisualState (bool with_tracks)
4262 : gui_state (with_tracks ? new GUIObjectState : 0)
4266 Editor::VisualState::~VisualState ()
4271 Editor::VisualState*
4272 Editor::current_visual_state (bool with_tracks)
4274 VisualState* vs = new VisualState (with_tracks);
4275 vs->y_position = vertical_adjustment.get_value();
4276 vs->samples_per_pixel = samples_per_pixel;
4277 vs->leftmost_frame = leftmost_frame;
4278 vs->zoom_focus = zoom_focus;
4281 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4288 Editor::undo_visual_state ()
4290 if (undo_visual_stack.empty()) {
4294 VisualState* vs = undo_visual_stack.back();
4295 undo_visual_stack.pop_back();
4298 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4301 use_visual_state (*vs);
4306 Editor::redo_visual_state ()
4308 if (redo_visual_stack.empty()) {
4312 VisualState* vs = redo_visual_stack.back();
4313 redo_visual_stack.pop_back();
4315 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4316 // why do we check here?
4317 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4320 use_visual_state (*vs);
4325 Editor::swap_visual_state ()
4327 if (undo_visual_stack.empty()) {
4328 redo_visual_state ();
4330 undo_visual_state ();
4335 Editor::use_visual_state (VisualState& vs)
4337 PBD::Unwinder<bool> nsv (no_save_visual, true);
4338 DisplaySuspender ds;
4340 vertical_adjustment.set_value (vs.y_position);
4342 set_zoom_focus (vs.zoom_focus);
4343 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4346 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4348 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4349 (*i)->reset_visual_state ();
4353 _routes->update_visibility ();
4356 /** This is the core function that controls the zoom level of the canvas. It is called
4357 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4358 * @param spp new number of samples per pixel
4361 Editor::set_samples_per_pixel (framecnt_t spp)
4367 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4368 const framecnt_t lots_of_pixels = 4000;
4370 /* if the zoom level is greater than what you'd get trying to display 3
4371 * days of audio on a really big screen, then it's too big.
4374 if (spp * lots_of_pixels > three_days) {
4378 samples_per_pixel = spp;
4381 tempo_lines->tempo_map_changed();
4384 bool const showing_time_selection = selection->time.length() > 0;
4386 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4387 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4388 (*i)->reshow_selection (selection->time);
4392 ZoomChanged (); /* EMIT_SIGNAL */
4394 ArdourCanvas::GtkCanvasViewport* c;
4396 c = get_track_canvas();
4398 c->canvas()->zoomed ();
4401 if (playhead_cursor) {
4402 playhead_cursor->set_position (playhead_cursor->current_frame ());
4405 refresh_location_display();
4406 _summary->set_overlays_dirty ();
4408 update_marker_labels ();
4414 Editor::queue_visual_videotimeline_update ()
4417 * pending_visual_change.add (VisualChange::VideoTimeline);
4418 * or maybe even more specific: which videotimeline-image
4419 * currently it calls update_video_timeline() to update
4420 * _all outdated_ images on the video-timeline.
4421 * see 'exposeimg()' in video_image_frame.cc
4423 ensure_visual_change_idle_handler ();
4427 Editor::ensure_visual_change_idle_handler ()
4429 if (pending_visual_change.idle_handler_id < 0) {
4430 // see comment in add_to_idle_resize above.
4431 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4432 pending_visual_change.being_handled = false;
4437 Editor::_idle_visual_changer (void* arg)
4439 return static_cast<Editor*>(arg)->idle_visual_changer ();
4443 Editor::idle_visual_changer ()
4445 /* set_horizontal_position() below (and maybe other calls) call
4446 gtk_main_iteration(), so it's possible that a signal will be handled
4447 half-way through this method. If this signal wants an
4448 idle_visual_changer we must schedule another one after this one, so
4449 mark the idle_handler_id as -1 here to allow that. Also make a note
4450 that we are doing the visual change, so that changes in response to
4451 super-rapid-screen-update can be dropped if we are still processing
4455 pending_visual_change.idle_handler_id = -1;
4456 pending_visual_change.being_handled = true;
4458 VisualChange vc = pending_visual_change;
4460 pending_visual_change.pending = (VisualChange::Type) 0;
4462 visual_changer (vc);
4464 pending_visual_change.being_handled = false;
4466 return 0; /* this is always a one-shot call */
4470 Editor::visual_changer (const VisualChange& vc)
4472 double const last_time_origin = horizontal_position ();
4474 if (vc.pending & VisualChange::ZoomLevel) {
4475 set_samples_per_pixel (vc.samples_per_pixel);
4477 compute_fixed_ruler_scale ();
4479 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4480 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4482 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4483 current_bbt_points_begin, current_bbt_points_end);
4484 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4485 current_bbt_points_begin, current_bbt_points_end);
4486 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4488 update_video_timeline();
4491 if (vc.pending & VisualChange::TimeOrigin) {
4492 set_horizontal_position (vc.time_origin / samples_per_pixel);
4495 if (vc.pending & VisualChange::YOrigin) {
4496 vertical_adjustment.set_value (vc.y_origin);
4499 if (last_time_origin == horizontal_position ()) {
4500 /* changed signal not emitted */
4501 update_fixed_rulers ();
4502 redisplay_tempo (true);
4505 if (!(vc.pending & VisualChange::ZoomLevel)) {
4506 update_video_timeline();
4509 _summary->set_overlays_dirty ();
4512 struct EditorOrderTimeAxisSorter {
4513 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4514 return a->order () < b->order ();
4519 Editor::sort_track_selection (TrackViewList& sel)
4521 EditorOrderTimeAxisSorter cmp;
4526 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4529 framepos_t where = 0;
4530 EditPoint ep = _edit_point;
4532 if(Profile->get_mixbus())
4533 if (ep == EditAtSelectedMarker)
4536 if (from_context_menu && (ep == EditAtMouse)) {
4537 return canvas_event_sample (&context_click_event, 0, 0);
4540 if (entered_marker) {
4541 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4542 return entered_marker->position();
4545 if (ignore_playhead && ep == EditAtPlayhead) {
4546 ep = EditAtSelectedMarker;
4550 case EditAtPlayhead:
4551 where = _session->audible_frame();
4552 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4555 case EditAtSelectedMarker:
4556 if (!selection->markers.empty()) {
4558 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4561 where = loc->start();
4565 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4573 if (!mouse_frame (where, ignored)) {
4574 /* XXX not right but what can we do ? */
4578 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4586 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4588 if (!_session) return;
4590 begin_reversible_command (cmd);
4594 if ((tll = transport_loop_location()) == 0) {
4595 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4596 XMLNode &before = _session->locations()->get_state();
4597 _session->locations()->add (loc, true);
4598 _session->set_auto_loop_location (loc);
4599 XMLNode &after = _session->locations()->get_state();
4600 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4602 XMLNode &before = tll->get_state();
4603 tll->set_hidden (false, this);
4604 tll->set (start, end);
4605 XMLNode &after = tll->get_state();
4606 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4609 commit_reversible_command ();
4613 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4615 if (!_session) return;
4617 begin_reversible_command (cmd);
4621 if ((tpl = transport_punch_location()) == 0) {
4622 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4623 XMLNode &before = _session->locations()->get_state();
4624 _session->locations()->add (loc, true);
4625 _session->set_auto_punch_location (loc);
4626 XMLNode &after = _session->locations()->get_state();
4627 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4630 XMLNode &before = tpl->get_state();
4631 tpl->set_hidden (false, this);
4632 tpl->set (start, end);
4633 XMLNode &after = tpl->get_state();
4634 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4637 commit_reversible_command ();
4640 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4641 * @param rs List to which found regions are added.
4642 * @param where Time to look at.
4643 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4646 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4648 const TrackViewList* tracks;
4651 tracks = &track_views;
4656 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4658 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4661 boost::shared_ptr<Track> tr;
4662 boost::shared_ptr<Playlist> pl;
4664 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4666 boost::shared_ptr<RegionList> regions = pl->regions_at (
4667 (framepos_t) floor ( (double) where * tr->speed()));
4669 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4670 RegionView* rv = rtv->view()->find_view (*i);
4681 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4683 const TrackViewList* tracks;
4686 tracks = &track_views;
4691 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4692 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4694 boost::shared_ptr<Track> tr;
4695 boost::shared_ptr<Playlist> pl;
4697 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4699 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4700 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4702 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4704 RegionView* rv = rtv->view()->find_view (*i);
4715 /** Get regions using the following method:
4717 * Make a region list using:
4718 * (a) any selected regions
4719 * (b) the intersection of any selected tracks and the edit point(*)
4720 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4722 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4724 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4728 Editor::get_regions_from_selection_and_edit_point ()
4730 RegionSelection regions;
4732 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4733 regions.add (entered_regionview);
4735 regions = selection->regions;
4738 if ( regions.empty() ) {
4739 TrackViewList tracks = selection->tracks;
4741 if (!tracks.empty()) {
4742 /* no region selected or entered, but some selected tracks:
4743 * act on all regions on the selected tracks at the edit point
4745 framepos_t const where = get_preferred_edit_position ();
4746 get_regions_at(regions, where, tracks);
4753 /** Get regions using the following method:
4755 * Make a region list using:
4756 * (a) any selected regions
4757 * (b) the intersection of any selected tracks and the edit point(*)
4758 * (c) if neither exists, then whatever region is under the mouse
4760 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4762 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4765 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4767 RegionSelection regions;
4769 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4770 regions.add (entered_regionview);
4772 regions = selection->regions;
4775 if ( regions.empty() ) {
4776 TrackViewList tracks = selection->tracks;
4778 if (!tracks.empty()) {
4779 /* no region selected or entered, but some selected tracks:
4780 * act on all regions on the selected tracks at the edit point
4782 get_regions_at(regions, pos, tracks);
4789 /** Start with regions that are selected, or the entered regionview if none are selected.
4790 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4791 * of the regions that we started with.
4795 Editor::get_regions_from_selection_and_entered ()
4797 RegionSelection regions = selection->regions;
4799 if (regions.empty() && entered_regionview) {
4800 regions.add (entered_regionview);
4807 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4809 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4811 RouteTimeAxisView* tatv;
4813 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4815 boost::shared_ptr<Playlist> pl;
4816 vector<boost::shared_ptr<Region> > results;
4818 boost::shared_ptr<Track> tr;
4820 if ((tr = tatv->track()) == 0) {
4825 if ((pl = (tr->playlist())) != 0) {
4826 if (src_comparison) {
4827 pl->get_source_equivalent_regions (region, results);
4829 pl->get_region_list_equivalent_regions (region, results);
4833 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4834 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4835 regions.push_back (marv);
4844 Editor::show_rhythm_ferret ()
4846 if (rhythm_ferret == 0) {
4847 rhythm_ferret = new RhythmFerret(*this);
4850 rhythm_ferret->set_session (_session);
4851 rhythm_ferret->show ();
4852 rhythm_ferret->present ();
4856 Editor::first_idle ()
4858 MessageDialog* dialog = 0;
4860 if (track_views.size() > 1) {
4861 dialog = new MessageDialog (
4863 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4867 ARDOUR_UI::instance()->flush_pending ();
4870 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4874 // first idle adds route children (automation tracks), so we need to redisplay here
4875 _routes->redisplay ();
4882 Editor::_idle_resize (gpointer arg)
4884 return ((Editor*)arg)->idle_resize ();
4888 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4890 if (resize_idle_id < 0) {
4891 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
4892 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
4893 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
4895 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
4896 _pending_resize_amount = 0;
4899 /* make a note of the smallest resulting height, so that we can clamp the
4900 lower limit at TimeAxisView::hSmall */
4902 int32_t min_resulting = INT32_MAX;
4904 _pending_resize_amount += h;
4905 _pending_resize_view = view;
4907 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4909 if (selection->tracks.contains (_pending_resize_view)) {
4910 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4911 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4915 if (min_resulting < 0) {
4920 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4921 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4925 /** Handle pending resizing of tracks */
4927 Editor::idle_resize ()
4929 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4931 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4932 selection->tracks.contains (_pending_resize_view)) {
4934 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4935 if (*i != _pending_resize_view) {
4936 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4941 _pending_resize_amount = 0;
4942 _group_tabs->set_dirty ();
4943 resize_idle_id = -1;
4951 ENSURE_GUI_THREAD (*this, &Editor::located);
4954 playhead_cursor->set_position (_session->audible_frame ());
4955 if (_follow_playhead && !_pending_initial_locate) {
4956 reset_x_origin_to_follow_playhead ();
4960 _pending_locate_request = false;
4961 _pending_initial_locate = false;
4965 Editor::region_view_added (RegionView *)
4967 _summary->set_background_dirty ();
4971 Editor::region_view_removed ()
4973 _summary->set_background_dirty ();
4977 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4979 TrackViewList::const_iterator j = track_views.begin ();
4980 while (j != track_views.end()) {
4981 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4982 if (rtv && rtv->route() == r) {
4993 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4997 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4998 TimeAxisView* tv = axis_view_from_route (*i);
5008 Editor::suspend_route_redisplay ()
5011 _routes->suspend_redisplay();
5016 Editor::resume_route_redisplay ()
5019 _routes->resume_redisplay();
5024 Editor::add_routes (RouteList& routes)
5026 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5028 RouteTimeAxisView *rtv;
5029 list<RouteTimeAxisView*> new_views;
5031 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5032 boost::shared_ptr<Route> route = (*x);
5034 if (route->is_auditioner() || route->is_monitor()) {
5038 DataType dt = route->input()->default_type();
5040 if (dt == ARDOUR::DataType::AUDIO) {
5041 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5042 rtv->set_route (route);
5043 } else if (dt == ARDOUR::DataType::MIDI) {
5044 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5045 rtv->set_route (route);
5047 throw unknown_type();
5050 new_views.push_back (rtv);
5051 track_views.push_back (rtv);
5053 rtv->effective_gain_display ();
5055 if (internal_editing()) {
5056 rtv->enter_internal_edit_mode ();
5058 rtv->leave_internal_edit_mode ();
5061 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5062 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5065 if (new_views.size() > 0) {
5066 _routes->routes_added (new_views);
5067 _summary->routes_added (new_views);
5070 if (show_editor_mixer_when_tracks_arrive) {
5071 show_editor_mixer (true);
5074 editor_list_button.set_sensitive (true);
5078 Editor::timeaxisview_deleted (TimeAxisView *tv)
5080 if (tv == entered_track) {
5084 if (_session && _session->deletion_in_progress()) {
5085 /* the situation is under control */
5089 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5091 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5093 _routes->route_removed (tv);
5095 TimeAxisView::Children c = tv->get_child_list ();
5096 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5097 if (entered_track == i->get()) {
5102 /* remove it from the list of track views */
5104 TrackViewList::iterator i;
5106 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5107 i = track_views.erase (i);
5110 /* update whatever the current mixer strip is displaying, if revelant */
5112 boost::shared_ptr<Route> route;
5115 route = rtav->route ();
5118 if (current_mixer_strip && current_mixer_strip->route() == route) {
5120 TimeAxisView* next_tv;
5122 if (track_views.empty()) {
5124 } else if (i == track_views.end()) {
5125 next_tv = track_views.front();
5132 set_selected_mixer_strip (*next_tv);
5134 /* make the editor mixer strip go away setting the
5135 * button to inactive (which also unticks the menu option)
5138 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5144 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5146 if (apply_to_selection) {
5147 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5149 TrackSelection::iterator j = i;
5152 hide_track_in_display (*i, false);
5157 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5159 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5160 // this will hide the mixer strip
5161 set_selected_mixer_strip (*tv);
5164 _routes->hide_track_in_display (*tv);
5169 Editor::sync_track_view_list_and_routes ()
5171 track_views = TrackViewList (_routes->views ());
5173 _summary->set_dirty ();
5174 _group_tabs->set_dirty ();
5176 return false; // do not call again (until needed)
5180 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5182 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5187 /** Find a RouteTimeAxisView by the ID of its route */
5189 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5191 RouteTimeAxisView* v;
5193 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5194 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5195 if(v->route()->id() == id) {
5205 Editor::fit_route_group (RouteGroup *g)
5207 TrackViewList ts = axis_views_from_routes (g->route_list ());
5212 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5214 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5217 _session->cancel_audition ();
5221 if (_session->is_auditioning()) {
5222 _session->cancel_audition ();
5223 if (r == last_audition_region) {
5228 _session->audition_region (r);
5229 last_audition_region = r;
5234 Editor::hide_a_region (boost::shared_ptr<Region> r)
5236 r->set_hidden (true);
5240 Editor::show_a_region (boost::shared_ptr<Region> r)
5242 r->set_hidden (false);
5246 Editor::audition_region_from_region_list ()
5248 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5252 Editor::hide_region_from_region_list ()
5254 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5258 Editor::show_region_in_region_list ()
5260 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5264 Editor::step_edit_status_change (bool yn)
5267 start_step_editing ();
5269 stop_step_editing ();
5274 Editor::start_step_editing ()
5276 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5280 Editor::stop_step_editing ()
5282 step_edit_connection.disconnect ();
5286 Editor::check_step_edit ()
5288 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5289 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5291 mtv->check_step_edit ();
5295 return true; // do it again, till we stop
5299 Editor::scroll_press (Direction dir)
5301 ++_scroll_callbacks;
5303 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5304 /* delay the first auto-repeat */
5310 scroll_backward (1);
5318 scroll_up_one_track ();
5322 scroll_down_one_track ();
5326 /* do hacky auto-repeat */
5327 if (!_scroll_connection.connected ()) {
5329 _scroll_connection = Glib::signal_timeout().connect (
5330 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5333 _scroll_callbacks = 0;
5340 Editor::scroll_release ()
5342 _scroll_connection.disconnect ();
5345 /** Queue a change for the Editor viewport x origin to follow the playhead */
5347 Editor::reset_x_origin_to_follow_playhead ()
5349 framepos_t const frame = playhead_cursor->current_frame ();
5351 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5353 if (_session->transport_speed() < 0) {
5355 if (frame > (current_page_samples() / 2)) {
5356 center_screen (frame-(current_page_samples()/2));
5358 center_screen (current_page_samples()/2);
5365 if (frame < leftmost_frame) {
5367 if (_session->transport_rolling()) {
5368 /* rolling; end up with the playhead at the right of the page */
5369 l = frame - current_page_samples ();
5371 /* not rolling: end up with the playhead 1/4 of the way along the page */
5372 l = frame - current_page_samples() / 4;
5376 if (_session->transport_rolling()) {
5377 /* rolling: end up with the playhead on the left of the page */
5380 /* not rolling: end up with the playhead 3/4 of the way along the page */
5381 l = frame - 3 * current_page_samples() / 4;
5389 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5395 Editor::super_rapid_screen_update ()
5397 if (!_session || !_session->engine().running()) {
5401 /* METERING / MIXER STRIPS */
5403 /* update track meters, if required */
5404 if (is_mapped() && meters_running) {
5405 RouteTimeAxisView* rtv;
5406 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5407 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5408 rtv->fast_update ();
5413 /* and any current mixer strip */
5414 if (current_mixer_strip) {
5415 current_mixer_strip->fast_update ();
5418 /* PLAYHEAD AND VIEWPORT */
5420 framepos_t const frame = _session->audible_frame();
5422 /* There are a few reasons why we might not update the playhead / viewport stuff:
5424 * 1. we don't update things when there's a pending locate request, otherwise
5425 * when the editor requests a locate there is a chance that this method
5426 * will move the playhead before the locate request is processed, causing
5428 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5429 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5432 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5434 last_update_frame = frame;
5436 if (!_dragging_playhead) {
5437 playhead_cursor->set_position (frame);
5440 if (!_stationary_playhead) {
5442 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5443 /* We only do this if we aren't already
5444 handling a visual change (ie if
5445 pending_visual_change.being_handled is
5446 false) so that these requests don't stack
5447 up there are too many of them to handle in
5450 reset_x_origin_to_follow_playhead ();
5455 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5459 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5460 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5461 if (target <= 0.0) {
5464 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5465 target = (target * 0.15) + (current * 0.85);
5471 set_horizontal_position (current);
5480 Editor::session_going_away ()
5482 _have_idled = false;
5484 _session_connections.drop_connections ();
5486 super_rapid_screen_update_connection.disconnect ();
5488 selection->clear ();
5489 cut_buffer->clear ();
5491 clicked_regionview = 0;
5492 clicked_axisview = 0;
5493 clicked_routeview = 0;
5494 entered_regionview = 0;
5496 last_update_frame = 0;
5499 playhead_cursor->hide ();
5501 /* rip everything out of the list displays */
5505 _route_groups->clear ();
5507 /* do this first so that deleting a track doesn't reset cms to null
5508 and thus cause a leak.
5511 if (current_mixer_strip) {
5512 if (current_mixer_strip->get_parent() != 0) {
5513 global_hpacker.remove (*current_mixer_strip);
5515 delete current_mixer_strip;
5516 current_mixer_strip = 0;
5519 /* delete all trackviews */
5521 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5524 track_views.clear ();
5526 nudge_clock->set_session (0);
5528 editor_list_button.set_active(false);
5529 editor_list_button.set_sensitive(false);
5531 /* clear tempo/meter rulers */
5532 remove_metric_marks ();
5534 clear_marker_display ();
5536 stop_step_editing ();
5538 /* get rid of any existing editor mixer strip */
5540 WindowTitle title(Glib::get_application_name());
5541 title += _("Editor");
5543 set_title (title.get_string());
5545 SessionHandlePtr::session_going_away ();
5550 Editor::show_editor_list (bool yn)
5553 _the_notebook.show ();
5555 _the_notebook.hide ();
5560 Editor::change_region_layering_order (bool from_context_menu)
5562 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5564 if (!clicked_routeview) {
5565 if (layering_order_editor) {
5566 layering_order_editor->hide ();
5571 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5577 boost::shared_ptr<Playlist> pl = track->playlist();
5583 if (layering_order_editor == 0) {
5584 layering_order_editor = new RegionLayeringOrderEditor (*this);
5587 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5588 layering_order_editor->maybe_present ();
5592 Editor::update_region_layering_order_editor ()
5594 if (layering_order_editor && layering_order_editor->is_visible ()) {
5595 change_region_layering_order (true);
5600 Editor::setup_fade_images ()
5602 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5603 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5604 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5605 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5606 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5608 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5609 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5610 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5611 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5612 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5614 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5615 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5616 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5617 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5618 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5620 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5621 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5622 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5623 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5624 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5628 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5630 Editor::action_menu_item (std::string const & name)
5632 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5635 return *manage (a->create_menu_item ());
5639 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5641 EventBox* b = manage (new EventBox);
5642 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5643 Label* l = manage (new Label (name));
5647 _the_notebook.append_page (widget, *b);
5651 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5653 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5654 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5657 if (ev->type == GDK_2BUTTON_PRESS) {
5659 /* double-click on a notebook tab shrinks or expands the notebook */
5661 if (_notebook_shrunk) {
5662 if (pre_notebook_shrink_pane_width) {
5663 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5665 _notebook_shrunk = false;
5667 pre_notebook_shrink_pane_width = edit_pane.get_position();
5669 /* this expands the LHS of the edit pane to cover the notebook
5670 PAGE but leaves the tabs visible.
5672 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5673 _notebook_shrunk = true;
5681 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5683 using namespace Menu_Helpers;
5685 MenuList& items = _control_point_context_menu.items ();
5688 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5689 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5690 if (!can_remove_control_point (item)) {
5691 items.back().set_sensitive (false);
5694 _control_point_context_menu.popup (event->button.button, event->button.time);
5698 Editor::zoom_vertical_modifier_released()
5700 _stepping_axis_view = 0;
5704 Editor::ui_parameter_changed (string parameter)
5706 if (parameter == "icon-set") {
5707 while (!_cursor_stack.empty()) {
5708 _cursor_stack.pop();
5710 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5711 } else if (parameter == "draggable-playhead") {
5712 if (_verbose_cursor) {
5713 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());