2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include "gtkmm2ext/tearoff.h"
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/audio_track.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/audioregion.h"
71 #include "ardour/location.h"
72 #include "ardour/profile.h"
73 #include "ardour/route_group.h"
74 #include "ardour/session_playlists.h"
75 #include "ardour/tempo.h"
76 #include "ardour/utils.h"
78 #include "canvas/debug.h"
79 #include "canvas/text.h"
81 #include "control_protocol/control_protocol.h"
85 #include "analysis_window.h"
86 #include "audio_clock.h"
87 #include "audio_region_view.h"
88 #include "audio_streamview.h"
89 #include "audio_time_axis.h"
90 #include "automation_time_axis.h"
91 #include "bundle_manager.h"
92 #include "crossfade_edit.h"
96 #include "editor_cursors.h"
97 #include "editor_drag.h"
98 #include "editor_group_tabs.h"
99 #include "editor_locations.h"
100 #include "editor_regions.h"
101 #include "editor_route_groups.h"
102 #include "editor_routes.h"
103 #include "editor_snapshots.h"
104 #include "editor_summary.h"
105 #include "global_port_matrix.h"
106 #include "gui_object.h"
107 #include "gui_thread.h"
108 #include "keyboard.h"
110 #include "midi_time_axis.h"
111 #include "mixer_strip.h"
112 #include "mixer_ui.h"
113 #include "mouse_cursors.h"
114 #include "playlist_selector.h"
115 #include "public_editor.h"
116 #include "region_layering_order_editor.h"
117 #include "rgb_macros.h"
118 #include "rhythm_ferret.h"
119 #include "selection.h"
121 #include "tempo_lines.h"
122 #include "time_axis_view.h"
124 #include "verbose_cursor.h"
129 using namespace ARDOUR;
130 using namespace ARDOUR_UI_UTILS;
133 using namespace Glib;
134 using namespace Gtkmm2ext;
135 using namespace Editing;
137 using PBD::internationalize;
139 using Gtkmm2ext::Keyboard;
141 const double Editor::timebar_height = 15.0;
143 static const gchar *_snap_type_strings[] = {
177 static const gchar *_snap_mode_strings[] = {
184 static const gchar *_edit_point_strings[] = {
191 static const gchar *_edit_mode_strings[] = {
199 static const gchar *_zoom_focus_strings[] = {
209 #ifdef USE_RUBBERBAND
210 static const gchar *_rb_opt_strings[] = {
213 N_("Balanced multitimbral mixture"),
214 N_("Unpitched percussion with stable notes"),
215 N_("Crisp monophonic instrumental"),
216 N_("Unpitched solo percussion"),
217 N_("Resample without preserving pitch"),
222 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
225 pane_size_watcher (Paned* pane)
227 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
231 Quartz: impossible to access
233 so stop that by preventing it from ever getting too narrow. 35
234 pixels is basically a rough guess at the tab width.
239 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
241 gint pos = pane->get_position ();
243 if (pos > max_width_of_lhs) {
244 pane->set_position (max_width_of_lhs);
249 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
251 /* time display buttons */
252 , minsec_label (_("Mins:Secs"))
253 , bbt_label (_("Bars:Beats"))
254 , timecode_label (_("Timecode"))
255 , samples_label (_("Samples"))
256 , tempo_label (_("Tempo"))
257 , meter_label (_("Meter"))
258 , mark_label (_("Location Markers"))
259 , range_mark_label (_("Range Markers"))
260 , transport_mark_label (_("Loop/Punch Ranges"))
261 , cd_mark_label (_("CD Markers"))
262 , videotl_label (_("Video Timeline"))
263 , edit_packer (4, 4, true)
265 /* the values here don't matter: layout widgets
266 reset them as needed.
269 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
270 , horizontal_adjustment (0.0, 0.0, 1e16)
271 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
273 , controls_layout (unused_adjustment, vertical_adjustment)
275 /* tool bar related */
277 , toolbar_selection_clock_table (2,3)
278 , _mouse_mode_tearoff (0)
279 , automation_mode_button (_("mode"))
283 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
287 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
288 , meters_running(false)
289 , _pending_locate_request (false)
290 , _pending_initial_locate (false)
291 , _last_cut_copy_source_track (0)
293 , _region_selection_change_updates_region_list (true)
294 , _following_mixer_selection (false)
295 , _control_point_toggled_on_press (false)
296 , _stepping_axis_view (0)
300 /* we are a singleton */
302 PublicEditor::_instance = this;
306 selection = new Selection (this);
307 cut_buffer = new Selection (this);
309 clicked_regionview = 0;
310 clicked_axisview = 0;
311 clicked_routeview = 0;
312 clicked_control_point = 0;
313 last_update_frame = 0;
314 pre_press_cursor = 0;
317 _drags = new DragManager (this);
320 current_mixer_strip = 0;
323 snap_type_strings = I18N (_snap_type_strings);
324 snap_mode_strings = I18N (_snap_mode_strings);
325 zoom_focus_strings = I18N (_zoom_focus_strings);
326 edit_mode_strings = I18N (_edit_mode_strings);
327 edit_point_strings = I18N (_edit_point_strings);
328 #ifdef USE_RUBBERBAND
329 rb_opt_strings = I18N (_rb_opt_strings);
333 build_edit_mode_menu();
334 build_zoom_focus_menu();
335 build_track_count_menu();
336 build_snap_mode_menu();
337 build_snap_type_menu();
338 build_edit_point_menu();
340 snap_threshold = 5.0;
341 bbt_beat_subdivision = 4;
342 _visible_canvas_width = 0;
343 _visible_canvas_height = 0;
344 autoscroll_horizontal_allowed = false;
345 autoscroll_vertical_allowed = false;
350 current_interthread_info = 0;
351 _show_measures = true;
353 show_gain_after_trim = false;
355 have_pending_keyboard_selection = false;
356 _follow_playhead = true;
357 _stationary_playhead = false;
358 editor_ruler_menu = 0;
359 no_ruler_shown_update = false;
361 range_marker_menu = 0;
362 marker_menu_item = 0;
363 tempo_or_meter_marker_menu = 0;
364 transport_marker_menu = 0;
365 new_transport_marker_menu = 0;
366 editor_mixer_strip_width = Wide;
367 show_editor_mixer_when_tracks_arrive = false;
368 region_edit_menu_split_multichannel_item = 0;
369 region_edit_menu_split_item = 0;
372 current_stepping_trackview = 0;
374 entered_regionview = 0;
376 clear_entered_track = false;
379 button_release_can_deselect = true;
380 _dragging_playhead = false;
381 _dragging_edit_point = false;
382 select_new_marker = false;
384 layering_order_editor = 0;
385 no_save_visual = false;
387 within_track_canvas = false;
389 scrubbing_direction = 0;
393 location_marker_color = ARDOUR_UI::config()->get_LocationMarker();
394 location_range_color = ARDOUR_UI::config()->get_LocationRange();
395 location_cd_marker_color = ARDOUR_UI::config()->get_LocationCDMarker();
396 location_loop_color = ARDOUR_UI::config()->get_LocationLoop();
397 location_punch_color = ARDOUR_UI::config()->get_LocationPunch();
399 zoom_focus = ZoomFocusLeft;
400 _edit_point = EditAtMouse;
401 _internal_editing = false;
402 current_canvas_cursor = 0;
403 _visible_track_count = -1;
405 samples_per_pixel = 2048; /* too early to use reset_zoom () */
407 _scroll_callbacks = 0;
409 bbt_label.set_name ("EditorRulerLabel");
410 bbt_label.set_size_request (-1, (int)timebar_height);
411 bbt_label.set_alignment (1.0, 0.5);
412 bbt_label.set_padding (5,0);
414 bbt_label.set_no_show_all();
415 minsec_label.set_name ("EditorRulerLabel");
416 minsec_label.set_size_request (-1, (int)timebar_height);
417 minsec_label.set_alignment (1.0, 0.5);
418 minsec_label.set_padding (5,0);
419 minsec_label.hide ();
420 minsec_label.set_no_show_all();
421 timecode_label.set_name ("EditorRulerLabel");
422 timecode_label.set_size_request (-1, (int)timebar_height);
423 timecode_label.set_alignment (1.0, 0.5);
424 timecode_label.set_padding (5,0);
425 timecode_label.hide ();
426 timecode_label.set_no_show_all();
427 samples_label.set_name ("EditorRulerLabel");
428 samples_label.set_size_request (-1, (int)timebar_height);
429 samples_label.set_alignment (1.0, 0.5);
430 samples_label.set_padding (5,0);
431 samples_label.hide ();
432 samples_label.set_no_show_all();
434 tempo_label.set_name ("EditorRulerLabel");
435 tempo_label.set_size_request (-1, (int)timebar_height);
436 tempo_label.set_alignment (1.0, 0.5);
437 tempo_label.set_padding (5,0);
439 tempo_label.set_no_show_all();
441 meter_label.set_name ("EditorRulerLabel");
442 meter_label.set_size_request (-1, (int)timebar_height);
443 meter_label.set_alignment (1.0, 0.5);
444 meter_label.set_padding (5,0);
446 meter_label.set_no_show_all();
448 if (Profile->get_trx()) {
449 mark_label.set_text (_("Markers"));
451 mark_label.set_name ("EditorRulerLabel");
452 mark_label.set_size_request (-1, (int)timebar_height);
453 mark_label.set_alignment (1.0, 0.5);
454 mark_label.set_padding (5,0);
456 mark_label.set_no_show_all();
458 cd_mark_label.set_name ("EditorRulerLabel");
459 cd_mark_label.set_size_request (-1, (int)timebar_height);
460 cd_mark_label.set_alignment (1.0, 0.5);
461 cd_mark_label.set_padding (5,0);
462 cd_mark_label.hide();
463 cd_mark_label.set_no_show_all();
465 videotl_bar_height = 4;
466 videotl_label.set_name ("EditorRulerLabel");
467 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
468 videotl_label.set_alignment (1.0, 0.5);
469 videotl_label.set_padding (5,0);
470 videotl_label.hide();
471 videotl_label.set_no_show_all();
473 range_mark_label.set_name ("EditorRulerLabel");
474 range_mark_label.set_size_request (-1, (int)timebar_height);
475 range_mark_label.set_alignment (1.0, 0.5);
476 range_mark_label.set_padding (5,0);
477 range_mark_label.hide();
478 range_mark_label.set_no_show_all();
480 transport_mark_label.set_name ("EditorRulerLabel");
481 transport_mark_label.set_size_request (-1, (int)timebar_height);
482 transport_mark_label.set_alignment (1.0, 0.5);
483 transport_mark_label.set_padding (5,0);
484 transport_mark_label.hide();
485 transport_mark_label.set_no_show_all();
487 initialize_canvas ();
489 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
491 _summary = new EditorSummary (this);
493 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
494 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
496 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
498 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
499 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
501 edit_controls_vbox.set_spacing (0);
502 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
503 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
505 HBox* h = manage (new HBox);
506 _group_tabs = new EditorGroupTabs (this);
507 if (!ARDOUR::Profile->get_trx()) {
508 h->pack_start (*_group_tabs, PACK_SHRINK);
510 h->pack_start (edit_controls_vbox);
511 controls_layout.add (*h);
513 controls_layout.set_name ("EditControlsBase");
514 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
515 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
516 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
518 _cursors = new MouseCursors;
519 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
520 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
522 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
524 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
525 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
526 pad_line_1->set_outline_color (0xFF0000FF);
532 edit_packer.set_col_spacings (0);
533 edit_packer.set_row_spacings (0);
534 edit_packer.set_homogeneous (false);
535 edit_packer.set_border_width (0);
536 edit_packer.set_name ("EditorWindow");
538 time_bars_event_box.add (time_bars_vbox);
539 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
540 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
542 /* labels for the time bars */
543 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
545 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
547 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
549 bottom_hbox.set_border_width (2);
550 bottom_hbox.set_spacing (3);
552 _route_groups = new EditorRouteGroups (this);
553 _routes = new EditorRoutes (this);
554 _regions = new EditorRegions (this);
555 _snapshots = new EditorSnapshots (this);
556 _locations = new EditorLocations (this);
558 /* these are static location signals */
560 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
561 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
562 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
564 add_notebook_page (_("Regions"), _regions->widget ());
565 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
566 add_notebook_page (_("Snapshots"), _snapshots->widget ());
567 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
568 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
570 _the_notebook.set_show_tabs (true);
571 _the_notebook.set_scrollable (true);
572 _the_notebook.popup_disable ();
573 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
574 _the_notebook.show_all ();
576 _notebook_shrunk = false;
578 editor_summary_pane.pack1(edit_packer);
580 Button* summary_arrows_left_left = manage (new Button);
581 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
582 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
583 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
585 Button* summary_arrows_left_right = manage (new Button);
586 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
587 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
588 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
590 VBox* summary_arrows_left = manage (new VBox);
591 summary_arrows_left->pack_start (*summary_arrows_left_left);
592 summary_arrows_left->pack_start (*summary_arrows_left_right);
594 Button* summary_arrows_right_up = manage (new Button);
595 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
596 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
597 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
599 Button* summary_arrows_right_down = manage (new Button);
600 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
601 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
602 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
604 VBox* summary_arrows_right = manage (new VBox);
605 summary_arrows_right->pack_start (*summary_arrows_right_up);
606 summary_arrows_right->pack_start (*summary_arrows_right_down);
608 Frame* summary_frame = manage (new Frame);
609 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
611 summary_frame->add (*_summary);
612 summary_frame->show ();
614 _summary_hbox.pack_start (*summary_arrows_left, false, false);
615 _summary_hbox.pack_start (*summary_frame, true, true);
616 _summary_hbox.pack_start (*summary_arrows_right, false, false);
618 if (!ARDOUR::Profile->get_trx()) {
619 editor_summary_pane.pack2 (_summary_hbox);
622 edit_pane.pack1 (editor_summary_pane, true, true);
623 if (!ARDOUR::Profile->get_trx()) {
624 edit_pane.pack2 (_the_notebook, false, true);
627 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
629 /* XXX: editor_summary_pane might need similar to the edit_pane */
631 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
633 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
634 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
636 top_hbox.pack_start (toolbar_frame);
638 HBox *hbox = manage (new HBox);
639 hbox->pack_start (edit_pane, true, true);
641 global_vpacker.pack_start (top_hbox, false, false);
642 global_vpacker.pack_start (*hbox, true, true);
644 global_hpacker.pack_start (global_vpacker, true, true);
646 set_name ("EditorWindow");
647 add_accel_group (ActionManager::ui_manager->get_accel_group());
649 status_bar_hpacker.show ();
651 vpacker.pack_end (status_bar_hpacker, false, false);
652 vpacker.pack_end (global_hpacker, true, true);
654 /* register actions now so that set_state() can find them and set toggles/checks etc */
657 /* when we start using our own keybinding system for the editor, this
658 * will be uncommented
664 set_zoom_focus (zoom_focus);
665 set_visible_track_count (_visible_track_count);
666 _snap_type = SnapToBeat;
667 set_snap_to (_snap_type);
668 _snap_mode = SnapOff;
669 set_snap_mode (_snap_mode);
670 set_mouse_mode (MouseObject, true);
671 pre_internal_mouse_mode = MouseObject;
672 pre_internal_snap_type = _snap_type;
673 pre_internal_snap_mode = _snap_mode;
674 internal_snap_type = _snap_type;
675 internal_snap_mode = _snap_mode;
676 set_edit_point_preference (EditAtMouse, true);
678 _playlist_selector = new PlaylistSelector();
679 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
681 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
685 nudge_forward_button.set_name ("nudge button");
686 nudge_forward_button.set_image(::get_icon("nudge_right"));
688 nudge_backward_button.set_name ("nudge button");
689 nudge_backward_button.set_image(::get_icon("nudge_left"));
691 fade_context_menu.set_name ("ArdourContextMenu");
693 /* icons, titles, WM stuff */
695 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
696 Glib::RefPtr<Gdk::Pixbuf> icon;
698 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
699 window_icons.push_back (icon);
701 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
702 window_icons.push_back (icon);
704 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
705 window_icons.push_back (icon);
707 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
708 window_icons.push_back (icon);
710 if (!window_icons.empty()) {
711 // set_icon_list (window_icons);
712 set_default_icon_list (window_icons);
715 WindowTitle title(Glib::get_application_name());
716 title += _("Editor");
717 set_title (title.get_string());
718 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
721 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
723 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
724 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
726 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
728 /* allow external control surfaces/protocols to do various things */
730 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
731 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
732 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
733 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
734 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
735 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
736 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
737 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
738 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
739 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
740 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
741 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
742 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
743 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
745 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
746 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
747 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
748 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
749 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
751 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
753 /* problematic: has to return a value and thus cannot be x-thread */
755 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
757 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
758 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
760 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
762 _ignore_region_action = false;
763 _last_region_menu_was_main = false;
764 _popup_region_menu_item = 0;
766 _ignore_follow_edits = false;
768 _show_marker_lines = false;
770 /* Button bindings */
772 button_bindings = new Bindings;
774 XMLNode* node = button_settings();
776 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
777 button_bindings->load (**i);
783 /* grab current parameter state */
784 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
785 ARDOUR_UI::config()->map_parameters (pc);
787 setup_fade_images ();
794 delete button_bindings;
796 delete _route_groups;
797 delete _track_canvas_viewport;
803 Editor::button_settings () const
805 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
806 XMLNode* node = find_named_node (*settings, X_("Buttons"));
809 node = new XMLNode (X_("Buttons"));
816 Editor::add_toplevel_menu (Container& cont)
818 vpacker.pack_start (cont, false, false);
823 Editor::add_transport_frame (Container& cont)
825 if(ARDOUR::Profile->get_mixbus()) {
826 global_vpacker.pack_start (cont, false, false);
827 global_vpacker.reorder_child (cont, 0);
830 vpacker.pack_start (cont, false, false);
835 Editor::get_smart_mode () const
837 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
841 Editor::catch_vanishing_regionview (RegionView *rv)
843 /* note: the selection will take care of the vanishing
844 audioregionview by itself.
847 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
851 if (clicked_regionview == rv) {
852 clicked_regionview = 0;
855 if (entered_regionview == rv) {
856 set_entered_regionview (0);
859 if (!_all_region_actions_sensitized) {
860 sensitize_all_region_actions (true);
865 Editor::set_entered_regionview (RegionView* rv)
867 if (rv == entered_regionview) {
871 if (entered_regionview) {
872 entered_regionview->exited ();
875 entered_regionview = rv;
877 if (entered_regionview != 0) {
878 entered_regionview->entered (internal_editing ());
881 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
882 /* This RegionView entry might have changed what region actions
883 are allowed, so sensitize them all in case a key is pressed.
885 sensitize_all_region_actions (true);
890 Editor::set_entered_track (TimeAxisView* tav)
893 entered_track->exited ();
899 entered_track->entered ();
904 Editor::show_window ()
906 if (!is_visible ()) {
910 /* XXX: this is a bit unfortunate; it would probably
911 be nicer if we could just call show () above rather
912 than needing the show_all ()
915 /* re-hide stuff if necessary */
916 editor_list_button_toggled ();
917 parameter_changed ("show-summary");
918 parameter_changed ("show-group-tabs");
919 parameter_changed ("show-zoom-tools");
921 /* now reset all audio_time_axis heights, because widgets might need
927 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
928 tv = (static_cast<TimeAxisView*>(*i));
932 if (current_mixer_strip) {
933 current_mixer_strip->hide_things ();
934 current_mixer_strip->parameter_changed ("mixer-element-visibility");
942 Editor::instant_save ()
944 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
949 _session->add_instant_xml(get_state());
951 Config->add_instant_xml(get_state());
956 Editor::control_vertical_zoom_in_all ()
958 tav_zoom_smooth (false, true);
962 Editor::control_vertical_zoom_out_all ()
964 tav_zoom_smooth (true, true);
968 Editor::control_vertical_zoom_in_selected ()
970 tav_zoom_smooth (false, false);
974 Editor::control_vertical_zoom_out_selected ()
976 tav_zoom_smooth (true, false);
980 Editor::control_view (uint32_t view)
982 goto_visual_state (view);
986 Editor::control_unselect ()
988 selection->clear_tracks ();
992 Editor::control_select (uint32_t rid, Selection::Operation op)
994 /* handles the (static) signal from the ControlProtocol class that
995 * requests setting the selected track to a given RID
1002 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1008 TimeAxisView* tav = axis_view_from_route (r);
1012 case Selection::Add:
1013 selection->add (tav);
1015 case Selection::Toggle:
1016 selection->toggle (tav);
1018 case Selection::Extend:
1020 case Selection::Set:
1021 selection->set (tav);
1025 selection->clear_tracks ();
1030 Editor::control_step_tracks_up ()
1032 scroll_tracks_up_line ();
1036 Editor::control_step_tracks_down ()
1038 scroll_tracks_down_line ();
1042 Editor::control_scroll (float fraction)
1044 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1050 double step = fraction * current_page_samples();
1053 _control_scroll_target is an optional<T>
1055 it acts like a pointer to an framepos_t, with
1056 a operator conversion to boolean to check
1057 that it has a value could possibly use
1058 playhead_cursor->current_frame to store the
1059 value and a boolean in the class to know
1060 when it's out of date
1063 if (!_control_scroll_target) {
1064 _control_scroll_target = _session->transport_frame();
1065 _dragging_playhead = true;
1068 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1069 *_control_scroll_target = 0;
1070 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1071 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1073 *_control_scroll_target += (framepos_t) trunc (step);
1076 /* move visuals, we'll catch up with it later */
1078 playhead_cursor->set_position (*_control_scroll_target);
1079 UpdateAllTransportClocks (*_control_scroll_target);
1081 if (*_control_scroll_target > (current_page_samples() / 2)) {
1082 /* try to center PH in window */
1083 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1089 Now we do a timeout to actually bring the session to the right place
1090 according to the playhead. This is to avoid reading disk buffers on every
1091 call to control_scroll, which is driven by ScrollTimeline and therefore
1092 probably by a control surface wheel which can generate lots of events.
1094 /* cancel the existing timeout */
1096 control_scroll_connection.disconnect ();
1098 /* add the next timeout */
1100 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1104 Editor::deferred_control_scroll (framepos_t /*target*/)
1106 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1107 // reset for next stream
1108 _control_scroll_target = boost::none;
1109 _dragging_playhead = false;
1114 Editor::access_action (std::string action_group, std::string action_item)
1120 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1123 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1131 Editor::on_realize ()
1133 Window::on_realize ();
1136 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1137 start_lock_event_timing ();
1140 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1144 Editor::start_lock_event_timing ()
1146 /* check if we should lock the GUI every 30 seconds */
1148 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1152 Editor::generic_event_handler (GdkEvent* ev)
1155 case GDK_BUTTON_PRESS:
1156 case GDK_BUTTON_RELEASE:
1157 case GDK_MOTION_NOTIFY:
1159 case GDK_KEY_RELEASE:
1160 gettimeofday (&last_event_time, 0);
1163 case GDK_LEAVE_NOTIFY:
1164 switch (ev->crossing.detail) {
1165 case GDK_NOTIFY_UNKNOWN:
1166 case GDK_NOTIFY_INFERIOR:
1167 case GDK_NOTIFY_ANCESTOR:
1169 case GDK_NOTIFY_VIRTUAL:
1170 case GDK_NOTIFY_NONLINEAR:
1171 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1172 /* leaving window, so reset focus, thus ending any and
1173 all text entry operations.
1188 Editor::lock_timeout_callback ()
1190 struct timeval now, delta;
1192 gettimeofday (&now, 0);
1194 timersub (&now, &last_event_time, &delta);
1196 if (delta.tv_sec > (time_t) ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1198 /* don't call again. Returning false will effectively
1199 disconnect us from the timer callback.
1201 unlock() will call start_lock_event_timing() to get things
1211 Editor::map_position_change (framepos_t frame)
1213 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1215 if (_session == 0) {
1219 if (_follow_playhead) {
1220 center_screen (frame);
1223 playhead_cursor->set_position (frame);
1227 Editor::center_screen (framepos_t frame)
1229 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1231 /* if we're off the page, then scroll.
1234 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1235 center_screen_internal (frame, page);
1240 Editor::center_screen_internal (framepos_t frame, float page)
1245 frame -= (framepos_t) page;
1250 reset_x_origin (frame);
1255 Editor::update_title ()
1257 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1260 bool dirty = _session->dirty();
1262 string session_name;
1264 if (_session->snap_name() != _session->name()) {
1265 session_name = _session->snap_name();
1267 session_name = _session->name();
1271 session_name = "*" + session_name;
1274 WindowTitle title(session_name);
1275 title += Glib::get_application_name();
1276 set_title (title.get_string());
1278 /* ::session_going_away() will have taken care of it */
1283 Editor::set_session (Session *t)
1285 SessionHandlePtr::set_session (t);
1291 _playlist_selector->set_session (_session);
1292 nudge_clock->set_session (_session);
1293 _summary->set_session (_session);
1294 _group_tabs->set_session (_session);
1295 _route_groups->set_session (_session);
1296 _regions->set_session (_session);
1297 _snapshots->set_session (_session);
1298 _routes->set_session (_session);
1299 _locations->set_session (_session);
1301 if (rhythm_ferret) {
1302 rhythm_ferret->set_session (_session);
1305 if (analysis_window) {
1306 analysis_window->set_session (_session);
1310 sfbrowser->set_session (_session);
1313 compute_fixed_ruler_scale ();
1315 /* Make sure we have auto loop and auto punch ranges */
1317 Location* loc = _session->locations()->auto_loop_location();
1319 loc->set_name (_("Loop"));
1322 loc = _session->locations()->auto_punch_location();
1325 loc->set_name (_("Punch"));
1328 refresh_location_display ();
1330 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1331 the selected Marker; this needs the LocationMarker list to be available.
1333 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1334 set_state (*node, Stateful::loading_state_version);
1336 /* catch up with the playhead */
1338 _session->request_locate (playhead_cursor->current_frame ());
1339 _pending_initial_locate = true;
1343 /* These signals can all be emitted by a non-GUI thread. Therefore the
1344 handlers for them must not attempt to directly interact with the GUI,
1345 but use PBD::Signal<T>::connect() which accepts an event loop
1346 ("context") where the handler will be asked to run.
1349 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1350 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1351 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1352 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1353 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1354 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1355 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1356 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1357 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1358 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1359 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1360 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1361 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1363 playhead_cursor->show ();
1365 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1366 Config->map_parameters (pc);
1367 _session->config.map_parameters (pc);
1369 restore_ruler_visibility ();
1370 //tempo_map_changed (PropertyChange (0));
1371 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1373 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1374 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1377 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1378 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1381 switch (_snap_type) {
1382 case SnapToRegionStart:
1383 case SnapToRegionEnd:
1384 case SnapToRegionSync:
1385 case SnapToRegionBoundary:
1386 build_region_boundary_cache ();
1393 /* register for undo history */
1394 _session->register_with_memento_command_factory(id(), this);
1396 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1398 start_updating_meters ();
1402 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1404 if (a->get_name() == "RegionMenu") {
1405 /* When the main menu's region menu is opened, we setup the actions so that they look right
1406 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1407 so we resensitize all region actions when the entered regionview or the region selection
1408 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1409 happens after the region context menu is opened. So we set a flag here, too.
1413 sensitize_the_right_region_actions ();
1414 _last_region_menu_was_main = true;
1419 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1421 using namespace Menu_Helpers;
1423 void (Editor::*emf)(FadeShape);
1424 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1427 images = &_xfade_in_images;
1428 emf = &Editor::set_fade_in_shape;
1430 images = &_xfade_out_images;
1431 emf = &Editor::set_fade_out_shape;
1436 _("Linear (for highly correlated material)"),
1437 *(*images)[FadeLinear],
1438 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1442 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1446 _("Constant power"),
1447 *(*images)[FadeConstantPower],
1448 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1451 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1456 *(*images)[FadeSymmetric],
1457 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1461 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1466 *(*images)[FadeSlow],
1467 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1470 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1475 *(*images)[FadeFast],
1476 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1479 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1482 /** Pop up a context menu for when the user clicks on a start crossfade */
1484 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1486 using namespace Menu_Helpers;
1487 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1490 MenuList& items (xfade_in_context_menu.items());
1493 if (arv->audio_region()->fade_in_active()) {
1494 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1496 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1499 items.push_back (SeparatorElem());
1500 fill_xfade_menu (items, true);
1502 xfade_in_context_menu.popup (button, time);
1505 /** Pop up a context menu for when the user clicks on an end crossfade */
1507 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1509 using namespace Menu_Helpers;
1510 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1513 MenuList& items (xfade_out_context_menu.items());
1516 if (arv->audio_region()->fade_out_active()) {
1517 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1519 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1522 items.push_back (SeparatorElem());
1523 fill_xfade_menu (items, false);
1525 xfade_out_context_menu.popup (button, time);
1529 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1531 using namespace Menu_Helpers;
1532 Menu* (Editor::*build_menu_function)();
1535 switch (item_type) {
1537 case RegionViewName:
1538 case RegionViewNameHighlight:
1539 case LeftFrameHandle:
1540 case RightFrameHandle:
1541 if (with_selection) {
1542 build_menu_function = &Editor::build_track_selection_context_menu;
1544 build_menu_function = &Editor::build_track_region_context_menu;
1549 if (with_selection) {
1550 build_menu_function = &Editor::build_track_selection_context_menu;
1552 build_menu_function = &Editor::build_track_context_menu;
1557 if (clicked_routeview->track()) {
1558 build_menu_function = &Editor::build_track_context_menu;
1560 build_menu_function = &Editor::build_track_bus_context_menu;
1565 /* probably shouldn't happen but if it does, we don't care */
1569 menu = (this->*build_menu_function)();
1570 menu->set_name ("ArdourContextMenu");
1572 /* now handle specific situations */
1574 switch (item_type) {
1576 case RegionViewName:
1577 case RegionViewNameHighlight:
1578 case LeftFrameHandle:
1579 case RightFrameHandle:
1580 if (!with_selection) {
1581 if (region_edit_menu_split_item) {
1582 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1583 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1585 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1588 if (region_edit_menu_split_multichannel_item) {
1589 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1590 region_edit_menu_split_multichannel_item->set_sensitive (true);
1592 region_edit_menu_split_multichannel_item->set_sensitive (false);
1605 /* probably shouldn't happen but if it does, we don't care */
1609 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1611 /* Bounce to disk */
1613 using namespace Menu_Helpers;
1614 MenuList& edit_items = menu->items();
1616 edit_items.push_back (SeparatorElem());
1618 switch (clicked_routeview->audio_track()->freeze_state()) {
1619 case AudioTrack::NoFreeze:
1620 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1623 case AudioTrack::Frozen:
1624 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1627 case AudioTrack::UnFrozen:
1628 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1634 if (item_type == StreamItem && clicked_routeview) {
1635 clicked_routeview->build_underlay_menu(menu);
1638 /* When the region menu is opened, we setup the actions so that they look right
1641 sensitize_the_right_region_actions ();
1642 _last_region_menu_was_main = false;
1644 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1645 menu->popup (button, time);
1649 Editor::build_track_context_menu ()
1651 using namespace Menu_Helpers;
1653 MenuList& edit_items = track_context_menu.items();
1656 add_dstream_context_items (edit_items);
1657 return &track_context_menu;
1661 Editor::build_track_bus_context_menu ()
1663 using namespace Menu_Helpers;
1665 MenuList& edit_items = track_context_menu.items();
1668 add_bus_context_items (edit_items);
1669 return &track_context_menu;
1673 Editor::build_track_region_context_menu ()
1675 using namespace Menu_Helpers;
1676 MenuList& edit_items = track_region_context_menu.items();
1679 /* we've just cleared the track region context menu, so the menu that these
1680 two items were on will have disappeared; stop them dangling.
1682 region_edit_menu_split_item = 0;
1683 region_edit_menu_split_multichannel_item = 0;
1685 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1688 boost::shared_ptr<Track> tr;
1689 boost::shared_ptr<Playlist> pl;
1691 if ((tr = rtv->track())) {
1692 add_region_context_items (edit_items, tr);
1696 add_dstream_context_items (edit_items);
1698 return &track_region_context_menu;
1702 Editor::analyze_region_selection ()
1704 if (analysis_window == 0) {
1705 analysis_window = new AnalysisWindow();
1708 analysis_window->set_session(_session);
1710 analysis_window->show_all();
1713 analysis_window->set_regionmode();
1714 analysis_window->analyze();
1716 analysis_window->present();
1720 Editor::analyze_range_selection()
1722 if (analysis_window == 0) {
1723 analysis_window = new AnalysisWindow();
1726 analysis_window->set_session(_session);
1728 analysis_window->show_all();
1731 analysis_window->set_rangemode();
1732 analysis_window->analyze();
1734 analysis_window->present();
1738 Editor::build_track_selection_context_menu ()
1740 using namespace Menu_Helpers;
1741 MenuList& edit_items = track_selection_context_menu.items();
1742 edit_items.clear ();
1744 add_selection_context_items (edit_items);
1745 // edit_items.push_back (SeparatorElem());
1746 // add_dstream_context_items (edit_items);
1748 return &track_selection_context_menu;
1752 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1754 using namespace Menu_Helpers;
1756 /* OK, stick the region submenu at the top of the list, and then add
1760 RegionSelection rs = get_regions_from_selection_and_entered ();
1762 string::size_type pos = 0;
1763 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1765 /* we have to hack up the region name because "_" has a special
1766 meaning for menu titles.
1769 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1770 menu_item_name.replace (pos, 1, "__");
1774 if (_popup_region_menu_item == 0) {
1775 _popup_region_menu_item = new MenuItem (menu_item_name);
1776 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1777 _popup_region_menu_item->show ();
1779 _popup_region_menu_item->set_label (menu_item_name);
1782 const framepos_t position = get_preferred_edit_position (false, true);
1784 edit_items.push_back (*_popup_region_menu_item);
1785 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1786 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1788 edit_items.push_back (SeparatorElem());
1791 /** Add context menu items relevant to selection ranges.
1792 * @param edit_items List to add the items to.
1795 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1797 using namespace Menu_Helpers;
1799 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1800 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1802 edit_items.push_back (SeparatorElem());
1803 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1805 edit_items.push_back (SeparatorElem());
1806 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1808 edit_items.push_back (SeparatorElem());
1810 edit_items.push_back (
1812 _("Move Range Start to Previous Region Boundary"),
1813 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1817 edit_items.push_back (
1819 _("Move Range Start to Next Region Boundary"),
1820 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1824 edit_items.push_back (
1826 _("Move Range End to Previous Region Boundary"),
1827 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1831 edit_items.push_back (
1833 _("Move Range End to Next Region Boundary"),
1834 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1838 edit_items.push_back (SeparatorElem());
1839 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1840 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1842 edit_items.push_back (SeparatorElem());
1843 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1845 edit_items.push_back (SeparatorElem());
1846 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1847 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1849 edit_items.push_back (SeparatorElem());
1850 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1852 edit_items.push_back (SeparatorElem());
1853 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1854 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1855 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1857 edit_items.push_back (SeparatorElem());
1858 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1859 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1860 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1861 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1862 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1863 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1864 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1870 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1872 using namespace Menu_Helpers;
1876 Menu *play_menu = manage (new Menu);
1877 MenuList& play_items = play_menu->items();
1878 play_menu->set_name ("ArdourContextMenu");
1880 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1881 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1882 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1883 play_items.push_back (SeparatorElem());
1884 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1886 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1890 Menu *select_menu = manage (new Menu);
1891 MenuList& select_items = select_menu->items();
1892 select_menu->set_name ("ArdourContextMenu");
1894 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1895 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1896 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1897 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1898 select_items.push_back (SeparatorElem());
1899 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1900 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1901 select_items.push_back (SeparatorElem());
1902 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1903 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1904 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1905 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1906 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1907 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1908 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1910 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1914 Menu *cutnpaste_menu = manage (new Menu);
1915 MenuList& cutnpaste_items = cutnpaste_menu->items();
1916 cutnpaste_menu->set_name ("ArdourContextMenu");
1918 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1919 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1920 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1922 cutnpaste_items.push_back (SeparatorElem());
1924 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1925 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1927 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1929 /* Adding new material */
1931 edit_items.push_back (SeparatorElem());
1932 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1933 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1937 Menu *nudge_menu = manage (new Menu());
1938 MenuList& nudge_items = nudge_menu->items();
1939 nudge_menu->set_name ("ArdourContextMenu");
1941 edit_items.push_back (SeparatorElem());
1942 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1943 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1944 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1945 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1947 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1951 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1953 using namespace Menu_Helpers;
1957 Menu *play_menu = manage (new Menu);
1958 MenuList& play_items = play_menu->items();
1959 play_menu->set_name ("ArdourContextMenu");
1961 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1962 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1963 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1967 Menu *select_menu = manage (new Menu);
1968 MenuList& select_items = select_menu->items();
1969 select_menu->set_name ("ArdourContextMenu");
1971 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1972 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1973 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1974 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1975 select_items.push_back (SeparatorElem());
1976 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1977 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1978 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1979 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1981 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1985 Menu *cutnpaste_menu = manage (new Menu);
1986 MenuList& cutnpaste_items = cutnpaste_menu->items();
1987 cutnpaste_menu->set_name ("ArdourContextMenu");
1989 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1990 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1991 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1993 Menu *nudge_menu = manage (new Menu());
1994 MenuList& nudge_items = nudge_menu->items();
1995 nudge_menu->set_name ("ArdourContextMenu");
1997 edit_items.push_back (SeparatorElem());
1998 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1999 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2000 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2001 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2003 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2007 Editor::snap_type() const
2013 Editor::snap_mode() const
2019 Editor::set_snap_to (SnapType st)
2021 unsigned int snap_ind = (unsigned int)st;
2025 if (snap_ind > snap_type_strings.size() - 1) {
2027 _snap_type = (SnapType)snap_ind;
2030 string str = snap_type_strings[snap_ind];
2032 if (str != snap_type_selector.get_text()) {
2033 snap_type_selector.set_text (str);
2038 switch (_snap_type) {
2039 case SnapToBeatDiv128:
2040 case SnapToBeatDiv64:
2041 case SnapToBeatDiv32:
2042 case SnapToBeatDiv28:
2043 case SnapToBeatDiv24:
2044 case SnapToBeatDiv20:
2045 case SnapToBeatDiv16:
2046 case SnapToBeatDiv14:
2047 case SnapToBeatDiv12:
2048 case SnapToBeatDiv10:
2049 case SnapToBeatDiv8:
2050 case SnapToBeatDiv7:
2051 case SnapToBeatDiv6:
2052 case SnapToBeatDiv5:
2053 case SnapToBeatDiv4:
2054 case SnapToBeatDiv3:
2055 case SnapToBeatDiv2: {
2056 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2057 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2059 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2060 current_bbt_points_begin, current_bbt_points_end);
2061 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2062 current_bbt_points_begin, current_bbt_points_end);
2063 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2067 case SnapToRegionStart:
2068 case SnapToRegionEnd:
2069 case SnapToRegionSync:
2070 case SnapToRegionBoundary:
2071 build_region_boundary_cache ();
2079 SnapChanged (); /* EMIT SIGNAL */
2083 Editor::set_snap_mode (SnapMode mode)
2085 string str = snap_mode_strings[(int)mode];
2087 if (_internal_editing) {
2088 internal_snap_mode = mode;
2090 pre_internal_snap_mode = mode;
2095 if (str != snap_mode_selector.get_text ()) {
2096 snap_mode_selector.set_text (str);
2102 Editor::set_edit_point_preference (EditPoint ep, bool force)
2104 bool changed = (_edit_point != ep);
2107 string str = edit_point_strings[(int)ep];
2109 if (Profile->get_mixbus())
2110 if (ep == EditAtSelectedMarker)
2111 ep = EditAtPlayhead;
2113 if (str != edit_point_selector.get_text ()) {
2114 edit_point_selector.set_text (str);
2117 reset_canvas_cursor ();
2119 if (!force && !changed) {
2123 const char* action=NULL;
2125 switch (_edit_point) {
2126 case EditAtPlayhead:
2127 action = "edit-at-playhead";
2129 case EditAtSelectedMarker:
2130 action = "edit-at-marker";
2133 action = "edit-at-mouse";
2137 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2139 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2143 bool in_track_canvas;
2145 if (!mouse_frame (foo, in_track_canvas)) {
2146 in_track_canvas = false;
2149 reset_canvas_action_sensitivity (in_track_canvas);
2155 Editor::set_state (const XMLNode& node, int /*version*/)
2157 const XMLProperty* prop;
2164 g.base_width = default_width;
2165 g.base_height = default_height;
2169 if ((geometry = find_named_node (node, "geometry")) != 0) {
2173 if ((prop = geometry->property("x_size")) == 0) {
2174 prop = geometry->property ("x-size");
2177 g.base_width = atoi(prop->value());
2179 if ((prop = geometry->property("y_size")) == 0) {
2180 prop = geometry->property ("y-size");
2183 g.base_height = atoi(prop->value());
2186 if ((prop = geometry->property ("x_pos")) == 0) {
2187 prop = geometry->property ("x-pos");
2190 x = atoi (prop->value());
2193 if ((prop = geometry->property ("y_pos")) == 0) {
2194 prop = geometry->property ("y-pos");
2197 y = atoi (prop->value());
2201 set_default_size (g.base_width, g.base_height);
2204 if (_session && (prop = node.property ("playhead"))) {
2206 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2208 playhead_cursor->set_position (pos);
2210 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2211 playhead_cursor->set_position (0);
2214 playhead_cursor->set_position (0);
2217 if ((prop = node.property ("mixer-width"))) {
2218 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2221 if ((prop = node.property ("zoom-focus"))) {
2222 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2225 if ((prop = node.property ("zoom"))) {
2226 /* older versions of ardour used floating point samples_per_pixel */
2227 double f = PBD::atof (prop->value());
2228 reset_zoom (llrintf (f));
2230 reset_zoom (samples_per_pixel);
2233 if ((prop = node.property ("visible-track-count"))) {
2234 set_visible_track_count (PBD::atoi (prop->value()));
2237 if ((prop = node.property ("snap-to"))) {
2238 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2241 if ((prop = node.property ("snap-mode"))) {
2242 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2245 if ((prop = node.property ("internal-snap-to"))) {
2246 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2249 if ((prop = node.property ("internal-snap-mode"))) {
2250 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2253 if ((prop = node.property ("pre-internal-snap-to"))) {
2254 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2258 if ((prop = node.property ("pre-internal-snap-mode"))) {
2259 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2262 if ((prop = node.property ("mouse-mode"))) {
2263 MouseMode m = str2mousemode(prop->value());
2264 set_mouse_mode (m, true);
2266 set_mouse_mode (MouseObject, true);
2269 if ((prop = node.property ("left-frame")) != 0) {
2271 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2275 reset_x_origin (pos);
2279 if ((prop = node.property ("y-origin")) != 0) {
2280 reset_y_origin (atof (prop->value ()));
2283 if ((prop = node.property ("internal-edit"))) {
2284 bool yn = string_is_affirmative (prop->value());
2285 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2287 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2288 tact->set_active (!yn);
2289 tact->set_active (yn);
2293 if ((prop = node.property ("join-object-range"))) {
2294 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2295 bool yn = string_is_affirmative (prop->value());
2297 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2298 tact->set_active (!yn);
2299 tact->set_active (yn);
2301 set_mouse_mode(mouse_mode, true);
2304 if ((prop = node.property ("edit-point"))) {
2305 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2308 if ((prop = node.property ("show-measures"))) {
2309 bool yn = string_is_affirmative (prop->value());
2310 _show_measures = yn;
2311 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2313 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2314 /* do it twice to force the change */
2315 tact->set_active (!yn);
2316 tact->set_active (yn);
2320 if ((prop = node.property ("follow-playhead"))) {
2321 bool yn = string_is_affirmative (prop->value());
2322 set_follow_playhead (yn);
2323 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2325 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2326 if (tact->get_active() != yn) {
2327 tact->set_active (yn);
2332 if ((prop = node.property ("stationary-playhead"))) {
2333 bool yn = string_is_affirmative (prop->value());
2334 set_stationary_playhead (yn);
2335 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2337 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2338 if (tact->get_active() != yn) {
2339 tact->set_active (yn);
2344 if ((prop = node.property ("region-list-sort-type"))) {
2345 RegionListSortType st;
2346 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2349 if ((prop = node.property ("show-editor-mixer"))) {
2351 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2354 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2355 bool yn = string_is_affirmative (prop->value());
2357 /* do it twice to force the change */
2359 tact->set_active (!yn);
2360 tact->set_active (yn);
2363 if ((prop = node.property ("show-editor-list"))) {
2365 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2368 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2369 bool yn = string_is_affirmative (prop->value());
2371 /* do it twice to force the change */
2373 tact->set_active (!yn);
2374 tact->set_active (yn);
2377 if ((prop = node.property (X_("editor-list-page")))) {
2378 _the_notebook.set_current_page (atoi (prop->value ()));
2381 if ((prop = node.property (X_("show-marker-lines")))) {
2382 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2384 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2385 bool yn = string_is_affirmative (prop->value ());
2387 tact->set_active (!yn);
2388 tact->set_active (yn);
2391 XMLNodeList children = node.children ();
2392 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2393 selection->set_state (**i, Stateful::current_state_version);
2394 _regions->set_state (**i);
2397 if ((prop = node.property ("maximised"))) {
2398 bool yn = string_is_affirmative (prop->value());
2399 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2401 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2402 bool fs = tact && tact->get_active();
2404 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2408 if ((prop = node.property ("nudge-clock-value"))) {
2410 sscanf (prop->value().c_str(), "%" PRId64, &f);
2411 nudge_clock->set (f);
2413 nudge_clock->set_mode (AudioClock::Timecode);
2414 nudge_clock->set (_session->frame_rate() * 5, true);
2421 Editor::get_state ()
2423 XMLNode* node = new XMLNode ("Editor");
2426 id().print (buf, sizeof (buf));
2427 node->add_property ("id", buf);
2429 if (is_realized()) {
2430 Glib::RefPtr<Gdk::Window> win = get_window();
2432 int x, y, width, height;
2433 win->get_root_origin(x, y);
2434 win->get_size(width, height);
2436 XMLNode* geometry = new XMLNode ("geometry");
2438 snprintf(buf, sizeof(buf), "%d", width);
2439 geometry->add_property("x-size", string(buf));
2440 snprintf(buf, sizeof(buf), "%d", height);
2441 geometry->add_property("y-size", string(buf));
2442 snprintf(buf, sizeof(buf), "%d", x);
2443 geometry->add_property("x-pos", string(buf));
2444 snprintf(buf, sizeof(buf), "%d", y);
2445 geometry->add_property("y-pos", string(buf));
2446 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2447 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2448 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2449 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2450 geometry->add_property("edit-vertical-pane-pos", string(buf));
2452 node->add_child_nocopy (*geometry);
2455 maybe_add_mixer_strip_width (*node);
2457 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2459 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2460 node->add_property ("zoom", buf);
2461 node->add_property ("snap-to", enum_2_string (_snap_type));
2462 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2463 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2464 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2465 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2466 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2467 node->add_property ("edit-point", enum_2_string (_edit_point));
2468 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2469 node->add_property ("visible-track-count", buf);
2471 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2472 node->add_property ("playhead", buf);
2473 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2474 node->add_property ("left-frame", buf);
2475 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2476 node->add_property ("y-origin", buf);
2478 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2479 node->add_property ("maximised", _maximised ? "yes" : "no");
2480 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2481 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2482 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2483 node->add_property ("mouse-mode", enum2str(mouse_mode));
2484 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2485 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2487 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2489 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2490 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2493 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2495 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2496 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2499 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2500 node->add_property (X_("editor-list-page"), buf);
2502 if (button_bindings) {
2503 XMLNode* bb = new XMLNode (X_("Buttons"));
2504 button_bindings->save (*bb);
2505 node->add_child_nocopy (*bb);
2508 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2510 node->add_child_nocopy (selection->get_state ());
2511 node->add_child_nocopy (_regions->get_state ());
2513 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2514 node->add_property ("nudge-clock-value", buf);
2519 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2520 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2522 * @return pair: TimeAxisView that y is over, layer index.
2524 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2525 * in stacked or expanded region display mode, otherwise 0.
2527 std::pair<TimeAxisView *, double>
2528 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2530 if (!trackview_relative_offset) {
2531 y -= _trackview_group->canvas_origin().y;
2535 return std::make_pair ( (TimeAxisView *) 0, 0);
2538 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2540 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2547 return std::make_pair ( (TimeAxisView *) 0, 0);
2550 /** Snap a position to the grid, if appropriate, taking into account current
2551 * grid settings and also the state of any snap modifier keys that may be pressed.
2552 * @param start Position to snap.
2553 * @param event Event to get current key modifier information from, or 0.
2556 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2558 if (!_session || !event) {
2562 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2563 if (_snap_mode == SnapOff) {
2564 snap_to_internal (start, direction, for_mark);
2567 if (_snap_mode != SnapOff) {
2568 snap_to_internal (start, direction, for_mark);
2574 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2576 if (!_session || _snap_mode == SnapOff) {
2580 snap_to_internal (start, direction, for_mark);
2584 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2586 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2587 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2589 switch (_snap_type) {
2590 case SnapToTimecodeFrame:
2591 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2592 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2594 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2598 case SnapToTimecodeSeconds:
2599 if (_session->config.get_timecode_offset_negative()) {
2600 start += _session->config.get_timecode_offset ();
2602 start -= _session->config.get_timecode_offset ();
2604 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2605 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2607 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2610 if (_session->config.get_timecode_offset_negative()) {
2611 start -= _session->config.get_timecode_offset ();
2613 start += _session->config.get_timecode_offset ();
2617 case SnapToTimecodeMinutes:
2618 if (_session->config.get_timecode_offset_negative()) {
2619 start += _session->config.get_timecode_offset ();
2621 start -= _session->config.get_timecode_offset ();
2623 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2624 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2626 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2628 if (_session->config.get_timecode_offset_negative()) {
2629 start -= _session->config.get_timecode_offset ();
2631 start += _session->config.get_timecode_offset ();
2635 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2636 abort(); /*NOTREACHED*/
2641 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2643 const framepos_t one_second = _session->frame_rate();
2644 const framepos_t one_minute = _session->frame_rate() * 60;
2645 framepos_t presnap = start;
2649 switch (_snap_type) {
2650 case SnapToTimecodeFrame:
2651 case SnapToTimecodeSeconds:
2652 case SnapToTimecodeMinutes:
2653 return timecode_snap_to_internal (start, direction, for_mark);
2656 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2657 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2659 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2664 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2665 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2667 start = (framepos_t) floor ((double) start / one_second) * one_second;
2672 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2673 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2675 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2680 start = _session->tempo_map().round_to_bar (start, direction);
2684 start = _session->tempo_map().round_to_beat (start, direction);
2687 case SnapToBeatDiv128:
2688 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2690 case SnapToBeatDiv64:
2691 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2693 case SnapToBeatDiv32:
2694 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2696 case SnapToBeatDiv28:
2697 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2699 case SnapToBeatDiv24:
2700 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2702 case SnapToBeatDiv20:
2703 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2705 case SnapToBeatDiv16:
2706 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2708 case SnapToBeatDiv14:
2709 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2711 case SnapToBeatDiv12:
2712 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2714 case SnapToBeatDiv10:
2715 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2717 case SnapToBeatDiv8:
2718 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2720 case SnapToBeatDiv7:
2721 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2723 case SnapToBeatDiv6:
2724 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2726 case SnapToBeatDiv5:
2727 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2729 case SnapToBeatDiv4:
2730 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2732 case SnapToBeatDiv3:
2733 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2735 case SnapToBeatDiv2:
2736 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2744 _session->locations()->marks_either_side (start, before, after);
2746 if (before == max_framepos && after == max_framepos) {
2747 /* No marks to snap to, so just don't snap */
2749 } else if (before == max_framepos) {
2751 } else if (after == max_framepos) {
2753 } else if (before != max_framepos && after != max_framepos) {
2754 /* have before and after */
2755 if ((start - before) < (after - start)) {
2764 case SnapToRegionStart:
2765 case SnapToRegionEnd:
2766 case SnapToRegionSync:
2767 case SnapToRegionBoundary:
2768 if (!region_boundary_cache.empty()) {
2770 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2771 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2773 if (direction > 0) {
2774 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2776 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2779 if (next != region_boundary_cache.begin ()) {
2784 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2785 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2787 if (start > (p + n) / 2) {
2796 switch (_snap_mode) {
2802 if (presnap > start) {
2803 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2807 } else if (presnap < start) {
2808 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2814 /* handled at entry */
2822 Editor::setup_toolbar ()
2824 HBox* mode_box = manage(new HBox);
2825 mode_box->set_border_width (2);
2826 mode_box->set_spacing(2);
2828 HBox* mouse_mode_box = manage (new HBox);
2829 HBox* mouse_mode_hbox = manage (new HBox);
2830 VBox* mouse_mode_vbox = manage (new VBox);
2831 Alignment* mouse_mode_align = manage (new Alignment);
2833 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2834 mouse_mode_size_group->add_widget (smart_mode_button);
2835 mouse_mode_size_group->add_widget (mouse_move_button);
2836 mouse_mode_size_group->add_widget (mouse_cut_button);
2837 mouse_mode_size_group->add_widget (mouse_select_button);
2838 mouse_mode_size_group->add_widget (mouse_gain_button);
2839 mouse_mode_size_group->add_widget (mouse_timefx_button);
2840 mouse_mode_size_group->add_widget (mouse_audition_button);
2841 mouse_mode_size_group->add_widget (mouse_draw_button);
2842 mouse_mode_size_group->add_widget (internal_edit_button);
2844 mouse_mode_size_group->add_widget (zoom_in_button);
2845 mouse_mode_size_group->add_widget (zoom_out_button);
2846 mouse_mode_size_group->add_widget (zoom_preset_selector);
2847 mouse_mode_size_group->add_widget (zoom_out_full_button);
2848 mouse_mode_size_group->add_widget (zoom_focus_selector);
2850 mouse_mode_size_group->add_widget (tav_shrink_button);
2851 mouse_mode_size_group->add_widget (tav_expand_button);
2852 mouse_mode_size_group->add_widget (visible_tracks_selector);
2854 mouse_mode_size_group->add_widget (snap_type_selector);
2855 mouse_mode_size_group->add_widget (snap_mode_selector);
2857 mouse_mode_size_group->add_widget (edit_point_selector);
2858 mouse_mode_size_group->add_widget (edit_mode_selector);
2860 mouse_mode_size_group->add_widget (*nudge_clock);
2861 mouse_mode_size_group->add_widget (nudge_forward_button);
2862 mouse_mode_size_group->add_widget (nudge_backward_button);
2864 mouse_mode_hbox->set_spacing (2);
2866 if (!ARDOUR::Profile->get_trx()) {
2867 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2870 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2871 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2873 if (!ARDOUR::Profile->get_mixbus()) {
2874 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2877 if (!ARDOUR::Profile->get_trx()) {
2878 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2879 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2880 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2881 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2882 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 0);
2885 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2887 mouse_mode_align->add (*mouse_mode_vbox);
2888 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2890 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2892 edit_mode_selector.set_name ("mouse mode button");
2894 if (!ARDOUR::Profile->get_trx()) {
2895 mode_box->pack_start (edit_mode_selector, false, false);
2897 mode_box->pack_start (*mouse_mode_box, false, false);
2899 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2900 _mouse_mode_tearoff->set_name ("MouseModeBase");
2901 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2903 if (Profile->get_sae() || Profile->get_mixbus() ) {
2904 _mouse_mode_tearoff->set_can_be_torn_off (false);
2907 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2908 &_mouse_mode_tearoff->tearoff_window()));
2909 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2910 &_mouse_mode_tearoff->tearoff_window(), 1));
2911 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2912 &_mouse_mode_tearoff->tearoff_window()));
2913 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2914 &_mouse_mode_tearoff->tearoff_window(), 1));
2918 _zoom_box.set_spacing (2);
2919 _zoom_box.set_border_width (2);
2923 zoom_preset_selector.set_name ("zoom button");
2924 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2925 zoom_preset_selector.set_size_request (42, -1);
2927 zoom_in_button.set_name ("zoom button");
2928 zoom_in_button.set_image(::get_icon ("zoom_in"));
2929 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2930 zoom_in_button.set_related_action (act);
2932 zoom_out_button.set_name ("zoom button");
2933 zoom_out_button.set_image(::get_icon ("zoom_out"));
2934 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2935 zoom_out_button.set_related_action (act);
2937 zoom_out_full_button.set_name ("zoom button");
2938 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2939 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2940 zoom_out_full_button.set_related_action (act);
2942 zoom_focus_selector.set_name ("zoom button");
2944 if (ARDOUR::Profile->get_mixbus()) {
2945 _zoom_box.pack_start (zoom_preset_selector, false, false);
2946 } else if (ARDOUR::Profile->get_trx()) {
2947 mode_box->pack_start (zoom_out_button, false, false);
2948 mode_box->pack_start (zoom_in_button, false, false);
2950 _zoom_box.pack_start (zoom_out_button, false, false);
2951 _zoom_box.pack_start (zoom_in_button, false, false);
2952 _zoom_box.pack_start (zoom_out_full_button, false, false);
2953 _zoom_box.pack_start (zoom_focus_selector, false, false);
2956 /* Track zoom buttons */
2957 visible_tracks_selector.set_name ("zoom button");
2958 if (Profile->get_mixbus()) {
2959 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2960 visible_tracks_selector.set_size_request (42, -1);
2962 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2965 tav_expand_button.set_name ("zoom button");
2966 tav_expand_button.set_image(::get_icon ("tav_exp"));
2967 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2968 tav_expand_button.set_related_action (act);
2970 tav_shrink_button.set_name ("zoom button");
2971 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2972 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2973 tav_shrink_button.set_related_action (act);
2975 if (ARDOUR::Profile->get_mixbus()) {
2976 _zoom_box.pack_start (visible_tracks_selector);
2977 } else if (ARDOUR::Profile->get_trx()) {
2978 _zoom_box.pack_start (tav_shrink_button);
2979 _zoom_box.pack_start (tav_expand_button);
2981 _zoom_box.pack_start (visible_tracks_selector);
2982 _zoom_box.pack_start (tav_shrink_button);
2983 _zoom_box.pack_start (tav_expand_button);
2986 if (!ARDOUR::Profile->get_trx()) {
2987 _zoom_tearoff = manage (new TearOff (_zoom_box));
2989 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2990 &_zoom_tearoff->tearoff_window()));
2991 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2992 &_zoom_tearoff->tearoff_window(), 0));
2993 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2994 &_zoom_tearoff->tearoff_window()));
2995 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2996 &_zoom_tearoff->tearoff_window(), 0));
2999 if (Profile->get_sae() || Profile->get_mixbus() ) {
3000 _zoom_tearoff->set_can_be_torn_off (false);
3003 snap_box.set_spacing (2);
3004 snap_box.set_border_width (2);
3006 snap_type_selector.set_name ("mouse mode button");
3008 snap_mode_selector.set_name ("mouse mode button");
3010 edit_point_selector.set_name ("mouse mode button");
3012 snap_box.pack_start (snap_mode_selector, false, false);
3013 snap_box.pack_start (snap_type_selector, false, false);
3014 snap_box.pack_start (edit_point_selector, false, false);
3018 HBox *nudge_box = manage (new HBox);
3019 nudge_box->set_spacing (2);
3020 nudge_box->set_border_width (2);
3022 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3023 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3025 nudge_box->pack_start (nudge_backward_button, false, false);
3026 nudge_box->pack_start (nudge_forward_button, false, false);
3027 nudge_box->pack_start (*nudge_clock, false, false);
3030 /* Pack everything in... */
3032 HBox* hbox = manage (new HBox);
3033 hbox->set_spacing(2);
3035 _tools_tearoff = manage (new TearOff (*hbox));
3036 _tools_tearoff->set_name ("MouseModeBase");
3037 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3039 if (Profile->get_sae() || Profile->get_mixbus()) {
3040 _tools_tearoff->set_can_be_torn_off (false);
3043 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3044 &_tools_tearoff->tearoff_window()));
3045 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3046 &_tools_tearoff->tearoff_window(), 0));
3047 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3048 &_tools_tearoff->tearoff_window()));
3049 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3050 &_tools_tearoff->tearoff_window(), 0));
3052 toolbar_hbox.set_spacing (2);
3053 toolbar_hbox.set_border_width (1);
3055 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3056 if (!ARDOUR::Profile->get_trx()) {
3057 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3058 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3061 if (!ARDOUR::Profile->get_trx()) {
3062 hbox->pack_start (snap_box, false, false);
3063 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3064 hbox->pack_start (*nudge_box, false, false);
3066 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3069 hbox->pack_start (panic_box, false, false);
3073 toolbar_base.set_name ("ToolBarBase");
3074 toolbar_base.add (toolbar_hbox);
3076 _toolbar_viewport.add (toolbar_base);
3077 /* stick to the required height but allow width to vary if there's not enough room */
3078 _toolbar_viewport.set_size_request (1, -1);
3080 toolbar_frame.set_shadow_type (SHADOW_OUT);
3081 toolbar_frame.set_name ("BaseFrame");
3082 toolbar_frame.add (_toolbar_viewport);
3086 Editor::build_edit_point_menu ()
3088 using namespace Menu_Helpers;
3090 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3091 if(!Profile->get_mixbus())
3092 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3093 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3095 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3099 Editor::build_edit_mode_menu ()
3101 using namespace Menu_Helpers;
3103 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3104 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3105 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3106 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3108 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3112 Editor::build_snap_mode_menu ()
3114 using namespace Menu_Helpers;
3116 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3117 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3118 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3120 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3124 Editor::build_snap_type_menu ()
3126 using namespace Menu_Helpers;
3128 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3129 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3130 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3131 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3132 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3133 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3134 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3135 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3136 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3137 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3138 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3139 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3140 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3141 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3142 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3143 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3144 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3145 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3146 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3147 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3148 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3149 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3150 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3151 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3152 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3153 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3154 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3155 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3156 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3157 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3159 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3164 Editor::setup_tooltips ()
3166 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3167 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3168 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3169 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3170 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3171 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3172 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3173 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3174 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3175 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3176 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3177 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3178 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3179 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3180 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3181 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3182 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3183 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3184 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3185 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3186 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3187 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3188 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3189 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3190 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3194 Editor::convert_drop_to_paths (
3195 vector<string>& paths,
3196 const RefPtr<Gdk::DragContext>& /*context*/,
3199 const SelectionData& data,
3203 if (_session == 0) {
3207 vector<string> uris = data.get_uris();
3211 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3212 are actually URI lists. So do it by hand.
3215 if (data.get_target() != "text/plain") {
3219 /* Parse the "uri-list" format that Nautilus provides,
3220 where each pathname is delimited by \r\n.
3222 THERE MAY BE NO NULL TERMINATING CHAR!!!
3225 string txt = data.get_text();
3229 p = (char *) malloc (txt.length() + 1);
3230 txt.copy (p, txt.length(), 0);
3231 p[txt.length()] = '\0';
3237 while (g_ascii_isspace (*p))
3241 while (*q && (*q != '\n') && (*q != '\r')) {
3248 while (q > p && g_ascii_isspace (*q))
3253 uris.push_back (string (p, q - p + 1));
3257 p = strchr (p, '\n');
3269 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3270 if ((*i).substr (0,7) == "file://") {
3271 paths.push_back (Glib::filename_from_uri (*i));
3279 Editor::new_tempo_section ()
3284 Editor::map_transport_state ()
3286 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3288 if (_session && _session->transport_stopped()) {
3289 have_pending_keyboard_selection = false;
3292 update_loop_range_view ();
3298 Editor::begin_reversible_command (string name)
3301 _session->begin_reversible_command (name);
3306 Editor::begin_reversible_command (GQuark q)
3309 _session->begin_reversible_command (q);
3314 Editor::commit_reversible_command ()
3317 _session->commit_reversible_command ();
3322 Editor::history_changed ()
3326 if (undo_action && _session) {
3327 if (_session->undo_depth() == 0) {
3328 label = S_("Command|Undo");
3330 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3332 undo_action->property_label() = label;
3335 if (redo_action && _session) {
3336 if (_session->redo_depth() == 0) {
3339 label = string_compose(_("Redo (%1)"), _session->next_redo());
3341 redo_action->property_label() = label;
3346 Editor::duplicate_range (bool with_dialog)
3350 RegionSelection rs = get_regions_from_selection_and_entered ();
3352 if ( selection->time.length() == 0 && rs.empty()) {
3358 ArdourDialog win (_("Duplicate"));
3359 Label label (_("Number of duplications:"));
3360 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3361 SpinButton spinner (adjustment, 0.0, 1);
3364 win.get_vbox()->set_spacing (12);
3365 win.get_vbox()->pack_start (hbox);
3366 hbox.set_border_width (6);
3367 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3369 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3370 place, visually. so do this by hand.
3373 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3374 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3375 spinner.grab_focus();
3381 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3382 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3383 win.set_default_response (RESPONSE_ACCEPT);
3385 spinner.grab_focus ();
3387 switch (win.run ()) {
3388 case RESPONSE_ACCEPT:
3394 times = adjustment.get_value();
3397 if ((current_mouse_mode() == Editing::MouseRange)) {
3398 if (selection->time.length()) {
3399 duplicate_selection (times);
3401 } else if (get_smart_mode()) {
3402 if (selection->time.length()) {
3403 duplicate_selection (times);
3405 duplicate_some_regions (rs, times);
3407 duplicate_some_regions (rs, times);
3412 Editor::set_edit_mode (EditMode m)
3414 Config->set_edit_mode (m);
3418 Editor::cycle_edit_mode ()
3420 switch (Config->get_edit_mode()) {
3422 if (Profile->get_sae()) {
3423 Config->set_edit_mode (Lock);
3425 Config->set_edit_mode (Ripple);
3430 Config->set_edit_mode (Lock);
3433 Config->set_edit_mode (Slide);
3439 Editor::edit_mode_selection_done ( EditMode m )
3441 Config->set_edit_mode ( m );
3445 Editor::snap_type_selection_done (SnapType snaptype)
3447 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3449 ract->set_active ();
3454 Editor::snap_mode_selection_done (SnapMode mode)
3456 RefPtr<RadioAction> ract = snap_mode_action (mode);
3459 ract->set_active (true);
3464 Editor::cycle_edit_point (bool with_marker)
3466 if(Profile->get_mixbus())
3467 with_marker = false;
3469 switch (_edit_point) {
3471 set_edit_point_preference (EditAtPlayhead);
3473 case EditAtPlayhead:
3475 set_edit_point_preference (EditAtSelectedMarker);
3477 set_edit_point_preference (EditAtMouse);
3480 case EditAtSelectedMarker:
3481 set_edit_point_preference (EditAtMouse);
3487 Editor::edit_point_selection_done (EditPoint ep)
3489 set_edit_point_preference ( ep );
3493 Editor::build_zoom_focus_menu ()
3495 using namespace Menu_Helpers;
3497 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3498 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3499 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3500 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3501 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3502 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3504 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3508 Editor::zoom_focus_selection_done ( ZoomFocus f )
3510 RefPtr<RadioAction> ract = zoom_focus_action (f);
3512 ract->set_active ();
3517 Editor::build_track_count_menu ()
3519 using namespace Menu_Helpers;
3521 if (!Profile->get_mixbus()) {
3522 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3523 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3524 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3525 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3526 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3527 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3528 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3529 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3530 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3531 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3532 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3533 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3534 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3536 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3537 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3538 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3539 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3540 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3541 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3542 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3543 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3544 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3545 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3547 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3548 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3549 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3550 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3551 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3552 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3553 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3554 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3555 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3556 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3557 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3562 Editor::set_zoom_preset (int64_t ms)
3565 temporal_zoom_session();
3569 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3570 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3574 Editor::set_visible_track_count (int32_t n)
3576 _visible_track_count = n;
3578 /* if the canvas hasn't really been allocated any size yet, just
3579 record the desired number of visible tracks and return. when canvas
3580 allocation happens, we will get called again and then we can do the
3584 if (_visible_canvas_height <= 1) {
3591 if (_visible_track_count > 0) {
3592 h = trackviews_height() / _visible_track_count;
3593 std::ostringstream s;
3594 s << _visible_track_count;
3596 } else if (_visible_track_count == 0) {
3598 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3599 if ((*i)->marked_for_display()) {
3603 h = trackviews_height() / n;
3606 /* negative value means that the visible track count has
3607 been overridden by explicit track height changes.
3609 visible_tracks_selector.set_text (X_("*"));
3613 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3614 (*i)->set_height (h);
3617 if (str != visible_tracks_selector.get_text()) {
3618 visible_tracks_selector.set_text (str);
3623 Editor::override_visible_track_count ()
3625 _visible_track_count = -1;
3626 visible_tracks_selector.set_text ( _("*") );
3630 Editor::edit_controls_button_release (GdkEventButton* ev)
3632 if (Keyboard::is_context_menu_event (ev)) {
3633 ARDOUR_UI::instance()->add_route (this);
3634 } else if (ev->button == 1) {
3635 selection->clear_tracks ();
3642 Editor::mouse_select_button_release (GdkEventButton* ev)
3644 /* this handles just right-clicks */
3646 if (ev->button != 3) {
3654 Editor::set_zoom_focus (ZoomFocus f)
3656 string str = zoom_focus_strings[(int)f];
3658 if (str != zoom_focus_selector.get_text()) {
3659 zoom_focus_selector.set_text (str);
3662 if (zoom_focus != f) {
3669 Editor::cycle_zoom_focus ()
3671 switch (zoom_focus) {
3673 set_zoom_focus (ZoomFocusRight);
3675 case ZoomFocusRight:
3676 set_zoom_focus (ZoomFocusCenter);
3678 case ZoomFocusCenter:
3679 set_zoom_focus (ZoomFocusPlayhead);
3681 case ZoomFocusPlayhead:
3682 set_zoom_focus (ZoomFocusMouse);
3684 case ZoomFocusMouse:
3685 set_zoom_focus (ZoomFocusEdit);
3688 set_zoom_focus (ZoomFocusLeft);
3694 Editor::ensure_float (Window& win)
3696 win.set_transient_for (*this);
3700 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3702 /* recover or initialize pane positions. do this here rather than earlier because
3703 we don't want the positions to change the child allocations, which they seem to do.
3709 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3718 XMLNode* geometry = find_named_node (*node, "geometry");
3720 if (which == static_cast<Paned*> (&edit_pane)) {
3722 if (done & Horizontal) {
3726 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3727 _notebook_shrunk = string_is_affirmative (prop->value ());
3730 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3731 /* initial allocation is 90% to canvas, 10% to notebook */
3732 pos = (int) floor (alloc.get_width() * 0.90f);
3733 snprintf (buf, sizeof(buf), "%d", pos);
3735 pos = atoi (prop->value());
3738 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3739 edit_pane.set_position (pos);
3742 done = (Pane) (done | Horizontal);
3744 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3746 if (done & Vertical) {
3750 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3751 /* initial allocation is 90% to canvas, 10% to summary */
3752 pos = (int) floor (alloc.get_height() * 0.90f);
3753 snprintf (buf, sizeof(buf), "%d", pos);
3756 pos = atoi (prop->value());
3759 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3760 editor_summary_pane.set_position (pos);
3763 done = (Pane) (done | Vertical);
3768 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3770 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3771 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3772 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3773 top_hbox.remove (toolbar_frame);
3778 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3780 if (toolbar_frame.get_parent() == 0) {
3781 top_hbox.pack_end (toolbar_frame);
3786 Editor::set_show_measures (bool yn)
3788 if (_show_measures != yn) {
3791 if ((_show_measures = yn) == true) {
3793 tempo_lines->show();
3796 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3797 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3799 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3800 draw_measures (begin, end);
3808 Editor::toggle_follow_playhead ()
3810 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3812 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3813 set_follow_playhead (tact->get_active());
3817 /** @param yn true to follow playhead, otherwise false.
3818 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3821 Editor::set_follow_playhead (bool yn, bool catch_up)
3823 if (_follow_playhead != yn) {
3824 if ((_follow_playhead = yn) == true && catch_up) {
3826 reset_x_origin_to_follow_playhead ();
3833 Editor::toggle_stationary_playhead ()
3835 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3837 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3838 set_stationary_playhead (tact->get_active());
3843 Editor::set_stationary_playhead (bool yn)
3845 if (_stationary_playhead != yn) {
3846 if ((_stationary_playhead = yn) == true) {
3848 // FIXME need a 3.0 equivalent of this 2.X call
3849 // update_current_screen ();
3856 Editor::playlist_selector () const
3858 return *_playlist_selector;
3862 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3864 if (paste_count == 0) {
3865 /* don't bother calculating an offset that will be zero anyway */
3869 /* calculate basic unsnapped multi-paste offset */
3870 framecnt_t offset = paste_count * duration;
3872 bool success = true;
3873 double snap_beats = get_grid_type_as_beats(success, pos);
3875 /* we're snapped to something musical, round duration up */
3876 BeatsFramesConverter conv(_session->tempo_map(), pos);
3877 const Evoral::MusicalTime dur_beats = conv.from(duration);
3878 const framecnt_t snap_dur_beats = ceil(dur_beats / snap_beats) * snap_beats;
3880 offset = paste_count * conv.to(snap_dur_beats);
3887 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3891 switch (_snap_type) {
3896 case SnapToBeatDiv128:
3899 case SnapToBeatDiv64:
3902 case SnapToBeatDiv32:
3905 case SnapToBeatDiv28:
3908 case SnapToBeatDiv24:
3911 case SnapToBeatDiv20:
3914 case SnapToBeatDiv16:
3917 case SnapToBeatDiv14:
3920 case SnapToBeatDiv12:
3923 case SnapToBeatDiv10:
3926 case SnapToBeatDiv8:
3929 case SnapToBeatDiv7:
3932 case SnapToBeatDiv6:
3935 case SnapToBeatDiv5:
3938 case SnapToBeatDiv4:
3941 case SnapToBeatDiv3:
3944 case SnapToBeatDiv2:
3950 return _session->tempo_map().meter_at (position).divisions_per_bar();
3955 case SnapToTimecodeFrame:
3956 case SnapToTimecodeSeconds:
3957 case SnapToTimecodeMinutes:
3960 case SnapToRegionStart:
3961 case SnapToRegionEnd:
3962 case SnapToRegionSync:
3963 case SnapToRegionBoundary:
3973 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3977 ret = nudge_clock->current_duration (pos);
3978 next = ret + 1; /* XXXX fix me */
3984 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3986 ArdourDialog dialog (_("Playlist Deletion"));
3987 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3988 "If it is kept, its audio files will not be cleaned.\n"
3989 "If it is deleted, audio files used by it alone will be cleaned."),
3992 dialog.set_position (WIN_POS_CENTER);
3993 dialog.get_vbox()->pack_start (label);
3997 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3998 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3999 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4001 switch (dialog.run ()) {
4002 case RESPONSE_ACCEPT:
4003 /* delete the playlist */
4007 case RESPONSE_REJECT:
4008 /* keep the playlist */
4020 Editor::audio_region_selection_covers (framepos_t where)
4022 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4023 if ((*a)->region()->covers (where)) {
4032 Editor::prepare_for_cleanup ()
4034 cut_buffer->clear_regions ();
4035 cut_buffer->clear_playlists ();
4037 selection->clear_regions ();
4038 selection->clear_playlists ();
4040 _regions->suspend_redisplay ();
4044 Editor::finish_cleanup ()
4046 _regions->resume_redisplay ();
4050 Editor::transport_loop_location()
4053 return _session->locations()->auto_loop_location();
4060 Editor::transport_punch_location()
4063 return _session->locations()->auto_punch_location();
4070 Editor::control_layout_scroll (GdkEventScroll* ev)
4072 /* Just forward to the normal canvas scroll method. The coordinate
4073 systems are different but since the canvas is always larger than the
4074 track headers, and aligned with the trackview area, this will work.
4076 In the not too distant future this layout is going away anyway and
4077 headers will be on the canvas.
4079 return canvas_scroll_event (ev, false);
4083 Editor::session_state_saved (string)
4086 _snapshots->redisplay ();
4090 Editor::update_tearoff_visibility()
4092 bool visible = Config->get_keep_tearoffs();
4093 _mouse_mode_tearoff->set_visible (visible);
4094 _tools_tearoff->set_visible (visible);
4095 if (_zoom_tearoff) {
4096 _zoom_tearoff->set_visible (visible);
4101 Editor::reattach_all_tearoffs ()
4103 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4104 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4105 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4109 Editor::maximise_editing_space ()
4121 Editor::restore_editing_space ()
4133 * Make new playlists for a given track and also any others that belong
4134 * to the same active route group with the `select' property.
4139 Editor::new_playlists (TimeAxisView* v)
4141 begin_reversible_command (_("new playlists"));
4142 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4143 _session->playlists->get (playlists);
4144 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4145 commit_reversible_command ();
4149 * Use a copy of the current playlist for a given track and also any others that belong
4150 * to the same active route group with the `select' property.
4155 Editor::copy_playlists (TimeAxisView* v)
4157 begin_reversible_command (_("copy playlists"));
4158 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4159 _session->playlists->get (playlists);
4160 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4161 commit_reversible_command ();
4164 /** Clear the current playlist for a given track and also any others that belong
4165 * to the same active route group with the `select' property.
4170 Editor::clear_playlists (TimeAxisView* v)
4172 begin_reversible_command (_("clear playlists"));
4173 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4174 _session->playlists->get (playlists);
4175 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4176 commit_reversible_command ();
4180 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4182 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4186 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4188 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4192 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4194 atv.clear_playlist ();
4198 Editor::on_key_press_event (GdkEventKey* ev)
4200 return key_press_focus_accelerator_handler (*this, ev);
4204 Editor::on_key_release_event (GdkEventKey* ev)
4206 return Gtk::Window::on_key_release_event (ev);
4207 // return key_press_focus_accelerator_handler (*this, ev);
4210 /** Queue up a change to the viewport x origin.
4211 * @param frame New x origin.
4214 Editor::reset_x_origin (framepos_t frame)
4216 pending_visual_change.add (VisualChange::TimeOrigin);
4217 pending_visual_change.time_origin = frame;
4218 ensure_visual_change_idle_handler ();
4222 Editor::reset_y_origin (double y)
4224 pending_visual_change.add (VisualChange::YOrigin);
4225 pending_visual_change.y_origin = y;
4226 ensure_visual_change_idle_handler ();
4230 Editor::reset_zoom (framecnt_t spp)
4232 if (spp == samples_per_pixel) {
4236 pending_visual_change.add (VisualChange::ZoomLevel);
4237 pending_visual_change.samples_per_pixel = spp;
4238 ensure_visual_change_idle_handler ();
4242 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4244 reset_x_origin (frame);
4247 if (!no_save_visual) {
4248 undo_visual_stack.push_back (current_visual_state(false));
4252 Editor::VisualState::VisualState (bool with_tracks)
4253 : gui_state (with_tracks ? new GUIObjectState : 0)
4257 Editor::VisualState::~VisualState ()
4262 Editor::VisualState*
4263 Editor::current_visual_state (bool with_tracks)
4265 VisualState* vs = new VisualState (with_tracks);
4266 vs->y_position = vertical_adjustment.get_value();
4267 vs->samples_per_pixel = samples_per_pixel;
4268 vs->leftmost_frame = leftmost_frame;
4269 vs->zoom_focus = zoom_focus;
4272 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4279 Editor::undo_visual_state ()
4281 if (undo_visual_stack.empty()) {
4285 VisualState* vs = undo_visual_stack.back();
4286 undo_visual_stack.pop_back();
4289 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4292 use_visual_state (*vs);
4297 Editor::redo_visual_state ()
4299 if (redo_visual_stack.empty()) {
4303 VisualState* vs = redo_visual_stack.back();
4304 redo_visual_stack.pop_back();
4306 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4307 // why do we check here?
4308 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4311 use_visual_state (*vs);
4316 Editor::swap_visual_state ()
4318 if (undo_visual_stack.empty()) {
4319 redo_visual_state ();
4321 undo_visual_state ();
4326 Editor::use_visual_state (VisualState& vs)
4328 PBD::Unwinder<bool> nsv (no_save_visual, true);
4329 DisplaySuspender ds;
4331 vertical_adjustment.set_value (vs.y_position);
4333 set_zoom_focus (vs.zoom_focus);
4334 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4337 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4339 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4340 (*i)->reset_visual_state ();
4344 _routes->update_visibility ();
4347 /** This is the core function that controls the zoom level of the canvas. It is called
4348 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4349 * @param spp new number of samples per pixel
4352 Editor::set_samples_per_pixel (framecnt_t spp)
4358 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4359 const framecnt_t lots_of_pixels = 4000;
4361 /* if the zoom level is greater than what you'd get trying to display 3
4362 * days of audio on a really big screen, then it's too big.
4365 if (spp * lots_of_pixels > three_days) {
4369 samples_per_pixel = spp;
4372 tempo_lines->tempo_map_changed();
4375 bool const showing_time_selection = selection->time.length() > 0;
4377 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4378 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4379 (*i)->reshow_selection (selection->time);
4383 ZoomChanged (); /* EMIT_SIGNAL */
4385 ArdourCanvas::GtkCanvasViewport* c;
4387 c = get_track_canvas();
4389 c->canvas()->zoomed ();
4392 if (playhead_cursor) {
4393 playhead_cursor->set_position (playhead_cursor->current_frame ());
4396 refresh_location_display();
4397 _summary->set_overlays_dirty ();
4399 update_marker_labels ();
4405 Editor::queue_visual_videotimeline_update ()
4408 * pending_visual_change.add (VisualChange::VideoTimeline);
4409 * or maybe even more specific: which videotimeline-image
4410 * currently it calls update_video_timeline() to update
4411 * _all outdated_ images on the video-timeline.
4412 * see 'exposeimg()' in video_image_frame.cc
4414 ensure_visual_change_idle_handler ();
4418 Editor::ensure_visual_change_idle_handler ()
4420 if (pending_visual_change.idle_handler_id < 0) {
4421 // see comment in add_to_idle_resize above.
4422 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4423 pending_visual_change.being_handled = false;
4428 Editor::_idle_visual_changer (void* arg)
4430 return static_cast<Editor*>(arg)->idle_visual_changer ();
4434 Editor::idle_visual_changer ()
4436 /* set_horizontal_position() below (and maybe other calls) call
4437 gtk_main_iteration(), so it's possible that a signal will be handled
4438 half-way through this method. If this signal wants an
4439 idle_visual_changer we must schedule another one after this one, so
4440 mark the idle_handler_id as -1 here to allow that. Also make a note
4441 that we are doing the visual change, so that changes in response to
4442 super-rapid-screen-update can be dropped if we are still processing
4446 pending_visual_change.idle_handler_id = -1;
4447 pending_visual_change.being_handled = true;
4449 VisualChange vc = pending_visual_change;
4451 pending_visual_change.pending = (VisualChange::Type) 0;
4453 visual_changer (vc);
4455 pending_visual_change.being_handled = false;
4457 return 0; /* this is always a one-shot call */
4461 Editor::visual_changer (const VisualChange& vc)
4463 double const last_time_origin = horizontal_position ();
4465 if (vc.pending & VisualChange::ZoomLevel) {
4466 set_samples_per_pixel (vc.samples_per_pixel);
4468 compute_fixed_ruler_scale ();
4470 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4471 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4473 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4474 current_bbt_points_begin, current_bbt_points_end);
4475 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4476 current_bbt_points_begin, current_bbt_points_end);
4477 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4479 update_video_timeline();
4482 if (vc.pending & VisualChange::TimeOrigin) {
4483 set_horizontal_position (vc.time_origin / samples_per_pixel);
4486 if (vc.pending & VisualChange::YOrigin) {
4487 vertical_adjustment.set_value (vc.y_origin);
4490 if (last_time_origin == horizontal_position ()) {
4491 /* changed signal not emitted */
4492 update_fixed_rulers ();
4493 redisplay_tempo (true);
4496 if (!(vc.pending & VisualChange::ZoomLevel)) {
4497 update_video_timeline();
4500 _summary->set_overlays_dirty ();
4503 struct EditorOrderTimeAxisSorter {
4504 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4505 return a->order () < b->order ();
4510 Editor::sort_track_selection (TrackViewList& sel)
4512 EditorOrderTimeAxisSorter cmp;
4517 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4520 framepos_t where = 0;
4521 EditPoint ep = _edit_point;
4523 if(Profile->get_mixbus())
4524 if (ep == EditAtSelectedMarker)
4527 if (from_context_menu && (ep == EditAtMouse)) {
4528 return canvas_event_sample (&context_click_event, 0, 0);
4531 if (entered_marker) {
4532 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4533 return entered_marker->position();
4536 if (ignore_playhead && ep == EditAtPlayhead) {
4537 ep = EditAtSelectedMarker;
4541 case EditAtPlayhead:
4542 where = _session->audible_frame();
4543 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4546 case EditAtSelectedMarker:
4547 if (!selection->markers.empty()) {
4549 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4552 where = loc->start();
4556 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4564 if (!mouse_frame (where, ignored)) {
4565 /* XXX not right but what can we do ? */
4569 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4577 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4579 if (!_session) return;
4581 begin_reversible_command (cmd);
4585 if ((tll = transport_loop_location()) == 0) {
4586 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4587 XMLNode &before = _session->locations()->get_state();
4588 _session->locations()->add (loc, true);
4589 _session->set_auto_loop_location (loc);
4590 XMLNode &after = _session->locations()->get_state();
4591 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4593 XMLNode &before = tll->get_state();
4594 tll->set_hidden (false, this);
4595 tll->set (start, end);
4596 XMLNode &after = tll->get_state();
4597 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4600 commit_reversible_command ();
4604 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4606 if (!_session) return;
4608 begin_reversible_command (cmd);
4612 if ((tpl = transport_punch_location()) == 0) {
4613 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4614 XMLNode &before = _session->locations()->get_state();
4615 _session->locations()->add (loc, true);
4616 _session->set_auto_punch_location (loc);
4617 XMLNode &after = _session->locations()->get_state();
4618 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4621 XMLNode &before = tpl->get_state();
4622 tpl->set_hidden (false, this);
4623 tpl->set (start, end);
4624 XMLNode &after = tpl->get_state();
4625 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4628 commit_reversible_command ();
4631 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4632 * @param rs List to which found regions are added.
4633 * @param where Time to look at.
4634 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4637 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4639 const TrackViewList* tracks;
4642 tracks = &track_views;
4647 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4649 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4652 boost::shared_ptr<Track> tr;
4653 boost::shared_ptr<Playlist> pl;
4655 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4657 boost::shared_ptr<RegionList> regions = pl->regions_at (
4658 (framepos_t) floor ( (double) where * tr->speed()));
4660 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4661 RegionView* rv = rtv->view()->find_view (*i);
4672 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4674 const TrackViewList* tracks;
4677 tracks = &track_views;
4682 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4683 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4685 boost::shared_ptr<Track> tr;
4686 boost::shared_ptr<Playlist> pl;
4688 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4690 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4691 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4693 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4695 RegionView* rv = rtv->view()->find_view (*i);
4706 /** Get regions using the following method:
4708 * Make a region list using:
4709 * (a) any selected regions
4710 * (b) the intersection of any selected tracks and the edit point(*)
4711 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4713 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4715 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4719 Editor::get_regions_from_selection_and_edit_point ()
4721 RegionSelection regions;
4723 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4724 regions.add (entered_regionview);
4726 regions = selection->regions;
4729 if ( regions.empty() ) {
4730 TrackViewList tracks = selection->tracks;
4732 if (!tracks.empty()) {
4733 /* no region selected or entered, but some selected tracks:
4734 * act on all regions on the selected tracks at the edit point
4736 framepos_t const where = get_preferred_edit_position ();
4737 get_regions_at(regions, where, tracks);
4744 /** Get regions using the following method:
4746 * Make a region list using:
4747 * (a) any selected regions
4748 * (b) the intersection of any selected tracks and the edit point(*)
4749 * (c) if neither exists, then whatever region is under the mouse
4751 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4753 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4756 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4758 RegionSelection regions;
4760 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4761 regions.add (entered_regionview);
4763 regions = selection->regions;
4766 if ( regions.empty() ) {
4767 TrackViewList tracks = selection->tracks;
4769 if (!tracks.empty()) {
4770 /* no region selected or entered, but some selected tracks:
4771 * act on all regions on the selected tracks at the edit point
4773 get_regions_at(regions, pos, tracks);
4780 /** Start with regions that are selected, or the entered regionview if none are selected.
4781 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4782 * of the regions that we started with.
4786 Editor::get_regions_from_selection_and_entered ()
4788 RegionSelection regions = selection->regions;
4790 if (regions.empty() && entered_regionview) {
4791 regions.add (entered_regionview);
4798 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4800 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4802 RouteTimeAxisView* tatv;
4804 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4806 boost::shared_ptr<Playlist> pl;
4807 vector<boost::shared_ptr<Region> > results;
4809 boost::shared_ptr<Track> tr;
4811 if ((tr = tatv->track()) == 0) {
4816 if ((pl = (tr->playlist())) != 0) {
4817 if (src_comparison) {
4818 pl->get_source_equivalent_regions (region, results);
4820 pl->get_region_list_equivalent_regions (region, results);
4824 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4825 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4826 regions.push_back (marv);
4835 Editor::show_rhythm_ferret ()
4837 if (rhythm_ferret == 0) {
4838 rhythm_ferret = new RhythmFerret(*this);
4841 rhythm_ferret->set_session (_session);
4842 rhythm_ferret->show ();
4843 rhythm_ferret->present ();
4847 Editor::first_idle ()
4849 MessageDialog* dialog = 0;
4851 if (track_views.size() > 1) {
4852 dialog = new MessageDialog (
4854 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4858 ARDOUR_UI::instance()->flush_pending ();
4861 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4865 // first idle adds route children (automation tracks), so we need to redisplay here
4866 _routes->redisplay ();
4873 Editor::_idle_resize (gpointer arg)
4875 return ((Editor*)arg)->idle_resize ();
4879 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4881 if (resize_idle_id < 0) {
4882 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
4883 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
4884 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
4886 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
4887 _pending_resize_amount = 0;
4890 /* make a note of the smallest resulting height, so that we can clamp the
4891 lower limit at TimeAxisView::hSmall */
4893 int32_t min_resulting = INT32_MAX;
4895 _pending_resize_amount += h;
4896 _pending_resize_view = view;
4898 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4900 if (selection->tracks.contains (_pending_resize_view)) {
4901 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4902 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4906 if (min_resulting < 0) {
4911 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4912 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4916 /** Handle pending resizing of tracks */
4918 Editor::idle_resize ()
4920 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4922 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4923 selection->tracks.contains (_pending_resize_view)) {
4925 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4926 if (*i != _pending_resize_view) {
4927 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4932 _pending_resize_amount = 0;
4933 _group_tabs->set_dirty ();
4934 resize_idle_id = -1;
4942 ENSURE_GUI_THREAD (*this, &Editor::located);
4945 playhead_cursor->set_position (_session->audible_frame ());
4946 if (_follow_playhead && !_pending_initial_locate) {
4947 reset_x_origin_to_follow_playhead ();
4951 _pending_locate_request = false;
4952 _pending_initial_locate = false;
4956 Editor::region_view_added (RegionView *)
4958 _summary->set_background_dirty ();
4962 Editor::region_view_removed ()
4964 _summary->set_background_dirty ();
4968 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4970 TrackViewList::const_iterator j = track_views.begin ();
4971 while (j != track_views.end()) {
4972 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4973 if (rtv && rtv->route() == r) {
4984 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4988 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4989 TimeAxisView* tv = axis_view_from_route (*i);
4999 Editor::suspend_route_redisplay ()
5002 _routes->suspend_redisplay();
5007 Editor::resume_route_redisplay ()
5010 _routes->resume_redisplay();
5015 Editor::add_routes (RouteList& routes)
5017 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5019 RouteTimeAxisView *rtv;
5020 list<RouteTimeAxisView*> new_views;
5022 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5023 boost::shared_ptr<Route> route = (*x);
5025 if (route->is_auditioner() || route->is_monitor()) {
5029 DataType dt = route->input()->default_type();
5031 if (dt == ARDOUR::DataType::AUDIO) {
5032 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5033 rtv->set_route (route);
5034 } else if (dt == ARDOUR::DataType::MIDI) {
5035 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5036 rtv->set_route (route);
5038 throw unknown_type();
5041 new_views.push_back (rtv);
5042 track_views.push_back (rtv);
5044 rtv->effective_gain_display ();
5046 if (internal_editing()) {
5047 rtv->enter_internal_edit_mode ();
5049 rtv->leave_internal_edit_mode ();
5052 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5053 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5056 if (new_views.size() > 0) {
5057 _routes->routes_added (new_views);
5058 _summary->routes_added (new_views);
5061 if (show_editor_mixer_when_tracks_arrive) {
5062 show_editor_mixer (true);
5065 editor_list_button.set_sensitive (true);
5069 Editor::timeaxisview_deleted (TimeAxisView *tv)
5071 if (tv == entered_track) {
5075 if (_session && _session->deletion_in_progress()) {
5076 /* the situation is under control */
5080 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5082 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5084 _routes->route_removed (tv);
5086 TimeAxisView::Children c = tv->get_child_list ();
5087 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5088 if (entered_track == i->get()) {
5093 /* remove it from the list of track views */
5095 TrackViewList::iterator i;
5097 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5098 i = track_views.erase (i);
5101 /* update whatever the current mixer strip is displaying, if revelant */
5103 boost::shared_ptr<Route> route;
5106 route = rtav->route ();
5109 if (current_mixer_strip && current_mixer_strip->route() == route) {
5111 TimeAxisView* next_tv;
5113 if (track_views.empty()) {
5115 } else if (i == track_views.end()) {
5116 next_tv = track_views.front();
5123 set_selected_mixer_strip (*next_tv);
5125 /* make the editor mixer strip go away setting the
5126 * button to inactive (which also unticks the menu option)
5129 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5135 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5137 if (apply_to_selection) {
5138 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5140 TrackSelection::iterator j = i;
5143 hide_track_in_display (*i, false);
5148 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5150 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5151 // this will hide the mixer strip
5152 set_selected_mixer_strip (*tv);
5155 _routes->hide_track_in_display (*tv);
5160 Editor::sync_track_view_list_and_routes ()
5162 track_views = TrackViewList (_routes->views ());
5164 _summary->set_dirty ();
5165 _group_tabs->set_dirty ();
5167 return false; // do not call again (until needed)
5171 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5173 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5178 /** Find a RouteTimeAxisView by the ID of its route */
5180 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5182 RouteTimeAxisView* v;
5184 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5185 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5186 if(v->route()->id() == id) {
5196 Editor::fit_route_group (RouteGroup *g)
5198 TrackViewList ts = axis_views_from_routes (g->route_list ());
5203 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5205 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5208 _session->cancel_audition ();
5212 if (_session->is_auditioning()) {
5213 _session->cancel_audition ();
5214 if (r == last_audition_region) {
5219 _session->audition_region (r);
5220 last_audition_region = r;
5225 Editor::hide_a_region (boost::shared_ptr<Region> r)
5227 r->set_hidden (true);
5231 Editor::show_a_region (boost::shared_ptr<Region> r)
5233 r->set_hidden (false);
5237 Editor::audition_region_from_region_list ()
5239 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5243 Editor::hide_region_from_region_list ()
5245 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5249 Editor::show_region_in_region_list ()
5251 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5255 Editor::step_edit_status_change (bool yn)
5258 start_step_editing ();
5260 stop_step_editing ();
5265 Editor::start_step_editing ()
5267 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5271 Editor::stop_step_editing ()
5273 step_edit_connection.disconnect ();
5277 Editor::check_step_edit ()
5279 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5280 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5282 mtv->check_step_edit ();
5286 return true; // do it again, till we stop
5290 Editor::scroll_press (Direction dir)
5292 ++_scroll_callbacks;
5294 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5295 /* delay the first auto-repeat */
5301 scroll_backward (1);
5309 scroll_up_one_track ();
5313 scroll_down_one_track ();
5317 /* do hacky auto-repeat */
5318 if (!_scroll_connection.connected ()) {
5320 _scroll_connection = Glib::signal_timeout().connect (
5321 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5324 _scroll_callbacks = 0;
5331 Editor::scroll_release ()
5333 _scroll_connection.disconnect ();
5336 /** Queue a change for the Editor viewport x origin to follow the playhead */
5338 Editor::reset_x_origin_to_follow_playhead ()
5340 framepos_t const frame = playhead_cursor->current_frame ();
5342 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5344 if (_session->transport_speed() < 0) {
5346 if (frame > (current_page_samples() / 2)) {
5347 center_screen (frame-(current_page_samples()/2));
5349 center_screen (current_page_samples()/2);
5356 if (frame < leftmost_frame) {
5358 if (_session->transport_rolling()) {
5359 /* rolling; end up with the playhead at the right of the page */
5360 l = frame - current_page_samples ();
5362 /* not rolling: end up with the playhead 1/4 of the way along the page */
5363 l = frame - current_page_samples() / 4;
5367 if (_session->transport_rolling()) {
5368 /* rolling: end up with the playhead on the left of the page */
5371 /* not rolling: end up with the playhead 3/4 of the way along the page */
5372 l = frame - 3 * current_page_samples() / 4;
5380 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5386 Editor::super_rapid_screen_update ()
5388 if (!_session || !_session->engine().running()) {
5392 /* METERING / MIXER STRIPS */
5394 /* update track meters, if required */
5395 if (is_mapped() && meters_running) {
5396 RouteTimeAxisView* rtv;
5397 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5398 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5399 rtv->fast_update ();
5404 /* and any current mixer strip */
5405 if (current_mixer_strip) {
5406 current_mixer_strip->fast_update ();
5409 /* PLAYHEAD AND VIEWPORT */
5411 framepos_t const frame = _session->audible_frame();
5413 /* There are a few reasons why we might not update the playhead / viewport stuff:
5415 * 1. we don't update things when there's a pending locate request, otherwise
5416 * when the editor requests a locate there is a chance that this method
5417 * will move the playhead before the locate request is processed, causing
5419 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5420 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5423 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5425 last_update_frame = frame;
5427 if (!_dragging_playhead) {
5428 playhead_cursor->set_position (frame);
5431 if (!_stationary_playhead) {
5433 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5434 /* We only do this if we aren't already
5435 handling a visual change (ie if
5436 pending_visual_change.being_handled is
5437 false) so that these requests don't stack
5438 up there are too many of them to handle in
5441 reset_x_origin_to_follow_playhead ();
5446 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5450 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5451 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5452 if (target <= 0.0) {
5455 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5456 target = (target * 0.15) + (current * 0.85);
5462 set_horizontal_position (current);
5471 Editor::session_going_away ()
5473 _have_idled = false;
5475 _session_connections.drop_connections ();
5477 super_rapid_screen_update_connection.disconnect ();
5479 selection->clear ();
5480 cut_buffer->clear ();
5482 clicked_regionview = 0;
5483 clicked_axisview = 0;
5484 clicked_routeview = 0;
5485 entered_regionview = 0;
5487 last_update_frame = 0;
5490 playhead_cursor->hide ();
5492 /* rip everything out of the list displays */
5496 _route_groups->clear ();
5498 /* do this first so that deleting a track doesn't reset cms to null
5499 and thus cause a leak.
5502 if (current_mixer_strip) {
5503 if (current_mixer_strip->get_parent() != 0) {
5504 global_hpacker.remove (*current_mixer_strip);
5506 delete current_mixer_strip;
5507 current_mixer_strip = 0;
5510 /* delete all trackviews */
5512 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5515 track_views.clear ();
5517 nudge_clock->set_session (0);
5519 editor_list_button.set_active(false);
5520 editor_list_button.set_sensitive(false);
5522 /* clear tempo/meter rulers */
5523 remove_metric_marks ();
5525 clear_marker_display ();
5527 stop_step_editing ();
5529 /* get rid of any existing editor mixer strip */
5531 WindowTitle title(Glib::get_application_name());
5532 title += _("Editor");
5534 set_title (title.get_string());
5536 SessionHandlePtr::session_going_away ();
5541 Editor::show_editor_list (bool yn)
5544 _the_notebook.show ();
5546 _the_notebook.hide ();
5551 Editor::change_region_layering_order (bool from_context_menu)
5553 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5555 if (!clicked_routeview) {
5556 if (layering_order_editor) {
5557 layering_order_editor->hide ();
5562 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5568 boost::shared_ptr<Playlist> pl = track->playlist();
5574 if (layering_order_editor == 0) {
5575 layering_order_editor = new RegionLayeringOrderEditor (*this);
5578 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5579 layering_order_editor->maybe_present ();
5583 Editor::update_region_layering_order_editor ()
5585 if (layering_order_editor && layering_order_editor->is_visible ()) {
5586 change_region_layering_order (true);
5591 Editor::setup_fade_images ()
5593 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5594 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5595 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5596 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5597 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5599 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5600 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5601 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5602 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5603 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5605 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5606 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5607 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5608 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5609 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5611 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5612 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5613 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5614 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5615 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5619 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5621 Editor::action_menu_item (std::string const & name)
5623 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5626 return *manage (a->create_menu_item ());
5630 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5632 EventBox* b = manage (new EventBox);
5633 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5634 Label* l = manage (new Label (name));
5638 _the_notebook.append_page (widget, *b);
5642 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5644 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5645 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5648 if (ev->type == GDK_2BUTTON_PRESS) {
5650 /* double-click on a notebook tab shrinks or expands the notebook */
5652 if (_notebook_shrunk) {
5653 if (pre_notebook_shrink_pane_width) {
5654 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5656 _notebook_shrunk = false;
5658 pre_notebook_shrink_pane_width = edit_pane.get_position();
5660 /* this expands the LHS of the edit pane to cover the notebook
5661 PAGE but leaves the tabs visible.
5663 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5664 _notebook_shrunk = true;
5672 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5674 using namespace Menu_Helpers;
5676 MenuList& items = _control_point_context_menu.items ();
5679 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5680 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5681 if (!can_remove_control_point (item)) {
5682 items.back().set_sensitive (false);
5685 _control_point_context_menu.popup (event->button.button, event->button.time);
5689 Editor::zoom_vertical_modifier_released()
5691 _stepping_axis_view = 0;
5695 Editor::ui_parameter_changed (string parameter)
5697 if (parameter == "icon-set") {
5698 while (!_cursor_stack.empty()) {
5699 _cursor_stack.pop();
5701 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5702 } else if (parameter == "draggable-playhead") {
5703 if (_verbose_cursor) {
5704 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());