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_gain_button);
2856 mouse_mode_size_group->add_widget (mouse_timefx_button);
2857 mouse_mode_size_group->add_widget (mouse_audition_button);
2858 mouse_mode_size_group->add_widget (mouse_draw_button);
2859 mouse_mode_size_group->add_widget (internal_edit_button);
2861 mouse_mode_size_group->add_widget (zoom_in_button);
2862 mouse_mode_size_group->add_widget (zoom_out_button);
2863 mouse_mode_size_group->add_widget (zoom_preset_selector);
2864 mouse_mode_size_group->add_widget (zoom_out_full_button);
2865 mouse_mode_size_group->add_widget (zoom_focus_selector);
2867 mouse_mode_size_group->add_widget (tav_shrink_button);
2868 mouse_mode_size_group->add_widget (tav_expand_button);
2869 mouse_mode_size_group->add_widget (visible_tracks_selector);
2871 mouse_mode_size_group->add_widget (snap_type_selector);
2872 mouse_mode_size_group->add_widget (snap_mode_selector);
2874 mouse_mode_size_group->add_widget (edit_point_selector);
2875 mouse_mode_size_group->add_widget (edit_mode_selector);
2877 mouse_mode_size_group->add_widget (*nudge_clock);
2878 mouse_mode_size_group->add_widget (nudge_forward_button);
2879 mouse_mode_size_group->add_widget (nudge_backward_button);
2881 mouse_mode_hbox->set_spacing (2);
2883 if (!ARDOUR::Profile->get_trx()) {
2884 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2887 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2888 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2890 if (!ARDOUR::Profile->get_mixbus()) {
2891 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2894 if (!ARDOUR::Profile->get_trx()) {
2895 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2896 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2897 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2898 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2899 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 0);
2902 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2904 mouse_mode_align->add (*mouse_mode_vbox);
2905 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2907 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2909 edit_mode_selector.set_name ("mouse mode button");
2911 if (!ARDOUR::Profile->get_trx()) {
2912 mode_box->pack_start (edit_mode_selector, false, false);
2914 mode_box->pack_start (*mouse_mode_box, false, false);
2916 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2917 _mouse_mode_tearoff->set_name ("MouseModeBase");
2918 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2920 if (Profile->get_sae() || Profile->get_mixbus() ) {
2921 _mouse_mode_tearoff->set_can_be_torn_off (false);
2924 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2925 &_mouse_mode_tearoff->tearoff_window()));
2926 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2927 &_mouse_mode_tearoff->tearoff_window(), 1));
2928 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2929 &_mouse_mode_tearoff->tearoff_window()));
2930 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2931 &_mouse_mode_tearoff->tearoff_window(), 1));
2935 _zoom_box.set_spacing (2);
2936 _zoom_box.set_border_width (2);
2940 zoom_preset_selector.set_name ("zoom button");
2941 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2942 zoom_preset_selector.set_size_request (42, -1);
2944 zoom_in_button.set_name ("zoom button");
2945 zoom_in_button.set_image(::get_icon ("zoom_in"));
2946 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2947 zoom_in_button.set_related_action (act);
2949 zoom_out_button.set_name ("zoom button");
2950 zoom_out_button.set_image(::get_icon ("zoom_out"));
2951 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2952 zoom_out_button.set_related_action (act);
2954 zoom_out_full_button.set_name ("zoom button");
2955 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2956 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2957 zoom_out_full_button.set_related_action (act);
2959 zoom_focus_selector.set_name ("zoom button");
2961 if (ARDOUR::Profile->get_mixbus()) {
2962 _zoom_box.pack_start (zoom_preset_selector, false, false);
2963 } else if (ARDOUR::Profile->get_trx()) {
2964 mode_box->pack_start (zoom_out_button, false, false);
2965 mode_box->pack_start (zoom_in_button, false, false);
2967 _zoom_box.pack_start (zoom_out_button, false, false);
2968 _zoom_box.pack_start (zoom_in_button, false, false);
2969 _zoom_box.pack_start (zoom_out_full_button, false, false);
2970 _zoom_box.pack_start (zoom_focus_selector, false, false);
2973 /* Track zoom buttons */
2974 visible_tracks_selector.set_name ("zoom button");
2975 if (Profile->get_mixbus()) {
2976 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2977 visible_tracks_selector.set_size_request (42, -1);
2979 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2982 tav_expand_button.set_name ("zoom button");
2983 tav_expand_button.set_image(::get_icon ("tav_exp"));
2984 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2985 tav_expand_button.set_related_action (act);
2987 tav_shrink_button.set_name ("zoom button");
2988 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2989 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2990 tav_shrink_button.set_related_action (act);
2992 if (ARDOUR::Profile->get_mixbus()) {
2993 _zoom_box.pack_start (visible_tracks_selector);
2994 } else if (ARDOUR::Profile->get_trx()) {
2995 _zoom_box.pack_start (tav_shrink_button);
2996 _zoom_box.pack_start (tav_expand_button);
2998 _zoom_box.pack_start (visible_tracks_selector);
2999 _zoom_box.pack_start (tav_shrink_button);
3000 _zoom_box.pack_start (tav_expand_button);
3003 if (!ARDOUR::Profile->get_trx()) {
3004 _zoom_tearoff = manage (new TearOff (_zoom_box));
3006 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3007 &_zoom_tearoff->tearoff_window()));
3008 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3009 &_zoom_tearoff->tearoff_window(), 0));
3010 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3011 &_zoom_tearoff->tearoff_window()));
3012 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3013 &_zoom_tearoff->tearoff_window(), 0));
3016 if (Profile->get_sae() || Profile->get_mixbus() ) {
3017 _zoom_tearoff->set_can_be_torn_off (false);
3020 snap_box.set_spacing (2);
3021 snap_box.set_border_width (2);
3023 snap_type_selector.set_name ("mouse mode button");
3025 snap_mode_selector.set_name ("mouse mode button");
3027 edit_point_selector.set_name ("mouse mode button");
3029 snap_box.pack_start (snap_mode_selector, false, false);
3030 snap_box.pack_start (snap_type_selector, false, false);
3031 snap_box.pack_start (edit_point_selector, false, false);
3035 HBox *nudge_box = manage (new HBox);
3036 nudge_box->set_spacing (2);
3037 nudge_box->set_border_width (2);
3039 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3040 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3042 nudge_box->pack_start (nudge_backward_button, false, false);
3043 nudge_box->pack_start (nudge_forward_button, false, false);
3044 nudge_box->pack_start (*nudge_clock, false, false);
3047 /* Pack everything in... */
3049 HBox* hbox = manage (new HBox);
3050 hbox->set_spacing(2);
3052 _tools_tearoff = manage (new TearOff (*hbox));
3053 _tools_tearoff->set_name ("MouseModeBase");
3054 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3056 if (Profile->get_sae() || Profile->get_mixbus()) {
3057 _tools_tearoff->set_can_be_torn_off (false);
3060 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3061 &_tools_tearoff->tearoff_window()));
3062 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3063 &_tools_tearoff->tearoff_window(), 0));
3064 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3065 &_tools_tearoff->tearoff_window()));
3066 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3067 &_tools_tearoff->tearoff_window(), 0));
3069 toolbar_hbox.set_spacing (2);
3070 toolbar_hbox.set_border_width (1);
3072 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3073 if (!ARDOUR::Profile->get_trx()) {
3074 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3075 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3078 if (!ARDOUR::Profile->get_trx()) {
3079 hbox->pack_start (snap_box, false, false);
3080 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3081 hbox->pack_start (*nudge_box, false, false);
3083 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3086 hbox->pack_start (panic_box, false, false);
3090 toolbar_base.set_name ("ToolBarBase");
3091 toolbar_base.add (toolbar_hbox);
3093 _toolbar_viewport.add (toolbar_base);
3094 /* stick to the required height but allow width to vary if there's not enough room */
3095 _toolbar_viewport.set_size_request (1, -1);
3097 toolbar_frame.set_shadow_type (SHADOW_OUT);
3098 toolbar_frame.set_name ("BaseFrame");
3099 toolbar_frame.add (_toolbar_viewport);
3103 Editor::build_edit_point_menu ()
3105 using namespace Menu_Helpers;
3107 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3108 if(!Profile->get_mixbus())
3109 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3110 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3112 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3116 Editor::build_edit_mode_menu ()
3118 using namespace Menu_Helpers;
3120 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3121 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3122 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3123 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3125 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3129 Editor::build_snap_mode_menu ()
3131 using namespace Menu_Helpers;
3133 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3134 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3135 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3137 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3141 Editor::build_snap_type_menu ()
3143 using namespace Menu_Helpers;
3145 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3146 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3147 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3148 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3149 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3150 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3151 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3152 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3153 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3154 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3155 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3156 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3157 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3158 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3159 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3160 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3161 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3162 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3163 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3164 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3165 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3166 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3167 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3168 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3169 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3170 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3171 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3172 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3173 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3174 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3176 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3181 Editor::setup_tooltips ()
3183 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3184 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3185 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3186 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3187 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3188 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3189 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3190 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3191 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3192 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3193 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3194 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3195 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3196 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3197 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3198 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3199 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3200 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3201 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3202 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3203 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3204 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3205 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3206 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3207 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3211 Editor::convert_drop_to_paths (
3212 vector<string>& paths,
3213 const RefPtr<Gdk::DragContext>& /*context*/,
3216 const SelectionData& data,
3220 if (_session == 0) {
3224 vector<string> uris = data.get_uris();
3228 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3229 are actually URI lists. So do it by hand.
3232 if (data.get_target() != "text/plain") {
3236 /* Parse the "uri-list" format that Nautilus provides,
3237 where each pathname is delimited by \r\n.
3239 THERE MAY BE NO NULL TERMINATING CHAR!!!
3242 string txt = data.get_text();
3246 p = (char *) malloc (txt.length() + 1);
3247 txt.copy (p, txt.length(), 0);
3248 p[txt.length()] = '\0';
3254 while (g_ascii_isspace (*p))
3258 while (*q && (*q != '\n') && (*q != '\r')) {
3265 while (q > p && g_ascii_isspace (*q))
3270 uris.push_back (string (p, q - p + 1));
3274 p = strchr (p, '\n');
3286 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3287 if ((*i).substr (0,7) == "file://") {
3288 paths.push_back (Glib::filename_from_uri (*i));
3296 Editor::new_tempo_section ()
3301 Editor::map_transport_state ()
3303 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3305 if (_session && _session->transport_stopped()) {
3306 have_pending_keyboard_selection = false;
3309 update_loop_range_view ();
3315 Editor::begin_reversible_command (string name)
3318 _session->begin_reversible_command (name);
3323 Editor::begin_reversible_command (GQuark q)
3326 _session->begin_reversible_command (q);
3331 Editor::commit_reversible_command ()
3334 _session->commit_reversible_command ();
3339 Editor::history_changed ()
3343 if (undo_action && _session) {
3344 if (_session->undo_depth() == 0) {
3345 label = S_("Command|Undo");
3347 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3349 undo_action->property_label() = label;
3352 if (redo_action && _session) {
3353 if (_session->redo_depth() == 0) {
3356 label = string_compose(_("Redo (%1)"), _session->next_redo());
3358 redo_action->property_label() = label;
3363 Editor::duplicate_range (bool with_dialog)
3367 RegionSelection rs = get_regions_from_selection_and_entered ();
3369 if ( selection->time.length() == 0 && rs.empty()) {
3375 ArdourDialog win (_("Duplicate"));
3376 Label label (_("Number of duplications:"));
3377 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3378 SpinButton spinner (adjustment, 0.0, 1);
3381 win.get_vbox()->set_spacing (12);
3382 win.get_vbox()->pack_start (hbox);
3383 hbox.set_border_width (6);
3384 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3386 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3387 place, visually. so do this by hand.
3390 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3391 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3392 spinner.grab_focus();
3398 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3399 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3400 win.set_default_response (RESPONSE_ACCEPT);
3402 spinner.grab_focus ();
3404 switch (win.run ()) {
3405 case RESPONSE_ACCEPT:
3411 times = adjustment.get_value();
3414 if ((current_mouse_mode() == Editing::MouseRange)) {
3415 if (selection->time.length()) {
3416 duplicate_selection (times);
3418 } else if (get_smart_mode()) {
3419 if (selection->time.length()) {
3420 duplicate_selection (times);
3422 duplicate_some_regions (rs, times);
3424 duplicate_some_regions (rs, times);
3429 Editor::set_edit_mode (EditMode m)
3431 Config->set_edit_mode (m);
3435 Editor::cycle_edit_mode ()
3437 switch (Config->get_edit_mode()) {
3439 if (Profile->get_sae()) {
3440 Config->set_edit_mode (Lock);
3442 Config->set_edit_mode (Ripple);
3447 Config->set_edit_mode (Lock);
3450 Config->set_edit_mode (Slide);
3456 Editor::edit_mode_selection_done ( EditMode m )
3458 Config->set_edit_mode ( m );
3462 Editor::snap_type_selection_done (SnapType snaptype)
3464 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3466 ract->set_active ();
3471 Editor::snap_mode_selection_done (SnapMode mode)
3473 RefPtr<RadioAction> ract = snap_mode_action (mode);
3476 ract->set_active (true);
3481 Editor::cycle_edit_point (bool with_marker)
3483 if(Profile->get_mixbus())
3484 with_marker = false;
3486 switch (_edit_point) {
3488 set_edit_point_preference (EditAtPlayhead);
3490 case EditAtPlayhead:
3492 set_edit_point_preference (EditAtSelectedMarker);
3494 set_edit_point_preference (EditAtMouse);
3497 case EditAtSelectedMarker:
3498 set_edit_point_preference (EditAtMouse);
3504 Editor::edit_point_selection_done (EditPoint ep)
3506 set_edit_point_preference ( ep );
3510 Editor::build_zoom_focus_menu ()
3512 using namespace Menu_Helpers;
3514 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3515 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3516 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3517 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3518 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3519 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3521 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3525 Editor::zoom_focus_selection_done ( ZoomFocus f )
3527 RefPtr<RadioAction> ract = zoom_focus_action (f);
3529 ract->set_active ();
3534 Editor::build_track_count_menu ()
3536 using namespace Menu_Helpers;
3538 if (!Profile->get_mixbus()) {
3539 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3540 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3541 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3542 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3543 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3544 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3545 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3546 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3547 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3548 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3549 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3550 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3551 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3553 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3554 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3555 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3556 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3557 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3558 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3559 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3560 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3561 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3562 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3564 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3565 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3566 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3567 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3568 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3569 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3570 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3571 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3572 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3573 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3574 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3579 Editor::set_zoom_preset (int64_t ms)
3582 temporal_zoom_session();
3586 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3587 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3591 Editor::set_visible_track_count (int32_t n)
3593 _visible_track_count = n;
3595 /* if the canvas hasn't really been allocated any size yet, just
3596 record the desired number of visible tracks and return. when canvas
3597 allocation happens, we will get called again and then we can do the
3601 if (_visible_canvas_height <= 1) {
3608 if (_visible_track_count > 0) {
3609 h = trackviews_height() / _visible_track_count;
3610 std::ostringstream s;
3611 s << _visible_track_count;
3613 } else if (_visible_track_count == 0) {
3615 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3616 if ((*i)->marked_for_display()) {
3620 h = trackviews_height() / n;
3623 /* negative value means that the visible track count has
3624 been overridden by explicit track height changes.
3626 visible_tracks_selector.set_text (X_("*"));
3630 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3631 (*i)->set_height (h);
3634 if (str != visible_tracks_selector.get_text()) {
3635 visible_tracks_selector.set_text (str);
3640 Editor::override_visible_track_count ()
3642 _visible_track_count = -1;
3643 visible_tracks_selector.set_text ( _("*") );
3647 Editor::edit_controls_button_release (GdkEventButton* ev)
3649 if (Keyboard::is_context_menu_event (ev)) {
3650 ARDOUR_UI::instance()->add_route (this);
3651 } else if (ev->button == 1) {
3652 selection->clear_tracks ();
3659 Editor::mouse_select_button_release (GdkEventButton* ev)
3661 /* this handles just right-clicks */
3663 if (ev->button != 3) {
3671 Editor::set_zoom_focus (ZoomFocus f)
3673 string str = zoom_focus_strings[(int)f];
3675 if (str != zoom_focus_selector.get_text()) {
3676 zoom_focus_selector.set_text (str);
3679 if (zoom_focus != f) {
3686 Editor::cycle_zoom_focus ()
3688 switch (zoom_focus) {
3690 set_zoom_focus (ZoomFocusRight);
3692 case ZoomFocusRight:
3693 set_zoom_focus (ZoomFocusCenter);
3695 case ZoomFocusCenter:
3696 set_zoom_focus (ZoomFocusPlayhead);
3698 case ZoomFocusPlayhead:
3699 set_zoom_focus (ZoomFocusMouse);
3701 case ZoomFocusMouse:
3702 set_zoom_focus (ZoomFocusEdit);
3705 set_zoom_focus (ZoomFocusLeft);
3711 Editor::ensure_float (Window& win)
3713 win.set_transient_for (*this);
3717 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3719 /* recover or initialize pane positions. do this here rather than earlier because
3720 we don't want the positions to change the child allocations, which they seem to do.
3726 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3735 XMLNode* geometry = find_named_node (*node, "geometry");
3737 if (which == static_cast<Paned*> (&edit_pane)) {
3739 if (done & Horizontal) {
3743 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3744 _notebook_shrunk = string_is_affirmative (prop->value ());
3747 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3748 /* initial allocation is 90% to canvas, 10% to notebook */
3749 pos = (int) floor (alloc.get_width() * 0.90f);
3750 snprintf (buf, sizeof(buf), "%d", pos);
3752 pos = atoi (prop->value());
3755 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3756 edit_pane.set_position (pos);
3759 done = (Pane) (done | Horizontal);
3761 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3763 if (done & Vertical) {
3767 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3768 /* initial allocation is 90% to canvas, 10% to summary */
3769 pos = (int) floor (alloc.get_height() * 0.90f);
3770 snprintf (buf, sizeof(buf), "%d", pos);
3773 pos = atoi (prop->value());
3776 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3777 editor_summary_pane.set_position (pos);
3780 done = (Pane) (done | Vertical);
3785 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3787 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3788 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3789 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3790 top_hbox.remove (toolbar_frame);
3795 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3797 if (toolbar_frame.get_parent() == 0) {
3798 top_hbox.pack_end (toolbar_frame);
3803 Editor::set_show_measures (bool yn)
3805 if (_show_measures != yn) {
3808 if ((_show_measures = yn) == true) {
3810 tempo_lines->show();
3813 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3814 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3816 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3817 draw_measures (begin, end);
3825 Editor::toggle_follow_playhead ()
3827 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3829 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3830 set_follow_playhead (tact->get_active());
3834 /** @param yn true to follow playhead, otherwise false.
3835 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3838 Editor::set_follow_playhead (bool yn, bool catch_up)
3840 if (_follow_playhead != yn) {
3841 if ((_follow_playhead = yn) == true && catch_up) {
3843 reset_x_origin_to_follow_playhead ();
3850 Editor::toggle_stationary_playhead ()
3852 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3854 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3855 set_stationary_playhead (tact->get_active());
3860 Editor::set_stationary_playhead (bool yn)
3862 if (_stationary_playhead != yn) {
3863 if ((_stationary_playhead = yn) == true) {
3865 // FIXME need a 3.0 equivalent of this 2.X call
3866 // update_current_screen ();
3873 Editor::playlist_selector () const
3875 return *_playlist_selector;
3879 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3881 if (paste_count == 0) {
3882 /* don't bother calculating an offset that will be zero anyway */
3886 /* calculate basic unsnapped multi-paste offset */
3887 framecnt_t offset = paste_count * duration;
3889 /* snap offset so pos + offset is aligned to the grid */
3890 framepos_t offset_pos = pos + offset;
3891 snap_to(offset_pos, RoundUpMaybe);
3892 offset = offset_pos - pos;
3898 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3902 switch (_snap_type) {
3904 return Evoral::MusicalTime(1.0);
3907 case SnapToBeatDiv128:
3908 return Evoral::MusicalTime(1.0/128.0);
3910 case SnapToBeatDiv64:
3911 return Evoral::MusicalTime(1.0/64.0);
3913 case SnapToBeatDiv32:
3914 return Evoral::MusicalTime(1.0/32.0);
3916 case SnapToBeatDiv28:
3917 return Evoral::MusicalTime(1.0/28.0);
3919 case SnapToBeatDiv24:
3920 return Evoral::MusicalTime(1.0/24.0);
3922 case SnapToBeatDiv20:
3923 return Evoral::MusicalTime(1.0/20.0);
3925 case SnapToBeatDiv16:
3926 return Evoral::MusicalTime(1.0/16.0);
3928 case SnapToBeatDiv14:
3929 return Evoral::MusicalTime(1.0/14.0);
3931 case SnapToBeatDiv12:
3932 return Evoral::MusicalTime(1.0/12.0);
3934 case SnapToBeatDiv10:
3935 return Evoral::MusicalTime(1.0/10.0);
3937 case SnapToBeatDiv8:
3938 return Evoral::MusicalTime(1.0/8.0);
3940 case SnapToBeatDiv7:
3941 return Evoral::MusicalTime(1.0/7.0);
3943 case SnapToBeatDiv6:
3944 return Evoral::MusicalTime(1.0/6.0);
3946 case SnapToBeatDiv5:
3947 return Evoral::MusicalTime(1.0/5.0);
3949 case SnapToBeatDiv4:
3950 return Evoral::MusicalTime(1.0/4.0);
3952 case SnapToBeatDiv3:
3953 return Evoral::MusicalTime(1.0/3.0);
3955 case SnapToBeatDiv2:
3956 return Evoral::MusicalTime(1.0/2.0);
3961 return Evoral::MusicalTime(_session->tempo_map().meter_at (position).divisions_per_bar());
3966 case SnapToTimecodeFrame:
3967 case SnapToTimecodeSeconds:
3968 case SnapToTimecodeMinutes:
3971 case SnapToRegionStart:
3972 case SnapToRegionEnd:
3973 case SnapToRegionSync:
3974 case SnapToRegionBoundary:
3980 return Evoral::MusicalTime();
3984 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3988 ret = nudge_clock->current_duration (pos);
3989 next = ret + 1; /* XXXX fix me */
3995 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3997 ArdourDialog dialog (_("Playlist Deletion"));
3998 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3999 "If it is kept, its audio files will not be cleaned.\n"
4000 "If it is deleted, audio files used by it alone will be cleaned."),
4003 dialog.set_position (WIN_POS_CENTER);
4004 dialog.get_vbox()->pack_start (label);
4008 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4009 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4010 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4012 switch (dialog.run ()) {
4013 case RESPONSE_ACCEPT:
4014 /* delete the playlist */
4018 case RESPONSE_REJECT:
4019 /* keep the playlist */
4031 Editor::audio_region_selection_covers (framepos_t where)
4033 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4034 if ((*a)->region()->covers (where)) {
4043 Editor::prepare_for_cleanup ()
4045 cut_buffer->clear_regions ();
4046 cut_buffer->clear_playlists ();
4048 selection->clear_regions ();
4049 selection->clear_playlists ();
4051 _regions->suspend_redisplay ();
4055 Editor::finish_cleanup ()
4057 _regions->resume_redisplay ();
4061 Editor::transport_loop_location()
4064 return _session->locations()->auto_loop_location();
4071 Editor::transport_punch_location()
4074 return _session->locations()->auto_punch_location();
4081 Editor::control_layout_scroll (GdkEventScroll* ev)
4083 /* Just forward to the normal canvas scroll method. The coordinate
4084 systems are different but since the canvas is always larger than the
4085 track headers, and aligned with the trackview area, this will work.
4087 In the not too distant future this layout is going away anyway and
4088 headers will be on the canvas.
4090 return canvas_scroll_event (ev, false);
4094 Editor::session_state_saved (string)
4097 _snapshots->redisplay ();
4101 Editor::update_tearoff_visibility()
4103 bool visible = Config->get_keep_tearoffs();
4104 _mouse_mode_tearoff->set_visible (visible);
4105 _tools_tearoff->set_visible (visible);
4106 if (_zoom_tearoff) {
4107 _zoom_tearoff->set_visible (visible);
4112 Editor::reattach_all_tearoffs ()
4114 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4115 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4116 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4120 Editor::maximise_editing_space ()
4132 Editor::restore_editing_space ()
4144 * Make new playlists for a given track and also any others that belong
4145 * to the same active route group with the `select' property.
4150 Editor::new_playlists (TimeAxisView* v)
4152 begin_reversible_command (_("new playlists"));
4153 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4154 _session->playlists->get (playlists);
4155 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4156 commit_reversible_command ();
4160 * Use a copy of the current playlist for a given track and also any others that belong
4161 * to the same active route group with the `select' property.
4166 Editor::copy_playlists (TimeAxisView* v)
4168 begin_reversible_command (_("copy playlists"));
4169 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4170 _session->playlists->get (playlists);
4171 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4172 commit_reversible_command ();
4175 /** Clear the current playlist for a given track and also any others that belong
4176 * to the same active route group with the `select' property.
4181 Editor::clear_playlists (TimeAxisView* v)
4183 begin_reversible_command (_("clear playlists"));
4184 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4185 _session->playlists->get (playlists);
4186 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4187 commit_reversible_command ();
4191 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4193 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4197 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4199 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4203 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4205 atv.clear_playlist ();
4209 Editor::on_key_press_event (GdkEventKey* ev)
4211 return key_press_focus_accelerator_handler (*this, ev);
4215 Editor::on_key_release_event (GdkEventKey* ev)
4217 return Gtk::Window::on_key_release_event (ev);
4218 // return key_press_focus_accelerator_handler (*this, ev);
4221 /** Queue up a change to the viewport x origin.
4222 * @param frame New x origin.
4225 Editor::reset_x_origin (framepos_t frame)
4227 pending_visual_change.add (VisualChange::TimeOrigin);
4228 pending_visual_change.time_origin = frame;
4229 ensure_visual_change_idle_handler ();
4233 Editor::reset_y_origin (double y)
4235 pending_visual_change.add (VisualChange::YOrigin);
4236 pending_visual_change.y_origin = y;
4237 ensure_visual_change_idle_handler ();
4241 Editor::reset_zoom (framecnt_t spp)
4243 if (spp == samples_per_pixel) {
4247 pending_visual_change.add (VisualChange::ZoomLevel);
4248 pending_visual_change.samples_per_pixel = spp;
4249 ensure_visual_change_idle_handler ();
4253 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4255 reset_x_origin (frame);
4258 if (!no_save_visual) {
4259 undo_visual_stack.push_back (current_visual_state(false));
4263 Editor::VisualState::VisualState (bool with_tracks)
4264 : gui_state (with_tracks ? new GUIObjectState : 0)
4268 Editor::VisualState::~VisualState ()
4273 Editor::VisualState*
4274 Editor::current_visual_state (bool with_tracks)
4276 VisualState* vs = new VisualState (with_tracks);
4277 vs->y_position = vertical_adjustment.get_value();
4278 vs->samples_per_pixel = samples_per_pixel;
4279 vs->leftmost_frame = leftmost_frame;
4280 vs->zoom_focus = zoom_focus;
4283 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4290 Editor::undo_visual_state ()
4292 if (undo_visual_stack.empty()) {
4296 VisualState* vs = undo_visual_stack.back();
4297 undo_visual_stack.pop_back();
4300 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4303 use_visual_state (*vs);
4308 Editor::redo_visual_state ()
4310 if (redo_visual_stack.empty()) {
4314 VisualState* vs = redo_visual_stack.back();
4315 redo_visual_stack.pop_back();
4317 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4318 // why do we check here?
4319 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4322 use_visual_state (*vs);
4327 Editor::swap_visual_state ()
4329 if (undo_visual_stack.empty()) {
4330 redo_visual_state ();
4332 undo_visual_state ();
4337 Editor::use_visual_state (VisualState& vs)
4339 PBD::Unwinder<bool> nsv (no_save_visual, true);
4340 DisplaySuspender ds;
4342 vertical_adjustment.set_value (vs.y_position);
4344 set_zoom_focus (vs.zoom_focus);
4345 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4348 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4350 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4351 (*i)->reset_visual_state ();
4355 _routes->update_visibility ();
4358 /** This is the core function that controls the zoom level of the canvas. It is called
4359 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4360 * @param spp new number of samples per pixel
4363 Editor::set_samples_per_pixel (framecnt_t spp)
4369 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4370 const framecnt_t lots_of_pixels = 4000;
4372 /* if the zoom level is greater than what you'd get trying to display 3
4373 * days of audio on a really big screen, then it's too big.
4376 if (spp * lots_of_pixels > three_days) {
4380 samples_per_pixel = spp;
4383 tempo_lines->tempo_map_changed();
4386 bool const showing_time_selection = selection->time.length() > 0;
4388 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4389 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4390 (*i)->reshow_selection (selection->time);
4394 ZoomChanged (); /* EMIT_SIGNAL */
4396 ArdourCanvas::GtkCanvasViewport* c;
4398 c = get_track_canvas();
4400 c->canvas()->zoomed ();
4403 if (playhead_cursor) {
4404 playhead_cursor->set_position (playhead_cursor->current_frame ());
4407 refresh_location_display();
4408 _summary->set_overlays_dirty ();
4410 update_marker_labels ();
4416 Editor::queue_visual_videotimeline_update ()
4419 * pending_visual_change.add (VisualChange::VideoTimeline);
4420 * or maybe even more specific: which videotimeline-image
4421 * currently it calls update_video_timeline() to update
4422 * _all outdated_ images on the video-timeline.
4423 * see 'exposeimg()' in video_image_frame.cc
4425 ensure_visual_change_idle_handler ();
4429 Editor::ensure_visual_change_idle_handler ()
4431 if (pending_visual_change.idle_handler_id < 0) {
4432 // see comment in add_to_idle_resize above.
4433 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4434 pending_visual_change.being_handled = false;
4439 Editor::_idle_visual_changer (void* arg)
4441 return static_cast<Editor*>(arg)->idle_visual_changer ();
4445 Editor::idle_visual_changer ()
4447 /* set_horizontal_position() below (and maybe other calls) call
4448 gtk_main_iteration(), so it's possible that a signal will be handled
4449 half-way through this method. If this signal wants an
4450 idle_visual_changer we must schedule another one after this one, so
4451 mark the idle_handler_id as -1 here to allow that. Also make a note
4452 that we are doing the visual change, so that changes in response to
4453 super-rapid-screen-update can be dropped if we are still processing
4457 pending_visual_change.idle_handler_id = -1;
4458 pending_visual_change.being_handled = true;
4460 VisualChange vc = pending_visual_change;
4462 pending_visual_change.pending = (VisualChange::Type) 0;
4464 visual_changer (vc);
4466 pending_visual_change.being_handled = false;
4468 return 0; /* this is always a one-shot call */
4472 Editor::visual_changer (const VisualChange& vc)
4474 double const last_time_origin = horizontal_position ();
4476 if (vc.pending & VisualChange::ZoomLevel) {
4477 set_samples_per_pixel (vc.samples_per_pixel);
4479 compute_fixed_ruler_scale ();
4481 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4482 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4484 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4485 current_bbt_points_begin, current_bbt_points_end);
4486 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4487 current_bbt_points_begin, current_bbt_points_end);
4488 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4490 update_video_timeline();
4493 if (vc.pending & VisualChange::TimeOrigin) {
4494 set_horizontal_position (vc.time_origin / samples_per_pixel);
4497 if (vc.pending & VisualChange::YOrigin) {
4498 vertical_adjustment.set_value (vc.y_origin);
4501 if (last_time_origin == horizontal_position ()) {
4502 /* changed signal not emitted */
4503 update_fixed_rulers ();
4504 redisplay_tempo (true);
4507 if (!(vc.pending & VisualChange::ZoomLevel)) {
4508 update_video_timeline();
4511 _summary->set_overlays_dirty ();
4514 struct EditorOrderTimeAxisSorter {
4515 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4516 return a->order () < b->order ();
4521 Editor::sort_track_selection (TrackViewList& sel)
4523 EditorOrderTimeAxisSorter cmp;
4528 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4531 framepos_t where = 0;
4532 EditPoint ep = _edit_point;
4534 if(Profile->get_mixbus())
4535 if (ep == EditAtSelectedMarker)
4538 if (from_context_menu && (ep == EditAtMouse)) {
4539 return canvas_event_sample (&context_click_event, 0, 0);
4542 if (entered_marker) {
4543 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4544 return entered_marker->position();
4547 if (ignore_playhead && ep == EditAtPlayhead) {
4548 ep = EditAtSelectedMarker;
4552 case EditAtPlayhead:
4553 where = _session->audible_frame();
4554 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4557 case EditAtSelectedMarker:
4558 if (!selection->markers.empty()) {
4560 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4563 where = loc->start();
4567 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4575 if (!mouse_frame (where, ignored)) {
4576 /* XXX not right but what can we do ? */
4580 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4588 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4590 if (!_session) return;
4592 begin_reversible_command (cmd);
4596 if ((tll = transport_loop_location()) == 0) {
4597 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4598 XMLNode &before = _session->locations()->get_state();
4599 _session->locations()->add (loc, true);
4600 _session->set_auto_loop_location (loc);
4601 XMLNode &after = _session->locations()->get_state();
4602 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4604 XMLNode &before = tll->get_state();
4605 tll->set_hidden (false, this);
4606 tll->set (start, end);
4607 XMLNode &after = tll->get_state();
4608 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4611 commit_reversible_command ();
4615 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4617 if (!_session) return;
4619 begin_reversible_command (cmd);
4623 if ((tpl = transport_punch_location()) == 0) {
4624 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4625 XMLNode &before = _session->locations()->get_state();
4626 _session->locations()->add (loc, true);
4627 _session->set_auto_punch_location (loc);
4628 XMLNode &after = _session->locations()->get_state();
4629 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4632 XMLNode &before = tpl->get_state();
4633 tpl->set_hidden (false, this);
4634 tpl->set (start, end);
4635 XMLNode &after = tpl->get_state();
4636 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4639 commit_reversible_command ();
4642 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4643 * @param rs List to which found regions are added.
4644 * @param where Time to look at.
4645 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4648 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4650 const TrackViewList* tracks;
4653 tracks = &track_views;
4658 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4660 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4663 boost::shared_ptr<Track> tr;
4664 boost::shared_ptr<Playlist> pl;
4666 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4668 boost::shared_ptr<RegionList> regions = pl->regions_at (
4669 (framepos_t) floor ( (double) where * tr->speed()));
4671 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4672 RegionView* rv = rtv->view()->find_view (*i);
4683 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4685 const TrackViewList* tracks;
4688 tracks = &track_views;
4693 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4694 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4696 boost::shared_ptr<Track> tr;
4697 boost::shared_ptr<Playlist> pl;
4699 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4701 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4702 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4704 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4706 RegionView* rv = rtv->view()->find_view (*i);
4717 /** Get regions using the following method:
4719 * Make a region list using:
4720 * (a) any selected regions
4721 * (b) the intersection of any selected tracks and the edit point(*)
4722 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4724 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4726 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4730 Editor::get_regions_from_selection_and_edit_point ()
4732 RegionSelection regions;
4734 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4735 regions.add (entered_regionview);
4737 regions = selection->regions;
4740 if ( regions.empty() ) {
4741 TrackViewList tracks = selection->tracks;
4743 if (!tracks.empty()) {
4744 /* no region selected or entered, but some selected tracks:
4745 * act on all regions on the selected tracks at the edit point
4747 framepos_t const where = get_preferred_edit_position ();
4748 get_regions_at(regions, where, tracks);
4755 /** Get regions using the following method:
4757 * Make a region list using:
4758 * (a) any selected regions
4759 * (b) the intersection of any selected tracks and the edit point(*)
4760 * (c) if neither exists, then whatever region is under the mouse
4762 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4764 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4767 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4769 RegionSelection regions;
4771 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4772 regions.add (entered_regionview);
4774 regions = selection->regions;
4777 if ( regions.empty() ) {
4778 TrackViewList tracks = selection->tracks;
4780 if (!tracks.empty()) {
4781 /* no region selected or entered, but some selected tracks:
4782 * act on all regions on the selected tracks at the edit point
4784 get_regions_at(regions, pos, tracks);
4791 /** Start with regions that are selected, or the entered regionview if none are selected.
4792 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4793 * of the regions that we started with.
4797 Editor::get_regions_from_selection_and_entered ()
4799 RegionSelection regions = selection->regions;
4801 if (regions.empty() && entered_regionview) {
4802 regions.add (entered_regionview);
4809 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4811 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4813 RouteTimeAxisView* tatv;
4815 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4817 boost::shared_ptr<Playlist> pl;
4818 vector<boost::shared_ptr<Region> > results;
4820 boost::shared_ptr<Track> tr;
4822 if ((tr = tatv->track()) == 0) {
4827 if ((pl = (tr->playlist())) != 0) {
4828 if (src_comparison) {
4829 pl->get_source_equivalent_regions (region, results);
4831 pl->get_region_list_equivalent_regions (region, results);
4835 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4836 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4837 regions.push_back (marv);
4846 Editor::show_rhythm_ferret ()
4848 if (rhythm_ferret == 0) {
4849 rhythm_ferret = new RhythmFerret(*this);
4852 rhythm_ferret->set_session (_session);
4853 rhythm_ferret->show ();
4854 rhythm_ferret->present ();
4858 Editor::first_idle ()
4860 MessageDialog* dialog = 0;
4862 if (track_views.size() > 1) {
4863 dialog = new MessageDialog (
4865 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4869 ARDOUR_UI::instance()->flush_pending ();
4872 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4876 // first idle adds route children (automation tracks), so we need to redisplay here
4877 _routes->redisplay ();
4884 Editor::_idle_resize (gpointer arg)
4886 return ((Editor*)arg)->idle_resize ();
4890 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4892 if (resize_idle_id < 0) {
4893 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
4894 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
4895 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
4897 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
4898 _pending_resize_amount = 0;
4901 /* make a note of the smallest resulting height, so that we can clamp the
4902 lower limit at TimeAxisView::hSmall */
4904 int32_t min_resulting = INT32_MAX;
4906 _pending_resize_amount += h;
4907 _pending_resize_view = view;
4909 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4911 if (selection->tracks.contains (_pending_resize_view)) {
4912 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4913 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4917 if (min_resulting < 0) {
4922 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4923 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4927 /** Handle pending resizing of tracks */
4929 Editor::idle_resize ()
4931 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4933 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4934 selection->tracks.contains (_pending_resize_view)) {
4936 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4937 if (*i != _pending_resize_view) {
4938 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4943 _pending_resize_amount = 0;
4944 _group_tabs->set_dirty ();
4945 resize_idle_id = -1;
4953 ENSURE_GUI_THREAD (*this, &Editor::located);
4956 playhead_cursor->set_position (_session->audible_frame ());
4957 if (_follow_playhead && !_pending_initial_locate) {
4958 reset_x_origin_to_follow_playhead ();
4962 _pending_locate_request = false;
4963 _pending_initial_locate = false;
4967 Editor::region_view_added (RegionView *)
4969 _summary->set_background_dirty ();
4973 Editor::region_view_removed ()
4975 _summary->set_background_dirty ();
4979 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4981 TrackViewList::const_iterator j = track_views.begin ();
4982 while (j != track_views.end()) {
4983 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4984 if (rtv && rtv->route() == r) {
4995 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4999 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5000 TimeAxisView* tv = axis_view_from_route (*i);
5010 Editor::suspend_route_redisplay ()
5013 _routes->suspend_redisplay();
5018 Editor::resume_route_redisplay ()
5021 _routes->resume_redisplay();
5026 Editor::add_routes (RouteList& routes)
5028 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5030 RouteTimeAxisView *rtv;
5031 list<RouteTimeAxisView*> new_views;
5033 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5034 boost::shared_ptr<Route> route = (*x);
5036 if (route->is_auditioner() || route->is_monitor()) {
5040 DataType dt = route->input()->default_type();
5042 if (dt == ARDOUR::DataType::AUDIO) {
5043 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5044 rtv->set_route (route);
5045 } else if (dt == ARDOUR::DataType::MIDI) {
5046 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5047 rtv->set_route (route);
5049 throw unknown_type();
5052 new_views.push_back (rtv);
5053 track_views.push_back (rtv);
5055 rtv->effective_gain_display ();
5057 if (internal_editing()) {
5058 rtv->enter_internal_edit_mode ();
5060 rtv->leave_internal_edit_mode ();
5063 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5064 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5067 if (new_views.size() > 0) {
5068 _routes->routes_added (new_views);
5069 _summary->routes_added (new_views);
5072 if (show_editor_mixer_when_tracks_arrive) {
5073 show_editor_mixer (true);
5076 editor_list_button.set_sensitive (true);
5080 Editor::timeaxisview_deleted (TimeAxisView *tv)
5082 if (tv == entered_track) {
5086 if (_session && _session->deletion_in_progress()) {
5087 /* the situation is under control */
5091 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5093 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5095 _routes->route_removed (tv);
5097 TimeAxisView::Children c = tv->get_child_list ();
5098 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5099 if (entered_track == i->get()) {
5104 /* remove it from the list of track views */
5106 TrackViewList::iterator i;
5108 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5109 i = track_views.erase (i);
5112 /* update whatever the current mixer strip is displaying, if revelant */
5114 boost::shared_ptr<Route> route;
5117 route = rtav->route ();
5120 if (current_mixer_strip && current_mixer_strip->route() == route) {
5122 TimeAxisView* next_tv;
5124 if (track_views.empty()) {
5126 } else if (i == track_views.end()) {
5127 next_tv = track_views.front();
5134 set_selected_mixer_strip (*next_tv);
5136 /* make the editor mixer strip go away setting the
5137 * button to inactive (which also unticks the menu option)
5140 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5146 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5148 if (apply_to_selection) {
5149 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5151 TrackSelection::iterator j = i;
5154 hide_track_in_display (*i, false);
5159 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5161 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5162 // this will hide the mixer strip
5163 set_selected_mixer_strip (*tv);
5166 _routes->hide_track_in_display (*tv);
5171 Editor::sync_track_view_list_and_routes ()
5173 track_views = TrackViewList (_routes->views ());
5175 _summary->set_dirty ();
5176 _group_tabs->set_dirty ();
5178 return false; // do not call again (until needed)
5182 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5184 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5189 /** Find a RouteTimeAxisView by the ID of its route */
5191 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5193 RouteTimeAxisView* v;
5195 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5196 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5197 if(v->route()->id() == id) {
5207 Editor::fit_route_group (RouteGroup *g)
5209 TrackViewList ts = axis_views_from_routes (g->route_list ());
5214 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5216 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5219 _session->cancel_audition ();
5223 if (_session->is_auditioning()) {
5224 _session->cancel_audition ();
5225 if (r == last_audition_region) {
5230 _session->audition_region (r);
5231 last_audition_region = r;
5236 Editor::hide_a_region (boost::shared_ptr<Region> r)
5238 r->set_hidden (true);
5242 Editor::show_a_region (boost::shared_ptr<Region> r)
5244 r->set_hidden (false);
5248 Editor::audition_region_from_region_list ()
5250 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5254 Editor::hide_region_from_region_list ()
5256 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5260 Editor::show_region_in_region_list ()
5262 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5266 Editor::step_edit_status_change (bool yn)
5269 start_step_editing ();
5271 stop_step_editing ();
5276 Editor::start_step_editing ()
5278 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5282 Editor::stop_step_editing ()
5284 step_edit_connection.disconnect ();
5288 Editor::check_step_edit ()
5290 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5291 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5293 mtv->check_step_edit ();
5297 return true; // do it again, till we stop
5301 Editor::scroll_press (Direction dir)
5303 ++_scroll_callbacks;
5305 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5306 /* delay the first auto-repeat */
5312 scroll_backward (1);
5320 scroll_up_one_track ();
5324 scroll_down_one_track ();
5328 /* do hacky auto-repeat */
5329 if (!_scroll_connection.connected ()) {
5331 _scroll_connection = Glib::signal_timeout().connect (
5332 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5335 _scroll_callbacks = 0;
5342 Editor::scroll_release ()
5344 _scroll_connection.disconnect ();
5347 /** Queue a change for the Editor viewport x origin to follow the playhead */
5349 Editor::reset_x_origin_to_follow_playhead ()
5351 framepos_t const frame = playhead_cursor->current_frame ();
5353 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5355 if (_session->transport_speed() < 0) {
5357 if (frame > (current_page_samples() / 2)) {
5358 center_screen (frame-(current_page_samples()/2));
5360 center_screen (current_page_samples()/2);
5367 if (frame < leftmost_frame) {
5369 if (_session->transport_rolling()) {
5370 /* rolling; end up with the playhead at the right of the page */
5371 l = frame - current_page_samples ();
5373 /* not rolling: end up with the playhead 1/4 of the way along the page */
5374 l = frame - current_page_samples() / 4;
5378 if (_session->transport_rolling()) {
5379 /* rolling: end up with the playhead on the left of the page */
5382 /* not rolling: end up with the playhead 3/4 of the way along the page */
5383 l = frame - 3 * current_page_samples() / 4;
5391 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5397 Editor::super_rapid_screen_update ()
5399 if (!_session || !_session->engine().running()) {
5403 /* METERING / MIXER STRIPS */
5405 /* update track meters, if required */
5406 if (is_mapped() && meters_running) {
5407 RouteTimeAxisView* rtv;
5408 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5409 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5410 rtv->fast_update ();
5415 /* and any current mixer strip */
5416 if (current_mixer_strip) {
5417 current_mixer_strip->fast_update ();
5420 /* PLAYHEAD AND VIEWPORT */
5422 framepos_t const frame = _session->audible_frame();
5424 /* There are a few reasons why we might not update the playhead / viewport stuff:
5426 * 1. we don't update things when there's a pending locate request, otherwise
5427 * when the editor requests a locate there is a chance that this method
5428 * will move the playhead before the locate request is processed, causing
5430 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5431 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5434 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5436 last_update_frame = frame;
5438 if (!_dragging_playhead) {
5439 playhead_cursor->set_position (frame);
5442 if (!_stationary_playhead) {
5444 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5445 /* We only do this if we aren't already
5446 handling a visual change (ie if
5447 pending_visual_change.being_handled is
5448 false) so that these requests don't stack
5449 up there are too many of them to handle in
5452 reset_x_origin_to_follow_playhead ();
5457 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5461 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5462 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5463 if (target <= 0.0) {
5466 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5467 target = (target * 0.15) + (current * 0.85);
5473 set_horizontal_position (current);
5482 Editor::session_going_away ()
5484 _have_idled = false;
5486 _session_connections.drop_connections ();
5488 super_rapid_screen_update_connection.disconnect ();
5490 selection->clear ();
5491 cut_buffer->clear ();
5493 clicked_regionview = 0;
5494 clicked_axisview = 0;
5495 clicked_routeview = 0;
5496 entered_regionview = 0;
5498 last_update_frame = 0;
5501 playhead_cursor->hide ();
5503 /* rip everything out of the list displays */
5507 _route_groups->clear ();
5509 /* do this first so that deleting a track doesn't reset cms to null
5510 and thus cause a leak.
5513 if (current_mixer_strip) {
5514 if (current_mixer_strip->get_parent() != 0) {
5515 global_hpacker.remove (*current_mixer_strip);
5517 delete current_mixer_strip;
5518 current_mixer_strip = 0;
5521 /* delete all trackviews */
5523 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5526 track_views.clear ();
5528 nudge_clock->set_session (0);
5530 editor_list_button.set_active(false);
5531 editor_list_button.set_sensitive(false);
5533 /* clear tempo/meter rulers */
5534 remove_metric_marks ();
5536 clear_marker_display ();
5538 stop_step_editing ();
5540 /* get rid of any existing editor mixer strip */
5542 WindowTitle title(Glib::get_application_name());
5543 title += _("Editor");
5545 set_title (title.get_string());
5547 SessionHandlePtr::session_going_away ();
5552 Editor::show_editor_list (bool yn)
5555 _the_notebook.show ();
5557 _the_notebook.hide ();
5562 Editor::change_region_layering_order (bool from_context_menu)
5564 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5566 if (!clicked_routeview) {
5567 if (layering_order_editor) {
5568 layering_order_editor->hide ();
5573 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5579 boost::shared_ptr<Playlist> pl = track->playlist();
5585 if (layering_order_editor == 0) {
5586 layering_order_editor = new RegionLayeringOrderEditor (*this);
5589 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5590 layering_order_editor->maybe_present ();
5594 Editor::update_region_layering_order_editor ()
5596 if (layering_order_editor && layering_order_editor->is_visible ()) {
5597 change_region_layering_order (true);
5602 Editor::setup_fade_images ()
5604 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5605 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5606 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5607 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5608 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5610 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5611 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5612 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5613 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5614 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5616 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5617 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5618 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5619 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5620 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5622 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5623 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5624 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5625 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5626 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5630 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5632 Editor::action_menu_item (std::string const & name)
5634 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5637 return *manage (a->create_menu_item ());
5641 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5643 EventBox* b = manage (new EventBox);
5644 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5645 Label* l = manage (new Label (name));
5649 _the_notebook.append_page (widget, *b);
5653 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5655 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5656 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5659 if (ev->type == GDK_2BUTTON_PRESS) {
5661 /* double-click on a notebook tab shrinks or expands the notebook */
5663 if (_notebook_shrunk) {
5664 if (pre_notebook_shrink_pane_width) {
5665 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5667 _notebook_shrunk = false;
5669 pre_notebook_shrink_pane_width = edit_pane.get_position();
5671 /* this expands the LHS of the edit pane to cover the notebook
5672 PAGE but leaves the tabs visible.
5674 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5675 _notebook_shrunk = true;
5683 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5685 using namespace Menu_Helpers;
5687 MenuList& items = _control_point_context_menu.items ();
5690 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5691 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5692 if (!can_remove_control_point (item)) {
5693 items.back().set_sensitive (false);
5696 _control_point_context_menu.popup (event->button.button, event->button.time);
5700 Editor::zoom_vertical_modifier_released()
5702 _stepping_axis_view = 0;
5706 Editor::ui_parameter_changed (string parameter)
5708 if (parameter == "icon-set") {
5709 while (!_cursor_stack.empty()) {
5710 _cursor_stack.pop();
5712 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5713 } else if (parameter == "draggable-playhead") {
5714 if (_verbose_cursor) {
5715 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());