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);
308 _selection_memento = new SelectionMemento ();
311 clicked_regionview = 0;
312 clicked_axisview = 0;
313 clicked_routeview = 0;
314 clicked_control_point = 0;
315 last_update_frame = 0;
316 pre_press_cursor = 0;
319 _drags = new DragManager (this);
322 current_mixer_strip = 0;
325 snap_type_strings = I18N (_snap_type_strings);
326 snap_mode_strings = I18N (_snap_mode_strings);
327 zoom_focus_strings = I18N (_zoom_focus_strings);
328 edit_mode_strings = I18N (_edit_mode_strings);
329 edit_point_strings = I18N (_edit_point_strings);
330 #ifdef USE_RUBBERBAND
331 rb_opt_strings = I18N (_rb_opt_strings);
335 build_edit_mode_menu();
336 build_zoom_focus_menu();
337 build_track_count_menu();
338 build_snap_mode_menu();
339 build_snap_type_menu();
340 build_edit_point_menu();
342 snap_threshold = 5.0;
343 bbt_beat_subdivision = 4;
344 _visible_canvas_width = 0;
345 _visible_canvas_height = 0;
346 autoscroll_horizontal_allowed = false;
347 autoscroll_vertical_allowed = false;
352 current_interthread_info = 0;
353 _show_measures = true;
355 show_gain_after_trim = false;
357 have_pending_keyboard_selection = false;
358 _follow_playhead = true;
359 _stationary_playhead = false;
360 editor_ruler_menu = 0;
361 no_ruler_shown_update = false;
363 range_marker_menu = 0;
364 marker_menu_item = 0;
365 tempo_or_meter_marker_menu = 0;
366 transport_marker_menu = 0;
367 new_transport_marker_menu = 0;
368 editor_mixer_strip_width = Wide;
369 show_editor_mixer_when_tracks_arrive = false;
370 region_edit_menu_split_multichannel_item = 0;
371 region_edit_menu_split_item = 0;
374 current_stepping_trackview = 0;
376 entered_regionview = 0;
378 clear_entered_track = false;
381 button_release_can_deselect = true;
382 _dragging_playhead = false;
383 _dragging_edit_point = false;
384 select_new_marker = false;
386 layering_order_editor = 0;
387 no_save_visual = false;
389 within_track_canvas = false;
391 scrubbing_direction = 0;
395 location_marker_color = ARDOUR_UI::config()->color ("location marker");
396 location_range_color = ARDOUR_UI::config()->color ("location range");
397 location_cd_marker_color = ARDOUR_UI::config()->color ("location cd marker");
398 location_loop_color = ARDOUR_UI::config()->color ("location loop");
399 location_punch_color = ARDOUR_UI::config()->color ("location punch");
401 zoom_focus = ZoomFocusLeft;
402 _edit_point = EditAtMouse;
403 current_canvas_cursor = 0;
404 _visible_track_count = -1;
406 samples_per_pixel = 2048; /* too early to use reset_zoom () */
408 _scroll_callbacks = 0;
410 bbt_label.set_name ("EditorRulerLabel");
411 bbt_label.set_size_request (-1, (int)timebar_height);
412 bbt_label.set_alignment (1.0, 0.5);
413 bbt_label.set_padding (5,0);
415 bbt_label.set_no_show_all();
416 minsec_label.set_name ("EditorRulerLabel");
417 minsec_label.set_size_request (-1, (int)timebar_height);
418 minsec_label.set_alignment (1.0, 0.5);
419 minsec_label.set_padding (5,0);
420 minsec_label.hide ();
421 minsec_label.set_no_show_all();
422 timecode_label.set_name ("EditorRulerLabel");
423 timecode_label.set_size_request (-1, (int)timebar_height);
424 timecode_label.set_alignment (1.0, 0.5);
425 timecode_label.set_padding (5,0);
426 timecode_label.hide ();
427 timecode_label.set_no_show_all();
428 samples_label.set_name ("EditorRulerLabel");
429 samples_label.set_size_request (-1, (int)timebar_height);
430 samples_label.set_alignment (1.0, 0.5);
431 samples_label.set_padding (5,0);
432 samples_label.hide ();
433 samples_label.set_no_show_all();
435 tempo_label.set_name ("EditorRulerLabel");
436 tempo_label.set_size_request (-1, (int)timebar_height);
437 tempo_label.set_alignment (1.0, 0.5);
438 tempo_label.set_padding (5,0);
440 tempo_label.set_no_show_all();
442 meter_label.set_name ("EditorRulerLabel");
443 meter_label.set_size_request (-1, (int)timebar_height);
444 meter_label.set_alignment (1.0, 0.5);
445 meter_label.set_padding (5,0);
447 meter_label.set_no_show_all();
449 if (Profile->get_trx()) {
450 mark_label.set_text (_("Markers"));
452 mark_label.set_name ("EditorRulerLabel");
453 mark_label.set_size_request (-1, (int)timebar_height);
454 mark_label.set_alignment (1.0, 0.5);
455 mark_label.set_padding (5,0);
457 mark_label.set_no_show_all();
459 cd_mark_label.set_name ("EditorRulerLabel");
460 cd_mark_label.set_size_request (-1, (int)timebar_height);
461 cd_mark_label.set_alignment (1.0, 0.5);
462 cd_mark_label.set_padding (5,0);
463 cd_mark_label.hide();
464 cd_mark_label.set_no_show_all();
466 videotl_bar_height = 4;
467 videotl_label.set_name ("EditorRulerLabel");
468 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
469 videotl_label.set_alignment (1.0, 0.5);
470 videotl_label.set_padding (5,0);
471 videotl_label.hide();
472 videotl_label.set_no_show_all();
474 range_mark_label.set_name ("EditorRulerLabel");
475 range_mark_label.set_size_request (-1, (int)timebar_height);
476 range_mark_label.set_alignment (1.0, 0.5);
477 range_mark_label.set_padding (5,0);
478 range_mark_label.hide();
479 range_mark_label.set_no_show_all();
481 transport_mark_label.set_name ("EditorRulerLabel");
482 transport_mark_label.set_size_request (-1, (int)timebar_height);
483 transport_mark_label.set_alignment (1.0, 0.5);
484 transport_mark_label.set_padding (5,0);
485 transport_mark_label.hide();
486 transport_mark_label.set_no_show_all();
488 initialize_canvas ();
490 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
492 _summary = new EditorSummary (this);
494 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
495 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
497 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
499 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
500 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
502 edit_controls_vbox.set_spacing (0);
503 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
504 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
506 HBox* h = manage (new HBox);
507 _group_tabs = new EditorGroupTabs (this);
508 if (!ARDOUR::Profile->get_trx()) {
509 h->pack_start (*_group_tabs, PACK_SHRINK);
511 h->pack_start (edit_controls_vbox);
512 controls_layout.add (*h);
514 controls_layout.set_name ("EditControlsBase");
515 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
516 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
517 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
519 _cursors = new MouseCursors;
520 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
521 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
523 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
525 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
526 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
527 pad_line_1->set_outline_color (0xFF0000FF);
533 edit_packer.set_col_spacings (0);
534 edit_packer.set_row_spacings (0);
535 edit_packer.set_homogeneous (false);
536 edit_packer.set_border_width (0);
537 edit_packer.set_name ("EditorWindow");
539 time_bars_event_box.add (time_bars_vbox);
540 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
541 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
543 /* labels for the time bars */
544 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
546 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
548 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
550 bottom_hbox.set_border_width (2);
551 bottom_hbox.set_spacing (3);
553 _route_groups = new EditorRouteGroups (this);
554 _routes = new EditorRoutes (this);
555 _regions = new EditorRegions (this);
556 _snapshots = new EditorSnapshots (this);
557 _locations = new EditorLocations (this);
559 /* these are static location signals */
561 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
562 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
563 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
565 add_notebook_page (_("Regions"), _regions->widget ());
566 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
567 add_notebook_page (_("Snapshots"), _snapshots->widget ());
568 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
569 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
571 _the_notebook.set_show_tabs (true);
572 _the_notebook.set_scrollable (true);
573 _the_notebook.popup_disable ();
574 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
575 _the_notebook.show_all ();
577 _notebook_shrunk = false;
579 editor_summary_pane.pack1(edit_packer);
581 Button* summary_arrows_left_left = manage (new Button);
582 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
583 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
584 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
586 Button* summary_arrows_left_right = manage (new Button);
587 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
588 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
589 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
591 VBox* summary_arrows_left = manage (new VBox);
592 summary_arrows_left->pack_start (*summary_arrows_left_left);
593 summary_arrows_left->pack_start (*summary_arrows_left_right);
595 Button* summary_arrows_right_up = manage (new Button);
596 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
597 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
598 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
600 Button* summary_arrows_right_down = manage (new Button);
601 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
602 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
603 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
605 VBox* summary_arrows_right = manage (new VBox);
606 summary_arrows_right->pack_start (*summary_arrows_right_up);
607 summary_arrows_right->pack_start (*summary_arrows_right_down);
609 Frame* summary_frame = manage (new Frame);
610 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
612 summary_frame->add (*_summary);
613 summary_frame->show ();
615 _summary_hbox.pack_start (*summary_arrows_left, false, false);
616 _summary_hbox.pack_start (*summary_frame, true, true);
617 _summary_hbox.pack_start (*summary_arrows_right, false, false);
619 if (!ARDOUR::Profile->get_trx()) {
620 editor_summary_pane.pack2 (_summary_hbox);
623 edit_pane.pack1 (editor_summary_pane, true, true);
624 if (!ARDOUR::Profile->get_trx()) {
625 edit_pane.pack2 (_the_notebook, false, true);
628 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
630 /* XXX: editor_summary_pane might need similar to the edit_pane */
632 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
634 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
635 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
637 top_hbox.pack_start (toolbar_frame);
639 HBox *hbox = manage (new HBox);
640 hbox->pack_start (edit_pane, true, true);
642 global_vpacker.pack_start (top_hbox, false, false);
643 global_vpacker.pack_start (*hbox, true, true);
645 global_hpacker.pack_start (global_vpacker, true, true);
647 set_name ("EditorWindow");
648 add_accel_group (ActionManager::ui_manager->get_accel_group());
650 status_bar_hpacker.show ();
652 vpacker.pack_end (status_bar_hpacker, false, false);
653 vpacker.pack_end (global_hpacker, true, true);
655 /* register actions now so that set_state() can find them and set toggles/checks etc */
658 /* when we start using our own keybinding system for the editor, this
659 * will be uncommented
665 set_zoom_focus (zoom_focus);
666 set_visible_track_count (_visible_track_count);
667 _snap_type = SnapToBeat;
668 set_snap_to (_snap_type);
669 _snap_mode = SnapOff;
670 set_snap_mode (_snap_mode);
671 previous_mouse_mode = MouseObject;
672 set_mouse_mode (MouseObject, true);
673 set_edit_point_preference (EditAtMouse, true);
675 _playlist_selector = new PlaylistSelector();
676 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
678 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
682 nudge_forward_button.set_name ("nudge button");
683 nudge_forward_button.set_image(::get_icon("nudge_right"));
685 nudge_backward_button.set_name ("nudge button");
686 nudge_backward_button.set_image(::get_icon("nudge_left"));
688 fade_context_menu.set_name ("ArdourContextMenu");
690 /* icons, titles, WM stuff */
692 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
693 Glib::RefPtr<Gdk::Pixbuf> icon;
695 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
696 window_icons.push_back (icon);
698 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
699 window_icons.push_back (icon);
701 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
702 window_icons.push_back (icon);
704 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
705 window_icons.push_back (icon);
707 if (!window_icons.empty()) {
708 // set_icon_list (window_icons);
709 set_default_icon_list (window_icons);
712 WindowTitle title(Glib::get_application_name());
713 title += _("Editor");
714 set_title (title.get_string());
715 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
718 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
720 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
721 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
723 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
725 /* allow external control surfaces/protocols to do various things */
727 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
728 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
729 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
730 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
731 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
732 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
733 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
734 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
735 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
736 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
737 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
738 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
739 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
740 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
742 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
743 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
744 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
745 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
746 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
748 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
750 /* problematic: has to return a value and thus cannot be x-thread */
752 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
754 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
755 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
757 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
759 _ignore_region_action = false;
760 _last_region_menu_was_main = false;
761 _popup_region_menu_item = 0;
763 _ignore_follow_edits = false;
765 _show_marker_lines = false;
767 /* Button bindings */
769 button_bindings = new Bindings;
771 XMLNode* node = button_settings();
773 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
774 button_bindings->load (**i);
780 /* grab current parameter state */
781 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
782 ARDOUR_UI::config()->map_parameters (pc);
784 setup_fade_images ();
791 delete button_bindings;
793 delete _route_groups;
794 delete _track_canvas_viewport;
800 Editor::button_settings () const
802 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
803 XMLNode* node = find_named_node (*settings, X_("Buttons"));
806 node = new XMLNode (X_("Buttons"));
813 Editor::add_toplevel_menu (Container& cont)
815 vpacker.pack_start (cont, false, false);
820 Editor::add_transport_frame (Container& cont)
822 if(ARDOUR::Profile->get_mixbus()) {
823 global_vpacker.pack_start (cont, false, false);
824 global_vpacker.reorder_child (cont, 0);
827 vpacker.pack_start (cont, false, false);
832 Editor::get_smart_mode () const
834 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
838 Editor::catch_vanishing_regionview (RegionView *rv)
840 /* note: the selection will take care of the vanishing
841 audioregionview by itself.
844 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
848 if (clicked_regionview == rv) {
849 clicked_regionview = 0;
852 if (entered_regionview == rv) {
853 set_entered_regionview (0);
856 if (!_all_region_actions_sensitized) {
857 sensitize_all_region_actions (true);
862 Editor::set_entered_regionview (RegionView* rv)
864 if (rv == entered_regionview) {
868 if (entered_regionview) {
869 entered_regionview->exited ();
872 entered_regionview = rv;
874 if (entered_regionview != 0) {
875 entered_regionview->entered ();
878 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
879 /* This RegionView entry might have changed what region actions
880 are allowed, so sensitize them all in case a key is pressed.
882 sensitize_all_region_actions (true);
887 Editor::set_entered_track (TimeAxisView* tav)
890 entered_track->exited ();
896 entered_track->entered ();
901 Editor::show_window ()
903 if (!is_visible ()) {
907 /* XXX: this is a bit unfortunate; it would probably
908 be nicer if we could just call show () above rather
909 than needing the show_all ()
912 /* re-hide stuff if necessary */
913 editor_list_button_toggled ();
914 parameter_changed ("show-summary");
915 parameter_changed ("show-group-tabs");
916 parameter_changed ("show-zoom-tools");
918 /* now reset all audio_time_axis heights, because widgets might need
924 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
925 tv = (static_cast<TimeAxisView*>(*i));
929 if (current_mixer_strip) {
930 current_mixer_strip->hide_things ();
931 current_mixer_strip->parameter_changed ("mixer-element-visibility");
939 Editor::instant_save ()
941 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
946 _session->add_instant_xml(get_state());
948 Config->add_instant_xml(get_state());
953 Editor::control_vertical_zoom_in_all ()
955 tav_zoom_smooth (false, true);
959 Editor::control_vertical_zoom_out_all ()
961 tav_zoom_smooth (true, true);
965 Editor::control_vertical_zoom_in_selected ()
967 tav_zoom_smooth (false, false);
971 Editor::control_vertical_zoom_out_selected ()
973 tav_zoom_smooth (true, false);
977 Editor::control_view (uint32_t view)
979 goto_visual_state (view);
983 Editor::control_unselect ()
985 selection->clear_tracks ();
989 Editor::control_select (uint32_t rid, Selection::Operation op)
991 /* handles the (static) signal from the ControlProtocol class that
992 * requests setting the selected track to a given RID
999 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1005 TimeAxisView* tav = axis_view_from_route (r);
1009 case Selection::Add:
1010 selection->add (tav);
1012 case Selection::Toggle:
1013 selection->toggle (tav);
1015 case Selection::Extend:
1017 case Selection::Set:
1018 selection->set (tav);
1022 selection->clear_tracks ();
1027 Editor::control_step_tracks_up ()
1029 scroll_tracks_up_line ();
1033 Editor::control_step_tracks_down ()
1035 scroll_tracks_down_line ();
1039 Editor::control_scroll (float fraction)
1041 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1047 double step = fraction * current_page_samples();
1050 _control_scroll_target is an optional<T>
1052 it acts like a pointer to an framepos_t, with
1053 a operator conversion to boolean to check
1054 that it has a value could possibly use
1055 playhead_cursor->current_frame to store the
1056 value and a boolean in the class to know
1057 when it's out of date
1060 if (!_control_scroll_target) {
1061 _control_scroll_target = _session->transport_frame();
1062 _dragging_playhead = true;
1065 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1066 *_control_scroll_target = 0;
1067 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1068 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1070 *_control_scroll_target += (framepos_t) trunc (step);
1073 /* move visuals, we'll catch up with it later */
1075 playhead_cursor->set_position (*_control_scroll_target);
1076 UpdateAllTransportClocks (*_control_scroll_target);
1078 if (*_control_scroll_target > (current_page_samples() / 2)) {
1079 /* try to center PH in window */
1080 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1086 Now we do a timeout to actually bring the session to the right place
1087 according to the playhead. This is to avoid reading disk buffers on every
1088 call to control_scroll, which is driven by ScrollTimeline and therefore
1089 probably by a control surface wheel which can generate lots of events.
1091 /* cancel the existing timeout */
1093 control_scroll_connection.disconnect ();
1095 /* add the next timeout */
1097 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1101 Editor::deferred_control_scroll (framepos_t /*target*/)
1103 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1104 // reset for next stream
1105 _control_scroll_target = boost::none;
1106 _dragging_playhead = false;
1111 Editor::access_action (std::string action_group, std::string action_item)
1117 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1120 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1128 Editor::on_realize ()
1130 Window::on_realize ();
1133 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1134 start_lock_event_timing ();
1137 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1141 Editor::start_lock_event_timing ()
1143 /* check if we should lock the GUI every 30 seconds */
1145 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1149 Editor::generic_event_handler (GdkEvent* ev)
1152 case GDK_BUTTON_PRESS:
1153 case GDK_BUTTON_RELEASE:
1154 case GDK_MOTION_NOTIFY:
1156 case GDK_KEY_RELEASE:
1157 gettimeofday (&last_event_time, 0);
1160 case GDK_LEAVE_NOTIFY:
1161 switch (ev->crossing.detail) {
1162 case GDK_NOTIFY_UNKNOWN:
1163 case GDK_NOTIFY_INFERIOR:
1164 case GDK_NOTIFY_ANCESTOR:
1166 case GDK_NOTIFY_VIRTUAL:
1167 case GDK_NOTIFY_NONLINEAR:
1168 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1169 /* leaving window, so reset focus, thus ending any and
1170 all text entry operations.
1185 Editor::lock_timeout_callback ()
1187 struct timeval now, delta;
1189 gettimeofday (&now, 0);
1191 timersub (&now, &last_event_time, &delta);
1193 if (delta.tv_sec > (time_t) ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1195 /* don't call again. Returning false will effectively
1196 disconnect us from the timer callback.
1198 unlock() will call start_lock_event_timing() to get things
1208 Editor::map_position_change (framepos_t frame)
1210 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1212 if (_session == 0) {
1216 if (_follow_playhead) {
1217 center_screen (frame);
1220 playhead_cursor->set_position (frame);
1224 Editor::center_screen (framepos_t frame)
1226 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1228 /* if we're off the page, then scroll.
1231 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1232 center_screen_internal (frame, page);
1237 Editor::center_screen_internal (framepos_t frame, float page)
1242 frame -= (framepos_t) page;
1247 reset_x_origin (frame);
1252 Editor::update_title ()
1254 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1257 bool dirty = _session->dirty();
1259 string session_name;
1261 if (_session->snap_name() != _session->name()) {
1262 session_name = _session->snap_name();
1264 session_name = _session->name();
1268 session_name = "*" + session_name;
1271 WindowTitle title(session_name);
1272 title += Glib::get_application_name();
1273 set_title (title.get_string());
1275 /* ::session_going_away() will have taken care of it */
1280 Editor::set_session (Session *t)
1282 SessionHandlePtr::set_session (t);
1288 _playlist_selector->set_session (_session);
1289 nudge_clock->set_session (_session);
1290 _summary->set_session (_session);
1291 _group_tabs->set_session (_session);
1292 _route_groups->set_session (_session);
1293 _regions->set_session (_session);
1294 _snapshots->set_session (_session);
1295 _routes->set_session (_session);
1296 _locations->set_session (_session);
1298 if (rhythm_ferret) {
1299 rhythm_ferret->set_session (_session);
1302 if (analysis_window) {
1303 analysis_window->set_session (_session);
1307 sfbrowser->set_session (_session);
1310 compute_fixed_ruler_scale ();
1312 /* Make sure we have auto loop and auto punch ranges */
1314 Location* loc = _session->locations()->auto_loop_location();
1316 loc->set_name (_("Loop"));
1319 loc = _session->locations()->auto_punch_location();
1322 loc->set_name (_("Punch"));
1325 refresh_location_display ();
1327 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1328 the selected Marker; this needs the LocationMarker list to be available.
1330 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1331 set_state (*node, Stateful::loading_state_version);
1333 /* catch up with the playhead */
1335 _session->request_locate (playhead_cursor->current_frame ());
1336 _pending_initial_locate = true;
1340 /* These signals can all be emitted by a non-GUI thread. Therefore the
1341 handlers for them must not attempt to directly interact with the GUI,
1342 but use PBD::Signal<T>::connect() which accepts an event loop
1343 ("context") where the handler will be asked to run.
1346 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1347 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1348 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1349 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1350 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1351 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1352 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1353 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1354 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1355 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1356 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1357 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1358 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1360 playhead_cursor->show ();
1362 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1363 Config->map_parameters (pc);
1364 _session->config.map_parameters (pc);
1366 restore_ruler_visibility ();
1367 //tempo_map_changed (PropertyChange (0));
1368 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1370 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1371 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1374 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1375 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1378 switch (_snap_type) {
1379 case SnapToRegionStart:
1380 case SnapToRegionEnd:
1381 case SnapToRegionSync:
1382 case SnapToRegionBoundary:
1383 build_region_boundary_cache ();
1390 /* register for undo history */
1391 _session->register_with_memento_command_factory(id(), this);
1392 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1394 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1396 start_updating_meters ();
1400 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1402 if (a->get_name() == "RegionMenu") {
1403 /* When the main menu's region menu is opened, we setup the actions so that they look right
1404 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1405 so we resensitize all region actions when the entered regionview or the region selection
1406 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1407 happens after the region context menu is opened. So we set a flag here, too.
1411 sensitize_the_right_region_actions ();
1412 _last_region_menu_was_main = true;
1417 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1419 using namespace Menu_Helpers;
1421 void (Editor::*emf)(FadeShape);
1422 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1425 images = &_xfade_in_images;
1426 emf = &Editor::set_fade_in_shape;
1428 images = &_xfade_out_images;
1429 emf = &Editor::set_fade_out_shape;
1434 _("Linear (for highly correlated material)"),
1435 *(*images)[FadeLinear],
1436 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1440 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1444 _("Constant power"),
1445 *(*images)[FadeConstantPower],
1446 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1449 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1454 *(*images)[FadeSymmetric],
1455 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1459 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1464 *(*images)[FadeSlow],
1465 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1468 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1473 *(*images)[FadeFast],
1474 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1477 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1480 /** Pop up a context menu for when the user clicks on a start crossfade */
1482 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1484 using namespace Menu_Helpers;
1485 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)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 = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1515 MenuList& items (xfade_out_context_menu.items());
1518 if (arv->audio_region()->fade_out_active()) {
1519 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1521 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1524 items.push_back (SeparatorElem());
1525 fill_xfade_menu (items, false);
1527 xfade_out_context_menu.popup (button, time);
1531 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1533 using namespace Menu_Helpers;
1534 Menu* (Editor::*build_menu_function)();
1537 switch (item_type) {
1539 case RegionViewName:
1540 case RegionViewNameHighlight:
1541 case LeftFrameHandle:
1542 case RightFrameHandle:
1543 if (with_selection) {
1544 build_menu_function = &Editor::build_track_selection_context_menu;
1546 build_menu_function = &Editor::build_track_region_context_menu;
1551 if (with_selection) {
1552 build_menu_function = &Editor::build_track_selection_context_menu;
1554 build_menu_function = &Editor::build_track_context_menu;
1559 if (clicked_routeview->track()) {
1560 build_menu_function = &Editor::build_track_context_menu;
1562 build_menu_function = &Editor::build_track_bus_context_menu;
1567 /* probably shouldn't happen but if it does, we don't care */
1571 menu = (this->*build_menu_function)();
1572 menu->set_name ("ArdourContextMenu");
1574 /* now handle specific situations */
1576 switch (item_type) {
1578 case RegionViewName:
1579 case RegionViewNameHighlight:
1580 case LeftFrameHandle:
1581 case RightFrameHandle:
1582 if (!with_selection) {
1583 if (region_edit_menu_split_item) {
1584 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1585 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1587 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1590 if (region_edit_menu_split_multichannel_item) {
1591 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1592 region_edit_menu_split_multichannel_item->set_sensitive (true);
1594 region_edit_menu_split_multichannel_item->set_sensitive (false);
1607 /* probably shouldn't happen but if it does, we don't care */
1611 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1613 /* Bounce to disk */
1615 using namespace Menu_Helpers;
1616 MenuList& edit_items = menu->items();
1618 edit_items.push_back (SeparatorElem());
1620 switch (clicked_routeview->audio_track()->freeze_state()) {
1621 case AudioTrack::NoFreeze:
1622 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1625 case AudioTrack::Frozen:
1626 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1629 case AudioTrack::UnFrozen:
1630 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1636 if (item_type == StreamItem && clicked_routeview) {
1637 clicked_routeview->build_underlay_menu(menu);
1640 /* When the region menu is opened, we setup the actions so that they look right
1643 sensitize_the_right_region_actions ();
1644 _last_region_menu_was_main = false;
1646 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1647 menu->popup (button, time);
1651 Editor::build_track_context_menu ()
1653 using namespace Menu_Helpers;
1655 MenuList& edit_items = track_context_menu.items();
1658 add_dstream_context_items (edit_items);
1659 return &track_context_menu;
1663 Editor::build_track_bus_context_menu ()
1665 using namespace Menu_Helpers;
1667 MenuList& edit_items = track_context_menu.items();
1670 add_bus_context_items (edit_items);
1671 return &track_context_menu;
1675 Editor::build_track_region_context_menu ()
1677 using namespace Menu_Helpers;
1678 MenuList& edit_items = track_region_context_menu.items();
1681 /* we've just cleared the track region context menu, so the menu that these
1682 two items were on will have disappeared; stop them dangling.
1684 region_edit_menu_split_item = 0;
1685 region_edit_menu_split_multichannel_item = 0;
1687 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1690 boost::shared_ptr<Track> tr;
1691 boost::shared_ptr<Playlist> pl;
1693 if ((tr = rtv->track())) {
1694 add_region_context_items (edit_items, tr);
1698 add_dstream_context_items (edit_items);
1700 return &track_region_context_menu;
1704 Editor::analyze_region_selection ()
1706 if (analysis_window == 0) {
1707 analysis_window = new AnalysisWindow();
1710 analysis_window->set_session(_session);
1712 analysis_window->show_all();
1715 analysis_window->set_regionmode();
1716 analysis_window->analyze();
1718 analysis_window->present();
1722 Editor::analyze_range_selection()
1724 if (analysis_window == 0) {
1725 analysis_window = new AnalysisWindow();
1728 analysis_window->set_session(_session);
1730 analysis_window->show_all();
1733 analysis_window->set_rangemode();
1734 analysis_window->analyze();
1736 analysis_window->present();
1740 Editor::build_track_selection_context_menu ()
1742 using namespace Menu_Helpers;
1743 MenuList& edit_items = track_selection_context_menu.items();
1744 edit_items.clear ();
1746 add_selection_context_items (edit_items);
1747 // edit_items.push_back (SeparatorElem());
1748 // add_dstream_context_items (edit_items);
1750 return &track_selection_context_menu;
1754 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1756 using namespace Menu_Helpers;
1758 /* OK, stick the region submenu at the top of the list, and then add
1762 RegionSelection rs = get_regions_from_selection_and_entered ();
1764 string::size_type pos = 0;
1765 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1767 /* we have to hack up the region name because "_" has a special
1768 meaning for menu titles.
1771 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1772 menu_item_name.replace (pos, 1, "__");
1776 if (_popup_region_menu_item == 0) {
1777 _popup_region_menu_item = new MenuItem (menu_item_name);
1778 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1779 _popup_region_menu_item->show ();
1781 _popup_region_menu_item->set_label (menu_item_name);
1784 const framepos_t position = get_preferred_edit_position (false, true);
1786 edit_items.push_back (*_popup_region_menu_item);
1787 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1788 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1790 edit_items.push_back (SeparatorElem());
1793 /** Add context menu items relevant to selection ranges.
1794 * @param edit_items List to add the items to.
1797 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1799 using namespace Menu_Helpers;
1801 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1802 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1804 edit_items.push_back (SeparatorElem());
1805 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1807 edit_items.push_back (SeparatorElem());
1808 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1810 edit_items.push_back (SeparatorElem());
1812 edit_items.push_back (
1814 _("Move Range Start to Previous Region Boundary"),
1815 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1819 edit_items.push_back (
1821 _("Move Range Start to Next Region Boundary"),
1822 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1826 edit_items.push_back (
1828 _("Move Range End to Previous Region Boundary"),
1829 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1833 edit_items.push_back (
1835 _("Move Range End to Next Region Boundary"),
1836 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1840 edit_items.push_back (SeparatorElem());
1841 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1842 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1844 edit_items.push_back (SeparatorElem());
1845 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1847 edit_items.push_back (SeparatorElem());
1848 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1849 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1850 edit_items.push_back (MenuElem (_("Set Session Start/End from Range"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1852 edit_items.push_back (SeparatorElem());
1853 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1855 edit_items.push_back (SeparatorElem());
1856 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1857 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1858 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1860 edit_items.push_back (SeparatorElem());
1861 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1862 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1863 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1864 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1865 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1866 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1867 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1873 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1875 using namespace Menu_Helpers;
1879 Menu *play_menu = manage (new Menu);
1880 MenuList& play_items = play_menu->items();
1881 play_menu->set_name ("ArdourContextMenu");
1883 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1884 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1885 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1886 play_items.push_back (SeparatorElem());
1887 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1889 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1893 Menu *select_menu = manage (new Menu);
1894 MenuList& select_items = select_menu->items();
1895 select_menu->set_name ("ArdourContextMenu");
1897 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1898 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1899 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1900 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1901 select_items.push_back (SeparatorElem());
1902 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1903 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1904 select_items.push_back (SeparatorElem());
1905 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1906 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1907 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1908 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1909 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1910 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1911 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1913 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1917 Menu *cutnpaste_menu = manage (new Menu);
1918 MenuList& cutnpaste_items = cutnpaste_menu->items();
1919 cutnpaste_menu->set_name ("ArdourContextMenu");
1921 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1922 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1923 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1925 cutnpaste_items.push_back (SeparatorElem());
1927 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1928 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1930 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1932 /* Adding new material */
1934 edit_items.push_back (SeparatorElem());
1935 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1936 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1940 Menu *nudge_menu = manage (new Menu());
1941 MenuList& nudge_items = nudge_menu->items();
1942 nudge_menu->set_name ("ArdourContextMenu");
1944 edit_items.push_back (SeparatorElem());
1945 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1946 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1947 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1948 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1950 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1954 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1956 using namespace Menu_Helpers;
1960 Menu *play_menu = manage (new Menu);
1961 MenuList& play_items = play_menu->items();
1962 play_menu->set_name ("ArdourContextMenu");
1964 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1965 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1966 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1970 Menu *select_menu = manage (new Menu);
1971 MenuList& select_items = select_menu->items();
1972 select_menu->set_name ("ArdourContextMenu");
1974 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1975 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1976 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1977 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1978 select_items.push_back (SeparatorElem());
1979 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1980 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1981 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1982 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1984 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1988 Menu *cutnpaste_menu = manage (new Menu);
1989 MenuList& cutnpaste_items = cutnpaste_menu->items();
1990 cutnpaste_menu->set_name ("ArdourContextMenu");
1992 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1993 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1994 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1996 Menu *nudge_menu = manage (new Menu());
1997 MenuList& nudge_items = nudge_menu->items();
1998 nudge_menu->set_name ("ArdourContextMenu");
2000 edit_items.push_back (SeparatorElem());
2001 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2002 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2003 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2004 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2006 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2010 Editor::snap_type() const
2016 Editor::snap_mode() const
2022 Editor::set_snap_to (SnapType st)
2024 unsigned int snap_ind = (unsigned int)st;
2028 if (snap_ind > snap_type_strings.size() - 1) {
2030 _snap_type = (SnapType)snap_ind;
2033 string str = snap_type_strings[snap_ind];
2035 if (str != snap_type_selector.get_text()) {
2036 snap_type_selector.set_text (str);
2041 switch (_snap_type) {
2042 case SnapToBeatDiv128:
2043 case SnapToBeatDiv64:
2044 case SnapToBeatDiv32:
2045 case SnapToBeatDiv28:
2046 case SnapToBeatDiv24:
2047 case SnapToBeatDiv20:
2048 case SnapToBeatDiv16:
2049 case SnapToBeatDiv14:
2050 case SnapToBeatDiv12:
2051 case SnapToBeatDiv10:
2052 case SnapToBeatDiv8:
2053 case SnapToBeatDiv7:
2054 case SnapToBeatDiv6:
2055 case SnapToBeatDiv5:
2056 case SnapToBeatDiv4:
2057 case SnapToBeatDiv3:
2058 case SnapToBeatDiv2: {
2059 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2060 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2062 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2063 current_bbt_points_begin, current_bbt_points_end);
2064 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2065 current_bbt_points_begin, current_bbt_points_end);
2066 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2070 case SnapToRegionStart:
2071 case SnapToRegionEnd:
2072 case SnapToRegionSync:
2073 case SnapToRegionBoundary:
2074 build_region_boundary_cache ();
2082 SnapChanged (); /* EMIT SIGNAL */
2086 Editor::set_snap_mode (SnapMode mode)
2088 string str = snap_mode_strings[(int)mode];
2092 if (str != snap_mode_selector.get_text ()) {
2093 snap_mode_selector.set_text (str);
2099 Editor::set_edit_point_preference (EditPoint ep, bool force)
2101 bool changed = (_edit_point != ep);
2104 if (Profile->get_mixbus())
2105 if (ep == EditAtSelectedMarker)
2106 ep = EditAtPlayhead;
2108 string str = edit_point_strings[(int)ep];
2109 if (str != edit_point_selector.get_text ()) {
2110 edit_point_selector.set_text (str);
2113 reset_canvas_cursor ();
2115 if (!force && !changed) {
2119 const char* action=NULL;
2121 switch (_edit_point) {
2122 case EditAtPlayhead:
2123 action = "edit-at-playhead";
2125 case EditAtSelectedMarker:
2126 action = "edit-at-marker";
2129 action = "edit-at-mouse";
2133 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2135 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2139 bool in_track_canvas;
2141 if (!mouse_frame (foo, in_track_canvas)) {
2142 in_track_canvas = false;
2145 reset_canvas_action_sensitivity (in_track_canvas);
2151 Editor::set_state (const XMLNode& node, int /*version*/)
2153 const XMLProperty* prop;
2160 g.base_width = default_width;
2161 g.base_height = default_height;
2165 if ((geometry = find_named_node (node, "geometry")) != 0) {
2169 if ((prop = geometry->property("x_size")) == 0) {
2170 prop = geometry->property ("x-size");
2173 g.base_width = atoi(prop->value());
2175 if ((prop = geometry->property("y_size")) == 0) {
2176 prop = geometry->property ("y-size");
2179 g.base_height = atoi(prop->value());
2182 if ((prop = geometry->property ("x_pos")) == 0) {
2183 prop = geometry->property ("x-pos");
2186 x = atoi (prop->value());
2189 if ((prop = geometry->property ("y_pos")) == 0) {
2190 prop = geometry->property ("y-pos");
2193 y = atoi (prop->value());
2197 set_default_size (g.base_width, g.base_height);
2200 if (_session && (prop = node.property ("playhead"))) {
2202 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2204 playhead_cursor->set_position (pos);
2206 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2207 playhead_cursor->set_position (0);
2210 playhead_cursor->set_position (0);
2213 if ((prop = node.property ("mixer-width"))) {
2214 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2217 if ((prop = node.property ("zoom-focus"))) {
2218 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2221 if ((prop = node.property ("zoom"))) {
2222 /* older versions of ardour used floating point samples_per_pixel */
2223 double f = PBD::atof (prop->value());
2224 reset_zoom (llrintf (f));
2226 reset_zoom (samples_per_pixel);
2229 if ((prop = node.property ("visible-track-count"))) {
2230 set_visible_track_count (PBD::atoi (prop->value()));
2233 if ((prop = node.property ("snap-to"))) {
2234 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2237 if ((prop = node.property ("snap-mode"))) {
2238 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2241 if ((prop = node.property ("mouse-mode"))) {
2242 MouseMode m = str2mousemode(prop->value());
2243 set_mouse_mode (m, true);
2245 set_mouse_mode (MouseObject, true);
2248 if ((prop = node.property ("left-frame")) != 0) {
2250 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2254 reset_x_origin (pos);
2258 if ((prop = node.property ("y-origin")) != 0) {
2259 reset_y_origin (atof (prop->value ()));
2262 if ((prop = node.property ("join-object-range"))) {
2263 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2264 bool yn = string_is_affirmative (prop->value());
2266 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2267 tact->set_active (!yn);
2268 tact->set_active (yn);
2270 set_mouse_mode(mouse_mode, true);
2273 if ((prop = node.property ("edit-point"))) {
2274 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2277 if ((prop = node.property ("show-measures"))) {
2278 bool yn = string_is_affirmative (prop->value());
2279 _show_measures = yn;
2280 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2282 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2283 /* do it twice to force the change */
2284 tact->set_active (!yn);
2285 tact->set_active (yn);
2289 if ((prop = node.property ("follow-playhead"))) {
2290 bool yn = string_is_affirmative (prop->value());
2291 set_follow_playhead (yn);
2292 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2294 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2295 if (tact->get_active() != yn) {
2296 tact->set_active (yn);
2301 if ((prop = node.property ("stationary-playhead"))) {
2302 bool yn = string_is_affirmative (prop->value());
2303 set_stationary_playhead (yn);
2304 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2306 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2307 if (tact->get_active() != yn) {
2308 tact->set_active (yn);
2313 if ((prop = node.property ("region-list-sort-type"))) {
2314 RegionListSortType st;
2315 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2318 if ((prop = node.property ("show-editor-mixer"))) {
2320 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2323 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2324 bool yn = string_is_affirmative (prop->value());
2326 /* do it twice to force the change */
2328 tact->set_active (!yn);
2329 tact->set_active (yn);
2332 if ((prop = node.property ("show-editor-list"))) {
2334 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2337 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2338 bool yn = string_is_affirmative (prop->value());
2340 /* do it twice to force the change */
2342 tact->set_active (!yn);
2343 tact->set_active (yn);
2346 if ((prop = node.property (X_("editor-list-page")))) {
2347 _the_notebook.set_current_page (atoi (prop->value ()));
2350 if ((prop = node.property (X_("show-marker-lines")))) {
2351 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2353 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2354 bool yn = string_is_affirmative (prop->value ());
2356 tact->set_active (!yn);
2357 tact->set_active (yn);
2360 XMLNodeList children = node.children ();
2361 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2362 selection->set_state (**i, Stateful::current_state_version);
2363 _regions->set_state (**i);
2366 if ((prop = node.property ("maximised"))) {
2367 bool yn = string_is_affirmative (prop->value());
2368 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2370 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2371 bool fs = tact && tact->get_active();
2373 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2377 if ((prop = node.property ("nudge-clock-value"))) {
2379 sscanf (prop->value().c_str(), "%" PRId64, &f);
2380 nudge_clock->set (f);
2382 nudge_clock->set_mode (AudioClock::Timecode);
2383 nudge_clock->set (_session->frame_rate() * 5, true);
2390 Editor::get_state ()
2392 XMLNode* node = new XMLNode ("Editor");
2395 id().print (buf, sizeof (buf));
2396 node->add_property ("id", buf);
2398 if (is_realized()) {
2399 Glib::RefPtr<Gdk::Window> win = get_window();
2401 int x, y, width, height;
2402 win->get_root_origin(x, y);
2403 win->get_size(width, height);
2405 XMLNode* geometry = new XMLNode ("geometry");
2407 snprintf(buf, sizeof(buf), "%d", width);
2408 geometry->add_property("x-size", string(buf));
2409 snprintf(buf, sizeof(buf), "%d", height);
2410 geometry->add_property("y-size", string(buf));
2411 snprintf(buf, sizeof(buf), "%d", x);
2412 geometry->add_property("x-pos", string(buf));
2413 snprintf(buf, sizeof(buf), "%d", y);
2414 geometry->add_property("y-pos", string(buf));
2415 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2416 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2417 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2418 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2419 geometry->add_property("edit-vertical-pane-pos", string(buf));
2421 node->add_child_nocopy (*geometry);
2424 maybe_add_mixer_strip_width (*node);
2426 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2428 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2429 node->add_property ("zoom", buf);
2430 node->add_property ("snap-to", enum_2_string (_snap_type));
2431 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2432 node->add_property ("edit-point", enum_2_string (_edit_point));
2433 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2434 node->add_property ("visible-track-count", buf);
2436 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2437 node->add_property ("playhead", buf);
2438 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2439 node->add_property ("left-frame", buf);
2440 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2441 node->add_property ("y-origin", buf);
2443 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2444 node->add_property ("maximised", _maximised ? "yes" : "no");
2445 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2446 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2447 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2448 node->add_property ("mouse-mode", enum2str(mouse_mode));
2449 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2451 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2453 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2454 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2457 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2459 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2460 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2463 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2464 node->add_property (X_("editor-list-page"), buf);
2466 if (button_bindings) {
2467 XMLNode* bb = new XMLNode (X_("Buttons"));
2468 button_bindings->save (*bb);
2469 node->add_child_nocopy (*bb);
2472 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2474 node->add_child_nocopy (selection->get_state ());
2475 node->add_child_nocopy (_regions->get_state ());
2477 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2478 node->add_property ("nudge-clock-value", buf);
2483 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2484 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2486 * @return pair: TimeAxisView that y is over, layer index.
2488 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2489 * in stacked or expanded region display mode, otherwise 0.
2491 std::pair<TimeAxisView *, double>
2492 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2494 if (!trackview_relative_offset) {
2495 y -= _trackview_group->canvas_origin().y;
2499 return std::make_pair ( (TimeAxisView *) 0, 0);
2502 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2504 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2511 return std::make_pair ( (TimeAxisView *) 0, 0);
2514 /** Snap a position to the grid, if appropriate, taking into account current
2515 * grid settings and also the state of any snap modifier keys that may be pressed.
2516 * @param start Position to snap.
2517 * @param event Event to get current key modifier information from, or 0.
2520 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2522 if (!_session || !event) {
2526 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2527 if (_snap_mode == SnapOff) {
2528 snap_to_internal (start, direction, for_mark);
2531 if (_snap_mode != SnapOff) {
2532 snap_to_internal (start, direction, for_mark);
2538 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark)
2540 if (!_session || _snap_mode == SnapOff) {
2544 snap_to_internal (start, direction, for_mark);
2548 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2550 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2551 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2553 switch (_snap_type) {
2554 case SnapToTimecodeFrame:
2555 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2556 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2557 /* start is already on a whole timecode frame, do nothing */
2558 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2559 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2561 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2565 case SnapToTimecodeSeconds:
2566 if (_session->config.get_timecode_offset_negative()) {
2567 start += _session->config.get_timecode_offset ();
2569 start -= _session->config.get_timecode_offset ();
2571 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2572 (start % one_timecode_second == 0)) {
2573 /* start is already on a whole second, do nothing */
2574 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2575 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2577 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2580 if (_session->config.get_timecode_offset_negative()) {
2581 start -= _session->config.get_timecode_offset ();
2583 start += _session->config.get_timecode_offset ();
2587 case SnapToTimecodeMinutes:
2588 if (_session->config.get_timecode_offset_negative()) {
2589 start += _session->config.get_timecode_offset ();
2591 start -= _session->config.get_timecode_offset ();
2593 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2594 (start % one_timecode_minute == 0)) {
2595 /* start is already on a whole minute, do nothing */
2596 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2597 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2599 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2601 if (_session->config.get_timecode_offset_negative()) {
2602 start -= _session->config.get_timecode_offset ();
2604 start += _session->config.get_timecode_offset ();
2608 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2609 abort(); /*NOTREACHED*/
2614 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark)
2616 const framepos_t one_second = _session->frame_rate();
2617 const framepos_t one_minute = _session->frame_rate() * 60;
2618 framepos_t presnap = start;
2622 switch (_snap_type) {
2623 case SnapToTimecodeFrame:
2624 case SnapToTimecodeSeconds:
2625 case SnapToTimecodeMinutes:
2626 return timecode_snap_to_internal (start, direction, for_mark);
2629 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2630 start % (one_second/75) == 0) {
2631 /* start is already on a whole CD frame, do nothing */
2632 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2633 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2635 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2640 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2641 start % one_second == 0) {
2642 /* start is already on a whole second, do nothing */
2643 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2644 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2646 start = (framepos_t) floor ((double) start / one_second) * one_second;
2651 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2652 start % one_minute == 0) {
2653 /* start is already on a whole minute, do nothing */
2654 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2655 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2657 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2662 start = _session->tempo_map().round_to_bar (start, direction);
2666 start = _session->tempo_map().round_to_beat (start, direction);
2669 case SnapToBeatDiv128:
2670 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2672 case SnapToBeatDiv64:
2673 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2675 case SnapToBeatDiv32:
2676 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2678 case SnapToBeatDiv28:
2679 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2681 case SnapToBeatDiv24:
2682 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2684 case SnapToBeatDiv20:
2685 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2687 case SnapToBeatDiv16:
2688 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2690 case SnapToBeatDiv14:
2691 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2693 case SnapToBeatDiv12:
2694 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2696 case SnapToBeatDiv10:
2697 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2699 case SnapToBeatDiv8:
2700 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2702 case SnapToBeatDiv7:
2703 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2705 case SnapToBeatDiv6:
2706 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2708 case SnapToBeatDiv5:
2709 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2711 case SnapToBeatDiv4:
2712 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2714 case SnapToBeatDiv3:
2715 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2717 case SnapToBeatDiv2:
2718 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2726 _session->locations()->marks_either_side (start, before, after);
2728 if (before == max_framepos && after == max_framepos) {
2729 /* No marks to snap to, so just don't snap */
2731 } else if (before == max_framepos) {
2733 } else if (after == max_framepos) {
2735 } else if (before != max_framepos && after != max_framepos) {
2736 /* have before and after */
2737 if ((start - before) < (after - start)) {
2746 case SnapToRegionStart:
2747 case SnapToRegionEnd:
2748 case SnapToRegionSync:
2749 case SnapToRegionBoundary:
2750 if (!region_boundary_cache.empty()) {
2752 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2753 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2755 if (direction > 0) {
2756 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2758 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2761 if (next != region_boundary_cache.begin ()) {
2766 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2767 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2769 if (start > (p + n) / 2) {
2778 switch (_snap_mode) {
2784 if (presnap > start) {
2785 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2789 } else if (presnap < start) {
2790 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2796 /* handled at entry */
2804 Editor::setup_toolbar ()
2806 HBox* mode_box = manage(new HBox);
2807 mode_box->set_border_width (2);
2808 mode_box->set_spacing(2);
2810 HBox* mouse_mode_box = manage (new HBox);
2811 HBox* mouse_mode_hbox = manage (new HBox);
2812 VBox* mouse_mode_vbox = manage (new VBox);
2813 Alignment* mouse_mode_align = manage (new Alignment);
2815 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2816 mouse_mode_size_group->add_widget (smart_mode_button);
2817 mouse_mode_size_group->add_widget (mouse_move_button);
2818 mouse_mode_size_group->add_widget (mouse_cut_button);
2819 mouse_mode_size_group->add_widget (mouse_select_button);
2820 mouse_mode_size_group->add_widget (mouse_timefx_button);
2821 mouse_mode_size_group->add_widget (mouse_audition_button);
2822 mouse_mode_size_group->add_widget (mouse_draw_button);
2823 mouse_mode_size_group->add_widget (mouse_content_button);
2825 mouse_mode_size_group->add_widget (zoom_in_button);
2826 mouse_mode_size_group->add_widget (zoom_out_button);
2827 mouse_mode_size_group->add_widget (zoom_preset_selector);
2828 mouse_mode_size_group->add_widget (zoom_out_full_button);
2829 mouse_mode_size_group->add_widget (zoom_focus_selector);
2831 mouse_mode_size_group->add_widget (tav_shrink_button);
2832 mouse_mode_size_group->add_widget (tav_expand_button);
2833 mouse_mode_size_group->add_widget (visible_tracks_selector);
2835 mouse_mode_size_group->add_widget (snap_type_selector);
2836 mouse_mode_size_group->add_widget (snap_mode_selector);
2838 mouse_mode_size_group->add_widget (edit_point_selector);
2839 mouse_mode_size_group->add_widget (edit_mode_selector);
2841 mouse_mode_size_group->add_widget (*nudge_clock);
2842 mouse_mode_size_group->add_widget (nudge_forward_button);
2843 mouse_mode_size_group->add_widget (nudge_backward_button);
2845 mouse_mode_hbox->set_spacing (2);
2847 if (!ARDOUR::Profile->get_trx()) {
2848 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2851 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2852 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2854 if (!ARDOUR::Profile->get_mixbus()) {
2855 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2858 if (!ARDOUR::Profile->get_trx()) {
2859 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2860 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2861 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2862 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2865 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2867 mouse_mode_align->add (*mouse_mode_vbox);
2868 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2870 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2872 edit_mode_selector.set_name ("mouse mode button");
2874 if (!ARDOUR::Profile->get_trx()) {
2875 mode_box->pack_start (edit_mode_selector, false, false);
2877 mode_box->pack_start (*mouse_mode_box, false, false);
2879 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2880 _mouse_mode_tearoff->set_name ("MouseModeBase");
2881 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2883 if (Profile->get_sae() || Profile->get_mixbus() ) {
2884 _mouse_mode_tearoff->set_can_be_torn_off (false);
2887 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2888 &_mouse_mode_tearoff->tearoff_window()));
2889 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2890 &_mouse_mode_tearoff->tearoff_window(), 1));
2891 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2892 &_mouse_mode_tearoff->tearoff_window()));
2893 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2894 &_mouse_mode_tearoff->tearoff_window(), 1));
2898 _zoom_box.set_spacing (2);
2899 _zoom_box.set_border_width (2);
2903 zoom_preset_selector.set_name ("zoom button");
2904 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2905 zoom_preset_selector.set_size_request (42, -1);
2907 zoom_in_button.set_name ("zoom button");
2908 zoom_in_button.set_image(::get_icon ("zoom_in"));
2909 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2910 zoom_in_button.set_related_action (act);
2912 zoom_out_button.set_name ("zoom button");
2913 zoom_out_button.set_image(::get_icon ("zoom_out"));
2914 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2915 zoom_out_button.set_related_action (act);
2917 zoom_out_full_button.set_name ("zoom button");
2918 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2919 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2920 zoom_out_full_button.set_related_action (act);
2922 zoom_focus_selector.set_name ("zoom button");
2924 if (ARDOUR::Profile->get_mixbus()) {
2925 _zoom_box.pack_start (zoom_preset_selector, false, false);
2926 } else if (ARDOUR::Profile->get_trx()) {
2927 mode_box->pack_start (zoom_out_button, false, false);
2928 mode_box->pack_start (zoom_in_button, false, false);
2930 _zoom_box.pack_start (zoom_out_button, false, false);
2931 _zoom_box.pack_start (zoom_in_button, false, false);
2932 _zoom_box.pack_start (zoom_out_full_button, false, false);
2933 _zoom_box.pack_start (zoom_focus_selector, false, false);
2936 /* Track zoom buttons */
2937 visible_tracks_selector.set_name ("zoom button");
2938 if (Profile->get_mixbus()) {
2939 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2940 visible_tracks_selector.set_size_request (42, -1);
2942 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2945 tav_expand_button.set_name ("zoom button");
2946 tav_expand_button.set_image(::get_icon ("tav_exp"));
2947 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2948 tav_expand_button.set_related_action (act);
2950 tav_shrink_button.set_name ("zoom button");
2951 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2952 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2953 tav_shrink_button.set_related_action (act);
2955 if (ARDOUR::Profile->get_mixbus()) {
2956 _zoom_box.pack_start (visible_tracks_selector);
2957 } else if (ARDOUR::Profile->get_trx()) {
2958 _zoom_box.pack_start (tav_shrink_button);
2959 _zoom_box.pack_start (tav_expand_button);
2961 _zoom_box.pack_start (visible_tracks_selector);
2962 _zoom_box.pack_start (tav_shrink_button);
2963 _zoom_box.pack_start (tav_expand_button);
2966 if (!ARDOUR::Profile->get_trx()) {
2967 _zoom_tearoff = manage (new TearOff (_zoom_box));
2969 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2970 &_zoom_tearoff->tearoff_window()));
2971 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2972 &_zoom_tearoff->tearoff_window(), 0));
2973 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2974 &_zoom_tearoff->tearoff_window()));
2975 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2976 &_zoom_tearoff->tearoff_window(), 0));
2979 if (Profile->get_sae() || Profile->get_mixbus() ) {
2980 _zoom_tearoff->set_can_be_torn_off (false);
2983 snap_box.set_spacing (2);
2984 snap_box.set_border_width (2);
2986 snap_type_selector.set_name ("mouse mode button");
2988 snap_mode_selector.set_name ("mouse mode button");
2990 edit_point_selector.set_name ("mouse mode button");
2992 snap_box.pack_start (snap_mode_selector, false, false);
2993 snap_box.pack_start (snap_type_selector, false, false);
2994 snap_box.pack_start (edit_point_selector, false, false);
2998 HBox *nudge_box = manage (new HBox);
2999 nudge_box->set_spacing (2);
3000 nudge_box->set_border_width (2);
3002 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3003 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3005 nudge_box->pack_start (nudge_backward_button, false, false);
3006 nudge_box->pack_start (nudge_forward_button, false, false);
3007 nudge_box->pack_start (*nudge_clock, false, false);
3010 /* Pack everything in... */
3012 HBox* hbox = manage (new HBox);
3013 hbox->set_spacing(2);
3015 _tools_tearoff = manage (new TearOff (*hbox));
3016 _tools_tearoff->set_name ("MouseModeBase");
3017 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3019 if (Profile->get_sae() || Profile->get_mixbus()) {
3020 _tools_tearoff->set_can_be_torn_off (false);
3023 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3024 &_tools_tearoff->tearoff_window()));
3025 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3026 &_tools_tearoff->tearoff_window(), 0));
3027 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3028 &_tools_tearoff->tearoff_window()));
3029 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3030 &_tools_tearoff->tearoff_window(), 0));
3032 toolbar_hbox.set_spacing (2);
3033 toolbar_hbox.set_border_width (1);
3035 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3036 if (!ARDOUR::Profile->get_trx()) {
3037 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3038 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3041 if (!ARDOUR::Profile->get_trx()) {
3042 hbox->pack_start (snap_box, false, false);
3043 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3044 hbox->pack_start (*nudge_box, false, false);
3046 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3049 hbox->pack_start (panic_box, false, false);
3053 toolbar_base.set_name ("ToolBarBase");
3054 toolbar_base.add (toolbar_hbox);
3056 _toolbar_viewport.add (toolbar_base);
3057 /* stick to the required height but allow width to vary if there's not enough room */
3058 _toolbar_viewport.set_size_request (1, -1);
3060 toolbar_frame.set_shadow_type (SHADOW_OUT);
3061 toolbar_frame.set_name ("BaseFrame");
3062 toolbar_frame.add (_toolbar_viewport);
3066 Editor::build_edit_point_menu ()
3068 using namespace Menu_Helpers;
3070 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3071 if(!Profile->get_mixbus())
3072 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3073 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3075 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3079 Editor::build_edit_mode_menu ()
3081 using namespace Menu_Helpers;
3083 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3084 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3085 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3086 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3088 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3092 Editor::build_snap_mode_menu ()
3094 using namespace Menu_Helpers;
3096 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3097 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3098 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3100 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3104 Editor::build_snap_type_menu ()
3106 using namespace Menu_Helpers;
3108 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3109 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3110 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3111 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3112 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3113 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3114 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3115 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3116 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3117 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3118 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3119 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3120 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3121 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3122 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3123 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3124 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3125 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3126 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3127 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3128 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3129 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3130 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3131 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3132 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3133 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3134 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3135 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3136 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3137 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3139 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3144 Editor::setup_tooltips ()
3146 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3147 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3148 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3149 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3150 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit Gain/Notes/Automation"));
3151 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3152 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3153 ARDOUR_UI::instance()->set_tip (mouse_content_button, _("Select/move contents (notes and automation)"));
3154 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3155 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3156 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3157 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3158 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3159 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3160 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3161 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3162 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3163 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3164 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3165 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3166 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3167 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3168 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3169 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3173 Editor::convert_drop_to_paths (
3174 vector<string>& paths,
3175 const RefPtr<Gdk::DragContext>& /*context*/,
3178 const SelectionData& data,
3182 if (_session == 0) {
3186 vector<string> uris = data.get_uris();
3190 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3191 are actually URI lists. So do it by hand.
3194 if (data.get_target() != "text/plain") {
3198 /* Parse the "uri-list" format that Nautilus provides,
3199 where each pathname is delimited by \r\n.
3201 THERE MAY BE NO NULL TERMINATING CHAR!!!
3204 string txt = data.get_text();
3208 p = (char *) malloc (txt.length() + 1);
3209 txt.copy (p, txt.length(), 0);
3210 p[txt.length()] = '\0';
3216 while (g_ascii_isspace (*p))
3220 while (*q && (*q != '\n') && (*q != '\r')) {
3227 while (q > p && g_ascii_isspace (*q))
3232 uris.push_back (string (p, q - p + 1));
3236 p = strchr (p, '\n');
3248 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3249 if ((*i).substr (0,7) == "file://") {
3250 paths.push_back (Glib::filename_from_uri (*i));
3258 Editor::new_tempo_section ()
3263 Editor::map_transport_state ()
3265 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3267 if (_session && _session->transport_stopped()) {
3268 have_pending_keyboard_selection = false;
3271 update_loop_range_view ();
3277 Editor::begin_reversible_command (string name)
3280 before.push_back (&_selection_memento->get_state ());
3281 _session->begin_reversible_command (name);
3286 Editor::begin_reversible_command (GQuark q)
3289 before.push_back (&_selection_memento->get_state ());
3290 _session->begin_reversible_command (q);
3295 Editor::commit_reversible_command ()
3298 if (before.size() == 1) {
3299 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3302 if (!before.empty()) {
3306 _session->commit_reversible_command ();
3311 Editor::history_changed ()
3315 if (undo_action && _session) {
3316 if (_session->undo_depth() == 0) {
3317 label = S_("Command|Undo");
3319 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3321 undo_action->property_label() = label;
3324 if (redo_action && _session) {
3325 if (_session->redo_depth() == 0) {
3328 label = string_compose(_("Redo (%1)"), _session->next_redo());
3330 redo_action->property_label() = label;
3335 Editor::duplicate_range (bool with_dialog)
3339 RegionSelection rs = get_regions_from_selection_and_entered ();
3341 if ( selection->time.length() == 0 && rs.empty()) {
3347 ArdourDialog win (_("Duplicate"));
3348 Label label (_("Number of duplications:"));
3349 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3350 SpinButton spinner (adjustment, 0.0, 1);
3353 win.get_vbox()->set_spacing (12);
3354 win.get_vbox()->pack_start (hbox);
3355 hbox.set_border_width (6);
3356 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3358 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3359 place, visually. so do this by hand.
3362 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3363 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3364 spinner.grab_focus();
3370 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3371 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3372 win.set_default_response (RESPONSE_ACCEPT);
3374 spinner.grab_focus ();
3376 switch (win.run ()) {
3377 case RESPONSE_ACCEPT:
3383 times = adjustment.get_value();
3386 if ((current_mouse_mode() == Editing::MouseRange)) {
3387 if (selection->time.length()) {
3388 duplicate_selection (times);
3390 } else if (get_smart_mode()) {
3391 if (selection->time.length()) {
3392 duplicate_selection (times);
3394 duplicate_some_regions (rs, times);
3396 duplicate_some_regions (rs, times);
3401 Editor::set_edit_mode (EditMode m)
3403 Config->set_edit_mode (m);
3407 Editor::cycle_edit_mode ()
3409 switch (Config->get_edit_mode()) {
3411 if (Profile->get_sae()) {
3412 Config->set_edit_mode (Lock);
3414 Config->set_edit_mode (Ripple);
3419 Config->set_edit_mode (Lock);
3422 Config->set_edit_mode (Slide);
3428 Editor::edit_mode_selection_done ( EditMode m )
3430 Config->set_edit_mode ( m );
3434 Editor::snap_type_selection_done (SnapType snaptype)
3436 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3438 ract->set_active ();
3443 Editor::snap_mode_selection_done (SnapMode mode)
3445 RefPtr<RadioAction> ract = snap_mode_action (mode);
3448 ract->set_active (true);
3453 Editor::cycle_edit_point (bool with_marker)
3455 if(Profile->get_mixbus())
3456 with_marker = false;
3458 switch (_edit_point) {
3460 set_edit_point_preference (EditAtPlayhead);
3462 case EditAtPlayhead:
3464 set_edit_point_preference (EditAtSelectedMarker);
3466 set_edit_point_preference (EditAtMouse);
3469 case EditAtSelectedMarker:
3470 set_edit_point_preference (EditAtMouse);
3476 Editor::edit_point_selection_done (EditPoint ep)
3478 set_edit_point_preference ( ep );
3482 Editor::build_zoom_focus_menu ()
3484 using namespace Menu_Helpers;
3486 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3487 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3488 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3489 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3490 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3491 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3493 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3497 Editor::zoom_focus_selection_done ( ZoomFocus f )
3499 RefPtr<RadioAction> ract = zoom_focus_action (f);
3501 ract->set_active ();
3506 Editor::build_track_count_menu ()
3508 using namespace Menu_Helpers;
3510 if (!Profile->get_mixbus()) {
3511 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3512 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3513 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3514 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3515 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3516 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3517 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3518 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3519 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3520 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3521 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3522 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3523 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3525 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3526 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3527 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3528 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3529 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3530 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3531 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3532 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3533 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3534 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3536 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3537 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3538 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3539 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3540 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3541 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3542 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3543 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3544 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3545 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3546 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3551 Editor::set_zoom_preset (int64_t ms)
3554 temporal_zoom_session();
3558 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3559 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3563 Editor::set_visible_track_count (int32_t n)
3565 _visible_track_count = n;
3567 /* if the canvas hasn't really been allocated any size yet, just
3568 record the desired number of visible tracks and return. when canvas
3569 allocation happens, we will get called again and then we can do the
3573 if (_visible_canvas_height <= 1) {
3580 if (_visible_track_count > 0) {
3581 h = trackviews_height() / _visible_track_count;
3582 std::ostringstream s;
3583 s << _visible_track_count;
3585 } else if (_visible_track_count == 0) {
3587 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3588 if ((*i)->marked_for_display()) {
3592 h = trackviews_height() / n;
3595 /* negative value means that the visible track count has
3596 been overridden by explicit track height changes.
3598 visible_tracks_selector.set_text (X_("*"));
3602 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3603 (*i)->set_height (h);
3606 if (str != visible_tracks_selector.get_text()) {
3607 visible_tracks_selector.set_text (str);
3612 Editor::override_visible_track_count ()
3614 _visible_track_count = -1;
3615 visible_tracks_selector.set_text ( _("*") );
3619 Editor::edit_controls_button_release (GdkEventButton* ev)
3621 if (Keyboard::is_context_menu_event (ev)) {
3622 ARDOUR_UI::instance()->add_route (this);
3623 } else if (ev->button == 1) {
3624 selection->clear_tracks ();
3631 Editor::mouse_select_button_release (GdkEventButton* ev)
3633 /* this handles just right-clicks */
3635 if (ev->button != 3) {
3643 Editor::set_zoom_focus (ZoomFocus f)
3645 string str = zoom_focus_strings[(int)f];
3647 if (str != zoom_focus_selector.get_text()) {
3648 zoom_focus_selector.set_text (str);
3651 if (zoom_focus != f) {
3658 Editor::cycle_zoom_focus ()
3660 switch (zoom_focus) {
3662 set_zoom_focus (ZoomFocusRight);
3664 case ZoomFocusRight:
3665 set_zoom_focus (ZoomFocusCenter);
3667 case ZoomFocusCenter:
3668 set_zoom_focus (ZoomFocusPlayhead);
3670 case ZoomFocusPlayhead:
3671 set_zoom_focus (ZoomFocusMouse);
3673 case ZoomFocusMouse:
3674 set_zoom_focus (ZoomFocusEdit);
3677 set_zoom_focus (ZoomFocusLeft);
3683 Editor::ensure_float (Window& win)
3685 win.set_transient_for (*this);
3689 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3691 /* recover or initialize pane positions. do this here rather than earlier because
3692 we don't want the positions to change the child allocations, which they seem to do.
3698 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3707 XMLNode* geometry = find_named_node (*node, "geometry");
3709 if (which == static_cast<Paned*> (&edit_pane)) {
3711 if (done & Horizontal) {
3715 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3716 _notebook_shrunk = string_is_affirmative (prop->value ());
3719 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3720 /* initial allocation is 90% to canvas, 10% to notebook */
3721 pos = (int) floor (alloc.get_width() * 0.90f);
3722 snprintf (buf, sizeof(buf), "%d", pos);
3724 pos = atoi (prop->value());
3727 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3728 edit_pane.set_position (pos);
3731 done = (Pane) (done | Horizontal);
3733 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3735 if (done & Vertical) {
3739 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3740 /* initial allocation is 90% to canvas, 10% to summary */
3741 pos = (int) floor (alloc.get_height() * 0.90f);
3742 snprintf (buf, sizeof(buf), "%d", pos);
3745 pos = atoi (prop->value());
3748 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3749 editor_summary_pane.set_position (pos);
3752 done = (Pane) (done | Vertical);
3757 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3759 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3760 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3761 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3762 top_hbox.remove (toolbar_frame);
3767 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3769 if (toolbar_frame.get_parent() == 0) {
3770 top_hbox.pack_end (toolbar_frame);
3775 Editor::set_show_measures (bool yn)
3777 if (_show_measures != yn) {
3780 if ((_show_measures = yn) == true) {
3782 tempo_lines->show();
3785 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3786 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3788 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3789 draw_measures (begin, end);
3797 Editor::toggle_follow_playhead ()
3799 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3801 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3802 set_follow_playhead (tact->get_active());
3806 /** @param yn true to follow playhead, otherwise false.
3807 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3810 Editor::set_follow_playhead (bool yn, bool catch_up)
3812 if (_follow_playhead != yn) {
3813 if ((_follow_playhead = yn) == true && catch_up) {
3815 reset_x_origin_to_follow_playhead ();
3822 Editor::toggle_stationary_playhead ()
3824 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3826 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3827 set_stationary_playhead (tact->get_active());
3832 Editor::set_stationary_playhead (bool yn)
3834 if (_stationary_playhead != yn) {
3835 if ((_stationary_playhead = yn) == true) {
3837 // FIXME need a 3.0 equivalent of this 2.X call
3838 // update_current_screen ();
3845 Editor::playlist_selector () const
3847 return *_playlist_selector;
3851 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3853 if (paste_count == 0) {
3854 /* don't bother calculating an offset that will be zero anyway */
3858 /* calculate basic unsnapped multi-paste offset */
3859 framecnt_t offset = paste_count * duration;
3861 /* snap offset so pos + offset is aligned to the grid */
3862 framepos_t offset_pos = pos + offset;
3863 snap_to(offset_pos, RoundUpMaybe);
3864 offset = offset_pos - pos;
3870 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3874 switch (_snap_type) {
3876 return Evoral::MusicalTime(1.0);
3879 case SnapToBeatDiv128:
3880 return Evoral::MusicalTime(1.0/128.0);
3882 case SnapToBeatDiv64:
3883 return Evoral::MusicalTime(1.0/64.0);
3885 case SnapToBeatDiv32:
3886 return Evoral::MusicalTime(1.0/32.0);
3888 case SnapToBeatDiv28:
3889 return Evoral::MusicalTime(1.0/28.0);
3891 case SnapToBeatDiv24:
3892 return Evoral::MusicalTime(1.0/24.0);
3894 case SnapToBeatDiv20:
3895 return Evoral::MusicalTime(1.0/20.0);
3897 case SnapToBeatDiv16:
3898 return Evoral::MusicalTime(1.0/16.0);
3900 case SnapToBeatDiv14:
3901 return Evoral::MusicalTime(1.0/14.0);
3903 case SnapToBeatDiv12:
3904 return Evoral::MusicalTime(1.0/12.0);
3906 case SnapToBeatDiv10:
3907 return Evoral::MusicalTime(1.0/10.0);
3909 case SnapToBeatDiv8:
3910 return Evoral::MusicalTime(1.0/8.0);
3912 case SnapToBeatDiv7:
3913 return Evoral::MusicalTime(1.0/7.0);
3915 case SnapToBeatDiv6:
3916 return Evoral::MusicalTime(1.0/6.0);
3918 case SnapToBeatDiv5:
3919 return Evoral::MusicalTime(1.0/5.0);
3921 case SnapToBeatDiv4:
3922 return Evoral::MusicalTime(1.0/4.0);
3924 case SnapToBeatDiv3:
3925 return Evoral::MusicalTime(1.0/3.0);
3927 case SnapToBeatDiv2:
3928 return Evoral::MusicalTime(1.0/2.0);
3933 return Evoral::MusicalTime(_session->tempo_map().meter_at (position).divisions_per_bar());
3938 case SnapToTimecodeFrame:
3939 case SnapToTimecodeSeconds:
3940 case SnapToTimecodeMinutes:
3943 case SnapToRegionStart:
3944 case SnapToRegionEnd:
3945 case SnapToRegionSync:
3946 case SnapToRegionBoundary:
3952 return Evoral::MusicalTime();
3956 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3960 ret = nudge_clock->current_duration (pos);
3961 next = ret + 1; /* XXXX fix me */
3967 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3969 ArdourDialog dialog (_("Playlist Deletion"));
3970 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3971 "If it is kept, its audio files will not be cleaned.\n"
3972 "If it is deleted, audio files used by it alone will be cleaned."),
3975 dialog.set_position (WIN_POS_CENTER);
3976 dialog.get_vbox()->pack_start (label);
3980 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3981 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3982 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3984 switch (dialog.run ()) {
3985 case RESPONSE_ACCEPT:
3986 /* delete the playlist */
3990 case RESPONSE_REJECT:
3991 /* keep the playlist */
4003 Editor::audio_region_selection_covers (framepos_t where)
4005 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4006 if ((*a)->region()->covers (where)) {
4015 Editor::prepare_for_cleanup ()
4017 cut_buffer->clear_regions ();
4018 cut_buffer->clear_playlists ();
4020 selection->clear_regions ();
4021 selection->clear_playlists ();
4023 _regions->suspend_redisplay ();
4027 Editor::finish_cleanup ()
4029 _regions->resume_redisplay ();
4033 Editor::transport_loop_location()
4036 return _session->locations()->auto_loop_location();
4043 Editor::transport_punch_location()
4046 return _session->locations()->auto_punch_location();
4053 Editor::control_layout_scroll (GdkEventScroll* ev)
4055 /* Just forward to the normal canvas scroll method. The coordinate
4056 systems are different but since the canvas is always larger than the
4057 track headers, and aligned with the trackview area, this will work.
4059 In the not too distant future this layout is going away anyway and
4060 headers will be on the canvas.
4062 return canvas_scroll_event (ev, false);
4066 Editor::session_state_saved (string)
4069 _snapshots->redisplay ();
4073 Editor::update_tearoff_visibility()
4075 bool visible = Config->get_keep_tearoffs();
4076 _mouse_mode_tearoff->set_visible (visible);
4077 _tools_tearoff->set_visible (visible);
4078 if (_zoom_tearoff) {
4079 _zoom_tearoff->set_visible (visible);
4084 Editor::reattach_all_tearoffs ()
4086 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4087 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4088 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4092 Editor::maximise_editing_space ()
4104 Editor::restore_editing_space ()
4116 * Make new playlists for a given track and also any others that belong
4117 * to the same active route group with the `select' property.
4122 Editor::new_playlists (TimeAxisView* v)
4124 begin_reversible_command (_("new playlists"));
4125 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4126 _session->playlists->get (playlists);
4127 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4128 commit_reversible_command ();
4132 * Use a copy of the current playlist for a given track and also any others that belong
4133 * to the same active route group with the `select' property.
4138 Editor::copy_playlists (TimeAxisView* v)
4140 begin_reversible_command (_("copy playlists"));
4141 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4142 _session->playlists->get (playlists);
4143 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4144 commit_reversible_command ();
4147 /** Clear the current playlist for a given track and also any others that belong
4148 * to the same active route group with the `select' property.
4153 Editor::clear_playlists (TimeAxisView* v)
4155 begin_reversible_command (_("clear playlists"));
4156 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4157 _session->playlists->get (playlists);
4158 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4159 commit_reversible_command ();
4163 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4165 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4169 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4171 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4175 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4177 atv.clear_playlist ();
4181 Editor::on_key_press_event (GdkEventKey* ev)
4183 return key_press_focus_accelerator_handler (*this, ev);
4187 Editor::on_key_release_event (GdkEventKey* ev)
4189 return Gtk::Window::on_key_release_event (ev);
4190 // return key_press_focus_accelerator_handler (*this, ev);
4194 Editor::get_y_origin () const
4196 return vertical_adjustment.get_value ();
4199 /** Queue up a change to the viewport x origin.
4200 * @param frame New x origin.
4203 Editor::reset_x_origin (framepos_t frame)
4205 pending_visual_change.add (VisualChange::TimeOrigin);
4206 pending_visual_change.time_origin = frame;
4207 ensure_visual_change_idle_handler ();
4211 Editor::reset_y_origin (double y)
4213 pending_visual_change.add (VisualChange::YOrigin);
4214 pending_visual_change.y_origin = y;
4215 ensure_visual_change_idle_handler ();
4219 Editor::reset_zoom (framecnt_t spp)
4221 if (spp == samples_per_pixel) {
4225 pending_visual_change.add (VisualChange::ZoomLevel);
4226 pending_visual_change.samples_per_pixel = spp;
4227 ensure_visual_change_idle_handler ();
4231 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4233 reset_x_origin (frame);
4236 if (!no_save_visual) {
4237 undo_visual_stack.push_back (current_visual_state(false));
4241 Editor::VisualState::VisualState (bool with_tracks)
4242 : gui_state (with_tracks ? new GUIObjectState : 0)
4246 Editor::VisualState::~VisualState ()
4251 Editor::VisualState*
4252 Editor::current_visual_state (bool with_tracks)
4254 VisualState* vs = new VisualState (with_tracks);
4255 vs->y_position = vertical_adjustment.get_value();
4256 vs->samples_per_pixel = samples_per_pixel;
4257 vs->leftmost_frame = leftmost_frame;
4258 vs->zoom_focus = zoom_focus;
4261 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4268 Editor::undo_visual_state ()
4270 if (undo_visual_stack.empty()) {
4274 VisualState* vs = undo_visual_stack.back();
4275 undo_visual_stack.pop_back();
4278 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4281 use_visual_state (*vs);
4286 Editor::redo_visual_state ()
4288 if (redo_visual_stack.empty()) {
4292 VisualState* vs = redo_visual_stack.back();
4293 redo_visual_stack.pop_back();
4295 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4296 // why do we check here?
4297 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4300 use_visual_state (*vs);
4305 Editor::swap_visual_state ()
4307 if (undo_visual_stack.empty()) {
4308 redo_visual_state ();
4310 undo_visual_state ();
4315 Editor::use_visual_state (VisualState& vs)
4317 PBD::Unwinder<bool> nsv (no_save_visual, true);
4318 DisplaySuspender ds;
4320 vertical_adjustment.set_value (vs.y_position);
4322 set_zoom_focus (vs.zoom_focus);
4323 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4326 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4328 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4329 (*i)->reset_visual_state ();
4333 _routes->update_visibility ();
4336 /** This is the core function that controls the zoom level of the canvas. It is called
4337 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4338 * @param spp new number of samples per pixel
4341 Editor::set_samples_per_pixel (framecnt_t spp)
4347 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4348 const framecnt_t lots_of_pixels = 4000;
4350 /* if the zoom level is greater than what you'd get trying to display 3
4351 * days of audio on a really big screen, then it's too big.
4354 if (spp * lots_of_pixels > three_days) {
4358 samples_per_pixel = spp;
4361 tempo_lines->tempo_map_changed();
4364 bool const showing_time_selection = selection->time.length() > 0;
4366 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4367 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4368 (*i)->reshow_selection (selection->time);
4372 ZoomChanged (); /* EMIT_SIGNAL */
4374 ArdourCanvas::GtkCanvasViewport* c;
4376 c = get_track_canvas();
4378 c->canvas()->zoomed ();
4381 if (playhead_cursor) {
4382 playhead_cursor->set_position (playhead_cursor->current_frame ());
4385 refresh_location_display();
4386 _summary->set_overlays_dirty ();
4388 update_marker_labels ();
4394 Editor::queue_visual_videotimeline_update ()
4397 * pending_visual_change.add (VisualChange::VideoTimeline);
4398 * or maybe even more specific: which videotimeline-image
4399 * currently it calls update_video_timeline() to update
4400 * _all outdated_ images on the video-timeline.
4401 * see 'exposeimg()' in video_image_frame.cc
4403 ensure_visual_change_idle_handler ();
4407 Editor::ensure_visual_change_idle_handler ()
4409 if (pending_visual_change.idle_handler_id < 0) {
4410 // see comment in add_to_idle_resize above.
4411 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4412 pending_visual_change.being_handled = false;
4417 Editor::_idle_visual_changer (void* arg)
4419 return static_cast<Editor*>(arg)->idle_visual_changer ();
4423 Editor::idle_visual_changer ()
4425 /* set_horizontal_position() below (and maybe other calls) call
4426 gtk_main_iteration(), so it's possible that a signal will be handled
4427 half-way through this method. If this signal wants an
4428 idle_visual_changer we must schedule another one after this one, so
4429 mark the idle_handler_id as -1 here to allow that. Also make a note
4430 that we are doing the visual change, so that changes in response to
4431 super-rapid-screen-update can be dropped if we are still processing
4435 pending_visual_change.idle_handler_id = -1;
4436 pending_visual_change.being_handled = true;
4438 VisualChange vc = pending_visual_change;
4440 pending_visual_change.pending = (VisualChange::Type) 0;
4442 visual_changer (vc);
4444 pending_visual_change.being_handled = false;
4446 return 0; /* this is always a one-shot call */
4450 Editor::visual_changer (const VisualChange& vc)
4452 double const last_time_origin = horizontal_position ();
4454 if (vc.pending & VisualChange::ZoomLevel) {
4455 set_samples_per_pixel (vc.samples_per_pixel);
4457 compute_fixed_ruler_scale ();
4459 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4460 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4462 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4463 current_bbt_points_begin, current_bbt_points_end);
4464 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4465 current_bbt_points_begin, current_bbt_points_end);
4466 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4468 update_video_timeline();
4471 if (vc.pending & VisualChange::TimeOrigin) {
4472 set_horizontal_position (vc.time_origin / samples_per_pixel);
4475 if (vc.pending & VisualChange::YOrigin) {
4476 vertical_adjustment.set_value (vc.y_origin);
4479 if (last_time_origin == horizontal_position ()) {
4480 /* changed signal not emitted */
4481 update_fixed_rulers ();
4482 redisplay_tempo (true);
4485 if (!(vc.pending & VisualChange::ZoomLevel)) {
4486 update_video_timeline();
4489 _summary->set_overlays_dirty ();
4492 struct EditorOrderTimeAxisSorter {
4493 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4494 return a->order () < b->order ();
4499 Editor::sort_track_selection (TrackViewList& sel)
4501 EditorOrderTimeAxisSorter cmp;
4506 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4509 framepos_t where = 0;
4510 EditPoint ep = _edit_point;
4512 if(Profile->get_mixbus())
4513 if (ep == EditAtSelectedMarker)
4516 if (from_context_menu && (ep == EditAtMouse)) {
4517 return canvas_event_sample (&context_click_event, 0, 0);
4520 if (entered_marker) {
4521 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4522 return entered_marker->position();
4525 if (ignore_playhead && ep == EditAtPlayhead) {
4526 ep = EditAtSelectedMarker;
4530 case EditAtPlayhead:
4531 where = _session->audible_frame();
4532 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4535 case EditAtSelectedMarker:
4536 if (!selection->markers.empty()) {
4538 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4541 where = loc->start();
4545 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4553 if (!mouse_frame (where, ignored)) {
4554 /* XXX not right but what can we do ? */
4558 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4566 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4568 if (!_session) return;
4570 begin_reversible_command (cmd);
4574 if ((tll = transport_loop_location()) == 0) {
4575 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4576 XMLNode &before = _session->locations()->get_state();
4577 _session->locations()->add (loc, true);
4578 _session->set_auto_loop_location (loc);
4579 XMLNode &after = _session->locations()->get_state();
4580 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4582 XMLNode &before = tll->get_state();
4583 tll->set_hidden (false, this);
4584 tll->set (start, end);
4585 XMLNode &after = tll->get_state();
4586 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4589 commit_reversible_command ();
4593 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4595 if (!_session) return;
4597 begin_reversible_command (cmd);
4601 if ((tpl = transport_punch_location()) == 0) {
4602 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4603 XMLNode &before = _session->locations()->get_state();
4604 _session->locations()->add (loc, true);
4605 _session->set_auto_punch_location (loc);
4606 XMLNode &after = _session->locations()->get_state();
4607 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4609 XMLNode &before = tpl->get_state();
4610 tpl->set_hidden (false, this);
4611 tpl->set (start, end);
4612 XMLNode &after = tpl->get_state();
4613 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4616 commit_reversible_command ();
4619 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4620 * @param rs List to which found regions are added.
4621 * @param where Time to look at.
4622 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4625 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4627 const TrackViewList* tracks;
4630 tracks = &track_views;
4635 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4637 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4640 boost::shared_ptr<Track> tr;
4641 boost::shared_ptr<Playlist> pl;
4643 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4645 boost::shared_ptr<RegionList> regions = pl->regions_at (
4646 (framepos_t) floor ( (double) where * tr->speed()));
4648 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4649 RegionView* rv = rtv->view()->find_view (*i);
4660 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4662 const TrackViewList* tracks;
4665 tracks = &track_views;
4670 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4671 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4673 boost::shared_ptr<Track> tr;
4674 boost::shared_ptr<Playlist> pl;
4676 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4678 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4679 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4681 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4683 RegionView* rv = rtv->view()->find_view (*i);
4694 /** Get regions using the following method:
4696 * Make a region list using:
4697 * (a) any selected regions
4698 * (b) the intersection of any selected tracks and the edit point(*)
4699 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4701 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4703 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4707 Editor::get_regions_from_selection_and_edit_point ()
4709 RegionSelection regions;
4711 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4712 regions.add (entered_regionview);
4714 regions = selection->regions;
4717 if ( regions.empty() ) {
4718 TrackViewList tracks = selection->tracks;
4720 if (!tracks.empty()) {
4721 /* no region selected or entered, but some selected tracks:
4722 * act on all regions on the selected tracks at the edit point
4724 framepos_t const where = get_preferred_edit_position ();
4725 get_regions_at(regions, where, tracks);
4732 /** Get regions using the following method:
4734 * Make a region list using:
4735 * (a) any selected regions
4736 * (b) the intersection of any selected tracks and the edit point(*)
4737 * (c) if neither exists, then whatever region is under the mouse
4739 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4741 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4744 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4746 RegionSelection regions;
4748 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4749 regions.add (entered_regionview);
4751 regions = selection->regions;
4754 if ( regions.empty() ) {
4755 TrackViewList tracks = selection->tracks;
4757 if (!tracks.empty()) {
4758 /* no region selected or entered, but some selected tracks:
4759 * act on all regions on the selected tracks at the edit point
4761 get_regions_at(regions, pos, tracks);
4768 /** Start with regions that are selected, or the entered regionview if none are selected.
4769 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4770 * of the regions that we started with.
4774 Editor::get_regions_from_selection_and_entered ()
4776 RegionSelection regions = selection->regions;
4778 if (regions.empty() && entered_regionview) {
4779 regions.add (entered_regionview);
4786 Editor::get_regionviews_by_id (PBD::ID const & id, RegionSelection & regions) const
4788 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4789 RouteTimeAxisView* tatv;
4791 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4792 boost::shared_ptr<Playlist> pl;
4793 std::vector<boost::shared_ptr<Region> > results;
4794 boost::shared_ptr<Track> tr;
4796 if ((tr = tatv->track()) == 0) {
4801 if ((pl = (tr->playlist())) != 0) {
4802 boost::shared_ptr<Region> r = pl->region_by_id (id);
4804 RegionView* marv = tatv->view()->find_view (r);
4806 regions.push_back (marv);
4815 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4817 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4819 RouteTimeAxisView* tatv;
4821 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4823 boost::shared_ptr<Playlist> pl;
4824 vector<boost::shared_ptr<Region> > results;
4826 boost::shared_ptr<Track> tr;
4828 if ((tr = tatv->track()) == 0) {
4833 if ((pl = (tr->playlist())) != 0) {
4834 if (src_comparison) {
4835 pl->get_source_equivalent_regions (region, results);
4837 pl->get_region_list_equivalent_regions (region, results);
4841 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4842 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4843 regions.push_back (marv);
4852 Editor::show_rhythm_ferret ()
4854 if (rhythm_ferret == 0) {
4855 rhythm_ferret = new RhythmFerret(*this);
4858 rhythm_ferret->set_session (_session);
4859 rhythm_ferret->show ();
4860 rhythm_ferret->present ();
4864 Editor::first_idle ()
4866 MessageDialog* dialog = 0;
4868 if (track_views.size() > 1) {
4869 dialog = new MessageDialog (
4871 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4875 ARDOUR_UI::instance()->flush_pending ();
4878 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4882 // first idle adds route children (automation tracks), so we need to redisplay here
4883 _routes->redisplay ();
4890 Editor::_idle_resize (gpointer arg)
4892 return ((Editor*)arg)->idle_resize ();
4896 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4898 if (resize_idle_id < 0) {
4899 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
4900 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
4901 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
4903 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
4904 _pending_resize_amount = 0;
4907 /* make a note of the smallest resulting height, so that we can clamp the
4908 lower limit at TimeAxisView::hSmall */
4910 int32_t min_resulting = INT32_MAX;
4912 _pending_resize_amount += h;
4913 _pending_resize_view = view;
4915 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4917 if (selection->tracks.contains (_pending_resize_view)) {
4918 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4919 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4923 if (min_resulting < 0) {
4928 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4929 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4933 /** Handle pending resizing of tracks */
4935 Editor::idle_resize ()
4937 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4939 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4940 selection->tracks.contains (_pending_resize_view)) {
4942 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4943 if (*i != _pending_resize_view) {
4944 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4949 _pending_resize_amount = 0;
4950 _group_tabs->set_dirty ();
4951 resize_idle_id = -1;
4959 ENSURE_GUI_THREAD (*this, &Editor::located);
4962 playhead_cursor->set_position (_session->audible_frame ());
4963 if (_follow_playhead && !_pending_initial_locate) {
4964 reset_x_origin_to_follow_playhead ();
4968 _pending_locate_request = false;
4969 _pending_initial_locate = false;
4973 Editor::region_view_added (RegionView * rv)
4975 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
4976 if (rv->region ()->id () == (*pr)) {
4977 selection->add (rv);
4978 selection->regions.pending.erase (pr);
4982 _summary->set_background_dirty ();
4986 Editor::region_view_removed ()
4988 _summary->set_background_dirty ();
4992 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4994 TrackViewList::const_iterator j = track_views.begin ();
4995 while (j != track_views.end()) {
4996 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4997 if (rtv && rtv->route() == r) {
5008 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5012 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5013 TimeAxisView* tv = axis_view_from_route (*i);
5023 Editor::suspend_route_redisplay ()
5026 _routes->suspend_redisplay();
5031 Editor::resume_route_redisplay ()
5034 _routes->resume_redisplay();
5039 Editor::add_routes (RouteList& routes)
5041 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5043 RouteTimeAxisView *rtv;
5044 list<RouteTimeAxisView*> new_views;
5046 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5047 boost::shared_ptr<Route> route = (*x);
5049 if (route->is_auditioner() || route->is_monitor()) {
5053 DataType dt = route->input()->default_type();
5055 if (dt == ARDOUR::DataType::AUDIO) {
5056 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5057 rtv->set_route (route);
5058 } else if (dt == ARDOUR::DataType::MIDI) {
5059 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5060 rtv->set_route (route);
5062 throw unknown_type();
5065 new_views.push_back (rtv);
5066 track_views.push_back (rtv);
5068 rtv->effective_gain_display ();
5070 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5071 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5074 if (new_views.size() > 0) {
5075 _routes->routes_added (new_views);
5076 _summary->routes_added (new_views);
5079 if (show_editor_mixer_when_tracks_arrive) {
5080 show_editor_mixer (true);
5083 editor_list_button.set_sensitive (true);
5087 Editor::timeaxisview_deleted (TimeAxisView *tv)
5089 if (tv == entered_track) {
5093 if (_session && _session->deletion_in_progress()) {
5094 /* the situation is under control */
5098 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5100 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5102 _routes->route_removed (tv);
5104 TimeAxisView::Children c = tv->get_child_list ();
5105 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5106 if (entered_track == i->get()) {
5111 /* remove it from the list of track views */
5113 TrackViewList::iterator i;
5115 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5116 i = track_views.erase (i);
5119 /* update whatever the current mixer strip is displaying, if revelant */
5121 boost::shared_ptr<Route> route;
5124 route = rtav->route ();
5127 if (current_mixer_strip && current_mixer_strip->route() == route) {
5129 TimeAxisView* next_tv;
5131 if (track_views.empty()) {
5133 } else if (i == track_views.end()) {
5134 next_tv = track_views.front();
5141 set_selected_mixer_strip (*next_tv);
5143 /* make the editor mixer strip go away setting the
5144 * button to inactive (which also unticks the menu option)
5147 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5153 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5155 if (apply_to_selection) {
5156 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5158 TrackSelection::iterator j = i;
5161 hide_track_in_display (*i, false);
5166 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5168 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5169 // this will hide the mixer strip
5170 set_selected_mixer_strip (*tv);
5173 _routes->hide_track_in_display (*tv);
5178 Editor::sync_track_view_list_and_routes ()
5180 track_views = TrackViewList (_routes->views ());
5182 _summary->set_dirty ();
5183 _group_tabs->set_dirty ();
5185 return false; // do not call again (until needed)
5189 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5191 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5196 /** Find a RouteTimeAxisView by the ID of its route */
5198 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5200 RouteTimeAxisView* v;
5202 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5203 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5204 if(v->route()->id() == id) {
5214 Editor::fit_route_group (RouteGroup *g)
5216 TrackViewList ts = axis_views_from_routes (g->route_list ());
5221 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5223 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5226 _session->cancel_audition ();
5230 if (_session->is_auditioning()) {
5231 _session->cancel_audition ();
5232 if (r == last_audition_region) {
5237 _session->audition_region (r);
5238 last_audition_region = r;
5243 Editor::hide_a_region (boost::shared_ptr<Region> r)
5245 r->set_hidden (true);
5249 Editor::show_a_region (boost::shared_ptr<Region> r)
5251 r->set_hidden (false);
5255 Editor::audition_region_from_region_list ()
5257 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5261 Editor::hide_region_from_region_list ()
5263 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5267 Editor::show_region_in_region_list ()
5269 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5273 Editor::step_edit_status_change (bool yn)
5276 start_step_editing ();
5278 stop_step_editing ();
5283 Editor::start_step_editing ()
5285 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5289 Editor::stop_step_editing ()
5291 step_edit_connection.disconnect ();
5295 Editor::check_step_edit ()
5297 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5298 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5300 mtv->check_step_edit ();
5304 return true; // do it again, till we stop
5308 Editor::scroll_press (Direction dir)
5310 ++_scroll_callbacks;
5312 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5313 /* delay the first auto-repeat */
5319 scroll_backward (1);
5327 scroll_up_one_track ();
5331 scroll_down_one_track ();
5335 /* do hacky auto-repeat */
5336 if (!_scroll_connection.connected ()) {
5338 _scroll_connection = Glib::signal_timeout().connect (
5339 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5342 _scroll_callbacks = 0;
5349 Editor::scroll_release ()
5351 _scroll_connection.disconnect ();
5354 /** Queue a change for the Editor viewport x origin to follow the playhead */
5356 Editor::reset_x_origin_to_follow_playhead ()
5358 framepos_t const frame = playhead_cursor->current_frame ();
5360 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5362 if (_session->transport_speed() < 0) {
5364 if (frame > (current_page_samples() / 2)) {
5365 center_screen (frame-(current_page_samples()/2));
5367 center_screen (current_page_samples()/2);
5374 if (frame < leftmost_frame) {
5376 if (_session->transport_rolling()) {
5377 /* rolling; end up with the playhead at the right of the page */
5378 l = frame - current_page_samples ();
5380 /* not rolling: end up with the playhead 1/4 of the way along the page */
5381 l = frame - current_page_samples() / 4;
5385 if (_session->transport_rolling()) {
5386 /* rolling: end up with the playhead on the left of the page */
5389 /* not rolling: end up with the playhead 3/4 of the way along the page */
5390 l = frame - 3 * current_page_samples() / 4;
5398 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5404 Editor::super_rapid_screen_update ()
5406 if (!_session || !_session->engine().running()) {
5410 /* METERING / MIXER STRIPS */
5412 /* update track meters, if required */
5413 if (is_mapped() && meters_running) {
5414 RouteTimeAxisView* rtv;
5415 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5416 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5417 rtv->fast_update ();
5422 /* and any current mixer strip */
5423 if (current_mixer_strip) {
5424 current_mixer_strip->fast_update ();
5427 /* PLAYHEAD AND VIEWPORT */
5429 framepos_t const frame = _session->audible_frame();
5431 /* There are a few reasons why we might not update the playhead / viewport stuff:
5433 * 1. we don't update things when there's a pending locate request, otherwise
5434 * when the editor requests a locate there is a chance that this method
5435 * will move the playhead before the locate request is processed, causing
5437 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5438 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5441 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5443 last_update_frame = frame;
5445 if (!_dragging_playhead) {
5446 playhead_cursor->set_position (frame);
5449 if (!_stationary_playhead) {
5451 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5452 /* We only do this if we aren't already
5453 handling a visual change (ie if
5454 pending_visual_change.being_handled is
5455 false) so that these requests don't stack
5456 up there are too many of them to handle in
5459 reset_x_origin_to_follow_playhead ();
5464 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5468 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5469 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5470 if (target <= 0.0) {
5473 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5474 target = (target * 0.15) + (current * 0.85);
5480 set_horizontal_position (current);
5489 Editor::session_going_away ()
5491 _have_idled = false;
5493 _session_connections.drop_connections ();
5495 super_rapid_screen_update_connection.disconnect ();
5497 selection->clear ();
5498 cut_buffer->clear ();
5500 clicked_regionview = 0;
5501 clicked_axisview = 0;
5502 clicked_routeview = 0;
5503 entered_regionview = 0;
5505 last_update_frame = 0;
5508 playhead_cursor->hide ();
5510 /* rip everything out of the list displays */
5514 _route_groups->clear ();
5516 /* do this first so that deleting a track doesn't reset cms to null
5517 and thus cause a leak.
5520 if (current_mixer_strip) {
5521 if (current_mixer_strip->get_parent() != 0) {
5522 global_hpacker.remove (*current_mixer_strip);
5524 delete current_mixer_strip;
5525 current_mixer_strip = 0;
5528 /* delete all trackviews */
5530 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5533 track_views.clear ();
5535 nudge_clock->set_session (0);
5537 editor_list_button.set_active(false);
5538 editor_list_button.set_sensitive(false);
5540 /* clear tempo/meter rulers */
5541 remove_metric_marks ();
5543 clear_marker_display ();
5545 stop_step_editing ();
5547 /* get rid of any existing editor mixer strip */
5549 WindowTitle title(Glib::get_application_name());
5550 title += _("Editor");
5552 set_title (title.get_string());
5554 SessionHandlePtr::session_going_away ();
5559 Editor::show_editor_list (bool yn)
5562 _the_notebook.show ();
5564 _the_notebook.hide ();
5569 Editor::change_region_layering_order (bool from_context_menu)
5571 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5573 if (!clicked_routeview) {
5574 if (layering_order_editor) {
5575 layering_order_editor->hide ();
5580 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5586 boost::shared_ptr<Playlist> pl = track->playlist();
5592 if (layering_order_editor == 0) {
5593 layering_order_editor = new RegionLayeringOrderEditor (*this);
5596 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5597 layering_order_editor->maybe_present ();
5601 Editor::update_region_layering_order_editor ()
5603 if (layering_order_editor && layering_order_editor->is_visible ()) {
5604 change_region_layering_order (true);
5609 Editor::setup_fade_images ()
5611 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5612 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5613 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5614 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5615 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5617 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5618 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5619 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5620 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5621 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5623 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5624 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5625 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5626 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5627 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5629 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5630 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5631 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5632 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5633 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5637 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5639 Editor::action_menu_item (std::string const & name)
5641 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5644 return *manage (a->create_menu_item ());
5648 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5650 EventBox* b = manage (new EventBox);
5651 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5652 Label* l = manage (new Label (name));
5656 _the_notebook.append_page (widget, *b);
5660 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5662 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5663 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5666 if (ev->type == GDK_2BUTTON_PRESS) {
5668 /* double-click on a notebook tab shrinks or expands the notebook */
5670 if (_notebook_shrunk) {
5671 if (pre_notebook_shrink_pane_width) {
5672 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5674 _notebook_shrunk = false;
5676 pre_notebook_shrink_pane_width = edit_pane.get_position();
5678 /* this expands the LHS of the edit pane to cover the notebook
5679 PAGE but leaves the tabs visible.
5681 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5682 _notebook_shrunk = true;
5690 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5692 using namespace Menu_Helpers;
5694 MenuList& items = _control_point_context_menu.items ();
5697 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5698 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5699 if (!can_remove_control_point (item)) {
5700 items.back().set_sensitive (false);
5703 _control_point_context_menu.popup (event->button.button, event->button.time);
5707 Editor::zoom_vertical_modifier_released()
5709 _stepping_axis_view = 0;
5713 Editor::ui_parameter_changed (string parameter)
5715 if (parameter == "icon-set") {
5716 while (!_cursor_stack.empty()) {
5717 _cursor_stack.pop();
5719 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5720 } else if (parameter == "draggable-playhead") {
5721 if (_verbose_cursor) {
5722 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());