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_region_view.h"
111 #include "midi_time_axis.h"
112 #include "mixer_strip.h"
113 #include "mixer_ui.h"
114 #include "mouse_cursors.h"
115 #include "note_base.h"
116 #include "playlist_selector.h"
117 #include "public_editor.h"
118 #include "region_layering_order_editor.h"
119 #include "rgb_macros.h"
120 #include "rhythm_ferret.h"
121 #include "selection.h"
123 #include "tempo_lines.h"
124 #include "time_axis_view.h"
126 #include "verbose_cursor.h"
131 using namespace ARDOUR;
132 using namespace ARDOUR_UI_UTILS;
135 using namespace Glib;
136 using namespace Gtkmm2ext;
137 using namespace Editing;
139 using PBD::internationalize;
141 using Gtkmm2ext::Keyboard;
143 double Editor::timebar_height = 15.0;
145 static const gchar *_snap_type_strings[] = {
179 static const gchar *_snap_mode_strings[] = {
186 static const gchar *_edit_point_strings[] = {
193 static const gchar *_edit_mode_strings[] = {
201 static const gchar *_zoom_focus_strings[] = {
211 #ifdef USE_RUBBERBAND
212 static const gchar *_rb_opt_strings[] = {
215 N_("Balanced multitimbral mixture"),
216 N_("Unpitched percussion with stable notes"),
217 N_("Crisp monophonic instrumental"),
218 N_("Unpitched solo percussion"),
219 N_("Resample without preserving pitch"),
224 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
227 pane_size_watcher (Paned* pane)
229 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
233 Quartz: impossible to access
235 so stop that by preventing it from ever getting too narrow. 35
236 pixels is basically a rough guess at the tab width.
241 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
243 gint pos = pane->get_position ();
245 if (pos > max_width_of_lhs) {
246 pane->set_position (max_width_of_lhs);
251 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
253 /* time display buttons */
254 , minsec_label (_("Mins:Secs"))
255 , bbt_label (_("Bars:Beats"))
256 , timecode_label (_("Timecode"))
257 , samples_label (_("Samples"))
258 , tempo_label (_("Tempo"))
259 , meter_label (_("Meter"))
260 , mark_label (_("Location Markers"))
261 , range_mark_label (_("Range Markers"))
262 , transport_mark_label (_("Loop/Punch Ranges"))
263 , cd_mark_label (_("CD Markers"))
264 , videotl_label (_("Video Timeline"))
265 , edit_packer (4, 4, true)
267 /* the values here don't matter: layout widgets
268 reset them as needed.
271 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
272 , horizontal_adjustment (0.0, 0.0, 1e16)
273 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
275 , controls_layout (unused_adjustment, vertical_adjustment)
277 /* tool bar related */
279 , toolbar_selection_clock_table (2,3)
280 , _mouse_mode_tearoff (0)
281 , automation_mode_button (_("mode"))
285 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
289 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
290 , meters_running(false)
291 , _pending_locate_request (false)
292 , _pending_initial_locate (false)
293 , _last_cut_copy_source_track (0)
295 , _region_selection_change_updates_region_list (true)
296 , _following_mixer_selection (false)
297 , _control_point_toggled_on_press (false)
298 , _stepping_axis_view (0)
302 /* we are a singleton */
304 PublicEditor::_instance = this;
308 selection = new Selection (this);
309 cut_buffer = new Selection (this);
310 _selection_memento = new SelectionMemento ();
313 clicked_regionview = 0;
314 clicked_axisview = 0;
315 clicked_routeview = 0;
316 clicked_control_point = 0;
317 last_update_frame = 0;
320 _drags = new DragManager (this);
323 current_mixer_strip = 0;
326 snap_type_strings = I18N (_snap_type_strings);
327 snap_mode_strings = I18N (_snap_mode_strings);
328 zoom_focus_strings = I18N (_zoom_focus_strings);
329 edit_mode_strings = I18N (_edit_mode_strings);
330 edit_point_strings = I18N (_edit_point_strings);
331 #ifdef USE_RUBBERBAND
332 rb_opt_strings = I18N (_rb_opt_strings);
336 build_edit_mode_menu();
337 build_zoom_focus_menu();
338 build_track_count_menu();
339 build_snap_mode_menu();
340 build_snap_type_menu();
341 build_edit_point_menu();
343 snap_threshold = 5.0;
344 bbt_beat_subdivision = 4;
345 _visible_canvas_width = 0;
346 _visible_canvas_height = 0;
347 autoscroll_horizontal_allowed = false;
348 autoscroll_vertical_allowed = false;
353 current_interthread_info = 0;
354 _show_measures = true;
356 show_gain_after_trim = false;
358 have_pending_keyboard_selection = false;
359 _follow_playhead = true;
360 _stationary_playhead = false;
361 editor_ruler_menu = 0;
362 no_ruler_shown_update = false;
364 range_marker_menu = 0;
365 marker_menu_item = 0;
366 tempo_or_meter_marker_menu = 0;
367 transport_marker_menu = 0;
368 new_transport_marker_menu = 0;
369 editor_mixer_strip_width = Wide;
370 show_editor_mixer_when_tracks_arrive = false;
371 region_edit_menu_split_multichannel_item = 0;
372 region_edit_menu_split_item = 0;
375 current_stepping_trackview = 0;
377 entered_regionview = 0;
379 clear_entered_track = false;
382 button_release_can_deselect = true;
383 _dragging_playhead = false;
384 _dragging_edit_point = false;
385 select_new_marker = false;
387 layering_order_editor = 0;
388 no_save_visual = false;
390 within_track_canvas = false;
392 scrubbing_direction = 0;
396 location_marker_color = ARDOUR_UI::config()->color ("location marker");
397 location_range_color = ARDOUR_UI::config()->color ("location range");
398 location_cd_marker_color = ARDOUR_UI::config()->color ("location cd marker");
399 location_loop_color = ARDOUR_UI::config()->color ("location loop");
400 location_punch_color = ARDOUR_UI::config()->color ("location punch");
402 zoom_focus = ZoomFocusLeft;
403 _edit_point = EditAtMouse;
404 _visible_track_count = -1;
406 samples_per_pixel = 2048; /* too early to use reset_zoom () */
408 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::config()->get_font_scale() / 102400.));
409 TimeAxisView::setup_sizes ();
410 Marker::setup_sizes (timebar_height);
412 _scroll_callbacks = 0;
414 bbt_label.set_name ("EditorRulerLabel");
415 bbt_label.set_size_request (-1, (int)timebar_height);
416 bbt_label.set_alignment (1.0, 0.5);
417 bbt_label.set_padding (5,0);
419 bbt_label.set_no_show_all();
420 minsec_label.set_name ("EditorRulerLabel");
421 minsec_label.set_size_request (-1, (int)timebar_height);
422 minsec_label.set_alignment (1.0, 0.5);
423 minsec_label.set_padding (5,0);
424 minsec_label.hide ();
425 minsec_label.set_no_show_all();
426 timecode_label.set_name ("EditorRulerLabel");
427 timecode_label.set_size_request (-1, (int)timebar_height);
428 timecode_label.set_alignment (1.0, 0.5);
429 timecode_label.set_padding (5,0);
430 timecode_label.hide ();
431 timecode_label.set_no_show_all();
432 samples_label.set_name ("EditorRulerLabel");
433 samples_label.set_size_request (-1, (int)timebar_height);
434 samples_label.set_alignment (1.0, 0.5);
435 samples_label.set_padding (5,0);
436 samples_label.hide ();
437 samples_label.set_no_show_all();
439 tempo_label.set_name ("EditorRulerLabel");
440 tempo_label.set_size_request (-1, (int)timebar_height);
441 tempo_label.set_alignment (1.0, 0.5);
442 tempo_label.set_padding (5,0);
444 tempo_label.set_no_show_all();
446 meter_label.set_name ("EditorRulerLabel");
447 meter_label.set_size_request (-1, (int)timebar_height);
448 meter_label.set_alignment (1.0, 0.5);
449 meter_label.set_padding (5,0);
451 meter_label.set_no_show_all();
453 if (Profile->get_trx()) {
454 mark_label.set_text (_("Markers"));
456 mark_label.set_name ("EditorRulerLabel");
457 mark_label.set_size_request (-1, (int)timebar_height);
458 mark_label.set_alignment (1.0, 0.5);
459 mark_label.set_padding (5,0);
461 mark_label.set_no_show_all();
463 cd_mark_label.set_name ("EditorRulerLabel");
464 cd_mark_label.set_size_request (-1, (int)timebar_height);
465 cd_mark_label.set_alignment (1.0, 0.5);
466 cd_mark_label.set_padding (5,0);
467 cd_mark_label.hide();
468 cd_mark_label.set_no_show_all();
470 videotl_bar_height = 4;
471 videotl_label.set_name ("EditorRulerLabel");
472 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
473 videotl_label.set_alignment (1.0, 0.5);
474 videotl_label.set_padding (5,0);
475 videotl_label.hide();
476 videotl_label.set_no_show_all();
478 range_mark_label.set_name ("EditorRulerLabel");
479 range_mark_label.set_size_request (-1, (int)timebar_height);
480 range_mark_label.set_alignment (1.0, 0.5);
481 range_mark_label.set_padding (5,0);
482 range_mark_label.hide();
483 range_mark_label.set_no_show_all();
485 transport_mark_label.set_name ("EditorRulerLabel");
486 transport_mark_label.set_size_request (-1, (int)timebar_height);
487 transport_mark_label.set_alignment (1.0, 0.5);
488 transport_mark_label.set_padding (5,0);
489 transport_mark_label.hide();
490 transport_mark_label.set_no_show_all();
492 initialize_canvas ();
494 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
496 _summary = new EditorSummary (this);
498 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
499 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
501 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
503 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
504 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
506 edit_controls_vbox.set_spacing (0);
507 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
508 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
510 HBox* h = manage (new HBox);
511 _group_tabs = new EditorGroupTabs (this);
512 if (!ARDOUR::Profile->get_trx()) {
513 h->pack_start (*_group_tabs, PACK_SHRINK);
515 h->pack_start (edit_controls_vbox);
516 controls_layout.add (*h);
518 controls_layout.set_name ("EditControlsBase");
519 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
520 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
521 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
523 _cursors = new MouseCursors;
524 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
525 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
527 /* Push default cursor to ever-present bottom of cursor stack. */
528 push_canvas_cursor(_cursors->grabber);
530 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
532 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
533 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
534 pad_line_1->set_outline_color (0xFF0000FF);
540 edit_packer.set_col_spacings (0);
541 edit_packer.set_row_spacings (0);
542 edit_packer.set_homogeneous (false);
543 edit_packer.set_border_width (0);
544 edit_packer.set_name ("EditorWindow");
546 time_bars_event_box.add (time_bars_vbox);
547 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
548 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
550 /* labels for the time bars */
551 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
553 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
555 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
557 bottom_hbox.set_border_width (2);
558 bottom_hbox.set_spacing (3);
560 _route_groups = new EditorRouteGroups (this);
561 _routes = new EditorRoutes (this);
562 _regions = new EditorRegions (this);
563 _snapshots = new EditorSnapshots (this);
564 _locations = new EditorLocations (this);
566 /* these are static location signals */
568 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
569 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
570 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
572 add_notebook_page (_("Regions"), _regions->widget ());
573 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
574 add_notebook_page (_("Snapshots"), _snapshots->widget ());
575 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
576 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
578 _the_notebook.set_show_tabs (true);
579 _the_notebook.set_scrollable (true);
580 _the_notebook.popup_disable ();
581 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
582 _the_notebook.show_all ();
584 _notebook_shrunk = false;
586 editor_summary_pane.pack1(edit_packer);
588 Button* summary_arrows_left_left = manage (new Button);
589 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
590 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
591 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
593 Button* summary_arrows_left_right = manage (new Button);
594 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
595 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
596 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
598 VBox* summary_arrows_left = manage (new VBox);
599 summary_arrows_left->pack_start (*summary_arrows_left_left);
600 summary_arrows_left->pack_start (*summary_arrows_left_right);
602 Button* summary_arrows_right_up = manage (new Button);
603 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
604 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
605 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
607 Button* summary_arrows_right_down = manage (new Button);
608 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
609 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
610 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
612 VBox* summary_arrows_right = manage (new VBox);
613 summary_arrows_right->pack_start (*summary_arrows_right_up);
614 summary_arrows_right->pack_start (*summary_arrows_right_down);
616 Frame* summary_frame = manage (new Frame);
617 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
619 summary_frame->add (*_summary);
620 summary_frame->show ();
622 _summary_hbox.pack_start (*summary_arrows_left, false, false);
623 _summary_hbox.pack_start (*summary_frame, true, true);
624 _summary_hbox.pack_start (*summary_arrows_right, false, false);
626 if (!ARDOUR::Profile->get_trx()) {
627 editor_summary_pane.pack2 (_summary_hbox);
630 edit_pane.pack1 (editor_summary_pane, true, true);
631 if (!ARDOUR::Profile->get_trx()) {
632 edit_pane.pack2 (_the_notebook, false, true);
635 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
637 /* XXX: editor_summary_pane might need similar to the edit_pane */
639 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
641 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
642 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
644 top_hbox.pack_start (toolbar_frame);
646 HBox *hbox = manage (new HBox);
647 hbox->pack_start (edit_pane, true, true);
649 global_vpacker.pack_start (top_hbox, false, false);
650 global_vpacker.pack_start (*hbox, true, true);
652 global_hpacker.pack_start (global_vpacker, true, true);
654 set_name ("EditorWindow");
655 add_accel_group (ActionManager::ui_manager->get_accel_group());
657 status_bar_hpacker.show ();
659 vpacker.pack_end (status_bar_hpacker, false, false);
660 vpacker.pack_end (global_hpacker, true, true);
662 /* register actions now so that set_state() can find them and set toggles/checks etc */
665 /* when we start using our own keybinding system for the editor, this
666 * will be uncommented
672 set_zoom_focus (zoom_focus);
673 set_visible_track_count (_visible_track_count);
674 _snap_type = SnapToBeat;
675 set_snap_to (_snap_type);
676 _snap_mode = SnapOff;
677 set_snap_mode (_snap_mode);
678 set_mouse_mode (MouseObject, true);
679 pre_internal_mouse_mode = MouseObject;
680 pre_internal_snap_type = _snap_type;
681 pre_internal_snap_mode = _snap_mode;
682 internal_snap_type = _snap_type;
683 internal_snap_mode = _snap_mode;
684 set_edit_point_preference (EditAtMouse, true);
686 _playlist_selector = new PlaylistSelector();
687 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
689 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
693 nudge_forward_button.set_name ("nudge button");
694 nudge_forward_button.set_image(::get_icon("nudge_right"));
696 nudge_backward_button.set_name ("nudge button");
697 nudge_backward_button.set_image(::get_icon("nudge_left"));
699 fade_context_menu.set_name ("ArdourContextMenu");
701 /* icons, titles, WM stuff */
703 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
704 Glib::RefPtr<Gdk::Pixbuf> icon;
706 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
707 window_icons.push_back (icon);
709 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
710 window_icons.push_back (icon);
712 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
713 window_icons.push_back (icon);
715 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
716 window_icons.push_back (icon);
718 if (!window_icons.empty()) {
719 // set_icon_list (window_icons);
720 set_default_icon_list (window_icons);
723 WindowTitle title(Glib::get_application_name());
724 title += _("Editor");
725 set_title (title.get_string());
726 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
729 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
731 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
732 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
734 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
736 /* allow external control surfaces/protocols to do various things */
738 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
739 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
740 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
741 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
742 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
743 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
744 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
745 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
746 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
747 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
748 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
749 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
750 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
751 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
753 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
754 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
755 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
756 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
757 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
759 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
761 /* problematic: has to return a value and thus cannot be x-thread */
763 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
765 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
766 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
768 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
770 _ignore_region_action = false;
771 _last_region_menu_was_main = false;
772 _popup_region_menu_item = 0;
774 _ignore_follow_edits = false;
776 _show_marker_lines = false;
778 /* Button bindings */
780 button_bindings = new Bindings;
782 XMLNode* node = button_settings();
784 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
785 button_bindings->load (**i);
791 /* grab current parameter state */
792 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
793 ARDOUR_UI::config()->map_parameters (pc);
795 setup_fade_images ();
802 delete button_bindings;
804 delete _route_groups;
805 delete _track_canvas_viewport;
811 Editor::button_settings () const
813 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
814 XMLNode* node = find_named_node (*settings, X_("Buttons"));
817 node = new XMLNode (X_("Buttons"));
824 Editor::add_toplevel_menu (Container& cont)
826 vpacker.pack_start (cont, false, false);
831 Editor::add_transport_frame (Container& cont)
833 if(ARDOUR::Profile->get_mixbus()) {
834 global_vpacker.pack_start (cont, false, false);
835 global_vpacker.reorder_child (cont, 0);
838 vpacker.pack_start (cont, false, false);
843 Editor::get_smart_mode () const
845 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
849 Editor::catch_vanishing_regionview (RegionView *rv)
851 /* note: the selection will take care of the vanishing
852 audioregionview by itself.
855 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
859 if (clicked_regionview == rv) {
860 clicked_regionview = 0;
863 if (entered_regionview == rv) {
864 set_entered_regionview (0);
867 if (!_all_region_actions_sensitized) {
868 sensitize_all_region_actions (true);
873 Editor::set_entered_regionview (RegionView* rv)
875 if (rv == entered_regionview) {
879 if (entered_regionview) {
880 entered_regionview->exited ();
883 entered_regionview = rv;
885 if (entered_regionview != 0) {
886 entered_regionview->entered ();
889 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
890 /* This RegionView entry might have changed what region actions
891 are allowed, so sensitize them all in case a key is pressed.
893 sensitize_all_region_actions (true);
898 Editor::set_entered_track (TimeAxisView* tav)
901 entered_track->exited ();
907 entered_track->entered ();
912 Editor::show_window ()
914 if (!is_visible ()) {
918 /* XXX: this is a bit unfortunate; it would probably
919 be nicer if we could just call show () above rather
920 than needing the show_all ()
923 /* re-hide stuff if necessary */
924 editor_list_button_toggled ();
925 parameter_changed ("show-summary");
926 parameter_changed ("show-group-tabs");
927 parameter_changed ("show-zoom-tools");
929 /* now reset all audio_time_axis heights, because widgets might need
935 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
936 tv = (static_cast<TimeAxisView*>(*i));
940 if (current_mixer_strip) {
941 current_mixer_strip->hide_things ();
942 current_mixer_strip->parameter_changed ("mixer-element-visibility");
950 Editor::instant_save ()
952 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
957 _session->add_instant_xml(get_state());
959 Config->add_instant_xml(get_state());
964 Editor::control_vertical_zoom_in_all ()
966 tav_zoom_smooth (false, true);
970 Editor::control_vertical_zoom_out_all ()
972 tav_zoom_smooth (true, true);
976 Editor::control_vertical_zoom_in_selected ()
978 tav_zoom_smooth (false, false);
982 Editor::control_vertical_zoom_out_selected ()
984 tav_zoom_smooth (true, false);
988 Editor::control_view (uint32_t view)
990 goto_visual_state (view);
994 Editor::control_unselect ()
996 selection->clear_tracks ();
1000 Editor::control_select (uint32_t rid, Selection::Operation op)
1002 /* handles the (static) signal from the ControlProtocol class that
1003 * requests setting the selected track to a given RID
1010 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1016 TimeAxisView* tav = axis_view_from_route (r);
1020 case Selection::Add:
1021 selection->add (tav);
1023 case Selection::Toggle:
1024 selection->toggle (tav);
1026 case Selection::Extend:
1028 case Selection::Set:
1029 selection->set (tav);
1033 selection->clear_tracks ();
1038 Editor::control_step_tracks_up ()
1040 scroll_tracks_up_line ();
1044 Editor::control_step_tracks_down ()
1046 scroll_tracks_down_line ();
1050 Editor::control_scroll (float fraction)
1052 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1058 double step = fraction * current_page_samples();
1061 _control_scroll_target is an optional<T>
1063 it acts like a pointer to an framepos_t, with
1064 a operator conversion to boolean to check
1065 that it has a value could possibly use
1066 playhead_cursor->current_frame to store the
1067 value and a boolean in the class to know
1068 when it's out of date
1071 if (!_control_scroll_target) {
1072 _control_scroll_target = _session->transport_frame();
1073 _dragging_playhead = true;
1076 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1077 *_control_scroll_target = 0;
1078 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1079 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1081 *_control_scroll_target += (framepos_t) trunc (step);
1084 /* move visuals, we'll catch up with it later */
1086 playhead_cursor->set_position (*_control_scroll_target);
1087 UpdateAllTransportClocks (*_control_scroll_target);
1089 if (*_control_scroll_target > (current_page_samples() / 2)) {
1090 /* try to center PH in window */
1091 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1097 Now we do a timeout to actually bring the session to the right place
1098 according to the playhead. This is to avoid reading disk buffers on every
1099 call to control_scroll, which is driven by ScrollTimeline and therefore
1100 probably by a control surface wheel which can generate lots of events.
1102 /* cancel the existing timeout */
1104 control_scroll_connection.disconnect ();
1106 /* add the next timeout */
1108 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1112 Editor::deferred_control_scroll (framepos_t /*target*/)
1114 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1115 // reset for next stream
1116 _control_scroll_target = boost::none;
1117 _dragging_playhead = false;
1122 Editor::access_action (std::string action_group, std::string action_item)
1128 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1131 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1139 Editor::on_realize ()
1141 Window::on_realize ();
1144 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1145 start_lock_event_timing ();
1148 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1152 Editor::start_lock_event_timing ()
1154 /* check if we should lock the GUI every 30 seconds */
1156 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1160 Editor::generic_event_handler (GdkEvent* ev)
1163 case GDK_BUTTON_PRESS:
1164 case GDK_BUTTON_RELEASE:
1165 case GDK_MOTION_NOTIFY:
1167 case GDK_KEY_RELEASE:
1168 gettimeofday (&last_event_time, 0);
1171 case GDK_LEAVE_NOTIFY:
1172 switch (ev->crossing.detail) {
1173 case GDK_NOTIFY_UNKNOWN:
1174 case GDK_NOTIFY_INFERIOR:
1175 case GDK_NOTIFY_ANCESTOR:
1177 case GDK_NOTIFY_VIRTUAL:
1178 case GDK_NOTIFY_NONLINEAR:
1179 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1180 /* leaving window, so reset focus, thus ending any and
1181 all text entry operations.
1196 Editor::lock_timeout_callback ()
1198 struct timeval now, delta;
1200 gettimeofday (&now, 0);
1202 timersub (&now, &last_event_time, &delta);
1204 if (delta.tv_sec > (time_t) ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1206 /* don't call again. Returning false will effectively
1207 disconnect us from the timer callback.
1209 unlock() will call start_lock_event_timing() to get things
1219 Editor::map_position_change (framepos_t frame)
1221 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1223 if (_session == 0) {
1227 if (_follow_playhead) {
1228 center_screen (frame);
1231 playhead_cursor->set_position (frame);
1235 Editor::center_screen (framepos_t frame)
1237 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1239 /* if we're off the page, then scroll.
1242 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1243 center_screen_internal (frame, page);
1248 Editor::center_screen_internal (framepos_t frame, float page)
1253 frame -= (framepos_t) page;
1258 reset_x_origin (frame);
1263 Editor::update_title ()
1265 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1268 bool dirty = _session->dirty();
1270 string session_name;
1272 if (_session->snap_name() != _session->name()) {
1273 session_name = _session->snap_name();
1275 session_name = _session->name();
1279 session_name = "*" + session_name;
1282 WindowTitle title(session_name);
1283 title += Glib::get_application_name();
1284 set_title (title.get_string());
1286 /* ::session_going_away() will have taken care of it */
1291 Editor::set_session (Session *t)
1293 SessionHandlePtr::set_session (t);
1299 _playlist_selector->set_session (_session);
1300 nudge_clock->set_session (_session);
1301 _summary->set_session (_session);
1302 _group_tabs->set_session (_session);
1303 _route_groups->set_session (_session);
1304 _regions->set_session (_session);
1305 _snapshots->set_session (_session);
1306 _routes->set_session (_session);
1307 _locations->set_session (_session);
1309 if (rhythm_ferret) {
1310 rhythm_ferret->set_session (_session);
1313 if (analysis_window) {
1314 analysis_window->set_session (_session);
1318 sfbrowser->set_session (_session);
1321 compute_fixed_ruler_scale ();
1323 /* Make sure we have auto loop and auto punch ranges */
1325 Location* loc = _session->locations()->auto_loop_location();
1327 loc->set_name (_("Loop"));
1330 loc = _session->locations()->auto_punch_location();
1333 loc->set_name (_("Punch"));
1336 refresh_location_display ();
1338 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1339 the selected Marker; this needs the LocationMarker list to be available.
1341 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1342 set_state (*node, Stateful::loading_state_version);
1344 /* catch up with the playhead */
1346 _session->request_locate (playhead_cursor->current_frame ());
1347 _pending_initial_locate = true;
1351 /* These signals can all be emitted by a non-GUI thread. Therefore the
1352 handlers for them must not attempt to directly interact with the GUI,
1353 but use PBD::Signal<T>::connect() which accepts an event loop
1354 ("context") where the handler will be asked to run.
1357 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1358 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1359 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1360 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1361 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1362 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1363 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1364 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1365 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1366 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1367 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1368 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1369 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1371 playhead_cursor->show ();
1373 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1374 Config->map_parameters (pc);
1375 _session->config.map_parameters (pc);
1377 restore_ruler_visibility ();
1378 //tempo_map_changed (PropertyChange (0));
1379 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1381 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1382 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1385 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1386 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1389 switch (_snap_type) {
1390 case SnapToRegionStart:
1391 case SnapToRegionEnd:
1392 case SnapToRegionSync:
1393 case SnapToRegionBoundary:
1394 build_region_boundary_cache ();
1401 /* register for undo history */
1402 _session->register_with_memento_command_factory(id(), this);
1403 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1405 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1407 start_updating_meters ();
1411 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1413 if (a->get_name() == "RegionMenu") {
1414 /* When the main menu's region menu is opened, we setup the actions so that they look right
1415 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1416 so we resensitize all region actions when the entered regionview or the region selection
1417 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1418 happens after the region context menu is opened. So we set a flag here, too.
1422 sensitize_the_right_region_actions ();
1423 _last_region_menu_was_main = true;
1428 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1430 using namespace Menu_Helpers;
1432 void (Editor::*emf)(FadeShape);
1433 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1436 images = &_xfade_in_images;
1437 emf = &Editor::set_fade_in_shape;
1439 images = &_xfade_out_images;
1440 emf = &Editor::set_fade_out_shape;
1445 _("Linear (for highly correlated material)"),
1446 *(*images)[FadeLinear],
1447 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1451 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1455 _("Constant power"),
1456 *(*images)[FadeConstantPower],
1457 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1460 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1465 *(*images)[FadeSymmetric],
1466 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1470 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1475 *(*images)[FadeSlow],
1476 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1479 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1484 *(*images)[FadeFast],
1485 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1488 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1491 /** Pop up a context menu for when the user clicks on a start crossfade */
1493 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1495 using namespace Menu_Helpers;
1496 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1501 MenuList& items (xfade_in_context_menu.items());
1504 if (arv->audio_region()->fade_in_active()) {
1505 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1507 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1510 items.push_back (SeparatorElem());
1511 fill_xfade_menu (items, true);
1513 xfade_in_context_menu.popup (button, time);
1516 /** Pop up a context menu for when the user clicks on an end crossfade */
1518 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1520 using namespace Menu_Helpers;
1521 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1526 MenuList& items (xfade_out_context_menu.items());
1529 if (arv->audio_region()->fade_out_active()) {
1530 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1532 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1535 items.push_back (SeparatorElem());
1536 fill_xfade_menu (items, false);
1538 xfade_out_context_menu.popup (button, time);
1542 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1544 using namespace Menu_Helpers;
1545 Menu* (Editor::*build_menu_function)();
1548 switch (item_type) {
1550 case RegionViewName:
1551 case RegionViewNameHighlight:
1552 case LeftFrameHandle:
1553 case RightFrameHandle:
1554 if (with_selection) {
1555 build_menu_function = &Editor::build_track_selection_context_menu;
1557 build_menu_function = &Editor::build_track_region_context_menu;
1562 if (with_selection) {
1563 build_menu_function = &Editor::build_track_selection_context_menu;
1565 build_menu_function = &Editor::build_track_context_menu;
1570 if (clicked_routeview->track()) {
1571 build_menu_function = &Editor::build_track_context_menu;
1573 build_menu_function = &Editor::build_track_bus_context_menu;
1578 /* probably shouldn't happen but if it does, we don't care */
1582 menu = (this->*build_menu_function)();
1583 menu->set_name ("ArdourContextMenu");
1585 /* now handle specific situations */
1587 switch (item_type) {
1589 case RegionViewName:
1590 case RegionViewNameHighlight:
1591 case LeftFrameHandle:
1592 case RightFrameHandle:
1593 if (!with_selection) {
1594 if (region_edit_menu_split_item) {
1595 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1596 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1598 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1601 if (region_edit_menu_split_multichannel_item) {
1602 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1603 region_edit_menu_split_multichannel_item->set_sensitive (true);
1605 region_edit_menu_split_multichannel_item->set_sensitive (false);
1618 /* probably shouldn't happen but if it does, we don't care */
1622 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1624 /* Bounce to disk */
1626 using namespace Menu_Helpers;
1627 MenuList& edit_items = menu->items();
1629 edit_items.push_back (SeparatorElem());
1631 switch (clicked_routeview->audio_track()->freeze_state()) {
1632 case AudioTrack::NoFreeze:
1633 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1636 case AudioTrack::Frozen:
1637 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1640 case AudioTrack::UnFrozen:
1641 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1647 if (item_type == StreamItem && clicked_routeview) {
1648 clicked_routeview->build_underlay_menu(menu);
1651 /* When the region menu is opened, we setup the actions so that they look right
1654 sensitize_the_right_region_actions ();
1655 _last_region_menu_was_main = false;
1657 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1658 menu->popup (button, time);
1662 Editor::build_track_context_menu ()
1664 using namespace Menu_Helpers;
1666 MenuList& edit_items = track_context_menu.items();
1669 add_dstream_context_items (edit_items);
1670 return &track_context_menu;
1674 Editor::build_track_bus_context_menu ()
1676 using namespace Menu_Helpers;
1678 MenuList& edit_items = track_context_menu.items();
1681 add_bus_context_items (edit_items);
1682 return &track_context_menu;
1686 Editor::build_track_region_context_menu ()
1688 using namespace Menu_Helpers;
1689 MenuList& edit_items = track_region_context_menu.items();
1692 /* we've just cleared the track region context menu, so the menu that these
1693 two items were on will have disappeared; stop them dangling.
1695 region_edit_menu_split_item = 0;
1696 region_edit_menu_split_multichannel_item = 0;
1698 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1701 boost::shared_ptr<Track> tr;
1702 boost::shared_ptr<Playlist> pl;
1704 if ((tr = rtv->track())) {
1705 add_region_context_items (edit_items, tr);
1709 add_dstream_context_items (edit_items);
1711 return &track_region_context_menu;
1715 Editor::analyze_region_selection ()
1717 if (analysis_window == 0) {
1718 analysis_window = new AnalysisWindow();
1721 analysis_window->set_session(_session);
1723 analysis_window->show_all();
1726 analysis_window->set_regionmode();
1727 analysis_window->analyze();
1729 analysis_window->present();
1733 Editor::analyze_range_selection()
1735 if (analysis_window == 0) {
1736 analysis_window = new AnalysisWindow();
1739 analysis_window->set_session(_session);
1741 analysis_window->show_all();
1744 analysis_window->set_rangemode();
1745 analysis_window->analyze();
1747 analysis_window->present();
1751 Editor::build_track_selection_context_menu ()
1753 using namespace Menu_Helpers;
1754 MenuList& edit_items = track_selection_context_menu.items();
1755 edit_items.clear ();
1757 add_selection_context_items (edit_items);
1758 // edit_items.push_back (SeparatorElem());
1759 // add_dstream_context_items (edit_items);
1761 return &track_selection_context_menu;
1765 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1767 using namespace Menu_Helpers;
1769 /* OK, stick the region submenu at the top of the list, and then add
1773 RegionSelection rs = get_regions_from_selection_and_entered ();
1775 string::size_type pos = 0;
1776 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1778 /* we have to hack up the region name because "_" has a special
1779 meaning for menu titles.
1782 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1783 menu_item_name.replace (pos, 1, "__");
1787 if (_popup_region_menu_item == 0) {
1788 _popup_region_menu_item = new MenuItem (menu_item_name);
1789 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1790 _popup_region_menu_item->show ();
1792 _popup_region_menu_item->set_label (menu_item_name);
1795 const framepos_t position = get_preferred_edit_position (false, true);
1797 edit_items.push_back (*_popup_region_menu_item);
1798 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1799 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1801 edit_items.push_back (SeparatorElem());
1804 /** Add context menu items relevant to selection ranges.
1805 * @param edit_items List to add the items to.
1808 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1810 using namespace Menu_Helpers;
1812 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1813 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1815 edit_items.push_back (SeparatorElem());
1816 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1818 edit_items.push_back (SeparatorElem());
1819 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1821 edit_items.push_back (SeparatorElem());
1823 edit_items.push_back (
1825 _("Move Range Start to Previous Region Boundary"),
1826 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1830 edit_items.push_back (
1832 _("Move Range Start to Next Region Boundary"),
1833 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1837 edit_items.push_back (
1839 _("Move Range End to Previous Region Boundary"),
1840 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1844 edit_items.push_back (
1846 _("Move Range End to Next Region Boundary"),
1847 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1851 edit_items.push_back (SeparatorElem());
1852 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1853 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1855 edit_items.push_back (SeparatorElem());
1856 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1858 edit_items.push_back (SeparatorElem());
1859 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1860 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1861 edit_items.push_back (MenuElem (_("Set Session Start/End from Range"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1863 edit_items.push_back (SeparatorElem());
1864 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1866 edit_items.push_back (SeparatorElem());
1867 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1868 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1869 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1871 edit_items.push_back (SeparatorElem());
1872 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1873 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1874 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1875 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1876 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1877 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1878 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1884 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1886 using namespace Menu_Helpers;
1890 Menu *play_menu = manage (new Menu);
1891 MenuList& play_items = play_menu->items();
1892 play_menu->set_name ("ArdourContextMenu");
1894 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1895 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1896 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1897 play_items.push_back (SeparatorElem());
1898 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1900 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1904 Menu *select_menu = manage (new Menu);
1905 MenuList& select_items = select_menu->items();
1906 select_menu->set_name ("ArdourContextMenu");
1908 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1909 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1910 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1911 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1912 select_items.push_back (SeparatorElem());
1913 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1914 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1915 select_items.push_back (SeparatorElem());
1916 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1917 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1918 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1919 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1920 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1921 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1922 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1924 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1928 Menu *cutnpaste_menu = manage (new Menu);
1929 MenuList& cutnpaste_items = cutnpaste_menu->items();
1930 cutnpaste_menu->set_name ("ArdourContextMenu");
1932 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1933 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1934 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1936 cutnpaste_items.push_back (SeparatorElem());
1938 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1939 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1941 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1943 /* Adding new material */
1945 edit_items.push_back (SeparatorElem());
1946 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1947 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1951 Menu *nudge_menu = manage (new Menu());
1952 MenuList& nudge_items = nudge_menu->items();
1953 nudge_menu->set_name ("ArdourContextMenu");
1955 edit_items.push_back (SeparatorElem());
1956 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1957 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1958 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1959 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1961 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1965 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1967 using namespace Menu_Helpers;
1971 Menu *play_menu = manage (new Menu);
1972 MenuList& play_items = play_menu->items();
1973 play_menu->set_name ("ArdourContextMenu");
1975 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1976 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1977 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1981 Menu *select_menu = manage (new Menu);
1982 MenuList& select_items = select_menu->items();
1983 select_menu->set_name ("ArdourContextMenu");
1985 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1986 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1987 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1988 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1989 select_items.push_back (SeparatorElem());
1990 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1991 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1992 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1993 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1995 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1999 Menu *cutnpaste_menu = manage (new Menu);
2000 MenuList& cutnpaste_items = cutnpaste_menu->items();
2001 cutnpaste_menu->set_name ("ArdourContextMenu");
2003 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2004 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2005 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2007 Menu *nudge_menu = manage (new Menu());
2008 MenuList& nudge_items = nudge_menu->items();
2009 nudge_menu->set_name ("ArdourContextMenu");
2011 edit_items.push_back (SeparatorElem());
2012 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2013 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2014 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2015 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2017 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2021 Editor::snap_type() const
2027 Editor::snap_mode() const
2033 Editor::set_snap_to (SnapType st)
2035 unsigned int snap_ind = (unsigned int)st;
2039 if (snap_ind > snap_type_strings.size() - 1) {
2041 _snap_type = (SnapType)snap_ind;
2044 string str = snap_type_strings[snap_ind];
2046 if (str != snap_type_selector.get_text()) {
2047 snap_type_selector.set_text (str);
2052 switch (_snap_type) {
2053 case SnapToBeatDiv128:
2054 case SnapToBeatDiv64:
2055 case SnapToBeatDiv32:
2056 case SnapToBeatDiv28:
2057 case SnapToBeatDiv24:
2058 case SnapToBeatDiv20:
2059 case SnapToBeatDiv16:
2060 case SnapToBeatDiv14:
2061 case SnapToBeatDiv12:
2062 case SnapToBeatDiv10:
2063 case SnapToBeatDiv8:
2064 case SnapToBeatDiv7:
2065 case SnapToBeatDiv6:
2066 case SnapToBeatDiv5:
2067 case SnapToBeatDiv4:
2068 case SnapToBeatDiv3:
2069 case SnapToBeatDiv2: {
2070 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2071 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2073 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2074 current_bbt_points_begin, current_bbt_points_end);
2075 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2076 current_bbt_points_begin, current_bbt_points_end);
2077 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2081 case SnapToRegionStart:
2082 case SnapToRegionEnd:
2083 case SnapToRegionSync:
2084 case SnapToRegionBoundary:
2085 build_region_boundary_cache ();
2093 SnapChanged (); /* EMIT SIGNAL */
2097 Editor::set_snap_mode (SnapMode mode)
2099 string str = snap_mode_strings[(int)mode];
2101 if (internal_editing()) {
2102 internal_snap_mode = mode;
2104 pre_internal_snap_mode = mode;
2109 if (str != snap_mode_selector.get_text ()) {
2110 snap_mode_selector.set_text (str);
2116 Editor::set_edit_point_preference (EditPoint ep, bool force)
2118 bool changed = (_edit_point != ep);
2121 if (Profile->get_mixbus())
2122 if (ep == EditAtSelectedMarker)
2123 ep = EditAtPlayhead;
2125 string str = edit_point_strings[(int)ep];
2126 if (str != edit_point_selector.get_text ()) {
2127 edit_point_selector.set_text (str);
2130 update_all_enter_cursors();
2132 if (!force && !changed) {
2136 const char* action=NULL;
2138 switch (_edit_point) {
2139 case EditAtPlayhead:
2140 action = "edit-at-playhead";
2142 case EditAtSelectedMarker:
2143 action = "edit-at-marker";
2146 action = "edit-at-mouse";
2150 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2152 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2156 bool in_track_canvas;
2158 if (!mouse_frame (foo, in_track_canvas)) {
2159 in_track_canvas = false;
2162 reset_canvas_action_sensitivity (in_track_canvas);
2168 Editor::set_state (const XMLNode& node, int /*version*/)
2170 const XMLProperty* prop;
2177 g.base_width = default_width;
2178 g.base_height = default_height;
2182 if ((geometry = find_named_node (node, "geometry")) != 0) {
2186 if ((prop = geometry->property("x_size")) == 0) {
2187 prop = geometry->property ("x-size");
2190 g.base_width = atoi(prop->value());
2192 if ((prop = geometry->property("y_size")) == 0) {
2193 prop = geometry->property ("y-size");
2196 g.base_height = atoi(prop->value());
2199 if ((prop = geometry->property ("x_pos")) == 0) {
2200 prop = geometry->property ("x-pos");
2203 x = atoi (prop->value());
2206 if ((prop = geometry->property ("y_pos")) == 0) {
2207 prop = geometry->property ("y-pos");
2210 y = atoi (prop->value());
2214 set_default_size (g.base_width, g.base_height);
2217 if (_session && (prop = node.property ("playhead"))) {
2219 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2221 playhead_cursor->set_position (pos);
2223 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2224 playhead_cursor->set_position (0);
2227 playhead_cursor->set_position (0);
2230 if ((prop = node.property ("mixer-width"))) {
2231 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2234 if ((prop = node.property ("zoom-focus"))) {
2235 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2238 if ((prop = node.property ("zoom"))) {
2239 /* older versions of ardour used floating point samples_per_pixel */
2240 double f = PBD::atof (prop->value());
2241 reset_zoom (llrintf (f));
2243 reset_zoom (samples_per_pixel);
2246 if ((prop = node.property ("visible-track-count"))) {
2247 set_visible_track_count (PBD::atoi (prop->value()));
2250 if ((prop = node.property ("snap-to"))) {
2251 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2254 if ((prop = node.property ("snap-mode"))) {
2255 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2258 if ((prop = node.property ("internal-snap-to"))) {
2259 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2262 if ((prop = node.property ("internal-snap-mode"))) {
2263 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2266 if ((prop = node.property ("pre-internal-snap-to"))) {
2267 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2270 if ((prop = node.property ("pre-internal-snap-mode"))) {
2271 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2274 if ((prop = node.property ("mouse-mode"))) {
2275 MouseMode m = str2mousemode(prop->value());
2276 set_mouse_mode (m, true);
2278 set_mouse_mode (MouseObject, true);
2281 if ((prop = node.property ("left-frame")) != 0) {
2283 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2287 reset_x_origin (pos);
2291 if ((prop = node.property ("y-origin")) != 0) {
2292 reset_y_origin (atof (prop->value ()));
2295 if ((prop = node.property ("join-object-range"))) {
2296 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2297 bool yn = string_is_affirmative (prop->value());
2299 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2300 tact->set_active (!yn);
2301 tact->set_active (yn);
2303 set_mouse_mode(mouse_mode, true);
2306 if ((prop = node.property ("edit-point"))) {
2307 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2310 if ((prop = node.property ("show-measures"))) {
2311 bool yn = string_is_affirmative (prop->value());
2312 _show_measures = yn;
2313 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2315 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2316 /* do it twice to force the change */
2317 tact->set_active (!yn);
2318 tact->set_active (yn);
2322 if ((prop = node.property ("follow-playhead"))) {
2323 bool yn = string_is_affirmative (prop->value());
2324 set_follow_playhead (yn);
2325 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2327 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2328 if (tact->get_active() != yn) {
2329 tact->set_active (yn);
2334 if ((prop = node.property ("stationary-playhead"))) {
2335 bool yn = string_is_affirmative (prop->value());
2336 set_stationary_playhead (yn);
2337 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2339 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2340 if (tact->get_active() != yn) {
2341 tact->set_active (yn);
2346 if ((prop = node.property ("region-list-sort-type"))) {
2347 RegionListSortType st;
2348 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2351 if ((prop = node.property ("show-editor-mixer"))) {
2353 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2356 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2357 bool yn = string_is_affirmative (prop->value());
2359 /* do it twice to force the change */
2361 tact->set_active (!yn);
2362 tact->set_active (yn);
2365 if ((prop = node.property ("show-editor-list"))) {
2367 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2370 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2371 bool yn = string_is_affirmative (prop->value());
2373 /* do it twice to force the change */
2375 tact->set_active (!yn);
2376 tact->set_active (yn);
2379 if ((prop = node.property (X_("editor-list-page")))) {
2380 _the_notebook.set_current_page (atoi (prop->value ()));
2383 if ((prop = node.property (X_("show-marker-lines")))) {
2384 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2386 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2387 bool yn = string_is_affirmative (prop->value ());
2389 tact->set_active (!yn);
2390 tact->set_active (yn);
2393 XMLNodeList children = node.children ();
2394 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2395 selection->set_state (**i, Stateful::current_state_version);
2396 _regions->set_state (**i);
2399 if ((prop = node.property ("maximised"))) {
2400 bool yn = string_is_affirmative (prop->value());
2401 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2403 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2404 bool fs = tact && tact->get_active();
2406 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2410 if ((prop = node.property ("nudge-clock-value"))) {
2412 sscanf (prop->value().c_str(), "%" PRId64, &f);
2413 nudge_clock->set (f);
2415 nudge_clock->set_mode (AudioClock::Timecode);
2416 nudge_clock->set (_session->frame_rate() * 5, true);
2423 Editor::get_state ()
2425 XMLNode* node = new XMLNode ("Editor");
2428 id().print (buf, sizeof (buf));
2429 node->add_property ("id", buf);
2431 if (is_realized()) {
2432 Glib::RefPtr<Gdk::Window> win = get_window();
2434 int x, y, width, height;
2435 win->get_root_origin(x, y);
2436 win->get_size(width, height);
2438 XMLNode* geometry = new XMLNode ("geometry");
2440 snprintf(buf, sizeof(buf), "%d", width);
2441 geometry->add_property("x-size", string(buf));
2442 snprintf(buf, sizeof(buf), "%d", height);
2443 geometry->add_property("y-size", string(buf));
2444 snprintf(buf, sizeof(buf), "%d", x);
2445 geometry->add_property("x-pos", string(buf));
2446 snprintf(buf, sizeof(buf), "%d", y);
2447 geometry->add_property("y-pos", string(buf));
2448 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2449 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2450 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2451 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2452 geometry->add_property("edit-vertical-pane-pos", string(buf));
2454 node->add_child_nocopy (*geometry);
2457 maybe_add_mixer_strip_width (*node);
2459 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2461 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2462 node->add_property ("zoom", buf);
2463 node->add_property ("snap-to", enum_2_string (_snap_type));
2464 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2465 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2466 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2467 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2468 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2469 node->add_property ("edit-point", enum_2_string (_edit_point));
2470 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2471 node->add_property ("visible-track-count", buf);
2473 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2474 node->add_property ("playhead", buf);
2475 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2476 node->add_property ("left-frame", buf);
2477 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2478 node->add_property ("y-origin", buf);
2480 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2481 node->add_property ("maximised", _maximised ? "yes" : "no");
2482 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2483 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2484 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2485 node->add_property ("mouse-mode", enum2str(mouse_mode));
2486 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2488 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2490 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2491 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2494 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2496 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2497 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2500 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2501 node->add_property (X_("editor-list-page"), buf);
2503 if (button_bindings) {
2504 XMLNode* bb = new XMLNode (X_("Buttons"));
2505 button_bindings->save (*bb);
2506 node->add_child_nocopy (*bb);
2509 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2511 node->add_child_nocopy (selection->get_state ());
2512 node->add_child_nocopy (_regions->get_state ());
2514 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2515 node->add_property ("nudge-clock-value", buf);
2520 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2521 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2523 * @return pair: TimeAxisView that y is over, layer index.
2525 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2526 * in stacked or expanded region display mode, otherwise 0.
2528 std::pair<TimeAxisView *, double>
2529 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2531 if (!trackview_relative_offset) {
2532 y -= _trackview_group->canvas_origin().y;
2536 return std::make_pair ( (TimeAxisView *) 0, 0);
2539 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2541 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2548 return std::make_pair ( (TimeAxisView *) 0, 0);
2551 /** Snap a position to the grid, if appropriate, taking into account current
2552 * grid settings and also the state of any snap modifier keys that may be pressed.
2553 * @param start Position to snap.
2554 * @param event Event to get current key modifier information from, or 0.
2557 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2559 if (!_session || !event) {
2563 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2564 if (_snap_mode == SnapOff) {
2565 snap_to_internal (start, direction, for_mark);
2568 if (_snap_mode != SnapOff) {
2569 snap_to_internal (start, direction, for_mark);
2575 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark)
2577 if (!_session || _snap_mode == SnapOff) {
2581 snap_to_internal (start, direction, for_mark);
2585 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2587 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2588 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2590 switch (_snap_type) {
2591 case SnapToTimecodeFrame:
2592 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2593 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2594 /* start is already on a whole timecode frame, do nothing */
2595 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2596 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2598 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2602 case SnapToTimecodeSeconds:
2603 if (_session->config.get_timecode_offset_negative()) {
2604 start += _session->config.get_timecode_offset ();
2606 start -= _session->config.get_timecode_offset ();
2608 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2609 (start % one_timecode_second == 0)) {
2610 /* start is already on a whole second, do nothing */
2611 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2612 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2614 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2617 if (_session->config.get_timecode_offset_negative()) {
2618 start -= _session->config.get_timecode_offset ();
2620 start += _session->config.get_timecode_offset ();
2624 case SnapToTimecodeMinutes:
2625 if (_session->config.get_timecode_offset_negative()) {
2626 start += _session->config.get_timecode_offset ();
2628 start -= _session->config.get_timecode_offset ();
2630 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2631 (start % one_timecode_minute == 0)) {
2632 /* start is already on a whole minute, do nothing */
2633 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2634 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2636 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2638 if (_session->config.get_timecode_offset_negative()) {
2639 start -= _session->config.get_timecode_offset ();
2641 start += _session->config.get_timecode_offset ();
2645 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2646 abort(); /*NOTREACHED*/
2651 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark)
2653 const framepos_t one_second = _session->frame_rate();
2654 const framepos_t one_minute = _session->frame_rate() * 60;
2655 framepos_t presnap = start;
2659 switch (_snap_type) {
2660 case SnapToTimecodeFrame:
2661 case SnapToTimecodeSeconds:
2662 case SnapToTimecodeMinutes:
2663 return timecode_snap_to_internal (start, direction, for_mark);
2666 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2667 start % (one_second/75) == 0) {
2668 /* start is already on a whole CD frame, do nothing */
2669 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2670 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2672 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2677 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2678 start % one_second == 0) {
2679 /* start is already on a whole second, do nothing */
2680 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2681 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2683 start = (framepos_t) floor ((double) start / one_second) * one_second;
2688 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2689 start % one_minute == 0) {
2690 /* start is already on a whole minute, do nothing */
2691 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2692 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2694 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2699 start = _session->tempo_map().round_to_bar (start, direction);
2703 start = _session->tempo_map().round_to_beat (start, direction);
2706 case SnapToBeatDiv128:
2707 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2709 case SnapToBeatDiv64:
2710 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2712 case SnapToBeatDiv32:
2713 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2715 case SnapToBeatDiv28:
2716 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2718 case SnapToBeatDiv24:
2719 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2721 case SnapToBeatDiv20:
2722 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2724 case SnapToBeatDiv16:
2725 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2727 case SnapToBeatDiv14:
2728 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2730 case SnapToBeatDiv12:
2731 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2733 case SnapToBeatDiv10:
2734 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2736 case SnapToBeatDiv8:
2737 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2739 case SnapToBeatDiv7:
2740 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2742 case SnapToBeatDiv6:
2743 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2745 case SnapToBeatDiv5:
2746 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2748 case SnapToBeatDiv4:
2749 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2751 case SnapToBeatDiv3:
2752 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2754 case SnapToBeatDiv2:
2755 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2763 _session->locations()->marks_either_side (start, before, after);
2765 if (before == max_framepos && after == max_framepos) {
2766 /* No marks to snap to, so just don't snap */
2768 } else if (before == max_framepos) {
2770 } else if (after == max_framepos) {
2772 } else if (before != max_framepos && after != max_framepos) {
2773 /* have before and after */
2774 if ((start - before) < (after - start)) {
2783 case SnapToRegionStart:
2784 case SnapToRegionEnd:
2785 case SnapToRegionSync:
2786 case SnapToRegionBoundary:
2787 if (!region_boundary_cache.empty()) {
2789 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2790 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2792 if (direction > 0) {
2793 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2795 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2798 if (next != region_boundary_cache.begin ()) {
2803 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2804 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2806 if (start > (p + n) / 2) {
2815 switch (_snap_mode) {
2821 if (presnap > start) {
2822 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2826 } else if (presnap < start) {
2827 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2833 /* handled at entry */
2841 Editor::setup_toolbar ()
2843 HBox* mode_box = manage(new HBox);
2844 mode_box->set_border_width (2);
2845 mode_box->set_spacing(2);
2847 HBox* mouse_mode_box = manage (new HBox);
2848 HBox* mouse_mode_hbox = manage (new HBox);
2849 VBox* mouse_mode_vbox = manage (new VBox);
2850 Alignment* mouse_mode_align = manage (new Alignment);
2852 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2853 mouse_mode_size_group->add_widget (smart_mode_button);
2854 mouse_mode_size_group->add_widget (mouse_move_button);
2855 mouse_mode_size_group->add_widget (mouse_cut_button);
2856 mouse_mode_size_group->add_widget (mouse_select_button);
2857 mouse_mode_size_group->add_widget (mouse_timefx_button);
2858 mouse_mode_size_group->add_widget (mouse_audition_button);
2859 mouse_mode_size_group->add_widget (mouse_draw_button);
2860 mouse_mode_size_group->add_widget (mouse_content_button);
2862 mouse_mode_size_group->add_widget (zoom_in_button);
2863 mouse_mode_size_group->add_widget (zoom_out_button);
2864 mouse_mode_size_group->add_widget (zoom_preset_selector);
2865 mouse_mode_size_group->add_widget (zoom_out_full_button);
2866 mouse_mode_size_group->add_widget (zoom_focus_selector);
2868 mouse_mode_size_group->add_widget (tav_shrink_button);
2869 mouse_mode_size_group->add_widget (tav_expand_button);
2870 mouse_mode_size_group->add_widget (visible_tracks_selector);
2872 mouse_mode_size_group->add_widget (snap_type_selector);
2873 mouse_mode_size_group->add_widget (snap_mode_selector);
2875 mouse_mode_size_group->add_widget (edit_point_selector);
2876 mouse_mode_size_group->add_widget (edit_mode_selector);
2878 mouse_mode_size_group->add_widget (*nudge_clock);
2879 mouse_mode_size_group->add_widget (nudge_forward_button);
2880 mouse_mode_size_group->add_widget (nudge_backward_button);
2882 mouse_mode_hbox->set_spacing (2);
2884 if (!ARDOUR::Profile->get_trx()) {
2885 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2888 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2889 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2891 if (!ARDOUR::Profile->get_mixbus()) {
2892 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2895 if (!ARDOUR::Profile->get_trx()) {
2896 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2897 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2898 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2899 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2902 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2904 mouse_mode_align->add (*mouse_mode_vbox);
2905 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2907 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2909 edit_mode_selector.set_name ("mouse mode button");
2911 if (!ARDOUR::Profile->get_trx()) {
2912 mode_box->pack_start (edit_mode_selector, false, false);
2914 mode_box->pack_start (*mouse_mode_box, false, false);
2916 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2917 _mouse_mode_tearoff->set_name ("MouseModeBase");
2918 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2920 if (Profile->get_sae() || Profile->get_mixbus() ) {
2921 _mouse_mode_tearoff->set_can_be_torn_off (false);
2924 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2925 &_mouse_mode_tearoff->tearoff_window()));
2926 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2927 &_mouse_mode_tearoff->tearoff_window(), 1));
2928 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2929 &_mouse_mode_tearoff->tearoff_window()));
2930 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2931 &_mouse_mode_tearoff->tearoff_window(), 1));
2935 _zoom_box.set_spacing (2);
2936 _zoom_box.set_border_width (2);
2940 zoom_preset_selector.set_name ("zoom button");
2941 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2942 zoom_preset_selector.set_size_request (42, -1);
2944 zoom_in_button.set_name ("zoom button");
2945 zoom_in_button.set_image(::get_icon ("zoom_in"));
2946 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2947 zoom_in_button.set_related_action (act);
2949 zoom_out_button.set_name ("zoom button");
2950 zoom_out_button.set_image(::get_icon ("zoom_out"));
2951 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2952 zoom_out_button.set_related_action (act);
2954 zoom_out_full_button.set_name ("zoom button");
2955 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2956 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2957 zoom_out_full_button.set_related_action (act);
2959 zoom_focus_selector.set_name ("zoom button");
2961 if (ARDOUR::Profile->get_mixbus()) {
2962 _zoom_box.pack_start (zoom_preset_selector, false, false);
2963 } else if (ARDOUR::Profile->get_trx()) {
2964 mode_box->pack_start (zoom_out_button, false, false);
2965 mode_box->pack_start (zoom_in_button, false, false);
2967 _zoom_box.pack_start (zoom_out_button, false, false);
2968 _zoom_box.pack_start (zoom_in_button, false, false);
2969 _zoom_box.pack_start (zoom_out_full_button, false, false);
2970 _zoom_box.pack_start (zoom_focus_selector, false, false);
2973 /* Track zoom buttons */
2974 visible_tracks_selector.set_name ("zoom button");
2975 if (Profile->get_mixbus()) {
2976 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2977 visible_tracks_selector.set_size_request (42, -1);
2979 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2982 tav_expand_button.set_name ("zoom button");
2983 tav_expand_button.set_image(::get_icon ("tav_exp"));
2984 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2985 tav_expand_button.set_related_action (act);
2987 tav_shrink_button.set_name ("zoom button");
2988 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2989 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2990 tav_shrink_button.set_related_action (act);
2992 if (ARDOUR::Profile->get_mixbus()) {
2993 _zoom_box.pack_start (visible_tracks_selector);
2994 } else if (ARDOUR::Profile->get_trx()) {
2995 _zoom_box.pack_start (tav_shrink_button);
2996 _zoom_box.pack_start (tav_expand_button);
2998 _zoom_box.pack_start (visible_tracks_selector);
2999 _zoom_box.pack_start (tav_shrink_button);
3000 _zoom_box.pack_start (tav_expand_button);
3003 if (!ARDOUR::Profile->get_trx()) {
3004 _zoom_tearoff = manage (new TearOff (_zoom_box));
3006 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3007 &_zoom_tearoff->tearoff_window()));
3008 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3009 &_zoom_tearoff->tearoff_window(), 0));
3010 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3011 &_zoom_tearoff->tearoff_window()));
3012 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3013 &_zoom_tearoff->tearoff_window(), 0));
3016 if (Profile->get_sae() || Profile->get_mixbus() ) {
3017 _zoom_tearoff->set_can_be_torn_off (false);
3020 snap_box.set_spacing (2);
3021 snap_box.set_border_width (2);
3023 snap_type_selector.set_name ("mouse mode button");
3025 snap_mode_selector.set_name ("mouse mode button");
3027 edit_point_selector.set_name ("mouse mode button");
3029 snap_box.pack_start (snap_mode_selector, false, false);
3030 snap_box.pack_start (snap_type_selector, false, false);
3031 snap_box.pack_start (edit_point_selector, false, false);
3035 HBox *nudge_box = manage (new HBox);
3036 nudge_box->set_spacing (2);
3037 nudge_box->set_border_width (2);
3039 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3040 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3042 nudge_box->pack_start (nudge_backward_button, false, false);
3043 nudge_box->pack_start (nudge_forward_button, false, false);
3044 nudge_box->pack_start (*nudge_clock, false, false);
3047 /* Pack everything in... */
3049 HBox* hbox = manage (new HBox);
3050 hbox->set_spacing(2);
3052 _tools_tearoff = manage (new TearOff (*hbox));
3053 _tools_tearoff->set_name ("MouseModeBase");
3054 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3056 if (Profile->get_sae() || Profile->get_mixbus()) {
3057 _tools_tearoff->set_can_be_torn_off (false);
3060 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3061 &_tools_tearoff->tearoff_window()));
3062 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3063 &_tools_tearoff->tearoff_window(), 0));
3064 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3065 &_tools_tearoff->tearoff_window()));
3066 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3067 &_tools_tearoff->tearoff_window(), 0));
3069 toolbar_hbox.set_spacing (2);
3070 toolbar_hbox.set_border_width (1);
3072 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3073 if (!ARDOUR::Profile->get_trx()) {
3074 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3075 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3078 if (!ARDOUR::Profile->get_trx()) {
3079 hbox->pack_start (snap_box, false, false);
3080 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3081 hbox->pack_start (*nudge_box, false, false);
3083 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3086 hbox->pack_start (panic_box, false, false);
3090 toolbar_base.set_name ("ToolBarBase");
3091 toolbar_base.add (toolbar_hbox);
3093 _toolbar_viewport.add (toolbar_base);
3094 /* stick to the required height but allow width to vary if there's not enough room */
3095 _toolbar_viewport.set_size_request (1, -1);
3097 toolbar_frame.set_shadow_type (SHADOW_OUT);
3098 toolbar_frame.set_name ("BaseFrame");
3099 toolbar_frame.add (_toolbar_viewport);
3103 Editor::build_edit_point_menu ()
3105 using namespace Menu_Helpers;
3107 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3108 if(!Profile->get_mixbus())
3109 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3110 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3112 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3116 Editor::build_edit_mode_menu ()
3118 using namespace Menu_Helpers;
3120 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3121 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3122 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3123 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3125 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3129 Editor::build_snap_mode_menu ()
3131 using namespace Menu_Helpers;
3133 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3134 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3135 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3137 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3141 Editor::build_snap_type_menu ()
3143 using namespace Menu_Helpers;
3145 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3146 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3147 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3148 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3149 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3150 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3151 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3152 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3153 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3154 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3155 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3156 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3157 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3158 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3159 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3160 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3161 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3162 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3163 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3164 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3165 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3166 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3167 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3168 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3169 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3170 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3171 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3172 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3173 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3174 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3176 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3181 Editor::setup_tooltips ()
3183 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3184 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3185 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3186 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Grab/Select Objects"));
3187 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit Gain/Notes/Automation"));
3188 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3189 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3190 ARDOUR_UI::instance()->set_tip (mouse_content_button, _("Edit Contents (notes and automation)"));
3191 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3192 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3193 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3194 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3195 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3196 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3197 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3198 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3199 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3200 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3201 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3202 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3203 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3204 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3205 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3206 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3210 Editor::convert_drop_to_paths (
3211 vector<string>& paths,
3212 const RefPtr<Gdk::DragContext>& /*context*/,
3215 const SelectionData& data,
3219 if (_session == 0) {
3223 vector<string> uris = data.get_uris();
3227 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3228 are actually URI lists. So do it by hand.
3231 if (data.get_target() != "text/plain") {
3235 /* Parse the "uri-list" format that Nautilus provides,
3236 where each pathname is delimited by \r\n.
3238 THERE MAY BE NO NULL TERMINATING CHAR!!!
3241 string txt = data.get_text();
3245 p = (char *) malloc (txt.length() + 1);
3246 txt.copy (p, txt.length(), 0);
3247 p[txt.length()] = '\0';
3253 while (g_ascii_isspace (*p))
3257 while (*q && (*q != '\n') && (*q != '\r')) {
3264 while (q > p && g_ascii_isspace (*q))
3269 uris.push_back (string (p, q - p + 1));
3273 p = strchr (p, '\n');
3285 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3286 if ((*i).substr (0,7) == "file://") {
3287 paths.push_back (Glib::filename_from_uri (*i));
3295 Editor::new_tempo_section ()
3300 Editor::map_transport_state ()
3302 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3304 if (_session && _session->transport_stopped()) {
3305 have_pending_keyboard_selection = false;
3308 update_loop_range_view ();
3314 Editor::begin_reversible_command (string name)
3317 before.push_back (&_selection_memento->get_state ());
3318 _session->begin_reversible_command (name);
3323 Editor::begin_reversible_command (GQuark q)
3326 before.push_back (&_selection_memento->get_state ());
3327 _session->begin_reversible_command (q);
3332 Editor::commit_reversible_command ()
3335 if (before.size() == 1) {
3336 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3339 if (!before.empty()) {
3343 _session->commit_reversible_command ();
3348 Editor::history_changed ()
3352 if (undo_action && _session) {
3353 if (_session->undo_depth() == 0) {
3354 label = S_("Command|Undo");
3356 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3358 undo_action->property_label() = label;
3361 if (redo_action && _session) {
3362 if (_session->redo_depth() == 0) {
3365 label = string_compose(_("Redo (%1)"), _session->next_redo());
3367 redo_action->property_label() = label;
3372 Editor::duplicate_range (bool with_dialog)
3376 RegionSelection rs = get_regions_from_selection_and_entered ();
3378 if ( selection->time.length() == 0 && rs.empty()) {
3384 ArdourDialog win (_("Duplicate"));
3385 Label label (_("Number of duplications:"));
3386 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3387 SpinButton spinner (adjustment, 0.0, 1);
3390 win.get_vbox()->set_spacing (12);
3391 win.get_vbox()->pack_start (hbox);
3392 hbox.set_border_width (6);
3393 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3395 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3396 place, visually. so do this by hand.
3399 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3400 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3401 spinner.grab_focus();
3407 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3408 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3409 win.set_default_response (RESPONSE_ACCEPT);
3411 spinner.grab_focus ();
3413 switch (win.run ()) {
3414 case RESPONSE_ACCEPT:
3420 times = adjustment.get_value();
3423 if ((current_mouse_mode() == Editing::MouseRange)) {
3424 if (selection->time.length()) {
3425 duplicate_selection (times);
3427 } else if (get_smart_mode()) {
3428 if (selection->time.length()) {
3429 duplicate_selection (times);
3431 duplicate_some_regions (rs, times);
3433 duplicate_some_regions (rs, times);
3438 Editor::set_edit_mode (EditMode m)
3440 Config->set_edit_mode (m);
3444 Editor::cycle_edit_mode ()
3446 switch (Config->get_edit_mode()) {
3448 if (Profile->get_sae()) {
3449 Config->set_edit_mode (Lock);
3451 Config->set_edit_mode (Ripple);
3456 Config->set_edit_mode (Lock);
3459 Config->set_edit_mode (Slide);
3465 Editor::edit_mode_selection_done ( EditMode m )
3467 Config->set_edit_mode ( m );
3471 Editor::snap_type_selection_done (SnapType snaptype)
3473 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3475 ract->set_active ();
3480 Editor::snap_mode_selection_done (SnapMode mode)
3482 RefPtr<RadioAction> ract = snap_mode_action (mode);
3485 ract->set_active (true);
3490 Editor::cycle_edit_point (bool with_marker)
3492 if(Profile->get_mixbus())
3493 with_marker = false;
3495 switch (_edit_point) {
3497 set_edit_point_preference (EditAtPlayhead);
3499 case EditAtPlayhead:
3501 set_edit_point_preference (EditAtSelectedMarker);
3503 set_edit_point_preference (EditAtMouse);
3506 case EditAtSelectedMarker:
3507 set_edit_point_preference (EditAtMouse);
3513 Editor::edit_point_selection_done (EditPoint ep)
3515 set_edit_point_preference ( ep );
3519 Editor::build_zoom_focus_menu ()
3521 using namespace Menu_Helpers;
3523 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3524 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3525 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3526 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3527 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3528 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3530 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3534 Editor::zoom_focus_selection_done ( ZoomFocus f )
3536 RefPtr<RadioAction> ract = zoom_focus_action (f);
3538 ract->set_active ();
3543 Editor::build_track_count_menu ()
3545 using namespace Menu_Helpers;
3547 if (!Profile->get_mixbus()) {
3548 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3549 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3550 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3551 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3552 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3553 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3554 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3555 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3556 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3557 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3558 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3559 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3560 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3562 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3563 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3564 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3565 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3566 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3567 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3568 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3569 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3570 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3571 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3573 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3574 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3575 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3576 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3577 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3578 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3579 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3580 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3581 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3582 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3583 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3588 Editor::set_zoom_preset (int64_t ms)
3591 temporal_zoom_session();
3595 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3596 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3600 Editor::set_visible_track_count (int32_t n)
3602 _visible_track_count = n;
3604 /* if the canvas hasn't really been allocated any size yet, just
3605 record the desired number of visible tracks and return. when canvas
3606 allocation happens, we will get called again and then we can do the
3610 if (_visible_canvas_height <= 1) {
3616 DisplaySuspender ds;
3618 if (_visible_track_count > 0) {
3619 h = trackviews_height() / _visible_track_count;
3620 std::ostringstream s;
3621 s << _visible_track_count;
3623 } else if (_visible_track_count == 0) {
3625 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3626 if ((*i)->marked_for_display()) {
3630 h = trackviews_height() / n;
3633 /* negative value means that the visible track count has
3634 been overridden by explicit track height changes.
3636 visible_tracks_selector.set_text (X_("*"));
3640 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3641 (*i)->set_height (h);
3644 if (str != visible_tracks_selector.get_text()) {
3645 visible_tracks_selector.set_text (str);
3650 Editor::override_visible_track_count ()
3652 _visible_track_count = -1;
3653 visible_tracks_selector.set_text ( _("*") );
3657 Editor::edit_controls_button_release (GdkEventButton* ev)
3659 if (Keyboard::is_context_menu_event (ev)) {
3660 ARDOUR_UI::instance()->add_route (this);
3661 } else if (ev->button == 1) {
3662 selection->clear_tracks ();
3669 Editor::mouse_select_button_release (GdkEventButton* ev)
3671 /* this handles just right-clicks */
3673 if (ev->button != 3) {
3681 Editor::set_zoom_focus (ZoomFocus f)
3683 string str = zoom_focus_strings[(int)f];
3685 if (str != zoom_focus_selector.get_text()) {
3686 zoom_focus_selector.set_text (str);
3689 if (zoom_focus != f) {
3696 Editor::cycle_zoom_focus ()
3698 switch (zoom_focus) {
3700 set_zoom_focus (ZoomFocusRight);
3702 case ZoomFocusRight:
3703 set_zoom_focus (ZoomFocusCenter);
3705 case ZoomFocusCenter:
3706 set_zoom_focus (ZoomFocusPlayhead);
3708 case ZoomFocusPlayhead:
3709 set_zoom_focus (ZoomFocusMouse);
3711 case ZoomFocusMouse:
3712 set_zoom_focus (ZoomFocusEdit);
3715 set_zoom_focus (ZoomFocusLeft);
3721 Editor::ensure_float (Window& win)
3723 win.set_transient_for (*this);
3727 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3729 /* recover or initialize pane positions. do this here rather than earlier because
3730 we don't want the positions to change the child allocations, which they seem to do.
3736 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3745 XMLNode* geometry = find_named_node (*node, "geometry");
3747 if (which == static_cast<Paned*> (&edit_pane)) {
3749 if (done & Horizontal) {
3753 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3754 _notebook_shrunk = string_is_affirmative (prop->value ());
3757 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3758 /* initial allocation is 90% to canvas, 10% to notebook */
3759 pos = (int) floor (alloc.get_width() * 0.90f);
3760 snprintf (buf, sizeof(buf), "%d", pos);
3762 pos = atoi (prop->value());
3765 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3766 edit_pane.set_position (pos);
3769 done = (Pane) (done | Horizontal);
3771 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3773 if (done & Vertical) {
3777 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3778 /* initial allocation is 90% to canvas, 10% to summary */
3779 pos = (int) floor (alloc.get_height() * 0.90f);
3780 snprintf (buf, sizeof(buf), "%d", pos);
3783 pos = atoi (prop->value());
3786 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3787 editor_summary_pane.set_position (pos);
3790 done = (Pane) (done | Vertical);
3795 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3797 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3798 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3799 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3800 top_hbox.remove (toolbar_frame);
3805 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3807 if (toolbar_frame.get_parent() == 0) {
3808 top_hbox.pack_end (toolbar_frame);
3813 Editor::set_show_measures (bool yn)
3815 if (_show_measures != yn) {
3818 if ((_show_measures = yn) == true) {
3820 tempo_lines->show();
3823 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3824 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3826 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3827 draw_measures (begin, end);
3835 Editor::toggle_follow_playhead ()
3837 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3839 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3840 set_follow_playhead (tact->get_active());
3844 /** @param yn true to follow playhead, otherwise false.
3845 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3848 Editor::set_follow_playhead (bool yn, bool catch_up)
3850 if (_follow_playhead != yn) {
3851 if ((_follow_playhead = yn) == true && catch_up) {
3853 reset_x_origin_to_follow_playhead ();
3860 Editor::toggle_stationary_playhead ()
3862 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3864 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3865 set_stationary_playhead (tact->get_active());
3870 Editor::set_stationary_playhead (bool yn)
3872 if (_stationary_playhead != yn) {
3873 if ((_stationary_playhead = yn) == true) {
3875 // FIXME need a 3.0 equivalent of this 2.X call
3876 // update_current_screen ();
3883 Editor::playlist_selector () const
3885 return *_playlist_selector;
3889 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3891 if (paste_count == 0) {
3892 /* don't bother calculating an offset that will be zero anyway */
3896 /* calculate basic unsnapped multi-paste offset */
3897 framecnt_t offset = paste_count * duration;
3899 /* snap offset so pos + offset is aligned to the grid */
3900 framepos_t offset_pos = pos + offset;
3901 snap_to(offset_pos, RoundUpMaybe);
3902 offset = offset_pos - pos;
3908 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3912 switch (_snap_type) {
3914 return Evoral::MusicalTime(1.0);
3917 case SnapToBeatDiv128:
3918 return Evoral::MusicalTime(1.0/128.0);
3920 case SnapToBeatDiv64:
3921 return Evoral::MusicalTime(1.0/64.0);
3923 case SnapToBeatDiv32:
3924 return Evoral::MusicalTime(1.0/32.0);
3926 case SnapToBeatDiv28:
3927 return Evoral::MusicalTime(1.0/28.0);
3929 case SnapToBeatDiv24:
3930 return Evoral::MusicalTime(1.0/24.0);
3932 case SnapToBeatDiv20:
3933 return Evoral::MusicalTime(1.0/20.0);
3935 case SnapToBeatDiv16:
3936 return Evoral::MusicalTime(1.0/16.0);
3938 case SnapToBeatDiv14:
3939 return Evoral::MusicalTime(1.0/14.0);
3941 case SnapToBeatDiv12:
3942 return Evoral::MusicalTime(1.0/12.0);
3944 case SnapToBeatDiv10:
3945 return Evoral::MusicalTime(1.0/10.0);
3947 case SnapToBeatDiv8:
3948 return Evoral::MusicalTime(1.0/8.0);
3950 case SnapToBeatDiv7:
3951 return Evoral::MusicalTime(1.0/7.0);
3953 case SnapToBeatDiv6:
3954 return Evoral::MusicalTime(1.0/6.0);
3956 case SnapToBeatDiv5:
3957 return Evoral::MusicalTime(1.0/5.0);
3959 case SnapToBeatDiv4:
3960 return Evoral::MusicalTime(1.0/4.0);
3962 case SnapToBeatDiv3:
3963 return Evoral::MusicalTime(1.0/3.0);
3965 case SnapToBeatDiv2:
3966 return Evoral::MusicalTime(1.0/2.0);
3971 return Evoral::MusicalTime(_session->tempo_map().meter_at (position).divisions_per_bar());
3976 case SnapToTimecodeFrame:
3977 case SnapToTimecodeSeconds:
3978 case SnapToTimecodeMinutes:
3981 case SnapToRegionStart:
3982 case SnapToRegionEnd:
3983 case SnapToRegionSync:
3984 case SnapToRegionBoundary:
3990 return Evoral::MusicalTime();
3994 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3998 ret = nudge_clock->current_duration (pos);
3999 next = ret + 1; /* XXXX fix me */
4005 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4007 ArdourDialog dialog (_("Playlist Deletion"));
4008 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4009 "If it is kept, its audio files will not be cleaned.\n"
4010 "If it is deleted, audio files used by it alone will be cleaned."),
4013 dialog.set_position (WIN_POS_CENTER);
4014 dialog.get_vbox()->pack_start (label);
4018 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4019 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4020 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4022 switch (dialog.run ()) {
4023 case RESPONSE_ACCEPT:
4024 /* delete the playlist */
4028 case RESPONSE_REJECT:
4029 /* keep the playlist */
4041 Editor::audio_region_selection_covers (framepos_t where)
4043 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4044 if ((*a)->region()->covers (where)) {
4053 Editor::prepare_for_cleanup ()
4055 cut_buffer->clear_regions ();
4056 cut_buffer->clear_playlists ();
4058 selection->clear_regions ();
4059 selection->clear_playlists ();
4061 _regions->suspend_redisplay ();
4065 Editor::finish_cleanup ()
4067 _regions->resume_redisplay ();
4071 Editor::transport_loop_location()
4074 return _session->locations()->auto_loop_location();
4081 Editor::transport_punch_location()
4084 return _session->locations()->auto_punch_location();
4091 Editor::control_layout_scroll (GdkEventScroll* ev)
4093 /* Just forward to the normal canvas scroll method. The coordinate
4094 systems are different but since the canvas is always larger than the
4095 track headers, and aligned with the trackview area, this will work.
4097 In the not too distant future this layout is going away anyway and
4098 headers will be on the canvas.
4100 return canvas_scroll_event (ev, false);
4104 Editor::session_state_saved (string)
4107 _snapshots->redisplay ();
4111 Editor::update_tearoff_visibility()
4113 bool visible = ARDOUR_UI::config()->get_keep_tearoffs();
4114 _mouse_mode_tearoff->set_visible (visible);
4115 _tools_tearoff->set_visible (visible);
4116 if (_zoom_tearoff) {
4117 _zoom_tearoff->set_visible (visible);
4122 Editor::reattach_all_tearoffs ()
4124 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4125 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4126 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4130 Editor::maximise_editing_space ()
4142 Editor::restore_editing_space ()
4154 * Make new playlists for a given track and also any others that belong
4155 * to the same active route group with the `select' property.
4160 Editor::new_playlists (TimeAxisView* v)
4162 begin_reversible_command (_("new playlists"));
4163 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4164 _session->playlists->get (playlists);
4165 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4166 commit_reversible_command ();
4170 * Use a copy of the current playlist for a given track and also any others that belong
4171 * to the same active route group with the `select' property.
4176 Editor::copy_playlists (TimeAxisView* v)
4178 begin_reversible_command (_("copy playlists"));
4179 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4180 _session->playlists->get (playlists);
4181 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4182 commit_reversible_command ();
4185 /** Clear the current playlist for a given track and also any others that belong
4186 * to the same active route group with the `select' property.
4191 Editor::clear_playlists (TimeAxisView* v)
4193 begin_reversible_command (_("clear playlists"));
4194 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4195 _session->playlists->get (playlists);
4196 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4197 commit_reversible_command ();
4201 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4203 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4207 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4209 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4213 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4215 atv.clear_playlist ();
4219 Editor::on_key_press_event (GdkEventKey* ev)
4221 return key_press_focus_accelerator_handler (*this, ev);
4225 Editor::on_key_release_event (GdkEventKey* ev)
4227 return Gtk::Window::on_key_release_event (ev);
4228 // return key_press_focus_accelerator_handler (*this, ev);
4232 Editor::get_y_origin () const
4234 return vertical_adjustment.get_value ();
4237 /** Queue up a change to the viewport x origin.
4238 * @param frame New x origin.
4241 Editor::reset_x_origin (framepos_t frame)
4243 pending_visual_change.add (VisualChange::TimeOrigin);
4244 pending_visual_change.time_origin = frame;
4245 ensure_visual_change_idle_handler ();
4249 Editor::reset_y_origin (double y)
4251 pending_visual_change.add (VisualChange::YOrigin);
4252 pending_visual_change.y_origin = y;
4253 ensure_visual_change_idle_handler ();
4257 Editor::reset_zoom (framecnt_t spp)
4259 if (spp == samples_per_pixel) {
4263 pending_visual_change.add (VisualChange::ZoomLevel);
4264 pending_visual_change.samples_per_pixel = spp;
4265 ensure_visual_change_idle_handler ();
4269 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4271 reset_x_origin (frame);
4274 if (!no_save_visual) {
4275 undo_visual_stack.push_back (current_visual_state(false));
4279 Editor::VisualState::VisualState (bool with_tracks)
4280 : gui_state (with_tracks ? new GUIObjectState : 0)
4284 Editor::VisualState::~VisualState ()
4289 Editor::VisualState*
4290 Editor::current_visual_state (bool with_tracks)
4292 VisualState* vs = new VisualState (with_tracks);
4293 vs->y_position = vertical_adjustment.get_value();
4294 vs->samples_per_pixel = samples_per_pixel;
4295 vs->leftmost_frame = leftmost_frame;
4296 vs->zoom_focus = zoom_focus;
4299 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4306 Editor::undo_visual_state ()
4308 if (undo_visual_stack.empty()) {
4312 VisualState* vs = undo_visual_stack.back();
4313 undo_visual_stack.pop_back();
4316 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4319 use_visual_state (*vs);
4324 Editor::redo_visual_state ()
4326 if (redo_visual_stack.empty()) {
4330 VisualState* vs = redo_visual_stack.back();
4331 redo_visual_stack.pop_back();
4333 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4334 // why do we check here?
4335 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4338 use_visual_state (*vs);
4343 Editor::swap_visual_state ()
4345 if (undo_visual_stack.empty()) {
4346 redo_visual_state ();
4348 undo_visual_state ();
4353 Editor::use_visual_state (VisualState& vs)
4355 PBD::Unwinder<bool> nsv (no_save_visual, true);
4356 DisplaySuspender ds;
4358 vertical_adjustment.set_value (vs.y_position);
4360 set_zoom_focus (vs.zoom_focus);
4361 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4364 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4366 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4367 (*i)->reset_visual_state ();
4371 _routes->update_visibility ();
4374 /** This is the core function that controls the zoom level of the canvas. It is called
4375 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4376 * @param spp new number of samples per pixel
4379 Editor::set_samples_per_pixel (framecnt_t spp)
4385 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4386 const framecnt_t lots_of_pixels = 4000;
4388 /* if the zoom level is greater than what you'd get trying to display 3
4389 * days of audio on a really big screen, then it's too big.
4392 if (spp * lots_of_pixels > three_days) {
4396 samples_per_pixel = spp;
4399 tempo_lines->tempo_map_changed();
4402 bool const showing_time_selection = selection->time.length() > 0;
4404 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4405 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4406 (*i)->reshow_selection (selection->time);
4410 ZoomChanged (); /* EMIT_SIGNAL */
4412 ArdourCanvas::GtkCanvasViewport* c;
4414 c = get_track_canvas();
4416 c->canvas()->zoomed ();
4419 if (playhead_cursor) {
4420 playhead_cursor->set_position (playhead_cursor->current_frame ());
4423 refresh_location_display();
4424 _summary->set_overlays_dirty ();
4426 update_marker_labels ();
4432 Editor::queue_visual_videotimeline_update ()
4435 * pending_visual_change.add (VisualChange::VideoTimeline);
4436 * or maybe even more specific: which videotimeline-image
4437 * currently it calls update_video_timeline() to update
4438 * _all outdated_ images on the video-timeline.
4439 * see 'exposeimg()' in video_image_frame.cc
4441 ensure_visual_change_idle_handler ();
4445 Editor::ensure_visual_change_idle_handler ()
4447 if (pending_visual_change.idle_handler_id < 0) {
4448 // see comment in add_to_idle_resize above.
4449 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4450 pending_visual_change.being_handled = false;
4455 Editor::_idle_visual_changer (void* arg)
4457 return static_cast<Editor*>(arg)->idle_visual_changer ();
4461 Editor::idle_visual_changer ()
4463 /* set_horizontal_position() below (and maybe other calls) call
4464 gtk_main_iteration(), so it's possible that a signal will be handled
4465 half-way through this method. If this signal wants an
4466 idle_visual_changer we must schedule another one after this one, so
4467 mark the idle_handler_id as -1 here to allow that. Also make a note
4468 that we are doing the visual change, so that changes in response to
4469 super-rapid-screen-update can be dropped if we are still processing
4473 pending_visual_change.idle_handler_id = -1;
4474 pending_visual_change.being_handled = true;
4476 VisualChange vc = pending_visual_change;
4478 pending_visual_change.pending = (VisualChange::Type) 0;
4480 visual_changer (vc);
4482 pending_visual_change.being_handled = false;
4484 return 0; /* this is always a one-shot call */
4488 Editor::visual_changer (const VisualChange& vc)
4490 double const last_time_origin = horizontal_position ();
4492 if (vc.pending & VisualChange::ZoomLevel) {
4493 set_samples_per_pixel (vc.samples_per_pixel);
4495 compute_fixed_ruler_scale ();
4497 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4498 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4500 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4501 current_bbt_points_begin, current_bbt_points_end);
4502 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4503 current_bbt_points_begin, current_bbt_points_end);
4504 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4506 update_video_timeline();
4509 if (vc.pending & VisualChange::TimeOrigin) {
4510 set_horizontal_position (vc.time_origin / samples_per_pixel);
4513 if (vc.pending & VisualChange::YOrigin) {
4514 vertical_adjustment.set_value (vc.y_origin);
4517 if (last_time_origin == horizontal_position ()) {
4518 /* changed signal not emitted */
4519 update_fixed_rulers ();
4520 redisplay_tempo (true);
4523 if (!(vc.pending & VisualChange::ZoomLevel)) {
4524 update_video_timeline();
4527 _summary->set_overlays_dirty ();
4530 struct EditorOrderTimeAxisSorter {
4531 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4532 return a->order () < b->order ();
4537 Editor::sort_track_selection (TrackViewList& sel)
4539 EditorOrderTimeAxisSorter cmp;
4544 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4547 framepos_t where = 0;
4548 EditPoint ep = _edit_point;
4550 if(Profile->get_mixbus())
4551 if (ep == EditAtSelectedMarker)
4554 if (from_context_menu && (ep == EditAtMouse)) {
4555 return canvas_event_sample (&context_click_event, 0, 0);
4558 if (entered_marker) {
4559 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4560 return entered_marker->position();
4563 if (ignore_playhead && ep == EditAtPlayhead) {
4564 ep = EditAtSelectedMarker;
4568 case EditAtPlayhead:
4569 where = _session->audible_frame();
4570 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4573 case EditAtSelectedMarker:
4574 if (!selection->markers.empty()) {
4576 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4579 where = loc->start();
4583 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4591 if (!mouse_frame (where, ignored)) {
4592 /* XXX not right but what can we do ? */
4596 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4604 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4606 if (!_session) return;
4608 begin_reversible_command (cmd);
4612 if ((tll = transport_loop_location()) == 0) {
4613 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4614 XMLNode &before = _session->locations()->get_state();
4615 _session->locations()->add (loc, true);
4616 _session->set_auto_loop_location (loc);
4617 XMLNode &after = _session->locations()->get_state();
4618 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4620 XMLNode &before = tll->get_state();
4621 tll->set_hidden (false, this);
4622 tll->set (start, end);
4623 XMLNode &after = tll->get_state();
4624 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4627 commit_reversible_command ();
4631 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4633 if (!_session) return;
4635 begin_reversible_command (cmd);
4639 if ((tpl = transport_punch_location()) == 0) {
4640 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4641 XMLNode &before = _session->locations()->get_state();
4642 _session->locations()->add (loc, true);
4643 _session->set_auto_punch_location (loc);
4644 XMLNode &after = _session->locations()->get_state();
4645 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4647 XMLNode &before = tpl->get_state();
4648 tpl->set_hidden (false, this);
4649 tpl->set (start, end);
4650 XMLNode &after = tpl->get_state();
4651 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4654 commit_reversible_command ();
4657 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4658 * @param rs List to which found regions are added.
4659 * @param where Time to look at.
4660 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4663 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4665 const TrackViewList* tracks;
4668 tracks = &track_views;
4673 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4675 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4678 boost::shared_ptr<Track> tr;
4679 boost::shared_ptr<Playlist> pl;
4681 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4683 boost::shared_ptr<RegionList> regions = pl->regions_at (
4684 (framepos_t) floor ( (double) where * tr->speed()));
4686 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4687 RegionView* rv = rtv->view()->find_view (*i);
4698 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4700 const TrackViewList* tracks;
4703 tracks = &track_views;
4708 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4709 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4711 boost::shared_ptr<Track> tr;
4712 boost::shared_ptr<Playlist> pl;
4714 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4716 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4717 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4719 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4721 RegionView* rv = rtv->view()->find_view (*i);
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, and edit_point == mouse, 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
4745 Editor::get_regions_from_selection_and_edit_point ()
4747 RegionSelection regions;
4749 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4750 regions.add (entered_regionview);
4752 regions = selection->regions;
4755 if ( regions.empty() ) {
4756 TrackViewList tracks = selection->tracks;
4758 if (!tracks.empty()) {
4759 /* no region selected or entered, but some selected tracks:
4760 * act on all regions on the selected tracks at the edit point
4762 framepos_t const where = get_preferred_edit_position ();
4763 get_regions_at(regions, where, tracks);
4770 /** Get regions using the following method:
4772 * Make a region list using:
4773 * (a) any selected regions
4774 * (b) the intersection of any selected tracks and the edit point(*)
4775 * (c) if neither exists, then whatever region is under the mouse
4777 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4779 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4782 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4784 RegionSelection regions;
4786 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4787 regions.add (entered_regionview);
4789 regions = selection->regions;
4792 if ( regions.empty() ) {
4793 TrackViewList tracks = selection->tracks;
4795 if (!tracks.empty()) {
4796 /* no region selected or entered, but some selected tracks:
4797 * act on all regions on the selected tracks at the edit point
4799 get_regions_at(regions, pos, tracks);
4806 /** Start with regions that are selected, or the entered regionview if none are selected.
4807 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4808 * of the regions that we started with.
4812 Editor::get_regions_from_selection_and_entered ()
4814 RegionSelection regions = selection->regions;
4816 if (regions.empty() && entered_regionview) {
4817 regions.add (entered_regionview);
4824 Editor::get_regionviews_by_id (PBD::ID const & id, RegionSelection & regions) const
4826 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4827 RouteTimeAxisView* tatv;
4829 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4830 boost::shared_ptr<Playlist> pl;
4831 std::vector<boost::shared_ptr<Region> > results;
4832 boost::shared_ptr<Track> tr;
4834 if ((tr = tatv->track()) == 0) {
4839 if ((pl = (tr->playlist())) != 0) {
4840 boost::shared_ptr<Region> r = pl->region_by_id (id);
4842 RegionView* marv = tatv->view()->find_view (r);
4844 regions.push_back (marv);
4853 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4855 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4857 RouteTimeAxisView* tatv;
4859 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4861 boost::shared_ptr<Playlist> pl;
4862 vector<boost::shared_ptr<Region> > results;
4864 boost::shared_ptr<Track> tr;
4866 if ((tr = tatv->track()) == 0) {
4871 if ((pl = (tr->playlist())) != 0) {
4872 if (src_comparison) {
4873 pl->get_source_equivalent_regions (region, results);
4875 pl->get_region_list_equivalent_regions (region, results);
4879 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4880 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4881 regions.push_back (marv);
4890 Editor::show_rhythm_ferret ()
4892 if (rhythm_ferret == 0) {
4893 rhythm_ferret = new RhythmFerret(*this);
4896 rhythm_ferret->set_session (_session);
4897 rhythm_ferret->show ();
4898 rhythm_ferret->present ();
4902 Editor::first_idle ()
4904 MessageDialog* dialog = 0;
4906 if (track_views.size() > 1) {
4907 dialog = new MessageDialog (
4909 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4913 ARDOUR_UI::instance()->flush_pending ();
4916 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4920 // first idle adds route children (automation tracks), so we need to redisplay here
4921 _routes->redisplay ();
4928 Editor::_idle_resize (gpointer arg)
4930 return ((Editor*)arg)->idle_resize ();
4934 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4936 if (resize_idle_id < 0) {
4937 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
4938 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
4939 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
4941 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
4942 _pending_resize_amount = 0;
4945 /* make a note of the smallest resulting height, so that we can clamp the
4946 lower limit at TimeAxisView::hSmall */
4948 int32_t min_resulting = INT32_MAX;
4950 _pending_resize_amount += h;
4951 _pending_resize_view = view;
4953 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4955 if (selection->tracks.contains (_pending_resize_view)) {
4956 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4957 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4961 if (min_resulting < 0) {
4966 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4967 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4971 /** Handle pending resizing of tracks */
4973 Editor::idle_resize ()
4975 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4977 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4978 selection->tracks.contains (_pending_resize_view)) {
4980 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4981 if (*i != _pending_resize_view) {
4982 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4987 _pending_resize_amount = 0;
4988 _group_tabs->set_dirty ();
4989 resize_idle_id = -1;
4997 ENSURE_GUI_THREAD (*this, &Editor::located);
5000 playhead_cursor->set_position (_session->audible_frame ());
5001 if (_follow_playhead && !_pending_initial_locate) {
5002 reset_x_origin_to_follow_playhead ();
5006 _pending_locate_request = false;
5007 _pending_initial_locate = false;
5011 Editor::region_view_added (RegionView * rv)
5013 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5014 if (rv->region ()->id () == (*pr)) {
5015 selection->add (rv);
5016 selection->regions.pending.erase (pr);
5020 _summary->set_background_dirty ();
5024 Editor::region_view_removed ()
5026 _summary->set_background_dirty ();
5030 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5032 TrackViewList::const_iterator j = track_views.begin ();
5033 while (j != track_views.end()) {
5034 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5035 if (rtv && rtv->route() == r) {
5046 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5050 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5051 TimeAxisView* tv = axis_view_from_route (*i);
5061 Editor::suspend_route_redisplay ()
5064 _routes->suspend_redisplay();
5069 Editor::resume_route_redisplay ()
5072 _routes->resume_redisplay();
5077 Editor::add_routes (RouteList& routes)
5079 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5081 RouteTimeAxisView *rtv;
5082 list<RouteTimeAxisView*> new_views;
5084 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5085 boost::shared_ptr<Route> route = (*x);
5087 if (route->is_auditioner() || route->is_monitor()) {
5091 DataType dt = route->input()->default_type();
5093 if (dt == ARDOUR::DataType::AUDIO) {
5094 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5095 rtv->set_route (route);
5096 } else if (dt == ARDOUR::DataType::MIDI) {
5097 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5098 rtv->set_route (route);
5100 throw unknown_type();
5103 new_views.push_back (rtv);
5104 track_views.push_back (rtv);
5106 rtv->effective_gain_display ();
5108 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5109 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5112 if (new_views.size() > 0) {
5113 _routes->routes_added (new_views);
5114 _summary->routes_added (new_views);
5117 if (show_editor_mixer_when_tracks_arrive) {
5118 show_editor_mixer (true);
5121 editor_list_button.set_sensitive (true);
5125 Editor::timeaxisview_deleted (TimeAxisView *tv)
5127 if (tv == entered_track) {
5131 if (_session && _session->deletion_in_progress()) {
5132 /* the situation is under control */
5136 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5138 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5140 _routes->route_removed (tv);
5142 TimeAxisView::Children c = tv->get_child_list ();
5143 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5144 if (entered_track == i->get()) {
5149 /* remove it from the list of track views */
5151 TrackViewList::iterator i;
5153 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5154 i = track_views.erase (i);
5157 /* update whatever the current mixer strip is displaying, if revelant */
5159 boost::shared_ptr<Route> route;
5162 route = rtav->route ();
5165 if (current_mixer_strip && current_mixer_strip->route() == route) {
5167 TimeAxisView* next_tv;
5169 if (track_views.empty()) {
5171 } else if (i == track_views.end()) {
5172 next_tv = track_views.front();
5179 set_selected_mixer_strip (*next_tv);
5181 /* make the editor mixer strip go away setting the
5182 * button to inactive (which also unticks the menu option)
5185 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5191 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5193 if (apply_to_selection) {
5194 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5196 TrackSelection::iterator j = i;
5199 hide_track_in_display (*i, false);
5204 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5206 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5207 // this will hide the mixer strip
5208 set_selected_mixer_strip (*tv);
5211 _routes->hide_track_in_display (*tv);
5216 Editor::sync_track_view_list_and_routes ()
5218 track_views = TrackViewList (_routes->views ());
5220 _summary->set_dirty ();
5221 _group_tabs->set_dirty ();
5223 return false; // do not call again (until needed)
5227 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5229 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5234 /** Find a RouteTimeAxisView by the ID of its route */
5236 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5238 RouteTimeAxisView* v;
5240 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5241 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5242 if(v->route()->id() == id) {
5252 Editor::fit_route_group (RouteGroup *g)
5254 TrackViewList ts = axis_views_from_routes (g->route_list ());
5259 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5261 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5264 _session->cancel_audition ();
5268 if (_session->is_auditioning()) {
5269 _session->cancel_audition ();
5270 if (r == last_audition_region) {
5275 _session->audition_region (r);
5276 last_audition_region = r;
5281 Editor::hide_a_region (boost::shared_ptr<Region> r)
5283 r->set_hidden (true);
5287 Editor::show_a_region (boost::shared_ptr<Region> r)
5289 r->set_hidden (false);
5293 Editor::audition_region_from_region_list ()
5295 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5299 Editor::hide_region_from_region_list ()
5301 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5305 Editor::show_region_in_region_list ()
5307 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5311 Editor::step_edit_status_change (bool yn)
5314 start_step_editing ();
5316 stop_step_editing ();
5321 Editor::start_step_editing ()
5323 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5327 Editor::stop_step_editing ()
5329 step_edit_connection.disconnect ();
5333 Editor::check_step_edit ()
5335 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5336 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5338 mtv->check_step_edit ();
5342 return true; // do it again, till we stop
5346 Editor::scroll_press (Direction dir)
5348 ++_scroll_callbacks;
5350 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5351 /* delay the first auto-repeat */
5357 scroll_backward (1);
5365 scroll_up_one_track ();
5369 scroll_down_one_track ();
5373 /* do hacky auto-repeat */
5374 if (!_scroll_connection.connected ()) {
5376 _scroll_connection = Glib::signal_timeout().connect (
5377 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5380 _scroll_callbacks = 0;
5387 Editor::scroll_release ()
5389 _scroll_connection.disconnect ();
5392 /** Queue a change for the Editor viewport x origin to follow the playhead */
5394 Editor::reset_x_origin_to_follow_playhead ()
5396 framepos_t const frame = playhead_cursor->current_frame ();
5398 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5400 if (_session->transport_speed() < 0) {
5402 if (frame > (current_page_samples() / 2)) {
5403 center_screen (frame-(current_page_samples()/2));
5405 center_screen (current_page_samples()/2);
5412 if (frame < leftmost_frame) {
5414 if (_session->transport_rolling()) {
5415 /* rolling; end up with the playhead at the right of the page */
5416 l = frame - current_page_samples ();
5418 /* not rolling: end up with the playhead 1/4 of the way along the page */
5419 l = frame - current_page_samples() / 4;
5423 if (_session->transport_rolling()) {
5424 /* rolling: end up with the playhead on the left of the page */
5427 /* not rolling: end up with the playhead 3/4 of the way along the page */
5428 l = frame - 3 * current_page_samples() / 4;
5436 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5442 Editor::super_rapid_screen_update ()
5444 if (!_session || !_session->engine().running()) {
5448 /* METERING / MIXER STRIPS */
5450 /* update track meters, if required */
5451 if (is_mapped() && meters_running) {
5452 RouteTimeAxisView* rtv;
5453 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5454 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5455 rtv->fast_update ();
5460 /* and any current mixer strip */
5461 if (current_mixer_strip) {
5462 current_mixer_strip->fast_update ();
5465 /* PLAYHEAD AND VIEWPORT */
5467 framepos_t const frame = _session->audible_frame();
5469 /* There are a few reasons why we might not update the playhead / viewport stuff:
5471 * 1. we don't update things when there's a pending locate request, otherwise
5472 * when the editor requests a locate there is a chance that this method
5473 * will move the playhead before the locate request is processed, causing
5475 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5476 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5479 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5481 last_update_frame = frame;
5483 if (!_dragging_playhead) {
5484 playhead_cursor->set_position (frame);
5487 if (!_stationary_playhead) {
5489 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5490 /* We only do this if we aren't already
5491 handling a visual change (ie if
5492 pending_visual_change.being_handled is
5493 false) so that these requests don't stack
5494 up there are too many of them to handle in
5497 reset_x_origin_to_follow_playhead ();
5502 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5506 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5507 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5508 if (target <= 0.0) {
5511 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5512 target = (target * 0.15) + (current * 0.85);
5518 set_horizontal_position (current);
5527 Editor::session_going_away ()
5529 _have_idled = false;
5531 _session_connections.drop_connections ();
5533 super_rapid_screen_update_connection.disconnect ();
5535 selection->clear ();
5536 cut_buffer->clear ();
5538 clicked_regionview = 0;
5539 clicked_axisview = 0;
5540 clicked_routeview = 0;
5541 entered_regionview = 0;
5543 last_update_frame = 0;
5546 playhead_cursor->hide ();
5548 /* rip everything out of the list displays */
5552 _route_groups->clear ();
5554 /* do this first so that deleting a track doesn't reset cms to null
5555 and thus cause a leak.
5558 if (current_mixer_strip) {
5559 if (current_mixer_strip->get_parent() != 0) {
5560 global_hpacker.remove (*current_mixer_strip);
5562 delete current_mixer_strip;
5563 current_mixer_strip = 0;
5566 /* delete all trackviews */
5568 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5571 track_views.clear ();
5573 nudge_clock->set_session (0);
5575 editor_list_button.set_active(false);
5576 editor_list_button.set_sensitive(false);
5578 /* clear tempo/meter rulers */
5579 remove_metric_marks ();
5581 clear_marker_display ();
5583 stop_step_editing ();
5585 /* get rid of any existing editor mixer strip */
5587 WindowTitle title(Glib::get_application_name());
5588 title += _("Editor");
5590 set_title (title.get_string());
5592 SessionHandlePtr::session_going_away ();
5597 Editor::show_editor_list (bool yn)
5600 _the_notebook.show ();
5602 _the_notebook.hide ();
5607 Editor::change_region_layering_order (bool from_context_menu)
5609 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5611 if (!clicked_routeview) {
5612 if (layering_order_editor) {
5613 layering_order_editor->hide ();
5618 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5624 boost::shared_ptr<Playlist> pl = track->playlist();
5630 if (layering_order_editor == 0) {
5631 layering_order_editor = new RegionLayeringOrderEditor (*this);
5634 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5635 layering_order_editor->maybe_present ();
5639 Editor::update_region_layering_order_editor ()
5641 if (layering_order_editor && layering_order_editor->is_visible ()) {
5642 change_region_layering_order (true);
5647 Editor::setup_fade_images ()
5649 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5650 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5651 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5652 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5653 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5655 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5656 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5657 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5658 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5659 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5661 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5662 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5663 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5664 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5665 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5667 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5668 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5669 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5670 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5671 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5675 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5677 Editor::action_menu_item (std::string const & name)
5679 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5682 return *manage (a->create_menu_item ());
5686 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5688 EventBox* b = manage (new EventBox);
5689 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5690 Label* l = manage (new Label (name));
5694 _the_notebook.append_page (widget, *b);
5698 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5700 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5701 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5704 if (ev->type == GDK_2BUTTON_PRESS) {
5706 /* double-click on a notebook tab shrinks or expands the notebook */
5708 if (_notebook_shrunk) {
5709 if (pre_notebook_shrink_pane_width) {
5710 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5712 _notebook_shrunk = false;
5714 pre_notebook_shrink_pane_width = edit_pane.get_position();
5716 /* this expands the LHS of the edit pane to cover the notebook
5717 PAGE but leaves the tabs visible.
5719 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5720 _notebook_shrunk = true;
5728 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5730 using namespace Menu_Helpers;
5732 MenuList& items = _control_point_context_menu.items ();
5735 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5736 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5737 if (!can_remove_control_point (item)) {
5738 items.back().set_sensitive (false);
5741 _control_point_context_menu.popup (event->button.button, event->button.time);
5745 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5747 using namespace Menu_Helpers;
5749 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5754 /* We need to get the selection here and pass it to the operations, since
5755 popping up the menu will cause a region leave event which clears
5756 entered_regionview. */
5758 MidiRegionView& mrv = note->region_view();
5759 const RegionSelection rs = get_regions_from_selection_and_entered ();
5761 MenuList& items = _note_context_menu.items();
5764 items.push_back(MenuElem(_("Delete"),
5765 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5766 items.push_back(MenuElem(_("Edit..."),
5767 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5768 items.push_back(MenuElem(_("Legatize"),
5769 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5770 items.push_back(MenuElem(_("Quantize..."),
5771 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5772 items.push_back(MenuElem(_("Remove Overlap"),
5773 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5774 items.push_back(MenuElem(_("Transform..."),
5775 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5777 _note_context_menu.popup (event->button.button, event->button.time);
5781 Editor::zoom_vertical_modifier_released()
5783 _stepping_axis_view = 0;
5787 Editor::ui_parameter_changed (string parameter)
5789 if (parameter == "icon-set") {
5790 while (!_cursor_stack.empty()) {
5791 _cursor_stack.pop_back();
5793 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5794 _cursor_stack.push_back(_cursors->grabber);
5795 } else if (parameter == "draggable-playhead") {
5796 if (_verbose_cursor) {
5797 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());