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));
4291 use_visual_state (*vs);
4295 Editor::redo_visual_state ()
4297 if (redo_visual_stack.empty()) {
4301 VisualState* vs = redo_visual_stack.back();
4302 redo_visual_stack.pop_back();
4304 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4306 use_visual_state (*vs);
4310 Editor::swap_visual_state ()
4312 if (undo_visual_stack.empty()) {
4313 redo_visual_state ();
4315 undo_visual_state ();
4320 Editor::use_visual_state (VisualState& vs)
4322 PBD::Unwinder<bool> nsv (no_save_visual, true);
4323 DisplaySuspender ds;
4325 vertical_adjustment.set_value (vs.y_position);
4327 set_zoom_focus (vs.zoom_focus);
4328 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4331 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4333 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4334 (*i)->reset_visual_state ();
4338 _routes->update_visibility ();
4341 /** This is the core function that controls the zoom level of the canvas. It is called
4342 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4343 * @param spp new number of samples per pixel
4346 Editor::set_samples_per_pixel (framecnt_t spp)
4352 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4353 const framecnt_t lots_of_pixels = 4000;
4355 /* if the zoom level is greater than what you'd get trying to display 3
4356 * days of audio on a really big screen, then it's too big.
4359 if (spp * lots_of_pixels > three_days) {
4363 samples_per_pixel = spp;
4366 tempo_lines->tempo_map_changed();
4369 bool const showing_time_selection = selection->time.length() > 0;
4371 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4372 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4373 (*i)->reshow_selection (selection->time);
4377 ZoomChanged (); /* EMIT_SIGNAL */
4379 ArdourCanvas::GtkCanvasViewport* c;
4381 c = get_track_canvas();
4383 c->canvas()->zoomed ();
4386 if (playhead_cursor) {
4387 playhead_cursor->set_position (playhead_cursor->current_frame ());
4390 refresh_location_display();
4391 _summary->set_overlays_dirty ();
4393 update_marker_labels ();
4399 Editor::queue_visual_videotimeline_update ()
4402 * pending_visual_change.add (VisualChange::VideoTimeline);
4403 * or maybe even more specific: which videotimeline-image
4404 * currently it calls update_video_timeline() to update
4405 * _all outdated_ images on the video-timeline.
4406 * see 'exposeimg()' in video_image_frame.cc
4408 ensure_visual_change_idle_handler ();
4412 Editor::ensure_visual_change_idle_handler ()
4414 if (pending_visual_change.idle_handler_id < 0) {
4415 // see comment in add_to_idle_resize above.
4416 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4417 pending_visual_change.being_handled = false;
4422 Editor::_idle_visual_changer (void* arg)
4424 return static_cast<Editor*>(arg)->idle_visual_changer ();
4428 Editor::idle_visual_changer ()
4430 /* set_horizontal_position() below (and maybe other calls) call
4431 gtk_main_iteration(), so it's possible that a signal will be handled
4432 half-way through this method. If this signal wants an
4433 idle_visual_changer we must schedule another one after this one, so
4434 mark the idle_handler_id as -1 here to allow that. Also make a note
4435 that we are doing the visual change, so that changes in response to
4436 super-rapid-screen-update can be dropped if we are still processing
4440 pending_visual_change.idle_handler_id = -1;
4441 pending_visual_change.being_handled = true;
4443 VisualChange vc = pending_visual_change;
4445 pending_visual_change.pending = (VisualChange::Type) 0;
4447 visual_changer (vc);
4449 pending_visual_change.being_handled = false;
4451 return 0; /* this is always a one-shot call */
4455 Editor::visual_changer (const VisualChange& vc)
4457 double const last_time_origin = horizontal_position ();
4459 if (vc.pending & VisualChange::ZoomLevel) {
4460 set_samples_per_pixel (vc.samples_per_pixel);
4462 compute_fixed_ruler_scale ();
4464 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4465 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4467 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4468 current_bbt_points_begin, current_bbt_points_end);
4469 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4470 current_bbt_points_begin, current_bbt_points_end);
4471 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4473 update_video_timeline();
4476 if (vc.pending & VisualChange::TimeOrigin) {
4477 set_horizontal_position (vc.time_origin / samples_per_pixel);
4480 if (vc.pending & VisualChange::YOrigin) {
4481 vertical_adjustment.set_value (vc.y_origin);
4484 if (last_time_origin == horizontal_position ()) {
4485 /* changed signal not emitted */
4486 update_fixed_rulers ();
4487 redisplay_tempo (true);
4490 if (!(vc.pending & VisualChange::ZoomLevel)) {
4491 update_video_timeline();
4494 _summary->set_overlays_dirty ();
4497 struct EditorOrderTimeAxisSorter {
4498 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4499 return a->order () < b->order ();
4504 Editor::sort_track_selection (TrackViewList& sel)
4506 EditorOrderTimeAxisSorter cmp;
4511 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4514 framepos_t where = 0;
4515 EditPoint ep = _edit_point;
4517 if(Profile->get_mixbus())
4518 if (ep == EditAtSelectedMarker)
4521 if (from_context_menu && (ep == EditAtMouse)) {
4522 return canvas_event_sample (&context_click_event, 0, 0);
4525 if (entered_marker) {
4526 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4527 return entered_marker->position();
4530 if (ignore_playhead && ep == EditAtPlayhead) {
4531 ep = EditAtSelectedMarker;
4535 case EditAtPlayhead:
4536 where = _session->audible_frame();
4537 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4540 case EditAtSelectedMarker:
4541 if (!selection->markers.empty()) {
4543 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4546 where = loc->start();
4550 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4558 if (!mouse_frame (where, ignored)) {
4559 /* XXX not right but what can we do ? */
4563 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4571 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4573 if (!_session) return;
4575 begin_reversible_command (cmd);
4579 if ((tll = transport_loop_location()) == 0) {
4580 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4581 XMLNode &before = _session->locations()->get_state();
4582 _session->locations()->add (loc, true);
4583 _session->set_auto_loop_location (loc);
4584 XMLNode &after = _session->locations()->get_state();
4585 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4587 XMLNode &before = tll->get_state();
4588 tll->set_hidden (false, this);
4589 tll->set (start, end);
4590 XMLNode &after = tll->get_state();
4591 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4594 commit_reversible_command ();
4598 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4600 if (!_session) return;
4602 begin_reversible_command (cmd);
4606 if ((tpl = transport_punch_location()) == 0) {
4607 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4608 XMLNode &before = _session->locations()->get_state();
4609 _session->locations()->add (loc, true);
4610 _session->set_auto_punch_location (loc);
4611 XMLNode &after = _session->locations()->get_state();
4612 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4615 XMLNode &before = tpl->get_state();
4616 tpl->set_hidden (false, this);
4617 tpl->set (start, end);
4618 XMLNode &after = tpl->get_state();
4619 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4622 commit_reversible_command ();
4625 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4626 * @param rs List to which found regions are added.
4627 * @param where Time to look at.
4628 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4631 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4633 const TrackViewList* tracks;
4636 tracks = &track_views;
4641 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4643 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4646 boost::shared_ptr<Track> tr;
4647 boost::shared_ptr<Playlist> pl;
4649 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4651 boost::shared_ptr<RegionList> regions = pl->regions_at (
4652 (framepos_t) floor ( (double) where * tr->speed()));
4654 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4655 RegionView* rv = rtv->view()->find_view (*i);
4666 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4668 const TrackViewList* tracks;
4671 tracks = &track_views;
4676 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4677 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4679 boost::shared_ptr<Track> tr;
4680 boost::shared_ptr<Playlist> pl;
4682 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4684 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4685 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4687 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4689 RegionView* rv = rtv->view()->find_view (*i);
4700 /** Get regions using the following method:
4702 * Make a region list using:
4703 * (a) any selected regions
4704 * (b) the intersection of any selected tracks and the edit point(*)
4705 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4707 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4709 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4713 Editor::get_regions_from_selection_and_edit_point ()
4715 RegionSelection regions;
4717 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4718 regions.add (entered_regionview);
4720 regions = selection->regions;
4723 if ( regions.empty() ) {
4724 TrackViewList tracks = selection->tracks;
4726 if (!tracks.empty()) {
4727 /* no region selected or entered, but some selected tracks:
4728 * act on all regions on the selected tracks at the edit point
4730 framepos_t const where = get_preferred_edit_position ();
4731 get_regions_at(regions, where, tracks);
4738 /** Get regions using the following method:
4740 * Make a region list using:
4741 * (a) any selected regions
4742 * (b) the intersection of any selected tracks and the edit point(*)
4743 * (c) if neither exists, then whatever region is under the mouse
4745 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4747 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4750 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4752 RegionSelection regions;
4754 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4755 regions.add (entered_regionview);
4757 regions = selection->regions;
4760 if ( regions.empty() ) {
4761 TrackViewList tracks = selection->tracks;
4763 if (!tracks.empty()) {
4764 /* no region selected or entered, but some selected tracks:
4765 * act on all regions on the selected tracks at the edit point
4767 get_regions_at(regions, pos, tracks);
4774 /** Start with regions that are selected, or the entered regionview if none are selected.
4775 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4776 * of the regions that we started with.
4780 Editor::get_regions_from_selection_and_entered ()
4782 RegionSelection regions = selection->regions;
4784 if (regions.empty() && entered_regionview) {
4785 regions.add (entered_regionview);
4792 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4794 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4796 RouteTimeAxisView* tatv;
4798 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4800 boost::shared_ptr<Playlist> pl;
4801 vector<boost::shared_ptr<Region> > results;
4803 boost::shared_ptr<Track> tr;
4805 if ((tr = tatv->track()) == 0) {
4810 if ((pl = (tr->playlist())) != 0) {
4811 if (src_comparison) {
4812 pl->get_source_equivalent_regions (region, results);
4814 pl->get_region_list_equivalent_regions (region, results);
4818 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4819 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4820 regions.push_back (marv);
4829 Editor::show_rhythm_ferret ()
4831 if (rhythm_ferret == 0) {
4832 rhythm_ferret = new RhythmFerret(*this);
4835 rhythm_ferret->set_session (_session);
4836 rhythm_ferret->show ();
4837 rhythm_ferret->present ();
4841 Editor::first_idle ()
4843 MessageDialog* dialog = 0;
4845 if (track_views.size() > 1) {
4846 dialog = new MessageDialog (
4848 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4852 ARDOUR_UI::instance()->flush_pending ();
4855 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4859 // first idle adds route children (automation tracks), so we need to redisplay here
4860 _routes->redisplay ();
4867 Editor::_idle_resize (gpointer arg)
4869 return ((Editor*)arg)->idle_resize ();
4873 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4875 if (resize_idle_id < 0) {
4876 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
4877 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
4878 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
4880 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
4881 _pending_resize_amount = 0;
4884 /* make a note of the smallest resulting height, so that we can clamp the
4885 lower limit at TimeAxisView::hSmall */
4887 int32_t min_resulting = INT32_MAX;
4889 _pending_resize_amount += h;
4890 _pending_resize_view = view;
4892 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4894 if (selection->tracks.contains (_pending_resize_view)) {
4895 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4896 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4900 if (min_resulting < 0) {
4905 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4906 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4910 /** Handle pending resizing of tracks */
4912 Editor::idle_resize ()
4914 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4916 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4917 selection->tracks.contains (_pending_resize_view)) {
4919 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4920 if (*i != _pending_resize_view) {
4921 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4926 _pending_resize_amount = 0;
4927 _group_tabs->set_dirty ();
4928 resize_idle_id = -1;
4936 ENSURE_GUI_THREAD (*this, &Editor::located);
4939 playhead_cursor->set_position (_session->audible_frame ());
4940 if (_follow_playhead && !_pending_initial_locate) {
4941 reset_x_origin_to_follow_playhead ();
4945 _pending_locate_request = false;
4946 _pending_initial_locate = false;
4950 Editor::region_view_added (RegionView *)
4952 _summary->set_background_dirty ();
4956 Editor::region_view_removed ()
4958 _summary->set_background_dirty ();
4962 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4964 TrackViewList::const_iterator j = track_views.begin ();
4965 while (j != track_views.end()) {
4966 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4967 if (rtv && rtv->route() == r) {
4978 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4982 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4983 TimeAxisView* tv = axis_view_from_route (*i);
4993 Editor::suspend_route_redisplay ()
4996 _routes->suspend_redisplay();
5001 Editor::resume_route_redisplay ()
5004 _routes->resume_redisplay();
5009 Editor::add_routes (RouteList& routes)
5011 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5013 RouteTimeAxisView *rtv;
5014 list<RouteTimeAxisView*> new_views;
5016 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5017 boost::shared_ptr<Route> route = (*x);
5019 if (route->is_auditioner() || route->is_monitor()) {
5023 DataType dt = route->input()->default_type();
5025 if (dt == ARDOUR::DataType::AUDIO) {
5026 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5027 rtv->set_route (route);
5028 } else if (dt == ARDOUR::DataType::MIDI) {
5029 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5030 rtv->set_route (route);
5032 throw unknown_type();
5035 new_views.push_back (rtv);
5036 track_views.push_back (rtv);
5038 rtv->effective_gain_display ();
5040 if (internal_editing()) {
5041 rtv->enter_internal_edit_mode ();
5043 rtv->leave_internal_edit_mode ();
5046 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5047 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5050 if (new_views.size() > 0) {
5051 _routes->routes_added (new_views);
5052 _summary->routes_added (new_views);
5055 if (show_editor_mixer_when_tracks_arrive) {
5056 show_editor_mixer (true);
5059 editor_list_button.set_sensitive (true);
5063 Editor::timeaxisview_deleted (TimeAxisView *tv)
5065 if (tv == entered_track) {
5069 if (_session && _session->deletion_in_progress()) {
5070 /* the situation is under control */
5074 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5076 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5078 _routes->route_removed (tv);
5080 TimeAxisView::Children c = tv->get_child_list ();
5081 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5082 if (entered_track == i->get()) {
5087 /* remove it from the list of track views */
5089 TrackViewList::iterator i;
5091 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5092 i = track_views.erase (i);
5095 /* update whatever the current mixer strip is displaying, if revelant */
5097 boost::shared_ptr<Route> route;
5100 route = rtav->route ();
5103 if (current_mixer_strip && current_mixer_strip->route() == route) {
5105 TimeAxisView* next_tv;
5107 if (track_views.empty()) {
5109 } else if (i == track_views.end()) {
5110 next_tv = track_views.front();
5117 set_selected_mixer_strip (*next_tv);
5119 /* make the editor mixer strip go away setting the
5120 * button to inactive (which also unticks the menu option)
5123 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5129 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5131 if (apply_to_selection) {
5132 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5134 TrackSelection::iterator j = i;
5137 hide_track_in_display (*i, false);
5142 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5144 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5145 // this will hide the mixer strip
5146 set_selected_mixer_strip (*tv);
5149 _routes->hide_track_in_display (*tv);
5154 Editor::sync_track_view_list_and_routes ()
5156 track_views = TrackViewList (_routes->views ());
5158 _summary->set_dirty ();
5159 _group_tabs->set_dirty ();
5161 return false; // do not call again (until needed)
5165 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5167 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5172 /** Find a RouteTimeAxisView by the ID of its route */
5174 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5176 RouteTimeAxisView* v;
5178 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5179 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5180 if(v->route()->id() == id) {
5190 Editor::fit_route_group (RouteGroup *g)
5192 TrackViewList ts = axis_views_from_routes (g->route_list ());
5197 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5199 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5202 _session->cancel_audition ();
5206 if (_session->is_auditioning()) {
5207 _session->cancel_audition ();
5208 if (r == last_audition_region) {
5213 _session->audition_region (r);
5214 last_audition_region = r;
5219 Editor::hide_a_region (boost::shared_ptr<Region> r)
5221 r->set_hidden (true);
5225 Editor::show_a_region (boost::shared_ptr<Region> r)
5227 r->set_hidden (false);
5231 Editor::audition_region_from_region_list ()
5233 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5237 Editor::hide_region_from_region_list ()
5239 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5243 Editor::show_region_in_region_list ()
5245 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5249 Editor::step_edit_status_change (bool yn)
5252 start_step_editing ();
5254 stop_step_editing ();
5259 Editor::start_step_editing ()
5261 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5265 Editor::stop_step_editing ()
5267 step_edit_connection.disconnect ();
5271 Editor::check_step_edit ()
5273 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5274 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5276 mtv->check_step_edit ();
5280 return true; // do it again, till we stop
5284 Editor::scroll_press (Direction dir)
5286 ++_scroll_callbacks;
5288 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5289 /* delay the first auto-repeat */
5295 scroll_backward (1);
5303 scroll_up_one_track ();
5307 scroll_down_one_track ();
5311 /* do hacky auto-repeat */
5312 if (!_scroll_connection.connected ()) {
5314 _scroll_connection = Glib::signal_timeout().connect (
5315 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5318 _scroll_callbacks = 0;
5325 Editor::scroll_release ()
5327 _scroll_connection.disconnect ();
5330 /** Queue a change for the Editor viewport x origin to follow the playhead */
5332 Editor::reset_x_origin_to_follow_playhead ()
5334 framepos_t const frame = playhead_cursor->current_frame ();
5336 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5338 if (_session->transport_speed() < 0) {
5340 if (frame > (current_page_samples() / 2)) {
5341 center_screen (frame-(current_page_samples()/2));
5343 center_screen (current_page_samples()/2);
5350 if (frame < leftmost_frame) {
5352 if (_session->transport_rolling()) {
5353 /* rolling; end up with the playhead at the right of the page */
5354 l = frame - current_page_samples ();
5356 /* not rolling: end up with the playhead 1/4 of the way along the page */
5357 l = frame - current_page_samples() / 4;
5361 if (_session->transport_rolling()) {
5362 /* rolling: end up with the playhead on the left of the page */
5365 /* not rolling: end up with the playhead 3/4 of the way along the page */
5366 l = frame - 3 * current_page_samples() / 4;
5374 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5380 Editor::super_rapid_screen_update ()
5382 if (!_session || !_session->engine().running()) {
5386 /* METERING / MIXER STRIPS */
5388 /* update track meters, if required */
5389 if (is_mapped() && meters_running) {
5390 RouteTimeAxisView* rtv;
5391 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5392 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5393 rtv->fast_update ();
5398 /* and any current mixer strip */
5399 if (current_mixer_strip) {
5400 current_mixer_strip->fast_update ();
5403 /* PLAYHEAD AND VIEWPORT */
5405 framepos_t const frame = _session->audible_frame();
5407 /* There are a few reasons why we might not update the playhead / viewport stuff:
5409 * 1. we don't update things when there's a pending locate request, otherwise
5410 * when the editor requests a locate there is a chance that this method
5411 * will move the playhead before the locate request is processed, causing
5413 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5414 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5417 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5419 last_update_frame = frame;
5421 if (!_dragging_playhead) {
5422 playhead_cursor->set_position (frame);
5425 if (!_stationary_playhead) {
5427 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5428 /* We only do this if we aren't already
5429 handling a visual change (ie if
5430 pending_visual_change.being_handled is
5431 false) so that these requests don't stack
5432 up there are too many of them to handle in
5435 reset_x_origin_to_follow_playhead ();
5440 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5444 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5445 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5446 if (target <= 0.0) {
5449 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5450 target = (target * 0.15) + (current * 0.85);
5456 set_horizontal_position (current);
5465 Editor::session_going_away ()
5467 _have_idled = false;
5469 _session_connections.drop_connections ();
5471 super_rapid_screen_update_connection.disconnect ();
5473 selection->clear ();
5474 cut_buffer->clear ();
5476 clicked_regionview = 0;
5477 clicked_axisview = 0;
5478 clicked_routeview = 0;
5479 entered_regionview = 0;
5481 last_update_frame = 0;
5484 playhead_cursor->hide ();
5486 /* rip everything out of the list displays */
5490 _route_groups->clear ();
5492 /* do this first so that deleting a track doesn't reset cms to null
5493 and thus cause a leak.
5496 if (current_mixer_strip) {
5497 if (current_mixer_strip->get_parent() != 0) {
5498 global_hpacker.remove (*current_mixer_strip);
5500 delete current_mixer_strip;
5501 current_mixer_strip = 0;
5504 /* delete all trackviews */
5506 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5509 track_views.clear ();
5511 nudge_clock->set_session (0);
5513 editor_list_button.set_active(false);
5514 editor_list_button.set_sensitive(false);
5516 /* clear tempo/meter rulers */
5517 remove_metric_marks ();
5519 clear_marker_display ();
5521 stop_step_editing ();
5523 /* get rid of any existing editor mixer strip */
5525 WindowTitle title(Glib::get_application_name());
5526 title += _("Editor");
5528 set_title (title.get_string());
5530 SessionHandlePtr::session_going_away ();
5535 Editor::show_editor_list (bool yn)
5538 _the_notebook.show ();
5540 _the_notebook.hide ();
5545 Editor::change_region_layering_order (bool from_context_menu)
5547 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5549 if (!clicked_routeview) {
5550 if (layering_order_editor) {
5551 layering_order_editor->hide ();
5556 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5562 boost::shared_ptr<Playlist> pl = track->playlist();
5568 if (layering_order_editor == 0) {
5569 layering_order_editor = new RegionLayeringOrderEditor (*this);
5572 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5573 layering_order_editor->maybe_present ();
5577 Editor::update_region_layering_order_editor ()
5579 if (layering_order_editor && layering_order_editor->is_visible ()) {
5580 change_region_layering_order (true);
5585 Editor::setup_fade_images ()
5587 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5588 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5589 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5590 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5591 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5593 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5594 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5595 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5596 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5597 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5599 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5600 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5601 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5602 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5603 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5605 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5606 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5607 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5608 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5609 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5613 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5615 Editor::action_menu_item (std::string const & name)
5617 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5620 return *manage (a->create_menu_item ());
5624 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5626 EventBox* b = manage (new EventBox);
5627 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5628 Label* l = manage (new Label (name));
5632 _the_notebook.append_page (widget, *b);
5636 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5638 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5639 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5642 if (ev->type == GDK_2BUTTON_PRESS) {
5644 /* double-click on a notebook tab shrinks or expands the notebook */
5646 if (_notebook_shrunk) {
5647 if (pre_notebook_shrink_pane_width) {
5648 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5650 _notebook_shrunk = false;
5652 pre_notebook_shrink_pane_width = edit_pane.get_position();
5654 /* this expands the LHS of the edit pane to cover the notebook
5655 PAGE but leaves the tabs visible.
5657 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5658 _notebook_shrunk = true;
5666 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5668 using namespace Menu_Helpers;
5670 MenuList& items = _control_point_context_menu.items ();
5673 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5674 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5675 if (!can_remove_control_point (item)) {
5676 items.back().set_sensitive (false);
5679 _control_point_context_menu.popup (event->button.button, event->button.time);
5683 Editor::zoom_vertical_modifier_released()
5685 _stepping_axis_view = 0;
5689 Editor::ui_parameter_changed (string parameter)
5691 if (parameter == "icon-set") {
5692 while (!_cursor_stack.empty()) {
5693 _cursor_stack.pop();
5695 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5696 } else if (parameter == "draggable-playhead") {
5697 if (_verbose_cursor) {
5698 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());