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 if (Profile->get_mixbus())
2108 if (ep == EditAtSelectedMarker)
2109 ep = EditAtPlayhead;
2111 string str = edit_point_strings[(int)ep];
2112 if (str != edit_point_selector.get_text ()) {
2113 edit_point_selector.set_text (str);
2116 reset_canvas_cursor ();
2118 if (!force && !changed) {
2122 const char* action=NULL;
2124 switch (_edit_point) {
2125 case EditAtPlayhead:
2126 action = "edit-at-playhead";
2128 case EditAtSelectedMarker:
2129 action = "edit-at-marker";
2132 action = "edit-at-mouse";
2136 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2138 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2142 bool in_track_canvas;
2144 if (!mouse_frame (foo, in_track_canvas)) {
2145 in_track_canvas = false;
2148 reset_canvas_action_sensitivity (in_track_canvas);
2154 Editor::set_state (const XMLNode& node, int /*version*/)
2156 const XMLProperty* prop;
2163 g.base_width = default_width;
2164 g.base_height = default_height;
2168 if ((geometry = find_named_node (node, "geometry")) != 0) {
2172 if ((prop = geometry->property("x_size")) == 0) {
2173 prop = geometry->property ("x-size");
2176 g.base_width = atoi(prop->value());
2178 if ((prop = geometry->property("y_size")) == 0) {
2179 prop = geometry->property ("y-size");
2182 g.base_height = atoi(prop->value());
2185 if ((prop = geometry->property ("x_pos")) == 0) {
2186 prop = geometry->property ("x-pos");
2189 x = atoi (prop->value());
2192 if ((prop = geometry->property ("y_pos")) == 0) {
2193 prop = geometry->property ("y-pos");
2196 y = atoi (prop->value());
2200 set_default_size (g.base_width, g.base_height);
2203 if (_session && (prop = node.property ("playhead"))) {
2205 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2207 playhead_cursor->set_position (pos);
2209 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2210 playhead_cursor->set_position (0);
2213 playhead_cursor->set_position (0);
2216 if ((prop = node.property ("mixer-width"))) {
2217 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2220 if ((prop = node.property ("zoom-focus"))) {
2221 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2224 if ((prop = node.property ("zoom"))) {
2225 /* older versions of ardour used floating point samples_per_pixel */
2226 double f = PBD::atof (prop->value());
2227 reset_zoom (llrintf (f));
2229 reset_zoom (samples_per_pixel);
2232 if ((prop = node.property ("visible-track-count"))) {
2233 set_visible_track_count (PBD::atoi (prop->value()));
2236 if ((prop = node.property ("snap-to"))) {
2237 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2240 if ((prop = node.property ("snap-mode"))) {
2241 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2244 if ((prop = node.property ("internal-snap-to"))) {
2245 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2248 if ((prop = node.property ("internal-snap-mode"))) {
2249 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2252 if ((prop = node.property ("pre-internal-snap-to"))) {
2253 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2257 if ((prop = node.property ("pre-internal-snap-mode"))) {
2258 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2261 if ((prop = node.property ("mouse-mode"))) {
2262 MouseMode m = str2mousemode(prop->value());
2263 set_mouse_mode (m, true);
2265 set_mouse_mode (MouseObject, true);
2268 if ((prop = node.property ("left-frame")) != 0) {
2270 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2274 reset_x_origin (pos);
2278 if ((prop = node.property ("y-origin")) != 0) {
2279 reset_y_origin (atof (prop->value ()));
2282 if ((prop = node.property ("internal-edit"))) {
2283 bool yn = string_is_affirmative (prop->value());
2284 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2286 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2287 tact->set_active (!yn);
2288 tact->set_active (yn);
2292 if ((prop = node.property ("join-object-range"))) {
2293 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2294 bool yn = string_is_affirmative (prop->value());
2296 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2297 tact->set_active (!yn);
2298 tact->set_active (yn);
2300 set_mouse_mode(mouse_mode, true);
2303 if ((prop = node.property ("edit-point"))) {
2304 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2307 if ((prop = node.property ("show-measures"))) {
2308 bool yn = string_is_affirmative (prop->value());
2309 _show_measures = yn;
2310 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2312 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2313 /* do it twice to force the change */
2314 tact->set_active (!yn);
2315 tact->set_active (yn);
2319 if ((prop = node.property ("follow-playhead"))) {
2320 bool yn = string_is_affirmative (prop->value());
2321 set_follow_playhead (yn);
2322 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2324 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2325 if (tact->get_active() != yn) {
2326 tact->set_active (yn);
2331 if ((prop = node.property ("stationary-playhead"))) {
2332 bool yn = string_is_affirmative (prop->value());
2333 set_stationary_playhead (yn);
2334 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2336 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2337 if (tact->get_active() != yn) {
2338 tact->set_active (yn);
2343 if ((prop = node.property ("region-list-sort-type"))) {
2344 RegionListSortType st;
2345 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2348 if ((prop = node.property ("show-editor-mixer"))) {
2350 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2353 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2354 bool yn = string_is_affirmative (prop->value());
2356 /* do it twice to force the change */
2358 tact->set_active (!yn);
2359 tact->set_active (yn);
2362 if ((prop = node.property ("show-editor-list"))) {
2364 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2367 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2368 bool yn = string_is_affirmative (prop->value());
2370 /* do it twice to force the change */
2372 tact->set_active (!yn);
2373 tact->set_active (yn);
2376 if ((prop = node.property (X_("editor-list-page")))) {
2377 _the_notebook.set_current_page (atoi (prop->value ()));
2380 if ((prop = node.property (X_("show-marker-lines")))) {
2381 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2383 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2384 bool yn = string_is_affirmative (prop->value ());
2386 tact->set_active (!yn);
2387 tact->set_active (yn);
2390 XMLNodeList children = node.children ();
2391 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2392 selection->set_state (**i, Stateful::current_state_version);
2393 _regions->set_state (**i);
2396 if ((prop = node.property ("maximised"))) {
2397 bool yn = string_is_affirmative (prop->value());
2398 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2400 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2401 bool fs = tact && tact->get_active();
2403 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2407 if ((prop = node.property ("nudge-clock-value"))) {
2409 sscanf (prop->value().c_str(), "%" PRId64, &f);
2410 nudge_clock->set (f);
2412 nudge_clock->set_mode (AudioClock::Timecode);
2413 nudge_clock->set (_session->frame_rate() * 5, true);
2420 Editor::get_state ()
2422 XMLNode* node = new XMLNode ("Editor");
2425 id().print (buf, sizeof (buf));
2426 node->add_property ("id", buf);
2428 if (is_realized()) {
2429 Glib::RefPtr<Gdk::Window> win = get_window();
2431 int x, y, width, height;
2432 win->get_root_origin(x, y);
2433 win->get_size(width, height);
2435 XMLNode* geometry = new XMLNode ("geometry");
2437 snprintf(buf, sizeof(buf), "%d", width);
2438 geometry->add_property("x-size", string(buf));
2439 snprintf(buf, sizeof(buf), "%d", height);
2440 geometry->add_property("y-size", string(buf));
2441 snprintf(buf, sizeof(buf), "%d", x);
2442 geometry->add_property("x-pos", string(buf));
2443 snprintf(buf, sizeof(buf), "%d", y);
2444 geometry->add_property("y-pos", string(buf));
2445 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2446 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2447 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2448 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2449 geometry->add_property("edit-vertical-pane-pos", string(buf));
2451 node->add_child_nocopy (*geometry);
2454 maybe_add_mixer_strip_width (*node);
2456 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2458 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2459 node->add_property ("zoom", buf);
2460 node->add_property ("snap-to", enum_2_string (_snap_type));
2461 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2462 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2463 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2464 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2465 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2466 node->add_property ("edit-point", enum_2_string (_edit_point));
2467 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2468 node->add_property ("visible-track-count", buf);
2470 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2471 node->add_property ("playhead", buf);
2472 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2473 node->add_property ("left-frame", buf);
2474 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2475 node->add_property ("y-origin", buf);
2477 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2478 node->add_property ("maximised", _maximised ? "yes" : "no");
2479 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2480 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2481 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2482 node->add_property ("mouse-mode", enum2str(mouse_mode));
2483 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2484 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2486 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2488 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2489 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2492 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2494 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2495 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2498 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2499 node->add_property (X_("editor-list-page"), buf);
2501 if (button_bindings) {
2502 XMLNode* bb = new XMLNode (X_("Buttons"));
2503 button_bindings->save (*bb);
2504 node->add_child_nocopy (*bb);
2507 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2509 node->add_child_nocopy (selection->get_state ());
2510 node->add_child_nocopy (_regions->get_state ());
2512 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2513 node->add_property ("nudge-clock-value", buf);
2518 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2519 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2521 * @return pair: TimeAxisView that y is over, layer index.
2523 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2524 * in stacked or expanded region display mode, otherwise 0.
2526 std::pair<TimeAxisView *, double>
2527 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2529 if (!trackview_relative_offset) {
2530 y -= _trackview_group->canvas_origin().y;
2534 return std::make_pair ( (TimeAxisView *) 0, 0);
2537 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2539 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2546 return std::make_pair ( (TimeAxisView *) 0, 0);
2549 /** Snap a position to the grid, if appropriate, taking into account current
2550 * grid settings and also the state of any snap modifier keys that may be pressed.
2551 * @param start Position to snap.
2552 * @param event Event to get current key modifier information from, or 0.
2555 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2557 if (!_session || !event) {
2561 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2562 if (_snap_mode == SnapOff) {
2563 snap_to_internal (start, direction, for_mark);
2566 if (_snap_mode != SnapOff) {
2567 snap_to_internal (start, direction, for_mark);
2573 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark)
2575 if (!_session || _snap_mode == SnapOff) {
2579 snap_to_internal (start, direction, for_mark);
2583 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2585 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2586 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2588 switch (_snap_type) {
2589 case SnapToTimecodeFrame:
2590 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2591 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2592 /* start is already on a whole timecode frame, do nothing */
2593 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2594 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2596 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2600 case SnapToTimecodeSeconds:
2601 if (_session->config.get_timecode_offset_negative()) {
2602 start += _session->config.get_timecode_offset ();
2604 start -= _session->config.get_timecode_offset ();
2606 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2607 (start % one_timecode_second == 0)) {
2608 /* start is already on a whole second, do nothing */
2609 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2610 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2612 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2615 if (_session->config.get_timecode_offset_negative()) {
2616 start -= _session->config.get_timecode_offset ();
2618 start += _session->config.get_timecode_offset ();
2622 case SnapToTimecodeMinutes:
2623 if (_session->config.get_timecode_offset_negative()) {
2624 start += _session->config.get_timecode_offset ();
2626 start -= _session->config.get_timecode_offset ();
2628 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2629 (start % one_timecode_minute == 0)) {
2630 /* start is already on a whole minute, do nothing */
2631 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2632 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2634 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2636 if (_session->config.get_timecode_offset_negative()) {
2637 start -= _session->config.get_timecode_offset ();
2639 start += _session->config.get_timecode_offset ();
2643 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2644 abort(); /*NOTREACHED*/
2649 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark)
2651 const framepos_t one_second = _session->frame_rate();
2652 const framepos_t one_minute = _session->frame_rate() * 60;
2653 framepos_t presnap = start;
2657 switch (_snap_type) {
2658 case SnapToTimecodeFrame:
2659 case SnapToTimecodeSeconds:
2660 case SnapToTimecodeMinutes:
2661 return timecode_snap_to_internal (start, direction, for_mark);
2664 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2665 start % (one_second/75) == 0) {
2666 /* start is already on a whole CD frame, do nothing */
2667 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2668 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2670 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2675 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2676 start % one_second == 0) {
2677 /* start is already on a whole second, do nothing */
2678 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2679 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2681 start = (framepos_t) floor ((double) start / one_second) * one_second;
2686 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2687 start % one_minute == 0) {
2688 /* start is already on a whole minute, do nothing */
2689 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2690 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2692 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2697 start = _session->tempo_map().round_to_bar (start, direction);
2701 start = _session->tempo_map().round_to_beat (start, direction);
2704 case SnapToBeatDiv128:
2705 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2707 case SnapToBeatDiv64:
2708 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2710 case SnapToBeatDiv32:
2711 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2713 case SnapToBeatDiv28:
2714 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2716 case SnapToBeatDiv24:
2717 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2719 case SnapToBeatDiv20:
2720 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2722 case SnapToBeatDiv16:
2723 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2725 case SnapToBeatDiv14:
2726 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2728 case SnapToBeatDiv12:
2729 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2731 case SnapToBeatDiv10:
2732 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2734 case SnapToBeatDiv8:
2735 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2737 case SnapToBeatDiv7:
2738 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2740 case SnapToBeatDiv6:
2741 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2743 case SnapToBeatDiv5:
2744 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2746 case SnapToBeatDiv4:
2747 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2749 case SnapToBeatDiv3:
2750 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2752 case SnapToBeatDiv2:
2753 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2761 _session->locations()->marks_either_side (start, before, after);
2763 if (before == max_framepos && after == max_framepos) {
2764 /* No marks to snap to, so just don't snap */
2766 } else if (before == max_framepos) {
2768 } else if (after == max_framepos) {
2770 } else if (before != max_framepos && after != max_framepos) {
2771 /* have before and after */
2772 if ((start - before) < (after - start)) {
2781 case SnapToRegionStart:
2782 case SnapToRegionEnd:
2783 case SnapToRegionSync:
2784 case SnapToRegionBoundary:
2785 if (!region_boundary_cache.empty()) {
2787 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2788 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2790 if (direction > 0) {
2791 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2793 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2796 if (next != region_boundary_cache.begin ()) {
2801 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2802 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2804 if (start > (p + n) / 2) {
2813 switch (_snap_mode) {
2819 if (presnap > start) {
2820 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2824 } else if (presnap < start) {
2825 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2831 /* handled at entry */
2839 Editor::setup_toolbar ()
2841 HBox* mode_box = manage(new HBox);
2842 mode_box->set_border_width (2);
2843 mode_box->set_spacing(2);
2845 HBox* mouse_mode_box = manage (new HBox);
2846 HBox* mouse_mode_hbox = manage (new HBox);
2847 VBox* mouse_mode_vbox = manage (new VBox);
2848 Alignment* mouse_mode_align = manage (new Alignment);
2850 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2851 mouse_mode_size_group->add_widget (smart_mode_button);
2852 mouse_mode_size_group->add_widget (mouse_move_button);
2853 mouse_mode_size_group->add_widget (mouse_cut_button);
2854 mouse_mode_size_group->add_widget (mouse_select_button);
2855 mouse_mode_size_group->add_widget (mouse_timefx_button);
2856 mouse_mode_size_group->add_widget (mouse_audition_button);
2857 mouse_mode_size_group->add_widget (mouse_draw_button);
2858 mouse_mode_size_group->add_widget (internal_edit_button);
2860 mouse_mode_size_group->add_widget (zoom_in_button);
2861 mouse_mode_size_group->add_widget (zoom_out_button);
2862 mouse_mode_size_group->add_widget (zoom_preset_selector);
2863 mouse_mode_size_group->add_widget (zoom_out_full_button);
2864 mouse_mode_size_group->add_widget (zoom_focus_selector);
2866 mouse_mode_size_group->add_widget (tav_shrink_button);
2867 mouse_mode_size_group->add_widget (tav_expand_button);
2868 mouse_mode_size_group->add_widget (visible_tracks_selector);
2870 mouse_mode_size_group->add_widget (snap_type_selector);
2871 mouse_mode_size_group->add_widget (snap_mode_selector);
2873 mouse_mode_size_group->add_widget (edit_point_selector);
2874 mouse_mode_size_group->add_widget (edit_mode_selector);
2876 mouse_mode_size_group->add_widget (*nudge_clock);
2877 mouse_mode_size_group->add_widget (nudge_forward_button);
2878 mouse_mode_size_group->add_widget (nudge_backward_button);
2880 mouse_mode_hbox->set_spacing (2);
2882 if (!ARDOUR::Profile->get_trx()) {
2883 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2886 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2887 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2889 if (!ARDOUR::Profile->get_mixbus()) {
2890 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2893 if (!ARDOUR::Profile->get_trx()) {
2894 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2895 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2896 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2897 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 0);
2900 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2902 mouse_mode_align->add (*mouse_mode_vbox);
2903 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2905 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2907 edit_mode_selector.set_name ("mouse mode button");
2909 if (!ARDOUR::Profile->get_trx()) {
2910 mode_box->pack_start (edit_mode_selector, false, false);
2912 mode_box->pack_start (*mouse_mode_box, false, false);
2914 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2915 _mouse_mode_tearoff->set_name ("MouseModeBase");
2916 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2918 if (Profile->get_sae() || Profile->get_mixbus() ) {
2919 _mouse_mode_tearoff->set_can_be_torn_off (false);
2922 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2923 &_mouse_mode_tearoff->tearoff_window()));
2924 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2925 &_mouse_mode_tearoff->tearoff_window(), 1));
2926 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2927 &_mouse_mode_tearoff->tearoff_window()));
2928 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2929 &_mouse_mode_tearoff->tearoff_window(), 1));
2933 _zoom_box.set_spacing (2);
2934 _zoom_box.set_border_width (2);
2938 zoom_preset_selector.set_name ("zoom button");
2939 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2940 zoom_preset_selector.set_size_request (42, -1);
2942 zoom_in_button.set_name ("zoom button");
2943 zoom_in_button.set_image(::get_icon ("zoom_in"));
2944 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2945 zoom_in_button.set_related_action (act);
2947 zoom_out_button.set_name ("zoom button");
2948 zoom_out_button.set_image(::get_icon ("zoom_out"));
2949 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2950 zoom_out_button.set_related_action (act);
2952 zoom_out_full_button.set_name ("zoom button");
2953 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2954 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2955 zoom_out_full_button.set_related_action (act);
2957 zoom_focus_selector.set_name ("zoom button");
2959 if (ARDOUR::Profile->get_mixbus()) {
2960 _zoom_box.pack_start (zoom_preset_selector, false, false);
2961 } else if (ARDOUR::Profile->get_trx()) {
2962 mode_box->pack_start (zoom_out_button, false, false);
2963 mode_box->pack_start (zoom_in_button, false, false);
2965 _zoom_box.pack_start (zoom_out_button, false, false);
2966 _zoom_box.pack_start (zoom_in_button, false, false);
2967 _zoom_box.pack_start (zoom_out_full_button, false, false);
2968 _zoom_box.pack_start (zoom_focus_selector, false, false);
2971 /* Track zoom buttons */
2972 visible_tracks_selector.set_name ("zoom button");
2973 if (Profile->get_mixbus()) {
2974 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2975 visible_tracks_selector.set_size_request (42, -1);
2977 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2980 tav_expand_button.set_name ("zoom button");
2981 tav_expand_button.set_image(::get_icon ("tav_exp"));
2982 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2983 tav_expand_button.set_related_action (act);
2985 tav_shrink_button.set_name ("zoom button");
2986 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2987 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2988 tav_shrink_button.set_related_action (act);
2990 if (ARDOUR::Profile->get_mixbus()) {
2991 _zoom_box.pack_start (visible_tracks_selector);
2992 } else if (ARDOUR::Profile->get_trx()) {
2993 _zoom_box.pack_start (tav_shrink_button);
2994 _zoom_box.pack_start (tav_expand_button);
2996 _zoom_box.pack_start (visible_tracks_selector);
2997 _zoom_box.pack_start (tav_shrink_button);
2998 _zoom_box.pack_start (tav_expand_button);
3001 if (!ARDOUR::Profile->get_trx()) {
3002 _zoom_tearoff = manage (new TearOff (_zoom_box));
3004 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3005 &_zoom_tearoff->tearoff_window()));
3006 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3007 &_zoom_tearoff->tearoff_window(), 0));
3008 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3009 &_zoom_tearoff->tearoff_window()));
3010 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3011 &_zoom_tearoff->tearoff_window(), 0));
3014 if (Profile->get_sae() || Profile->get_mixbus() ) {
3015 _zoom_tearoff->set_can_be_torn_off (false);
3018 snap_box.set_spacing (2);
3019 snap_box.set_border_width (2);
3021 snap_type_selector.set_name ("mouse mode button");
3023 snap_mode_selector.set_name ("mouse mode button");
3025 edit_point_selector.set_name ("mouse mode button");
3027 snap_box.pack_start (snap_mode_selector, false, false);
3028 snap_box.pack_start (snap_type_selector, false, false);
3029 snap_box.pack_start (edit_point_selector, false, false);
3033 HBox *nudge_box = manage (new HBox);
3034 nudge_box->set_spacing (2);
3035 nudge_box->set_border_width (2);
3037 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3038 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3040 nudge_box->pack_start (nudge_backward_button, false, false);
3041 nudge_box->pack_start (nudge_forward_button, false, false);
3042 nudge_box->pack_start (*nudge_clock, false, false);
3045 /* Pack everything in... */
3047 HBox* hbox = manage (new HBox);
3048 hbox->set_spacing(2);
3050 _tools_tearoff = manage (new TearOff (*hbox));
3051 _tools_tearoff->set_name ("MouseModeBase");
3052 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3054 if (Profile->get_sae() || Profile->get_mixbus()) {
3055 _tools_tearoff->set_can_be_torn_off (false);
3058 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3059 &_tools_tearoff->tearoff_window()));
3060 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3061 &_tools_tearoff->tearoff_window(), 0));
3062 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3063 &_tools_tearoff->tearoff_window()));
3064 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3065 &_tools_tearoff->tearoff_window(), 0));
3067 toolbar_hbox.set_spacing (2);
3068 toolbar_hbox.set_border_width (1);
3070 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3071 if (!ARDOUR::Profile->get_trx()) {
3072 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3073 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3076 if (!ARDOUR::Profile->get_trx()) {
3077 hbox->pack_start (snap_box, false, false);
3078 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3079 hbox->pack_start (*nudge_box, false, false);
3081 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3084 hbox->pack_start (panic_box, false, false);
3088 toolbar_base.set_name ("ToolBarBase");
3089 toolbar_base.add (toolbar_hbox);
3091 _toolbar_viewport.add (toolbar_base);
3092 /* stick to the required height but allow width to vary if there's not enough room */
3093 _toolbar_viewport.set_size_request (1, -1);
3095 toolbar_frame.set_shadow_type (SHADOW_OUT);
3096 toolbar_frame.set_name ("BaseFrame");
3097 toolbar_frame.add (_toolbar_viewport);
3101 Editor::build_edit_point_menu ()
3103 using namespace Menu_Helpers;
3105 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3106 if(!Profile->get_mixbus())
3107 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3108 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3110 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3114 Editor::build_edit_mode_menu ()
3116 using namespace Menu_Helpers;
3118 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3119 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3120 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3121 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3123 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3127 Editor::build_snap_mode_menu ()
3129 using namespace Menu_Helpers;
3131 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3132 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3133 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3135 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3139 Editor::build_snap_type_menu ()
3141 using namespace Menu_Helpers;
3143 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3144 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3145 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3146 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3147 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3148 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3149 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3150 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3151 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3152 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3153 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3154 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3155 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3156 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3157 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3158 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3159 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3160 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3161 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3162 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3163 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3164 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3165 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3166 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3167 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3168 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3169 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3170 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3171 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3172 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3174 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3179 Editor::setup_tooltips ()
3181 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3182 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3183 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3184 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3185 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit Gain/Notes/Automation"));
3186 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3187 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3188 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3189 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3190 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3191 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3192 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3193 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3194 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3195 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3196 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3197 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3198 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3199 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3200 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3201 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3202 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3203 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3204 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3208 Editor::convert_drop_to_paths (
3209 vector<string>& paths,
3210 const RefPtr<Gdk::DragContext>& /*context*/,
3213 const SelectionData& data,
3217 if (_session == 0) {
3221 vector<string> uris = data.get_uris();
3225 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3226 are actually URI lists. So do it by hand.
3229 if (data.get_target() != "text/plain") {
3233 /* Parse the "uri-list" format that Nautilus provides,
3234 where each pathname is delimited by \r\n.
3236 THERE MAY BE NO NULL TERMINATING CHAR!!!
3239 string txt = data.get_text();
3243 p = (char *) malloc (txt.length() + 1);
3244 txt.copy (p, txt.length(), 0);
3245 p[txt.length()] = '\0';
3251 while (g_ascii_isspace (*p))
3255 while (*q && (*q != '\n') && (*q != '\r')) {
3262 while (q > p && g_ascii_isspace (*q))
3267 uris.push_back (string (p, q - p + 1));
3271 p = strchr (p, '\n');
3283 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3284 if ((*i).substr (0,7) == "file://") {
3285 paths.push_back (Glib::filename_from_uri (*i));
3293 Editor::new_tempo_section ()
3298 Editor::map_transport_state ()
3300 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3302 if (_session && _session->transport_stopped()) {
3303 have_pending_keyboard_selection = false;
3306 update_loop_range_view ();
3312 Editor::begin_reversible_command (string name)
3315 _session->begin_reversible_command (name);
3320 Editor::begin_reversible_command (GQuark q)
3323 _session->begin_reversible_command (q);
3328 Editor::commit_reversible_command ()
3331 _session->commit_reversible_command ();
3336 Editor::history_changed ()
3340 if (undo_action && _session) {
3341 if (_session->undo_depth() == 0) {
3342 label = S_("Command|Undo");
3344 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3346 undo_action->property_label() = label;
3349 if (redo_action && _session) {
3350 if (_session->redo_depth() == 0) {
3353 label = string_compose(_("Redo (%1)"), _session->next_redo());
3355 redo_action->property_label() = label;
3360 Editor::duplicate_range (bool with_dialog)
3364 RegionSelection rs = get_regions_from_selection_and_entered ();
3366 if ( selection->time.length() == 0 && rs.empty()) {
3372 ArdourDialog win (_("Duplicate"));
3373 Label label (_("Number of duplications:"));
3374 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3375 SpinButton spinner (adjustment, 0.0, 1);
3378 win.get_vbox()->set_spacing (12);
3379 win.get_vbox()->pack_start (hbox);
3380 hbox.set_border_width (6);
3381 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3383 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3384 place, visually. so do this by hand.
3387 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3388 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3389 spinner.grab_focus();
3395 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3396 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3397 win.set_default_response (RESPONSE_ACCEPT);
3399 spinner.grab_focus ();
3401 switch (win.run ()) {
3402 case RESPONSE_ACCEPT:
3408 times = adjustment.get_value();
3411 if ((current_mouse_mode() == Editing::MouseRange)) {
3412 if (selection->time.length()) {
3413 duplicate_selection (times);
3415 } else if (get_smart_mode()) {
3416 if (selection->time.length()) {
3417 duplicate_selection (times);
3419 duplicate_some_regions (rs, times);
3421 duplicate_some_regions (rs, times);
3426 Editor::set_edit_mode (EditMode m)
3428 Config->set_edit_mode (m);
3432 Editor::cycle_edit_mode ()
3434 switch (Config->get_edit_mode()) {
3436 if (Profile->get_sae()) {
3437 Config->set_edit_mode (Lock);
3439 Config->set_edit_mode (Ripple);
3444 Config->set_edit_mode (Lock);
3447 Config->set_edit_mode (Slide);
3453 Editor::edit_mode_selection_done ( EditMode m )
3455 Config->set_edit_mode ( m );
3459 Editor::snap_type_selection_done (SnapType snaptype)
3461 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3463 ract->set_active ();
3468 Editor::snap_mode_selection_done (SnapMode mode)
3470 RefPtr<RadioAction> ract = snap_mode_action (mode);
3473 ract->set_active (true);
3478 Editor::cycle_edit_point (bool with_marker)
3480 if(Profile->get_mixbus())
3481 with_marker = false;
3483 switch (_edit_point) {
3485 set_edit_point_preference (EditAtPlayhead);
3487 case EditAtPlayhead:
3489 set_edit_point_preference (EditAtSelectedMarker);
3491 set_edit_point_preference (EditAtMouse);
3494 case EditAtSelectedMarker:
3495 set_edit_point_preference (EditAtMouse);
3501 Editor::edit_point_selection_done (EditPoint ep)
3503 set_edit_point_preference ( ep );
3507 Editor::build_zoom_focus_menu ()
3509 using namespace Menu_Helpers;
3511 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3512 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3513 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3514 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3515 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3516 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3518 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3522 Editor::zoom_focus_selection_done ( ZoomFocus f )
3524 RefPtr<RadioAction> ract = zoom_focus_action (f);
3526 ract->set_active ();
3531 Editor::build_track_count_menu ()
3533 using namespace Menu_Helpers;
3535 if (!Profile->get_mixbus()) {
3536 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3537 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3538 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3539 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3540 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3541 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3542 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3543 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3544 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3545 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3546 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3547 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3548 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3550 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3551 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3552 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3553 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3554 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3555 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3556 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3557 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3558 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3559 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3561 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3562 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3563 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3564 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3565 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3566 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3567 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3568 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3569 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3570 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3571 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3576 Editor::set_zoom_preset (int64_t ms)
3579 temporal_zoom_session();
3583 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3584 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3588 Editor::set_visible_track_count (int32_t n)
3590 _visible_track_count = n;
3592 /* if the canvas hasn't really been allocated any size yet, just
3593 record the desired number of visible tracks and return. when canvas
3594 allocation happens, we will get called again and then we can do the
3598 if (_visible_canvas_height <= 1) {
3605 if (_visible_track_count > 0) {
3606 h = trackviews_height() / _visible_track_count;
3607 std::ostringstream s;
3608 s << _visible_track_count;
3610 } else if (_visible_track_count == 0) {
3612 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3613 if ((*i)->marked_for_display()) {
3617 h = trackviews_height() / n;
3620 /* negative value means that the visible track count has
3621 been overridden by explicit track height changes.
3623 visible_tracks_selector.set_text (X_("*"));
3627 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3628 (*i)->set_height (h);
3631 if (str != visible_tracks_selector.get_text()) {
3632 visible_tracks_selector.set_text (str);
3637 Editor::override_visible_track_count ()
3639 _visible_track_count = -1;
3640 visible_tracks_selector.set_text ( _("*") );
3644 Editor::edit_controls_button_release (GdkEventButton* ev)
3646 if (Keyboard::is_context_menu_event (ev)) {
3647 ARDOUR_UI::instance()->add_route (this);
3648 } else if (ev->button == 1) {
3649 selection->clear_tracks ();
3656 Editor::mouse_select_button_release (GdkEventButton* ev)
3658 /* this handles just right-clicks */
3660 if (ev->button != 3) {
3668 Editor::set_zoom_focus (ZoomFocus f)
3670 string str = zoom_focus_strings[(int)f];
3672 if (str != zoom_focus_selector.get_text()) {
3673 zoom_focus_selector.set_text (str);
3676 if (zoom_focus != f) {
3683 Editor::cycle_zoom_focus ()
3685 switch (zoom_focus) {
3687 set_zoom_focus (ZoomFocusRight);
3689 case ZoomFocusRight:
3690 set_zoom_focus (ZoomFocusCenter);
3692 case ZoomFocusCenter:
3693 set_zoom_focus (ZoomFocusPlayhead);
3695 case ZoomFocusPlayhead:
3696 set_zoom_focus (ZoomFocusMouse);
3698 case ZoomFocusMouse:
3699 set_zoom_focus (ZoomFocusEdit);
3702 set_zoom_focus (ZoomFocusLeft);
3708 Editor::ensure_float (Window& win)
3710 win.set_transient_for (*this);
3714 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3716 /* recover or initialize pane positions. do this here rather than earlier because
3717 we don't want the positions to change the child allocations, which they seem to do.
3723 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3732 XMLNode* geometry = find_named_node (*node, "geometry");
3734 if (which == static_cast<Paned*> (&edit_pane)) {
3736 if (done & Horizontal) {
3740 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3741 _notebook_shrunk = string_is_affirmative (prop->value ());
3744 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3745 /* initial allocation is 90% to canvas, 10% to notebook */
3746 pos = (int) floor (alloc.get_width() * 0.90f);
3747 snprintf (buf, sizeof(buf), "%d", pos);
3749 pos = atoi (prop->value());
3752 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3753 edit_pane.set_position (pos);
3756 done = (Pane) (done | Horizontal);
3758 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3760 if (done & Vertical) {
3764 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3765 /* initial allocation is 90% to canvas, 10% to summary */
3766 pos = (int) floor (alloc.get_height() * 0.90f);
3767 snprintf (buf, sizeof(buf), "%d", pos);
3770 pos = atoi (prop->value());
3773 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3774 editor_summary_pane.set_position (pos);
3777 done = (Pane) (done | Vertical);
3782 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3784 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3785 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3786 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3787 top_hbox.remove (toolbar_frame);
3792 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3794 if (toolbar_frame.get_parent() == 0) {
3795 top_hbox.pack_end (toolbar_frame);
3800 Editor::set_show_measures (bool yn)
3802 if (_show_measures != yn) {
3805 if ((_show_measures = yn) == true) {
3807 tempo_lines->show();
3810 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3811 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3813 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3814 draw_measures (begin, end);
3822 Editor::toggle_follow_playhead ()
3824 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3826 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3827 set_follow_playhead (tact->get_active());
3831 /** @param yn true to follow playhead, otherwise false.
3832 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3835 Editor::set_follow_playhead (bool yn, bool catch_up)
3837 if (_follow_playhead != yn) {
3838 if ((_follow_playhead = yn) == true && catch_up) {
3840 reset_x_origin_to_follow_playhead ();
3847 Editor::toggle_stationary_playhead ()
3849 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3851 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3852 set_stationary_playhead (tact->get_active());
3857 Editor::set_stationary_playhead (bool yn)
3859 if (_stationary_playhead != yn) {
3860 if ((_stationary_playhead = yn) == true) {
3862 // FIXME need a 3.0 equivalent of this 2.X call
3863 // update_current_screen ();
3870 Editor::playlist_selector () const
3872 return *_playlist_selector;
3876 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3878 if (paste_count == 0) {
3879 /* don't bother calculating an offset that will be zero anyway */
3883 /* calculate basic unsnapped multi-paste offset */
3884 framecnt_t offset = paste_count * duration;
3886 /* snap offset so pos + offset is aligned to the grid */
3887 framepos_t offset_pos = pos + offset;
3888 snap_to(offset_pos, RoundUpMaybe);
3889 offset = offset_pos - pos;
3895 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3899 switch (_snap_type) {
3901 return Evoral::MusicalTime(1.0);
3904 case SnapToBeatDiv128:
3905 return Evoral::MusicalTime(1.0/128.0);
3907 case SnapToBeatDiv64:
3908 return Evoral::MusicalTime(1.0/64.0);
3910 case SnapToBeatDiv32:
3911 return Evoral::MusicalTime(1.0/32.0);
3913 case SnapToBeatDiv28:
3914 return Evoral::MusicalTime(1.0/28.0);
3916 case SnapToBeatDiv24:
3917 return Evoral::MusicalTime(1.0/24.0);
3919 case SnapToBeatDiv20:
3920 return Evoral::MusicalTime(1.0/20.0);
3922 case SnapToBeatDiv16:
3923 return Evoral::MusicalTime(1.0/16.0);
3925 case SnapToBeatDiv14:
3926 return Evoral::MusicalTime(1.0/14.0);
3928 case SnapToBeatDiv12:
3929 return Evoral::MusicalTime(1.0/12.0);
3931 case SnapToBeatDiv10:
3932 return Evoral::MusicalTime(1.0/10.0);
3934 case SnapToBeatDiv8:
3935 return Evoral::MusicalTime(1.0/8.0);
3937 case SnapToBeatDiv7:
3938 return Evoral::MusicalTime(1.0/7.0);
3940 case SnapToBeatDiv6:
3941 return Evoral::MusicalTime(1.0/6.0);
3943 case SnapToBeatDiv5:
3944 return Evoral::MusicalTime(1.0/5.0);
3946 case SnapToBeatDiv4:
3947 return Evoral::MusicalTime(1.0/4.0);
3949 case SnapToBeatDiv3:
3950 return Evoral::MusicalTime(1.0/3.0);
3952 case SnapToBeatDiv2:
3953 return Evoral::MusicalTime(1.0/2.0);
3958 return Evoral::MusicalTime(_session->tempo_map().meter_at (position).divisions_per_bar());
3963 case SnapToTimecodeFrame:
3964 case SnapToTimecodeSeconds:
3965 case SnapToTimecodeMinutes:
3968 case SnapToRegionStart:
3969 case SnapToRegionEnd:
3970 case SnapToRegionSync:
3971 case SnapToRegionBoundary:
3977 return Evoral::MusicalTime();
3981 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3985 ret = nudge_clock->current_duration (pos);
3986 next = ret + 1; /* XXXX fix me */
3992 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3994 ArdourDialog dialog (_("Playlist Deletion"));
3995 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3996 "If it is kept, its audio files will not be cleaned.\n"
3997 "If it is deleted, audio files used by it alone will be cleaned."),
4000 dialog.set_position (WIN_POS_CENTER);
4001 dialog.get_vbox()->pack_start (label);
4005 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4006 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4007 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4009 switch (dialog.run ()) {
4010 case RESPONSE_ACCEPT:
4011 /* delete the playlist */
4015 case RESPONSE_REJECT:
4016 /* keep the playlist */
4028 Editor::audio_region_selection_covers (framepos_t where)
4030 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4031 if ((*a)->region()->covers (where)) {
4040 Editor::prepare_for_cleanup ()
4042 cut_buffer->clear_regions ();
4043 cut_buffer->clear_playlists ();
4045 selection->clear_regions ();
4046 selection->clear_playlists ();
4048 _regions->suspend_redisplay ();
4052 Editor::finish_cleanup ()
4054 _regions->resume_redisplay ();
4058 Editor::transport_loop_location()
4061 return _session->locations()->auto_loop_location();
4068 Editor::transport_punch_location()
4071 return _session->locations()->auto_punch_location();
4078 Editor::control_layout_scroll (GdkEventScroll* ev)
4080 /* Just forward to the normal canvas scroll method. The coordinate
4081 systems are different but since the canvas is always larger than the
4082 track headers, and aligned with the trackview area, this will work.
4084 In the not too distant future this layout is going away anyway and
4085 headers will be on the canvas.
4087 return canvas_scroll_event (ev, false);
4091 Editor::session_state_saved (string)
4094 _snapshots->redisplay ();
4098 Editor::update_tearoff_visibility()
4100 bool visible = Config->get_keep_tearoffs();
4101 _mouse_mode_tearoff->set_visible (visible);
4102 _tools_tearoff->set_visible (visible);
4103 if (_zoom_tearoff) {
4104 _zoom_tearoff->set_visible (visible);
4109 Editor::reattach_all_tearoffs ()
4111 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4112 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4113 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4117 Editor::maximise_editing_space ()
4129 Editor::restore_editing_space ()
4141 * Make new playlists for a given track and also any others that belong
4142 * to the same active route group with the `select' property.
4147 Editor::new_playlists (TimeAxisView* v)
4149 begin_reversible_command (_("new playlists"));
4150 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4151 _session->playlists->get (playlists);
4152 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4153 commit_reversible_command ();
4157 * Use a copy of the current playlist for a given track and also any others that belong
4158 * to the same active route group with the `select' property.
4163 Editor::copy_playlists (TimeAxisView* v)
4165 begin_reversible_command (_("copy playlists"));
4166 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4167 _session->playlists->get (playlists);
4168 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4169 commit_reversible_command ();
4172 /** Clear the current playlist for a given track and also any others that belong
4173 * to the same active route group with the `select' property.
4178 Editor::clear_playlists (TimeAxisView* v)
4180 begin_reversible_command (_("clear playlists"));
4181 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4182 _session->playlists->get (playlists);
4183 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4184 commit_reversible_command ();
4188 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4190 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4194 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4196 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4200 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4202 atv.clear_playlist ();
4206 Editor::on_key_press_event (GdkEventKey* ev)
4208 return key_press_focus_accelerator_handler (*this, ev);
4212 Editor::on_key_release_event (GdkEventKey* ev)
4214 return Gtk::Window::on_key_release_event (ev);
4215 // return key_press_focus_accelerator_handler (*this, ev);
4218 /** Queue up a change to the viewport x origin.
4219 * @param frame New x origin.
4222 Editor::reset_x_origin (framepos_t frame)
4224 pending_visual_change.add (VisualChange::TimeOrigin);
4225 pending_visual_change.time_origin = frame;
4226 ensure_visual_change_idle_handler ();
4230 Editor::reset_y_origin (double y)
4232 pending_visual_change.add (VisualChange::YOrigin);
4233 pending_visual_change.y_origin = y;
4234 ensure_visual_change_idle_handler ();
4238 Editor::reset_zoom (framecnt_t spp)
4240 if (spp == samples_per_pixel) {
4244 pending_visual_change.add (VisualChange::ZoomLevel);
4245 pending_visual_change.samples_per_pixel = spp;
4246 ensure_visual_change_idle_handler ();
4250 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4252 reset_x_origin (frame);
4255 if (!no_save_visual) {
4256 undo_visual_stack.push_back (current_visual_state(false));
4260 Editor::VisualState::VisualState (bool with_tracks)
4261 : gui_state (with_tracks ? new GUIObjectState : 0)
4265 Editor::VisualState::~VisualState ()
4270 Editor::VisualState*
4271 Editor::current_visual_state (bool with_tracks)
4273 VisualState* vs = new VisualState (with_tracks);
4274 vs->y_position = vertical_adjustment.get_value();
4275 vs->samples_per_pixel = samples_per_pixel;
4276 vs->leftmost_frame = leftmost_frame;
4277 vs->zoom_focus = zoom_focus;
4280 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4287 Editor::undo_visual_state ()
4289 if (undo_visual_stack.empty()) {
4293 VisualState* vs = undo_visual_stack.back();
4294 undo_visual_stack.pop_back();
4297 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4300 use_visual_state (*vs);
4305 Editor::redo_visual_state ()
4307 if (redo_visual_stack.empty()) {
4311 VisualState* vs = redo_visual_stack.back();
4312 redo_visual_stack.pop_back();
4314 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4315 // why do we check here?
4316 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4319 use_visual_state (*vs);
4324 Editor::swap_visual_state ()
4326 if (undo_visual_stack.empty()) {
4327 redo_visual_state ();
4329 undo_visual_state ();
4334 Editor::use_visual_state (VisualState& vs)
4336 PBD::Unwinder<bool> nsv (no_save_visual, true);
4337 DisplaySuspender ds;
4339 vertical_adjustment.set_value (vs.y_position);
4341 set_zoom_focus (vs.zoom_focus);
4342 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4345 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4347 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4348 (*i)->reset_visual_state ();
4352 _routes->update_visibility ();
4355 /** This is the core function that controls the zoom level of the canvas. It is called
4356 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4357 * @param spp new number of samples per pixel
4360 Editor::set_samples_per_pixel (framecnt_t spp)
4366 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4367 const framecnt_t lots_of_pixels = 4000;
4369 /* if the zoom level is greater than what you'd get trying to display 3
4370 * days of audio on a really big screen, then it's too big.
4373 if (spp * lots_of_pixels > three_days) {
4377 samples_per_pixel = spp;
4380 tempo_lines->tempo_map_changed();
4383 bool const showing_time_selection = selection->time.length() > 0;
4385 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4386 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4387 (*i)->reshow_selection (selection->time);
4391 ZoomChanged (); /* EMIT_SIGNAL */
4393 ArdourCanvas::GtkCanvasViewport* c;
4395 c = get_track_canvas();
4397 c->canvas()->zoomed ();
4400 if (playhead_cursor) {
4401 playhead_cursor->set_position (playhead_cursor->current_frame ());
4404 refresh_location_display();
4405 _summary->set_overlays_dirty ();
4407 update_marker_labels ();
4413 Editor::queue_visual_videotimeline_update ()
4416 * pending_visual_change.add (VisualChange::VideoTimeline);
4417 * or maybe even more specific: which videotimeline-image
4418 * currently it calls update_video_timeline() to update
4419 * _all outdated_ images on the video-timeline.
4420 * see 'exposeimg()' in video_image_frame.cc
4422 ensure_visual_change_idle_handler ();
4426 Editor::ensure_visual_change_idle_handler ()
4428 if (pending_visual_change.idle_handler_id < 0) {
4429 // see comment in add_to_idle_resize above.
4430 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4431 pending_visual_change.being_handled = false;
4436 Editor::_idle_visual_changer (void* arg)
4438 return static_cast<Editor*>(arg)->idle_visual_changer ();
4442 Editor::idle_visual_changer ()
4444 /* set_horizontal_position() below (and maybe other calls) call
4445 gtk_main_iteration(), so it's possible that a signal will be handled
4446 half-way through this method. If this signal wants an
4447 idle_visual_changer we must schedule another one after this one, so
4448 mark the idle_handler_id as -1 here to allow that. Also make a note
4449 that we are doing the visual change, so that changes in response to
4450 super-rapid-screen-update can be dropped if we are still processing
4454 pending_visual_change.idle_handler_id = -1;
4455 pending_visual_change.being_handled = true;
4457 VisualChange vc = pending_visual_change;
4459 pending_visual_change.pending = (VisualChange::Type) 0;
4461 visual_changer (vc);
4463 pending_visual_change.being_handled = false;
4465 return 0; /* this is always a one-shot call */
4469 Editor::visual_changer (const VisualChange& vc)
4471 double const last_time_origin = horizontal_position ();
4473 if (vc.pending & VisualChange::ZoomLevel) {
4474 set_samples_per_pixel (vc.samples_per_pixel);
4476 compute_fixed_ruler_scale ();
4478 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4479 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4481 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4482 current_bbt_points_begin, current_bbt_points_end);
4483 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4484 current_bbt_points_begin, current_bbt_points_end);
4485 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4487 update_video_timeline();
4490 if (vc.pending & VisualChange::TimeOrigin) {
4491 set_horizontal_position (vc.time_origin / samples_per_pixel);
4494 if (vc.pending & VisualChange::YOrigin) {
4495 vertical_adjustment.set_value (vc.y_origin);
4498 if (last_time_origin == horizontal_position ()) {
4499 /* changed signal not emitted */
4500 update_fixed_rulers ();
4501 redisplay_tempo (true);
4504 if (!(vc.pending & VisualChange::ZoomLevel)) {
4505 update_video_timeline();
4508 _summary->set_overlays_dirty ();
4511 struct EditorOrderTimeAxisSorter {
4512 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4513 return a->order () < b->order ();
4518 Editor::sort_track_selection (TrackViewList& sel)
4520 EditorOrderTimeAxisSorter cmp;
4525 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4528 framepos_t where = 0;
4529 EditPoint ep = _edit_point;
4531 if(Profile->get_mixbus())
4532 if (ep == EditAtSelectedMarker)
4535 if (from_context_menu && (ep == EditAtMouse)) {
4536 return canvas_event_sample (&context_click_event, 0, 0);
4539 if (entered_marker) {
4540 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4541 return entered_marker->position();
4544 if (ignore_playhead && ep == EditAtPlayhead) {
4545 ep = EditAtSelectedMarker;
4549 case EditAtPlayhead:
4550 where = _session->audible_frame();
4551 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4554 case EditAtSelectedMarker:
4555 if (!selection->markers.empty()) {
4557 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4560 where = loc->start();
4564 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4572 if (!mouse_frame (where, ignored)) {
4573 /* XXX not right but what can we do ? */
4577 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4585 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4587 if (!_session) return;
4589 begin_reversible_command (cmd);
4593 if ((tll = transport_loop_location()) == 0) {
4594 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4595 XMLNode &before = _session->locations()->get_state();
4596 _session->locations()->add (loc, true);
4597 _session->set_auto_loop_location (loc);
4598 XMLNode &after = _session->locations()->get_state();
4599 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4601 XMLNode &before = tll->get_state();
4602 tll->set_hidden (false, this);
4603 tll->set (start, end);
4604 XMLNode &after = tll->get_state();
4605 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4608 commit_reversible_command ();
4612 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4614 if (!_session) return;
4616 begin_reversible_command (cmd);
4620 if ((tpl = transport_punch_location()) == 0) {
4621 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4622 XMLNode &before = _session->locations()->get_state();
4623 _session->locations()->add (loc, true);
4624 _session->set_auto_punch_location (loc);
4625 XMLNode &after = _session->locations()->get_state();
4626 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4629 XMLNode &before = tpl->get_state();
4630 tpl->set_hidden (false, this);
4631 tpl->set (start, end);
4632 XMLNode &after = tpl->get_state();
4633 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4636 commit_reversible_command ();
4639 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4640 * @param rs List to which found regions are added.
4641 * @param where Time to look at.
4642 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4645 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4647 const TrackViewList* tracks;
4650 tracks = &track_views;
4655 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4657 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4660 boost::shared_ptr<Track> tr;
4661 boost::shared_ptr<Playlist> pl;
4663 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4665 boost::shared_ptr<RegionList> regions = pl->regions_at (
4666 (framepos_t) floor ( (double) where * tr->speed()));
4668 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4669 RegionView* rv = rtv->view()->find_view (*i);
4680 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4682 const TrackViewList* tracks;
4685 tracks = &track_views;
4690 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4691 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4693 boost::shared_ptr<Track> tr;
4694 boost::shared_ptr<Playlist> pl;
4696 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4698 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4699 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4701 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4703 RegionView* rv = rtv->view()->find_view (*i);
4714 /** Get regions using the following method:
4716 * Make a region list using:
4717 * (a) any selected regions
4718 * (b) the intersection of any selected tracks and the edit point(*)
4719 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4721 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4723 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4727 Editor::get_regions_from_selection_and_edit_point ()
4729 RegionSelection regions;
4731 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4732 regions.add (entered_regionview);
4734 regions = selection->regions;
4737 if ( regions.empty() ) {
4738 TrackViewList tracks = selection->tracks;
4740 if (!tracks.empty()) {
4741 /* no region selected or entered, but some selected tracks:
4742 * act on all regions on the selected tracks at the edit point
4744 framepos_t const where = get_preferred_edit_position ();
4745 get_regions_at(regions, where, tracks);
4752 /** Get regions using the following method:
4754 * Make a region list using:
4755 * (a) any selected regions
4756 * (b) the intersection of any selected tracks and the edit point(*)
4757 * (c) if neither exists, then whatever region is under the mouse
4759 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4761 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4764 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4766 RegionSelection regions;
4768 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4769 regions.add (entered_regionview);
4771 regions = selection->regions;
4774 if ( regions.empty() ) {
4775 TrackViewList tracks = selection->tracks;
4777 if (!tracks.empty()) {
4778 /* no region selected or entered, but some selected tracks:
4779 * act on all regions on the selected tracks at the edit point
4781 get_regions_at(regions, pos, tracks);
4788 /** Start with regions that are selected, or the entered regionview if none are selected.
4789 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4790 * of the regions that we started with.
4794 Editor::get_regions_from_selection_and_entered ()
4796 RegionSelection regions = selection->regions;
4798 if (regions.empty() && entered_regionview) {
4799 regions.add (entered_regionview);
4806 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4808 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4810 RouteTimeAxisView* tatv;
4812 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4814 boost::shared_ptr<Playlist> pl;
4815 vector<boost::shared_ptr<Region> > results;
4817 boost::shared_ptr<Track> tr;
4819 if ((tr = tatv->track()) == 0) {
4824 if ((pl = (tr->playlist())) != 0) {
4825 if (src_comparison) {
4826 pl->get_source_equivalent_regions (region, results);
4828 pl->get_region_list_equivalent_regions (region, results);
4832 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4833 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4834 regions.push_back (marv);
4843 Editor::show_rhythm_ferret ()
4845 if (rhythm_ferret == 0) {
4846 rhythm_ferret = new RhythmFerret(*this);
4849 rhythm_ferret->set_session (_session);
4850 rhythm_ferret->show ();
4851 rhythm_ferret->present ();
4855 Editor::first_idle ()
4857 MessageDialog* dialog = 0;
4859 if (track_views.size() > 1) {
4860 dialog = new MessageDialog (
4862 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4866 ARDOUR_UI::instance()->flush_pending ();
4869 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4873 // first idle adds route children (automation tracks), so we need to redisplay here
4874 _routes->redisplay ();
4881 Editor::_idle_resize (gpointer arg)
4883 return ((Editor*)arg)->idle_resize ();
4887 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4889 if (resize_idle_id < 0) {
4890 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
4891 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
4892 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
4894 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
4895 _pending_resize_amount = 0;
4898 /* make a note of the smallest resulting height, so that we can clamp the
4899 lower limit at TimeAxisView::hSmall */
4901 int32_t min_resulting = INT32_MAX;
4903 _pending_resize_amount += h;
4904 _pending_resize_view = view;
4906 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4908 if (selection->tracks.contains (_pending_resize_view)) {
4909 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4910 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4914 if (min_resulting < 0) {
4919 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4920 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4924 /** Handle pending resizing of tracks */
4926 Editor::idle_resize ()
4928 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4930 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4931 selection->tracks.contains (_pending_resize_view)) {
4933 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4934 if (*i != _pending_resize_view) {
4935 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4940 _pending_resize_amount = 0;
4941 _group_tabs->set_dirty ();
4942 resize_idle_id = -1;
4950 ENSURE_GUI_THREAD (*this, &Editor::located);
4953 playhead_cursor->set_position (_session->audible_frame ());
4954 if (_follow_playhead && !_pending_initial_locate) {
4955 reset_x_origin_to_follow_playhead ();
4959 _pending_locate_request = false;
4960 _pending_initial_locate = false;
4964 Editor::region_view_added (RegionView *)
4966 _summary->set_background_dirty ();
4970 Editor::region_view_removed ()
4972 _summary->set_background_dirty ();
4976 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4978 TrackViewList::const_iterator j = track_views.begin ();
4979 while (j != track_views.end()) {
4980 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4981 if (rtv && rtv->route() == r) {
4992 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4996 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4997 TimeAxisView* tv = axis_view_from_route (*i);
5007 Editor::suspend_route_redisplay ()
5010 _routes->suspend_redisplay();
5015 Editor::resume_route_redisplay ()
5018 _routes->resume_redisplay();
5023 Editor::add_routes (RouteList& routes)
5025 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5027 RouteTimeAxisView *rtv;
5028 list<RouteTimeAxisView*> new_views;
5030 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5031 boost::shared_ptr<Route> route = (*x);
5033 if (route->is_auditioner() || route->is_monitor()) {
5037 DataType dt = route->input()->default_type();
5039 if (dt == ARDOUR::DataType::AUDIO) {
5040 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5041 rtv->set_route (route);
5042 } else if (dt == ARDOUR::DataType::MIDI) {
5043 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5044 rtv->set_route (route);
5046 throw unknown_type();
5049 new_views.push_back (rtv);
5050 track_views.push_back (rtv);
5052 rtv->effective_gain_display ();
5054 if (internal_editing()) {
5055 rtv->enter_internal_edit_mode ();
5057 rtv->leave_internal_edit_mode ();
5060 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5061 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5064 if (new_views.size() > 0) {
5065 _routes->routes_added (new_views);
5066 _summary->routes_added (new_views);
5069 if (show_editor_mixer_when_tracks_arrive) {
5070 show_editor_mixer (true);
5073 editor_list_button.set_sensitive (true);
5077 Editor::timeaxisview_deleted (TimeAxisView *tv)
5079 if (tv == entered_track) {
5083 if (_session && _session->deletion_in_progress()) {
5084 /* the situation is under control */
5088 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5090 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5092 _routes->route_removed (tv);
5094 TimeAxisView::Children c = tv->get_child_list ();
5095 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5096 if (entered_track == i->get()) {
5101 /* remove it from the list of track views */
5103 TrackViewList::iterator i;
5105 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5106 i = track_views.erase (i);
5109 /* update whatever the current mixer strip is displaying, if revelant */
5111 boost::shared_ptr<Route> route;
5114 route = rtav->route ();
5117 if (current_mixer_strip && current_mixer_strip->route() == route) {
5119 TimeAxisView* next_tv;
5121 if (track_views.empty()) {
5123 } else if (i == track_views.end()) {
5124 next_tv = track_views.front();
5131 set_selected_mixer_strip (*next_tv);
5133 /* make the editor mixer strip go away setting the
5134 * button to inactive (which also unticks the menu option)
5137 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5143 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5145 if (apply_to_selection) {
5146 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5148 TrackSelection::iterator j = i;
5151 hide_track_in_display (*i, false);
5156 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5158 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5159 // this will hide the mixer strip
5160 set_selected_mixer_strip (*tv);
5163 _routes->hide_track_in_display (*tv);
5168 Editor::sync_track_view_list_and_routes ()
5170 track_views = TrackViewList (_routes->views ());
5172 _summary->set_dirty ();
5173 _group_tabs->set_dirty ();
5175 return false; // do not call again (until needed)
5179 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5181 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5186 /** Find a RouteTimeAxisView by the ID of its route */
5188 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5190 RouteTimeAxisView* v;
5192 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5193 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5194 if(v->route()->id() == id) {
5204 Editor::fit_route_group (RouteGroup *g)
5206 TrackViewList ts = axis_views_from_routes (g->route_list ());
5211 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5213 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5216 _session->cancel_audition ();
5220 if (_session->is_auditioning()) {
5221 _session->cancel_audition ();
5222 if (r == last_audition_region) {
5227 _session->audition_region (r);
5228 last_audition_region = r;
5233 Editor::hide_a_region (boost::shared_ptr<Region> r)
5235 r->set_hidden (true);
5239 Editor::show_a_region (boost::shared_ptr<Region> r)
5241 r->set_hidden (false);
5245 Editor::audition_region_from_region_list ()
5247 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5251 Editor::hide_region_from_region_list ()
5253 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5257 Editor::show_region_in_region_list ()
5259 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5263 Editor::step_edit_status_change (bool yn)
5266 start_step_editing ();
5268 stop_step_editing ();
5273 Editor::start_step_editing ()
5275 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5279 Editor::stop_step_editing ()
5281 step_edit_connection.disconnect ();
5285 Editor::check_step_edit ()
5287 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5288 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5290 mtv->check_step_edit ();
5294 return true; // do it again, till we stop
5298 Editor::scroll_press (Direction dir)
5300 ++_scroll_callbacks;
5302 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5303 /* delay the first auto-repeat */
5309 scroll_backward (1);
5317 scroll_up_one_track ();
5321 scroll_down_one_track ();
5325 /* do hacky auto-repeat */
5326 if (!_scroll_connection.connected ()) {
5328 _scroll_connection = Glib::signal_timeout().connect (
5329 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5332 _scroll_callbacks = 0;
5339 Editor::scroll_release ()
5341 _scroll_connection.disconnect ();
5344 /** Queue a change for the Editor viewport x origin to follow the playhead */
5346 Editor::reset_x_origin_to_follow_playhead ()
5348 framepos_t const frame = playhead_cursor->current_frame ();
5350 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5352 if (_session->transport_speed() < 0) {
5354 if (frame > (current_page_samples() / 2)) {
5355 center_screen (frame-(current_page_samples()/2));
5357 center_screen (current_page_samples()/2);
5364 if (frame < leftmost_frame) {
5366 if (_session->transport_rolling()) {
5367 /* rolling; end up with the playhead at the right of the page */
5368 l = frame - current_page_samples ();
5370 /* not rolling: end up with the playhead 1/4 of the way along the page */
5371 l = frame - current_page_samples() / 4;
5375 if (_session->transport_rolling()) {
5376 /* rolling: end up with the playhead on the left of the page */
5379 /* not rolling: end up with the playhead 3/4 of the way along the page */
5380 l = frame - 3 * current_page_samples() / 4;
5388 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5394 Editor::super_rapid_screen_update ()
5396 if (!_session || !_session->engine().running()) {
5400 /* METERING / MIXER STRIPS */
5402 /* update track meters, if required */
5403 if (is_mapped() && meters_running) {
5404 RouteTimeAxisView* rtv;
5405 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5406 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5407 rtv->fast_update ();
5412 /* and any current mixer strip */
5413 if (current_mixer_strip) {
5414 current_mixer_strip->fast_update ();
5417 /* PLAYHEAD AND VIEWPORT */
5419 framepos_t const frame = _session->audible_frame();
5421 /* There are a few reasons why we might not update the playhead / viewport stuff:
5423 * 1. we don't update things when there's a pending locate request, otherwise
5424 * when the editor requests a locate there is a chance that this method
5425 * will move the playhead before the locate request is processed, causing
5427 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5428 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5431 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5433 last_update_frame = frame;
5435 if (!_dragging_playhead) {
5436 playhead_cursor->set_position (frame);
5439 if (!_stationary_playhead) {
5441 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5442 /* We only do this if we aren't already
5443 handling a visual change (ie if
5444 pending_visual_change.being_handled is
5445 false) so that these requests don't stack
5446 up there are too many of them to handle in
5449 reset_x_origin_to_follow_playhead ();
5454 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5458 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5459 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5460 if (target <= 0.0) {
5463 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5464 target = (target * 0.15) + (current * 0.85);
5470 set_horizontal_position (current);
5479 Editor::session_going_away ()
5481 _have_idled = false;
5483 _session_connections.drop_connections ();
5485 super_rapid_screen_update_connection.disconnect ();
5487 selection->clear ();
5488 cut_buffer->clear ();
5490 clicked_regionview = 0;
5491 clicked_axisview = 0;
5492 clicked_routeview = 0;
5493 entered_regionview = 0;
5495 last_update_frame = 0;
5498 playhead_cursor->hide ();
5500 /* rip everything out of the list displays */
5504 _route_groups->clear ();
5506 /* do this first so that deleting a track doesn't reset cms to null
5507 and thus cause a leak.
5510 if (current_mixer_strip) {
5511 if (current_mixer_strip->get_parent() != 0) {
5512 global_hpacker.remove (*current_mixer_strip);
5514 delete current_mixer_strip;
5515 current_mixer_strip = 0;
5518 /* delete all trackviews */
5520 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5523 track_views.clear ();
5525 nudge_clock->set_session (0);
5527 editor_list_button.set_active(false);
5528 editor_list_button.set_sensitive(false);
5530 /* clear tempo/meter rulers */
5531 remove_metric_marks ();
5533 clear_marker_display ();
5535 stop_step_editing ();
5537 /* get rid of any existing editor mixer strip */
5539 WindowTitle title(Glib::get_application_name());
5540 title += _("Editor");
5542 set_title (title.get_string());
5544 SessionHandlePtr::session_going_away ();
5549 Editor::show_editor_list (bool yn)
5552 _the_notebook.show ();
5554 _the_notebook.hide ();
5559 Editor::change_region_layering_order (bool from_context_menu)
5561 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5563 if (!clicked_routeview) {
5564 if (layering_order_editor) {
5565 layering_order_editor->hide ();
5570 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5576 boost::shared_ptr<Playlist> pl = track->playlist();
5582 if (layering_order_editor == 0) {
5583 layering_order_editor = new RegionLayeringOrderEditor (*this);
5586 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5587 layering_order_editor->maybe_present ();
5591 Editor::update_region_layering_order_editor ()
5593 if (layering_order_editor && layering_order_editor->is_visible ()) {
5594 change_region_layering_order (true);
5599 Editor::setup_fade_images ()
5601 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5602 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5603 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5604 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5605 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5607 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5608 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5609 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5610 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5611 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5613 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5614 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5615 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5616 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5617 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5619 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5620 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5621 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5622 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5623 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5627 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5629 Editor::action_menu_item (std::string const & name)
5631 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5634 return *manage (a->create_menu_item ());
5638 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5640 EventBox* b = manage (new EventBox);
5641 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5642 Label* l = manage (new Label (name));
5646 _the_notebook.append_page (widget, *b);
5650 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5652 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5653 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5656 if (ev->type == GDK_2BUTTON_PRESS) {
5658 /* double-click on a notebook tab shrinks or expands the notebook */
5660 if (_notebook_shrunk) {
5661 if (pre_notebook_shrink_pane_width) {
5662 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5664 _notebook_shrunk = false;
5666 pre_notebook_shrink_pane_width = edit_pane.get_position();
5668 /* this expands the LHS of the edit pane to cover the notebook
5669 PAGE but leaves the tabs visible.
5671 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5672 _notebook_shrunk = true;
5680 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5682 using namespace Menu_Helpers;
5684 MenuList& items = _control_point_context_menu.items ();
5687 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5688 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5689 if (!can_remove_control_point (item)) {
5690 items.back().set_sensitive (false);
5693 _control_point_context_menu.popup (event->button.button, event->button.time);
5697 Editor::zoom_vertical_modifier_released()
5699 _stepping_axis_view = 0;
5703 Editor::ui_parameter_changed (string parameter)
5705 if (parameter == "icon-set") {
5706 while (!_cursor_stack.empty()) {
5707 _cursor_stack.pop();
5709 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5710 } else if (parameter == "draggable-playhead") {
5711 if (_verbose_cursor) {
5712 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());