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()->get_LocationMarker();
394 location_range_color = ARDOUR_UI::config()->get_LocationRange();
395 location_cd_marker_color = ARDOUR_UI::config()->get_LocationCDMarker();
396 location_loop_color = ARDOUR_UI::config()->get_LocationLoop();
397 location_punch_color = ARDOUR_UI::config()->get_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)));
1849 edit_items.push_back (SeparatorElem());
1850 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1852 edit_items.push_back (SeparatorElem());
1853 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1854 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1855 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1857 edit_items.push_back (SeparatorElem());
1858 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1859 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1860 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1861 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1862 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1863 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1864 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1870 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1872 using namespace Menu_Helpers;
1876 Menu *play_menu = manage (new Menu);
1877 MenuList& play_items = play_menu->items();
1878 play_menu->set_name ("ArdourContextMenu");
1880 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1881 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1882 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1883 play_items.push_back (SeparatorElem());
1884 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1886 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1890 Menu *select_menu = manage (new Menu);
1891 MenuList& select_items = select_menu->items();
1892 select_menu->set_name ("ArdourContextMenu");
1894 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1895 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1896 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1897 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1898 select_items.push_back (SeparatorElem());
1899 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1900 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1901 select_items.push_back (SeparatorElem());
1902 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1903 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1904 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1905 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1906 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1907 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1908 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1910 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1914 Menu *cutnpaste_menu = manage (new Menu);
1915 MenuList& cutnpaste_items = cutnpaste_menu->items();
1916 cutnpaste_menu->set_name ("ArdourContextMenu");
1918 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1919 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1920 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1922 cutnpaste_items.push_back (SeparatorElem());
1924 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1925 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1927 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1929 /* Adding new material */
1931 edit_items.push_back (SeparatorElem());
1932 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1933 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1937 Menu *nudge_menu = manage (new Menu());
1938 MenuList& nudge_items = nudge_menu->items();
1939 nudge_menu->set_name ("ArdourContextMenu");
1941 edit_items.push_back (SeparatorElem());
1942 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1943 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1944 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1945 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1947 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1951 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1953 using namespace Menu_Helpers;
1957 Menu *play_menu = manage (new Menu);
1958 MenuList& play_items = play_menu->items();
1959 play_menu->set_name ("ArdourContextMenu");
1961 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1962 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1963 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1967 Menu *select_menu = manage (new Menu);
1968 MenuList& select_items = select_menu->items();
1969 select_menu->set_name ("ArdourContextMenu");
1971 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1972 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1973 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1974 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1975 select_items.push_back (SeparatorElem());
1976 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1977 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1978 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1979 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1981 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1985 Menu *cutnpaste_menu = manage (new Menu);
1986 MenuList& cutnpaste_items = cutnpaste_menu->items();
1987 cutnpaste_menu->set_name ("ArdourContextMenu");
1989 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1990 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1991 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1993 Menu *nudge_menu = manage (new Menu());
1994 MenuList& nudge_items = nudge_menu->items();
1995 nudge_menu->set_name ("ArdourContextMenu");
1997 edit_items.push_back (SeparatorElem());
1998 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1999 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2000 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2001 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2003 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2007 Editor::snap_type() const
2013 Editor::snap_mode() const
2019 Editor::set_snap_to (SnapType st)
2021 unsigned int snap_ind = (unsigned int)st;
2025 if (snap_ind > snap_type_strings.size() - 1) {
2027 _snap_type = (SnapType)snap_ind;
2030 string str = snap_type_strings[snap_ind];
2032 if (str != snap_type_selector.get_text()) {
2033 snap_type_selector.set_text (str);
2038 switch (_snap_type) {
2039 case SnapToBeatDiv128:
2040 case SnapToBeatDiv64:
2041 case SnapToBeatDiv32:
2042 case SnapToBeatDiv28:
2043 case SnapToBeatDiv24:
2044 case SnapToBeatDiv20:
2045 case SnapToBeatDiv16:
2046 case SnapToBeatDiv14:
2047 case SnapToBeatDiv12:
2048 case SnapToBeatDiv10:
2049 case SnapToBeatDiv8:
2050 case SnapToBeatDiv7:
2051 case SnapToBeatDiv6:
2052 case SnapToBeatDiv5:
2053 case SnapToBeatDiv4:
2054 case SnapToBeatDiv3:
2055 case SnapToBeatDiv2: {
2056 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2057 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2059 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2060 current_bbt_points_begin, current_bbt_points_end);
2061 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2062 current_bbt_points_begin, current_bbt_points_end);
2063 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2067 case SnapToRegionStart:
2068 case SnapToRegionEnd:
2069 case SnapToRegionSync:
2070 case SnapToRegionBoundary:
2071 build_region_boundary_cache ();
2079 SnapChanged (); /* EMIT SIGNAL */
2083 Editor::set_snap_mode (SnapMode mode)
2085 string str = snap_mode_strings[(int)mode];
2087 if (_internal_editing) {
2088 internal_snap_mode = mode;
2090 pre_internal_snap_mode = mode;
2095 if (str != snap_mode_selector.get_text ()) {
2096 snap_mode_selector.set_text (str);
2102 Editor::set_edit_point_preference (EditPoint ep, bool force)
2104 bool changed = (_edit_point != ep);
2107 string str = edit_point_strings[(int)ep];
2109 if (Profile->get_mixbus())
2110 if (ep == EditAtSelectedMarker)
2111 ep = EditAtPlayhead;
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_gain_button);
2857 mouse_mode_size_group->add_widget (mouse_timefx_button);
2858 mouse_mode_size_group->add_widget (mouse_audition_button);
2859 mouse_mode_size_group->add_widget (mouse_draw_button);
2860 mouse_mode_size_group->add_widget (internal_edit_button);
2862 mouse_mode_size_group->add_widget (zoom_in_button);
2863 mouse_mode_size_group->add_widget (zoom_out_button);
2864 mouse_mode_size_group->add_widget (zoom_preset_selector);
2865 mouse_mode_size_group->add_widget (zoom_out_full_button);
2866 mouse_mode_size_group->add_widget (zoom_focus_selector);
2868 mouse_mode_size_group->add_widget (tav_shrink_button);
2869 mouse_mode_size_group->add_widget (tav_expand_button);
2870 mouse_mode_size_group->add_widget (visible_tracks_selector);
2872 mouse_mode_size_group->add_widget (snap_type_selector);
2873 mouse_mode_size_group->add_widget (snap_mode_selector);
2875 mouse_mode_size_group->add_widget (edit_point_selector);
2876 mouse_mode_size_group->add_widget (edit_mode_selector);
2878 mouse_mode_size_group->add_widget (*nudge_clock);
2879 mouse_mode_size_group->add_widget (nudge_forward_button);
2880 mouse_mode_size_group->add_widget (nudge_backward_button);
2882 mouse_mode_hbox->set_spacing (2);
2884 if (!ARDOUR::Profile->get_trx()) {
2885 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2888 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2889 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2891 if (!ARDOUR::Profile->get_mixbus()) {
2892 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2895 if (!ARDOUR::Profile->get_trx()) {
2896 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2897 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2898 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2899 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2900 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 0);
2903 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2905 mouse_mode_align->add (*mouse_mode_vbox);
2906 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2908 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2910 edit_mode_selector.set_name ("mouse mode button");
2912 if (!ARDOUR::Profile->get_trx()) {
2913 mode_box->pack_start (edit_mode_selector, false, false);
2915 mode_box->pack_start (*mouse_mode_box, false, false);
2917 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2918 _mouse_mode_tearoff->set_name ("MouseModeBase");
2919 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2921 if (Profile->get_sae() || Profile->get_mixbus() ) {
2922 _mouse_mode_tearoff->set_can_be_torn_off (false);
2925 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2926 &_mouse_mode_tearoff->tearoff_window()));
2927 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2928 &_mouse_mode_tearoff->tearoff_window(), 1));
2929 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2930 &_mouse_mode_tearoff->tearoff_window()));
2931 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2932 &_mouse_mode_tearoff->tearoff_window(), 1));
2936 _zoom_box.set_spacing (2);
2937 _zoom_box.set_border_width (2);
2941 zoom_preset_selector.set_name ("zoom button");
2942 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2943 zoom_preset_selector.set_size_request (42, -1);
2945 zoom_in_button.set_name ("zoom button");
2946 zoom_in_button.set_image(::get_icon ("zoom_in"));
2947 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2948 zoom_in_button.set_related_action (act);
2950 zoom_out_button.set_name ("zoom button");
2951 zoom_out_button.set_image(::get_icon ("zoom_out"));
2952 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2953 zoom_out_button.set_related_action (act);
2955 zoom_out_full_button.set_name ("zoom button");
2956 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2957 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2958 zoom_out_full_button.set_related_action (act);
2960 zoom_focus_selector.set_name ("zoom button");
2962 if (ARDOUR::Profile->get_mixbus()) {
2963 _zoom_box.pack_start (zoom_preset_selector, false, false);
2964 } else if (ARDOUR::Profile->get_trx()) {
2965 mode_box->pack_start (zoom_out_button, false, false);
2966 mode_box->pack_start (zoom_in_button, false, false);
2968 _zoom_box.pack_start (zoom_out_button, false, false);
2969 _zoom_box.pack_start (zoom_in_button, false, false);
2970 _zoom_box.pack_start (zoom_out_full_button, false, false);
2971 _zoom_box.pack_start (zoom_focus_selector, false, false);
2974 /* Track zoom buttons */
2975 visible_tracks_selector.set_name ("zoom button");
2976 if (Profile->get_mixbus()) {
2977 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2978 visible_tracks_selector.set_size_request (42, -1);
2980 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2983 tav_expand_button.set_name ("zoom button");
2984 tav_expand_button.set_image(::get_icon ("tav_exp"));
2985 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2986 tav_expand_button.set_related_action (act);
2988 tav_shrink_button.set_name ("zoom button");
2989 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2990 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2991 tav_shrink_button.set_related_action (act);
2993 if (ARDOUR::Profile->get_mixbus()) {
2994 _zoom_box.pack_start (visible_tracks_selector);
2995 } else if (ARDOUR::Profile->get_trx()) {
2996 _zoom_box.pack_start (tav_shrink_button);
2997 _zoom_box.pack_start (tav_expand_button);
2999 _zoom_box.pack_start (visible_tracks_selector);
3000 _zoom_box.pack_start (tav_shrink_button);
3001 _zoom_box.pack_start (tav_expand_button);
3004 if (!ARDOUR::Profile->get_trx()) {
3005 _zoom_tearoff = manage (new TearOff (_zoom_box));
3007 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3008 &_zoom_tearoff->tearoff_window()));
3009 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3010 &_zoom_tearoff->tearoff_window(), 0));
3011 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3012 &_zoom_tearoff->tearoff_window()));
3013 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3014 &_zoom_tearoff->tearoff_window(), 0));
3017 if (Profile->get_sae() || Profile->get_mixbus() ) {
3018 _zoom_tearoff->set_can_be_torn_off (false);
3021 snap_box.set_spacing (2);
3022 snap_box.set_border_width (2);
3024 snap_type_selector.set_name ("mouse mode button");
3026 snap_mode_selector.set_name ("mouse mode button");
3028 edit_point_selector.set_name ("mouse mode button");
3030 snap_box.pack_start (snap_mode_selector, false, false);
3031 snap_box.pack_start (snap_type_selector, false, false);
3032 snap_box.pack_start (edit_point_selector, false, false);
3036 HBox *nudge_box = manage (new HBox);
3037 nudge_box->set_spacing (2);
3038 nudge_box->set_border_width (2);
3040 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3041 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3043 nudge_box->pack_start (nudge_backward_button, false, false);
3044 nudge_box->pack_start (nudge_forward_button, false, false);
3045 nudge_box->pack_start (*nudge_clock, false, false);
3048 /* Pack everything in... */
3050 HBox* hbox = manage (new HBox);
3051 hbox->set_spacing(2);
3053 _tools_tearoff = manage (new TearOff (*hbox));
3054 _tools_tearoff->set_name ("MouseModeBase");
3055 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3057 if (Profile->get_sae() || Profile->get_mixbus()) {
3058 _tools_tearoff->set_can_be_torn_off (false);
3061 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3062 &_tools_tearoff->tearoff_window()));
3063 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3064 &_tools_tearoff->tearoff_window(), 0));
3065 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3066 &_tools_tearoff->tearoff_window()));
3067 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3068 &_tools_tearoff->tearoff_window(), 0));
3070 toolbar_hbox.set_spacing (2);
3071 toolbar_hbox.set_border_width (1);
3073 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3074 if (!ARDOUR::Profile->get_trx()) {
3075 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3076 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3079 if (!ARDOUR::Profile->get_trx()) {
3080 hbox->pack_start (snap_box, false, false);
3081 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3082 hbox->pack_start (*nudge_box, false, false);
3084 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3087 hbox->pack_start (panic_box, false, false);
3091 toolbar_base.set_name ("ToolBarBase");
3092 toolbar_base.add (toolbar_hbox);
3094 _toolbar_viewport.add (toolbar_base);
3095 /* stick to the required height but allow width to vary if there's not enough room */
3096 _toolbar_viewport.set_size_request (1, -1);
3098 toolbar_frame.set_shadow_type (SHADOW_OUT);
3099 toolbar_frame.set_name ("BaseFrame");
3100 toolbar_frame.add (_toolbar_viewport);
3104 Editor::build_edit_point_menu ()
3106 using namespace Menu_Helpers;
3108 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3109 if(!Profile->get_mixbus())
3110 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3111 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3113 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3117 Editor::build_edit_mode_menu ()
3119 using namespace Menu_Helpers;
3121 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3122 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3123 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3124 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3126 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3130 Editor::build_snap_mode_menu ()
3132 using namespace Menu_Helpers;
3134 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3135 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3136 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3138 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3142 Editor::build_snap_type_menu ()
3144 using namespace Menu_Helpers;
3146 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3147 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3148 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3149 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3150 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3151 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3152 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3153 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3154 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3155 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3156 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3157 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3158 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3159 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3160 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3161 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3162 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3163 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3164 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3165 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3166 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3167 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3168 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3169 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3170 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3171 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3172 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3173 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3174 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3175 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3177 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3182 Editor::setup_tooltips ()
3184 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3185 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3186 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3187 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3188 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3189 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3190 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3191 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3192 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3193 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3194 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3195 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3196 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3197 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3198 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3199 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3200 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3201 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3202 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3203 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3204 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3205 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3206 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3207 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3208 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3212 Editor::convert_drop_to_paths (
3213 vector<string>& paths,
3214 const RefPtr<Gdk::DragContext>& /*context*/,
3217 const SelectionData& data,
3221 if (_session == 0) {
3225 vector<string> uris = data.get_uris();
3229 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3230 are actually URI lists. So do it by hand.
3233 if (data.get_target() != "text/plain") {
3237 /* Parse the "uri-list" format that Nautilus provides,
3238 where each pathname is delimited by \r\n.
3240 THERE MAY BE NO NULL TERMINATING CHAR!!!
3243 string txt = data.get_text();
3247 p = (char *) malloc (txt.length() + 1);
3248 txt.copy (p, txt.length(), 0);
3249 p[txt.length()] = '\0';
3255 while (g_ascii_isspace (*p))
3259 while (*q && (*q != '\n') && (*q != '\r')) {
3266 while (q > p && g_ascii_isspace (*q))
3271 uris.push_back (string (p, q - p + 1));
3275 p = strchr (p, '\n');
3287 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3288 if ((*i).substr (0,7) == "file://") {
3289 paths.push_back (Glib::filename_from_uri (*i));
3297 Editor::new_tempo_section ()
3302 Editor::map_transport_state ()
3304 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3306 if (_session && _session->transport_stopped()) {
3307 have_pending_keyboard_selection = false;
3310 update_loop_range_view ();
3316 Editor::begin_reversible_command (string name)
3319 _session->begin_reversible_command (name);
3324 Editor::begin_reversible_command (GQuark q)
3327 _session->begin_reversible_command (q);
3332 Editor::commit_reversible_command ()
3335 _session->commit_reversible_command ();
3340 Editor::history_changed ()
3344 if (undo_action && _session) {
3345 if (_session->undo_depth() == 0) {
3346 label = S_("Command|Undo");
3348 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3350 undo_action->property_label() = label;
3353 if (redo_action && _session) {
3354 if (_session->redo_depth() == 0) {
3357 label = string_compose(_("Redo (%1)"), _session->next_redo());
3359 redo_action->property_label() = label;
3364 Editor::duplicate_range (bool with_dialog)
3368 RegionSelection rs = get_regions_from_selection_and_entered ();
3370 if ( selection->time.length() == 0 && rs.empty()) {
3376 ArdourDialog win (_("Duplicate"));
3377 Label label (_("Number of duplications:"));
3378 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3379 SpinButton spinner (adjustment, 0.0, 1);
3382 win.get_vbox()->set_spacing (12);
3383 win.get_vbox()->pack_start (hbox);
3384 hbox.set_border_width (6);
3385 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3387 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3388 place, visually. so do this by hand.
3391 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3392 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3393 spinner.grab_focus();
3399 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3400 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3401 win.set_default_response (RESPONSE_ACCEPT);
3403 spinner.grab_focus ();
3405 switch (win.run ()) {
3406 case RESPONSE_ACCEPT:
3412 times = adjustment.get_value();
3415 if ((current_mouse_mode() == Editing::MouseRange)) {
3416 if (selection->time.length()) {
3417 duplicate_selection (times);
3419 } else if (get_smart_mode()) {
3420 if (selection->time.length()) {
3421 duplicate_selection (times);
3423 duplicate_some_regions (rs, times);
3425 duplicate_some_regions (rs, times);
3430 Editor::set_edit_mode (EditMode m)
3432 Config->set_edit_mode (m);
3436 Editor::cycle_edit_mode ()
3438 switch (Config->get_edit_mode()) {
3440 if (Profile->get_sae()) {
3441 Config->set_edit_mode (Lock);
3443 Config->set_edit_mode (Ripple);
3448 Config->set_edit_mode (Lock);
3451 Config->set_edit_mode (Slide);
3457 Editor::edit_mode_selection_done ( EditMode m )
3459 Config->set_edit_mode ( m );
3463 Editor::snap_type_selection_done (SnapType snaptype)
3465 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3467 ract->set_active ();
3472 Editor::snap_mode_selection_done (SnapMode mode)
3474 RefPtr<RadioAction> ract = snap_mode_action (mode);
3477 ract->set_active (true);
3482 Editor::cycle_edit_point (bool with_marker)
3484 if(Profile->get_mixbus())
3485 with_marker = false;
3487 switch (_edit_point) {
3489 set_edit_point_preference (EditAtPlayhead);
3491 case EditAtPlayhead:
3493 set_edit_point_preference (EditAtSelectedMarker);
3495 set_edit_point_preference (EditAtMouse);
3498 case EditAtSelectedMarker:
3499 set_edit_point_preference (EditAtMouse);
3505 Editor::edit_point_selection_done (EditPoint ep)
3507 set_edit_point_preference ( ep );
3511 Editor::build_zoom_focus_menu ()
3513 using namespace Menu_Helpers;
3515 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3516 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3517 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3518 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3519 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3520 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3522 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3526 Editor::zoom_focus_selection_done ( ZoomFocus f )
3528 RefPtr<RadioAction> ract = zoom_focus_action (f);
3530 ract->set_active ();
3535 Editor::build_track_count_menu ()
3537 using namespace Menu_Helpers;
3539 if (!Profile->get_mixbus()) {
3540 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3541 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3542 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3543 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3544 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3545 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3546 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3547 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3548 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3549 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3550 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3551 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3552 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3554 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3555 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3556 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3557 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3558 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3559 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3560 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3561 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3562 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3563 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3565 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3566 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3567 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3568 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3569 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3570 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3571 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3572 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3573 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3574 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3575 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3580 Editor::set_zoom_preset (int64_t ms)
3583 temporal_zoom_session();
3587 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3588 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3592 Editor::set_visible_track_count (int32_t n)
3594 _visible_track_count = n;
3596 /* if the canvas hasn't really been allocated any size yet, just
3597 record the desired number of visible tracks and return. when canvas
3598 allocation happens, we will get called again and then we can do the
3602 if (_visible_canvas_height <= 1) {
3609 if (_visible_track_count > 0) {
3610 h = trackviews_height() / _visible_track_count;
3611 std::ostringstream s;
3612 s << _visible_track_count;
3614 } else if (_visible_track_count == 0) {
3616 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3617 if ((*i)->marked_for_display()) {
3621 h = trackviews_height() / n;
3624 /* negative value means that the visible track count has
3625 been overridden by explicit track height changes.
3627 visible_tracks_selector.set_text (X_("*"));
3631 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3632 (*i)->set_height (h);
3635 if (str != visible_tracks_selector.get_text()) {
3636 visible_tracks_selector.set_text (str);
3641 Editor::override_visible_track_count ()
3643 _visible_track_count = -1;
3644 visible_tracks_selector.set_text ( _("*") );
3648 Editor::edit_controls_button_release (GdkEventButton* ev)
3650 if (Keyboard::is_context_menu_event (ev)) {
3651 ARDOUR_UI::instance()->add_route (this);
3652 } else if (ev->button == 1) {
3653 selection->clear_tracks ();
3660 Editor::mouse_select_button_release (GdkEventButton* ev)
3662 /* this handles just right-clicks */
3664 if (ev->button != 3) {
3672 Editor::set_zoom_focus (ZoomFocus f)
3674 string str = zoom_focus_strings[(int)f];
3676 if (str != zoom_focus_selector.get_text()) {
3677 zoom_focus_selector.set_text (str);
3680 if (zoom_focus != f) {
3687 Editor::cycle_zoom_focus ()
3689 switch (zoom_focus) {
3691 set_zoom_focus (ZoomFocusRight);
3693 case ZoomFocusRight:
3694 set_zoom_focus (ZoomFocusCenter);
3696 case ZoomFocusCenter:
3697 set_zoom_focus (ZoomFocusPlayhead);
3699 case ZoomFocusPlayhead:
3700 set_zoom_focus (ZoomFocusMouse);
3702 case ZoomFocusMouse:
3703 set_zoom_focus (ZoomFocusEdit);
3706 set_zoom_focus (ZoomFocusLeft);
3712 Editor::ensure_float (Window& win)
3714 win.set_transient_for (*this);
3718 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3720 /* recover or initialize pane positions. do this here rather than earlier because
3721 we don't want the positions to change the child allocations, which they seem to do.
3727 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3736 XMLNode* geometry = find_named_node (*node, "geometry");
3738 if (which == static_cast<Paned*> (&edit_pane)) {
3740 if (done & Horizontal) {
3744 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3745 _notebook_shrunk = string_is_affirmative (prop->value ());
3748 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3749 /* initial allocation is 90% to canvas, 10% to notebook */
3750 pos = (int) floor (alloc.get_width() * 0.90f);
3751 snprintf (buf, sizeof(buf), "%d", pos);
3753 pos = atoi (prop->value());
3756 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3757 edit_pane.set_position (pos);
3760 done = (Pane) (done | Horizontal);
3762 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3764 if (done & Vertical) {
3768 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3769 /* initial allocation is 90% to canvas, 10% to summary */
3770 pos = (int) floor (alloc.get_height() * 0.90f);
3771 snprintf (buf, sizeof(buf), "%d", pos);
3774 pos = atoi (prop->value());
3777 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3778 editor_summary_pane.set_position (pos);
3781 done = (Pane) (done | Vertical);
3786 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3788 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3789 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3790 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3791 top_hbox.remove (toolbar_frame);
3796 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3798 if (toolbar_frame.get_parent() == 0) {
3799 top_hbox.pack_end (toolbar_frame);
3804 Editor::set_show_measures (bool yn)
3806 if (_show_measures != yn) {
3809 if ((_show_measures = yn) == true) {
3811 tempo_lines->show();
3814 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3815 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3817 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3818 draw_measures (begin, end);
3826 Editor::toggle_follow_playhead ()
3828 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3830 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3831 set_follow_playhead (tact->get_active());
3835 /** @param yn true to follow playhead, otherwise false.
3836 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3839 Editor::set_follow_playhead (bool yn, bool catch_up)
3841 if (_follow_playhead != yn) {
3842 if ((_follow_playhead = yn) == true && catch_up) {
3844 reset_x_origin_to_follow_playhead ();
3851 Editor::toggle_stationary_playhead ()
3853 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3855 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3856 set_stationary_playhead (tact->get_active());
3861 Editor::set_stationary_playhead (bool yn)
3863 if (_stationary_playhead != yn) {
3864 if ((_stationary_playhead = yn) == true) {
3866 // FIXME need a 3.0 equivalent of this 2.X call
3867 // update_current_screen ();
3874 Editor::playlist_selector () const
3876 return *_playlist_selector;
3880 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3882 if (paste_count == 0) {
3883 /* don't bother calculating an offset that will be zero anyway */
3887 /* calculate basic unsnapped multi-paste offset */
3888 framecnt_t offset = paste_count * duration;
3890 bool success = true;
3891 double snap_beats = get_grid_type_as_beats(success, pos);
3893 /* we're snapped to something musical, round duration up */
3894 BeatsFramesConverter conv(_session->tempo_map(), pos);
3895 const Evoral::MusicalTime dur_beats = conv.from(duration);
3896 const framecnt_t snap_dur_beats = ceil(dur_beats / snap_beats) * snap_beats;
3898 offset = paste_count * conv.to(snap_dur_beats);
3905 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3909 switch (_snap_type) {
3914 case SnapToBeatDiv128:
3917 case SnapToBeatDiv64:
3920 case SnapToBeatDiv32:
3923 case SnapToBeatDiv28:
3926 case SnapToBeatDiv24:
3929 case SnapToBeatDiv20:
3932 case SnapToBeatDiv16:
3935 case SnapToBeatDiv14:
3938 case SnapToBeatDiv12:
3941 case SnapToBeatDiv10:
3944 case SnapToBeatDiv8:
3947 case SnapToBeatDiv7:
3950 case SnapToBeatDiv6:
3953 case SnapToBeatDiv5:
3956 case SnapToBeatDiv4:
3959 case SnapToBeatDiv3:
3962 case SnapToBeatDiv2:
3968 return _session->tempo_map().meter_at (position).divisions_per_bar();
3973 case SnapToTimecodeFrame:
3974 case SnapToTimecodeSeconds:
3975 case SnapToTimecodeMinutes:
3978 case SnapToRegionStart:
3979 case SnapToRegionEnd:
3980 case SnapToRegionSync:
3981 case SnapToRegionBoundary:
3991 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3995 ret = nudge_clock->current_duration (pos);
3996 next = ret + 1; /* XXXX fix me */
4002 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4004 ArdourDialog dialog (_("Playlist Deletion"));
4005 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4006 "If it is kept, its audio files will not be cleaned.\n"
4007 "If it is deleted, audio files used by it alone will be cleaned."),
4010 dialog.set_position (WIN_POS_CENTER);
4011 dialog.get_vbox()->pack_start (label);
4015 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4016 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4017 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4019 switch (dialog.run ()) {
4020 case RESPONSE_ACCEPT:
4021 /* delete the playlist */
4025 case RESPONSE_REJECT:
4026 /* keep the playlist */
4038 Editor::audio_region_selection_covers (framepos_t where)
4040 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4041 if ((*a)->region()->covers (where)) {
4050 Editor::prepare_for_cleanup ()
4052 cut_buffer->clear_regions ();
4053 cut_buffer->clear_playlists ();
4055 selection->clear_regions ();
4056 selection->clear_playlists ();
4058 _regions->suspend_redisplay ();
4062 Editor::finish_cleanup ()
4064 _regions->resume_redisplay ();
4068 Editor::transport_loop_location()
4071 return _session->locations()->auto_loop_location();
4078 Editor::transport_punch_location()
4081 return _session->locations()->auto_punch_location();
4088 Editor::control_layout_scroll (GdkEventScroll* ev)
4090 /* Just forward to the normal canvas scroll method. The coordinate
4091 systems are different but since the canvas is always larger than the
4092 track headers, and aligned with the trackview area, this will work.
4094 In the not too distant future this layout is going away anyway and
4095 headers will be on the canvas.
4097 return canvas_scroll_event (ev, false);
4101 Editor::session_state_saved (string)
4104 _snapshots->redisplay ();
4108 Editor::update_tearoff_visibility()
4110 bool visible = Config->get_keep_tearoffs();
4111 _mouse_mode_tearoff->set_visible (visible);
4112 _tools_tearoff->set_visible (visible);
4113 if (_zoom_tearoff) {
4114 _zoom_tearoff->set_visible (visible);
4119 Editor::reattach_all_tearoffs ()
4121 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4122 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4123 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4127 Editor::maximise_editing_space ()
4139 Editor::restore_editing_space ()
4151 * Make new playlists for a given track and also any others that belong
4152 * to the same active route group with the `select' property.
4157 Editor::new_playlists (TimeAxisView* v)
4159 begin_reversible_command (_("new playlists"));
4160 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4161 _session->playlists->get (playlists);
4162 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4163 commit_reversible_command ();
4167 * Use a copy of the current playlist for a given track and also any others that belong
4168 * to the same active route group with the `select' property.
4173 Editor::copy_playlists (TimeAxisView* v)
4175 begin_reversible_command (_("copy playlists"));
4176 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4177 _session->playlists->get (playlists);
4178 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4179 commit_reversible_command ();
4182 /** Clear the current playlist for a given track and also any others that belong
4183 * to the same active route group with the `select' property.
4188 Editor::clear_playlists (TimeAxisView* v)
4190 begin_reversible_command (_("clear playlists"));
4191 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4192 _session->playlists->get (playlists);
4193 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4194 commit_reversible_command ();
4198 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4200 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4204 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4206 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4210 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4212 atv.clear_playlist ();
4216 Editor::on_key_press_event (GdkEventKey* ev)
4218 return key_press_focus_accelerator_handler (*this, ev);
4222 Editor::on_key_release_event (GdkEventKey* ev)
4224 return Gtk::Window::on_key_release_event (ev);
4225 // return key_press_focus_accelerator_handler (*this, ev);
4228 /** Queue up a change to the viewport x origin.
4229 * @param frame New x origin.
4232 Editor::reset_x_origin (framepos_t frame)
4234 pending_visual_change.add (VisualChange::TimeOrigin);
4235 pending_visual_change.time_origin = frame;
4236 ensure_visual_change_idle_handler ();
4240 Editor::reset_y_origin (double y)
4242 pending_visual_change.add (VisualChange::YOrigin);
4243 pending_visual_change.y_origin = y;
4244 ensure_visual_change_idle_handler ();
4248 Editor::reset_zoom (framecnt_t spp)
4250 if (spp == samples_per_pixel) {
4254 pending_visual_change.add (VisualChange::ZoomLevel);
4255 pending_visual_change.samples_per_pixel = spp;
4256 ensure_visual_change_idle_handler ();
4260 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4262 reset_x_origin (frame);
4265 if (!no_save_visual) {
4266 undo_visual_stack.push_back (current_visual_state(false));
4270 Editor::VisualState::VisualState (bool with_tracks)
4271 : gui_state (with_tracks ? new GUIObjectState : 0)
4275 Editor::VisualState::~VisualState ()
4280 Editor::VisualState*
4281 Editor::current_visual_state (bool with_tracks)
4283 VisualState* vs = new VisualState (with_tracks);
4284 vs->y_position = vertical_adjustment.get_value();
4285 vs->samples_per_pixel = samples_per_pixel;
4286 vs->leftmost_frame = leftmost_frame;
4287 vs->zoom_focus = zoom_focus;
4290 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4297 Editor::undo_visual_state ()
4299 if (undo_visual_stack.empty()) {
4303 VisualState* vs = undo_visual_stack.back();
4304 undo_visual_stack.pop_back();
4307 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4310 use_visual_state (*vs);
4315 Editor::redo_visual_state ()
4317 if (redo_visual_stack.empty()) {
4321 VisualState* vs = redo_visual_stack.back();
4322 redo_visual_stack.pop_back();
4324 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4325 // why do we check here?
4326 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4329 use_visual_state (*vs);
4334 Editor::swap_visual_state ()
4336 if (undo_visual_stack.empty()) {
4337 redo_visual_state ();
4339 undo_visual_state ();
4344 Editor::use_visual_state (VisualState& vs)
4346 PBD::Unwinder<bool> nsv (no_save_visual, true);
4347 DisplaySuspender ds;
4349 vertical_adjustment.set_value (vs.y_position);
4351 set_zoom_focus (vs.zoom_focus);
4352 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4355 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4357 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4358 (*i)->reset_visual_state ();
4362 _routes->update_visibility ();
4365 /** This is the core function that controls the zoom level of the canvas. It is called
4366 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4367 * @param spp new number of samples per pixel
4370 Editor::set_samples_per_pixel (framecnt_t spp)
4376 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4377 const framecnt_t lots_of_pixels = 4000;
4379 /* if the zoom level is greater than what you'd get trying to display 3
4380 * days of audio on a really big screen, then it's too big.
4383 if (spp * lots_of_pixels > three_days) {
4387 samples_per_pixel = spp;
4390 tempo_lines->tempo_map_changed();
4393 bool const showing_time_selection = selection->time.length() > 0;
4395 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4396 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4397 (*i)->reshow_selection (selection->time);
4401 ZoomChanged (); /* EMIT_SIGNAL */
4403 ArdourCanvas::GtkCanvasViewport* c;
4405 c = get_track_canvas();
4407 c->canvas()->zoomed ();
4410 if (playhead_cursor) {
4411 playhead_cursor->set_position (playhead_cursor->current_frame ());
4414 refresh_location_display();
4415 _summary->set_overlays_dirty ();
4417 update_marker_labels ();
4423 Editor::queue_visual_videotimeline_update ()
4426 * pending_visual_change.add (VisualChange::VideoTimeline);
4427 * or maybe even more specific: which videotimeline-image
4428 * currently it calls update_video_timeline() to update
4429 * _all outdated_ images on the video-timeline.
4430 * see 'exposeimg()' in video_image_frame.cc
4432 ensure_visual_change_idle_handler ();
4436 Editor::ensure_visual_change_idle_handler ()
4438 if (pending_visual_change.idle_handler_id < 0) {
4439 // see comment in add_to_idle_resize above.
4440 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4441 pending_visual_change.being_handled = false;
4446 Editor::_idle_visual_changer (void* arg)
4448 return static_cast<Editor*>(arg)->idle_visual_changer ();
4452 Editor::idle_visual_changer ()
4454 /* set_horizontal_position() below (and maybe other calls) call
4455 gtk_main_iteration(), so it's possible that a signal will be handled
4456 half-way through this method. If this signal wants an
4457 idle_visual_changer we must schedule another one after this one, so
4458 mark the idle_handler_id as -1 here to allow that. Also make a note
4459 that we are doing the visual change, so that changes in response to
4460 super-rapid-screen-update can be dropped if we are still processing
4464 pending_visual_change.idle_handler_id = -1;
4465 pending_visual_change.being_handled = true;
4467 VisualChange vc = pending_visual_change;
4469 pending_visual_change.pending = (VisualChange::Type) 0;
4471 visual_changer (vc);
4473 pending_visual_change.being_handled = false;
4475 return 0; /* this is always a one-shot call */
4479 Editor::visual_changer (const VisualChange& vc)
4481 double const last_time_origin = horizontal_position ();
4483 if (vc.pending & VisualChange::ZoomLevel) {
4484 set_samples_per_pixel (vc.samples_per_pixel);
4486 compute_fixed_ruler_scale ();
4488 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4489 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4491 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4492 current_bbt_points_begin, current_bbt_points_end);
4493 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4494 current_bbt_points_begin, current_bbt_points_end);
4495 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4497 update_video_timeline();
4500 if (vc.pending & VisualChange::TimeOrigin) {
4501 set_horizontal_position (vc.time_origin / samples_per_pixel);
4504 if (vc.pending & VisualChange::YOrigin) {
4505 vertical_adjustment.set_value (vc.y_origin);
4508 if (last_time_origin == horizontal_position ()) {
4509 /* changed signal not emitted */
4510 update_fixed_rulers ();
4511 redisplay_tempo (true);
4514 if (!(vc.pending & VisualChange::ZoomLevel)) {
4515 update_video_timeline();
4518 _summary->set_overlays_dirty ();
4521 struct EditorOrderTimeAxisSorter {
4522 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4523 return a->order () < b->order ();
4528 Editor::sort_track_selection (TrackViewList& sel)
4530 EditorOrderTimeAxisSorter cmp;
4535 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4538 framepos_t where = 0;
4539 EditPoint ep = _edit_point;
4541 if(Profile->get_mixbus())
4542 if (ep == EditAtSelectedMarker)
4545 if (from_context_menu && (ep == EditAtMouse)) {
4546 return canvas_event_sample (&context_click_event, 0, 0);
4549 if (entered_marker) {
4550 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4551 return entered_marker->position();
4554 if (ignore_playhead && ep == EditAtPlayhead) {
4555 ep = EditAtSelectedMarker;
4559 case EditAtPlayhead:
4560 where = _session->audible_frame();
4561 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4564 case EditAtSelectedMarker:
4565 if (!selection->markers.empty()) {
4567 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4570 where = loc->start();
4574 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4582 if (!mouse_frame (where, ignored)) {
4583 /* XXX not right but what can we do ? */
4587 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4595 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4597 if (!_session) return;
4599 begin_reversible_command (cmd);
4603 if ((tll = transport_loop_location()) == 0) {
4604 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4605 XMLNode &before = _session->locations()->get_state();
4606 _session->locations()->add (loc, true);
4607 _session->set_auto_loop_location (loc);
4608 XMLNode &after = _session->locations()->get_state();
4609 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4611 XMLNode &before = tll->get_state();
4612 tll->set_hidden (false, this);
4613 tll->set (start, end);
4614 XMLNode &after = tll->get_state();
4615 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4618 commit_reversible_command ();
4622 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4624 if (!_session) return;
4626 begin_reversible_command (cmd);
4630 if ((tpl = transport_punch_location()) == 0) {
4631 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4632 XMLNode &before = _session->locations()->get_state();
4633 _session->locations()->add (loc, true);
4634 _session->set_auto_punch_location (loc);
4635 XMLNode &after = _session->locations()->get_state();
4636 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4639 XMLNode &before = tpl->get_state();
4640 tpl->set_hidden (false, this);
4641 tpl->set (start, end);
4642 XMLNode &after = tpl->get_state();
4643 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4646 commit_reversible_command ();
4649 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4650 * @param rs List to which found regions are added.
4651 * @param where Time to look at.
4652 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4655 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4657 const TrackViewList* tracks;
4660 tracks = &track_views;
4665 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4667 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4670 boost::shared_ptr<Track> tr;
4671 boost::shared_ptr<Playlist> pl;
4673 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4675 boost::shared_ptr<RegionList> regions = pl->regions_at (
4676 (framepos_t) floor ( (double) where * tr->speed()));
4678 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4679 RegionView* rv = rtv->view()->find_view (*i);
4690 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4692 const TrackViewList* tracks;
4695 tracks = &track_views;
4700 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4701 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4703 boost::shared_ptr<Track> tr;
4704 boost::shared_ptr<Playlist> pl;
4706 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4708 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4709 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4711 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4713 RegionView* rv = rtv->view()->find_view (*i);
4724 /** Get regions using the following method:
4726 * Make a region list using:
4727 * (a) any selected regions
4728 * (b) the intersection of any selected tracks and the edit point(*)
4729 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4731 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4733 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4737 Editor::get_regions_from_selection_and_edit_point ()
4739 RegionSelection regions;
4741 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4742 regions.add (entered_regionview);
4744 regions = selection->regions;
4747 if ( regions.empty() ) {
4748 TrackViewList tracks = selection->tracks;
4750 if (!tracks.empty()) {
4751 /* no region selected or entered, but some selected tracks:
4752 * act on all regions on the selected tracks at the edit point
4754 framepos_t const where = get_preferred_edit_position ();
4755 get_regions_at(regions, where, tracks);
4762 /** Get regions using the following method:
4764 * Make a region list using:
4765 * (a) any selected regions
4766 * (b) the intersection of any selected tracks and the edit point(*)
4767 * (c) if neither exists, then whatever region is under the mouse
4769 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4771 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4774 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4776 RegionSelection regions;
4778 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4779 regions.add (entered_regionview);
4781 regions = selection->regions;
4784 if ( regions.empty() ) {
4785 TrackViewList tracks = selection->tracks;
4787 if (!tracks.empty()) {
4788 /* no region selected or entered, but some selected tracks:
4789 * act on all regions on the selected tracks at the edit point
4791 get_regions_at(regions, pos, tracks);
4798 /** Start with regions that are selected, or the entered regionview if none are selected.
4799 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4800 * of the regions that we started with.
4804 Editor::get_regions_from_selection_and_entered ()
4806 RegionSelection regions = selection->regions;
4808 if (regions.empty() && entered_regionview) {
4809 regions.add (entered_regionview);
4816 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4818 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4820 RouteTimeAxisView* tatv;
4822 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4824 boost::shared_ptr<Playlist> pl;
4825 vector<boost::shared_ptr<Region> > results;
4827 boost::shared_ptr<Track> tr;
4829 if ((tr = tatv->track()) == 0) {
4834 if ((pl = (tr->playlist())) != 0) {
4835 if (src_comparison) {
4836 pl->get_source_equivalent_regions (region, results);
4838 pl->get_region_list_equivalent_regions (region, results);
4842 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4843 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4844 regions.push_back (marv);
4853 Editor::show_rhythm_ferret ()
4855 if (rhythm_ferret == 0) {
4856 rhythm_ferret = new RhythmFerret(*this);
4859 rhythm_ferret->set_session (_session);
4860 rhythm_ferret->show ();
4861 rhythm_ferret->present ();
4865 Editor::first_idle ()
4867 MessageDialog* dialog = 0;
4869 if (track_views.size() > 1) {
4870 dialog = new MessageDialog (
4872 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4876 ARDOUR_UI::instance()->flush_pending ();
4879 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4883 // first idle adds route children (automation tracks), so we need to redisplay here
4884 _routes->redisplay ();
4891 Editor::_idle_resize (gpointer arg)
4893 return ((Editor*)arg)->idle_resize ();
4897 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4899 if (resize_idle_id < 0) {
4900 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
4901 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
4902 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
4904 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
4905 _pending_resize_amount = 0;
4908 /* make a note of the smallest resulting height, so that we can clamp the
4909 lower limit at TimeAxisView::hSmall */
4911 int32_t min_resulting = INT32_MAX;
4913 _pending_resize_amount += h;
4914 _pending_resize_view = view;
4916 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4918 if (selection->tracks.contains (_pending_resize_view)) {
4919 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4920 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4924 if (min_resulting < 0) {
4929 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4930 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4934 /** Handle pending resizing of tracks */
4936 Editor::idle_resize ()
4938 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4940 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4941 selection->tracks.contains (_pending_resize_view)) {
4943 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4944 if (*i != _pending_resize_view) {
4945 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4950 _pending_resize_amount = 0;
4951 _group_tabs->set_dirty ();
4952 resize_idle_id = -1;
4960 ENSURE_GUI_THREAD (*this, &Editor::located);
4963 playhead_cursor->set_position (_session->audible_frame ());
4964 if (_follow_playhead && !_pending_initial_locate) {
4965 reset_x_origin_to_follow_playhead ();
4969 _pending_locate_request = false;
4970 _pending_initial_locate = false;
4974 Editor::region_view_added (RegionView *)
4976 _summary->set_background_dirty ();
4980 Editor::region_view_removed ()
4982 _summary->set_background_dirty ();
4986 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4988 TrackViewList::const_iterator j = track_views.begin ();
4989 while (j != track_views.end()) {
4990 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4991 if (rtv && rtv->route() == r) {
5002 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5006 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5007 TimeAxisView* tv = axis_view_from_route (*i);
5017 Editor::suspend_route_redisplay ()
5020 _routes->suspend_redisplay();
5025 Editor::resume_route_redisplay ()
5028 _routes->resume_redisplay();
5033 Editor::add_routes (RouteList& routes)
5035 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5037 RouteTimeAxisView *rtv;
5038 list<RouteTimeAxisView*> new_views;
5040 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5041 boost::shared_ptr<Route> route = (*x);
5043 if (route->is_auditioner() || route->is_monitor()) {
5047 DataType dt = route->input()->default_type();
5049 if (dt == ARDOUR::DataType::AUDIO) {
5050 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5051 rtv->set_route (route);
5052 } else if (dt == ARDOUR::DataType::MIDI) {
5053 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5054 rtv->set_route (route);
5056 throw unknown_type();
5059 new_views.push_back (rtv);
5060 track_views.push_back (rtv);
5062 rtv->effective_gain_display ();
5064 if (internal_editing()) {
5065 rtv->enter_internal_edit_mode ();
5067 rtv->leave_internal_edit_mode ();
5070 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5071 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5074 if (new_views.size() > 0) {
5075 _routes->routes_added (new_views);
5076 _summary->routes_added (new_views);
5079 if (show_editor_mixer_when_tracks_arrive) {
5080 show_editor_mixer (true);
5083 editor_list_button.set_sensitive (true);
5087 Editor::timeaxisview_deleted (TimeAxisView *tv)
5089 if (tv == entered_track) {
5093 if (_session && _session->deletion_in_progress()) {
5094 /* the situation is under control */
5098 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5100 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5102 _routes->route_removed (tv);
5104 TimeAxisView::Children c = tv->get_child_list ();
5105 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5106 if (entered_track == i->get()) {
5111 /* remove it from the list of track views */
5113 TrackViewList::iterator i;
5115 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5116 i = track_views.erase (i);
5119 /* update whatever the current mixer strip is displaying, if revelant */
5121 boost::shared_ptr<Route> route;
5124 route = rtav->route ();
5127 if (current_mixer_strip && current_mixer_strip->route() == route) {
5129 TimeAxisView* next_tv;
5131 if (track_views.empty()) {
5133 } else if (i == track_views.end()) {
5134 next_tv = track_views.front();
5141 set_selected_mixer_strip (*next_tv);
5143 /* make the editor mixer strip go away setting the
5144 * button to inactive (which also unticks the menu option)
5147 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5153 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5155 if (apply_to_selection) {
5156 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5158 TrackSelection::iterator j = i;
5161 hide_track_in_display (*i, false);
5166 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5168 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5169 // this will hide the mixer strip
5170 set_selected_mixer_strip (*tv);
5173 _routes->hide_track_in_display (*tv);
5178 Editor::sync_track_view_list_and_routes ()
5180 track_views = TrackViewList (_routes->views ());
5182 _summary->set_dirty ();
5183 _group_tabs->set_dirty ();
5185 return false; // do not call again (until needed)
5189 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5191 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5196 /** Find a RouteTimeAxisView by the ID of its route */
5198 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5200 RouteTimeAxisView* v;
5202 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5203 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5204 if(v->route()->id() == id) {
5214 Editor::fit_route_group (RouteGroup *g)
5216 TrackViewList ts = axis_views_from_routes (g->route_list ());
5221 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5223 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5226 _session->cancel_audition ();
5230 if (_session->is_auditioning()) {
5231 _session->cancel_audition ();
5232 if (r == last_audition_region) {
5237 _session->audition_region (r);
5238 last_audition_region = r;
5243 Editor::hide_a_region (boost::shared_ptr<Region> r)
5245 r->set_hidden (true);
5249 Editor::show_a_region (boost::shared_ptr<Region> r)
5251 r->set_hidden (false);
5255 Editor::audition_region_from_region_list ()
5257 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5261 Editor::hide_region_from_region_list ()
5263 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5267 Editor::show_region_in_region_list ()
5269 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5273 Editor::step_edit_status_change (bool yn)
5276 start_step_editing ();
5278 stop_step_editing ();
5283 Editor::start_step_editing ()
5285 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5289 Editor::stop_step_editing ()
5291 step_edit_connection.disconnect ();
5295 Editor::check_step_edit ()
5297 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5298 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5300 mtv->check_step_edit ();
5304 return true; // do it again, till we stop
5308 Editor::scroll_press (Direction dir)
5310 ++_scroll_callbacks;
5312 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5313 /* delay the first auto-repeat */
5319 scroll_backward (1);
5327 scroll_up_one_track ();
5331 scroll_down_one_track ();
5335 /* do hacky auto-repeat */
5336 if (!_scroll_connection.connected ()) {
5338 _scroll_connection = Glib::signal_timeout().connect (
5339 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5342 _scroll_callbacks = 0;
5349 Editor::scroll_release ()
5351 _scroll_connection.disconnect ();
5354 /** Queue a change for the Editor viewport x origin to follow the playhead */
5356 Editor::reset_x_origin_to_follow_playhead ()
5358 framepos_t const frame = playhead_cursor->current_frame ();
5360 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5362 if (_session->transport_speed() < 0) {
5364 if (frame > (current_page_samples() / 2)) {
5365 center_screen (frame-(current_page_samples()/2));
5367 center_screen (current_page_samples()/2);
5374 if (frame < leftmost_frame) {
5376 if (_session->transport_rolling()) {
5377 /* rolling; end up with the playhead at the right of the page */
5378 l = frame - current_page_samples ();
5380 /* not rolling: end up with the playhead 1/4 of the way along the page */
5381 l = frame - current_page_samples() / 4;
5385 if (_session->transport_rolling()) {
5386 /* rolling: end up with the playhead on the left of the page */
5389 /* not rolling: end up with the playhead 3/4 of the way along the page */
5390 l = frame - 3 * current_page_samples() / 4;
5398 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5404 Editor::super_rapid_screen_update ()
5406 if (!_session || !_session->engine().running()) {
5410 /* METERING / MIXER STRIPS */
5412 /* update track meters, if required */
5413 if (is_mapped() && meters_running) {
5414 RouteTimeAxisView* rtv;
5415 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5416 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5417 rtv->fast_update ();
5422 /* and any current mixer strip */
5423 if (current_mixer_strip) {
5424 current_mixer_strip->fast_update ();
5427 /* PLAYHEAD AND VIEWPORT */
5429 framepos_t const frame = _session->audible_frame();
5431 /* There are a few reasons why we might not update the playhead / viewport stuff:
5433 * 1. we don't update things when there's a pending locate request, otherwise
5434 * when the editor requests a locate there is a chance that this method
5435 * will move the playhead before the locate request is processed, causing
5437 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5438 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5441 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5443 last_update_frame = frame;
5445 if (!_dragging_playhead) {
5446 playhead_cursor->set_position (frame);
5449 if (!_stationary_playhead) {
5451 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5452 /* We only do this if we aren't already
5453 handling a visual change (ie if
5454 pending_visual_change.being_handled is
5455 false) so that these requests don't stack
5456 up there are too many of them to handle in
5459 reset_x_origin_to_follow_playhead ();
5464 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5468 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5469 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5470 if (target <= 0.0) {
5473 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5474 target = (target * 0.15) + (current * 0.85);
5480 set_horizontal_position (current);
5489 Editor::session_going_away ()
5491 _have_idled = false;
5493 _session_connections.drop_connections ();
5495 super_rapid_screen_update_connection.disconnect ();
5497 selection->clear ();
5498 cut_buffer->clear ();
5500 clicked_regionview = 0;
5501 clicked_axisview = 0;
5502 clicked_routeview = 0;
5503 entered_regionview = 0;
5505 last_update_frame = 0;
5508 playhead_cursor->hide ();
5510 /* rip everything out of the list displays */
5514 _route_groups->clear ();
5516 /* do this first so that deleting a track doesn't reset cms to null
5517 and thus cause a leak.
5520 if (current_mixer_strip) {
5521 if (current_mixer_strip->get_parent() != 0) {
5522 global_hpacker.remove (*current_mixer_strip);
5524 delete current_mixer_strip;
5525 current_mixer_strip = 0;
5528 /* delete all trackviews */
5530 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5533 track_views.clear ();
5535 nudge_clock->set_session (0);
5537 editor_list_button.set_active(false);
5538 editor_list_button.set_sensitive(false);
5540 /* clear tempo/meter rulers */
5541 remove_metric_marks ();
5543 clear_marker_display ();
5545 stop_step_editing ();
5547 /* get rid of any existing editor mixer strip */
5549 WindowTitle title(Glib::get_application_name());
5550 title += _("Editor");
5552 set_title (title.get_string());
5554 SessionHandlePtr::session_going_away ();
5559 Editor::show_editor_list (bool yn)
5562 _the_notebook.show ();
5564 _the_notebook.hide ();
5569 Editor::change_region_layering_order (bool from_context_menu)
5571 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5573 if (!clicked_routeview) {
5574 if (layering_order_editor) {
5575 layering_order_editor->hide ();
5580 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5586 boost::shared_ptr<Playlist> pl = track->playlist();
5592 if (layering_order_editor == 0) {
5593 layering_order_editor = new RegionLayeringOrderEditor (*this);
5596 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5597 layering_order_editor->maybe_present ();
5601 Editor::update_region_layering_order_editor ()
5603 if (layering_order_editor && layering_order_editor->is_visible ()) {
5604 change_region_layering_order (true);
5609 Editor::setup_fade_images ()
5611 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5612 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5613 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5614 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5615 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5617 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5618 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5619 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5620 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5621 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5623 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5624 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5625 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5626 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5627 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5629 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5630 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5631 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5632 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5633 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5637 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5639 Editor::action_menu_item (std::string const & name)
5641 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5644 return *manage (a->create_menu_item ());
5648 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5650 EventBox* b = manage (new EventBox);
5651 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5652 Label* l = manage (new Label (name));
5656 _the_notebook.append_page (widget, *b);
5660 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5662 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5663 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5666 if (ev->type == GDK_2BUTTON_PRESS) {
5668 /* double-click on a notebook tab shrinks or expands the notebook */
5670 if (_notebook_shrunk) {
5671 if (pre_notebook_shrink_pane_width) {
5672 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5674 _notebook_shrunk = false;
5676 pre_notebook_shrink_pane_width = edit_pane.get_position();
5678 /* this expands the LHS of the edit pane to cover the notebook
5679 PAGE but leaves the tabs visible.
5681 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5682 _notebook_shrunk = true;
5690 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5692 using namespace Menu_Helpers;
5694 MenuList& items = _control_point_context_menu.items ();
5697 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5698 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5699 if (!can_remove_control_point (item)) {
5700 items.back().set_sensitive (false);
5703 _control_point_context_menu.popup (event->button.button, event->button.time);
5707 Editor::zoom_vertical_modifier_released()
5709 _stepping_axis_view = 0;
5713 Editor::ui_parameter_changed (string parameter)
5715 if (parameter == "icon-set") {
5716 while (!_cursor_stack.empty()) {
5717 _cursor_stack.pop();
5719 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5720 } else if (parameter == "draggable-playhead") {
5721 if (_verbose_cursor) {
5722 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());