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;
315 _drags = new DragManager (this);
318 current_mixer_strip = 0;
321 snap_type_strings = I18N (_snap_type_strings);
322 snap_mode_strings = I18N (_snap_mode_strings);
323 zoom_focus_strings = I18N (_zoom_focus_strings);
324 edit_mode_strings = I18N (_edit_mode_strings);
325 edit_point_strings = I18N (_edit_point_strings);
326 #ifdef USE_RUBBERBAND
327 rb_opt_strings = I18N (_rb_opt_strings);
331 build_edit_mode_menu();
332 build_zoom_focus_menu();
333 build_track_count_menu();
334 build_snap_mode_menu();
335 build_snap_type_menu();
336 build_edit_point_menu();
338 snap_threshold = 5.0;
339 bbt_beat_subdivision = 4;
340 _visible_canvas_width = 0;
341 _visible_canvas_height = 0;
342 autoscroll_horizontal_allowed = false;
343 autoscroll_vertical_allowed = false;
348 current_interthread_info = 0;
349 _show_measures = true;
351 show_gain_after_trim = false;
353 have_pending_keyboard_selection = false;
354 _follow_playhead = true;
355 _stationary_playhead = false;
356 editor_ruler_menu = 0;
357 no_ruler_shown_update = false;
359 range_marker_menu = 0;
360 marker_menu_item = 0;
361 tempo_or_meter_marker_menu = 0;
362 transport_marker_menu = 0;
363 new_transport_marker_menu = 0;
364 editor_mixer_strip_width = Wide;
365 show_editor_mixer_when_tracks_arrive = false;
366 region_edit_menu_split_multichannel_item = 0;
367 region_edit_menu_split_item = 0;
370 current_stepping_trackview = 0;
372 entered_regionview = 0;
374 clear_entered_track = false;
377 button_release_can_deselect = true;
378 _dragging_playhead = false;
379 _dragging_edit_point = false;
380 select_new_marker = false;
382 layering_order_editor = 0;
383 no_save_visual = false;
385 within_track_canvas = false;
387 scrubbing_direction = 0;
391 location_marker_color = ARDOUR_UI::config()->get_LocationMarker();
392 location_range_color = ARDOUR_UI::config()->get_LocationRange();
393 location_cd_marker_color = ARDOUR_UI::config()->get_LocationCDMarker();
394 location_loop_color = ARDOUR_UI::config()->get_LocationLoop();
395 location_punch_color = ARDOUR_UI::config()->get_LocationPunch();
397 zoom_focus = ZoomFocusLeft;
398 _edit_point = EditAtMouse;
399 _internal_editing = false;
400 current_canvas_cursor = 0;
401 _visible_track_count = -1;
403 samples_per_pixel = 2048; /* too early to use reset_zoom () */
405 _scroll_callbacks = 0;
407 bbt_label.set_name ("EditorRulerLabel");
408 bbt_label.set_size_request (-1, (int)timebar_height);
409 bbt_label.set_alignment (1.0, 0.5);
410 bbt_label.set_padding (5,0);
412 bbt_label.set_no_show_all();
413 minsec_label.set_name ("EditorRulerLabel");
414 minsec_label.set_size_request (-1, (int)timebar_height);
415 minsec_label.set_alignment (1.0, 0.5);
416 minsec_label.set_padding (5,0);
417 minsec_label.hide ();
418 minsec_label.set_no_show_all();
419 timecode_label.set_name ("EditorRulerLabel");
420 timecode_label.set_size_request (-1, (int)timebar_height);
421 timecode_label.set_alignment (1.0, 0.5);
422 timecode_label.set_padding (5,0);
423 timecode_label.hide ();
424 timecode_label.set_no_show_all();
425 samples_label.set_name ("EditorRulerLabel");
426 samples_label.set_size_request (-1, (int)timebar_height);
427 samples_label.set_alignment (1.0, 0.5);
428 samples_label.set_padding (5,0);
429 samples_label.hide ();
430 samples_label.set_no_show_all();
432 tempo_label.set_name ("EditorRulerLabel");
433 tempo_label.set_size_request (-1, (int)timebar_height);
434 tempo_label.set_alignment (1.0, 0.5);
435 tempo_label.set_padding (5,0);
437 tempo_label.set_no_show_all();
439 meter_label.set_name ("EditorRulerLabel");
440 meter_label.set_size_request (-1, (int)timebar_height);
441 meter_label.set_alignment (1.0, 0.5);
442 meter_label.set_padding (5,0);
444 meter_label.set_no_show_all();
446 if (Profile->get_trx()) {
447 mark_label.set_text (_("Markers"));
449 mark_label.set_name ("EditorRulerLabel");
450 mark_label.set_size_request (-1, (int)timebar_height);
451 mark_label.set_alignment (1.0, 0.5);
452 mark_label.set_padding (5,0);
454 mark_label.set_no_show_all();
456 cd_mark_label.set_name ("EditorRulerLabel");
457 cd_mark_label.set_size_request (-1, (int)timebar_height);
458 cd_mark_label.set_alignment (1.0, 0.5);
459 cd_mark_label.set_padding (5,0);
460 cd_mark_label.hide();
461 cd_mark_label.set_no_show_all();
463 videotl_bar_height = 4;
464 videotl_label.set_name ("EditorRulerLabel");
465 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
466 videotl_label.set_alignment (1.0, 0.5);
467 videotl_label.set_padding (5,0);
468 videotl_label.hide();
469 videotl_label.set_no_show_all();
471 range_mark_label.set_name ("EditorRulerLabel");
472 range_mark_label.set_size_request (-1, (int)timebar_height);
473 range_mark_label.set_alignment (1.0, 0.5);
474 range_mark_label.set_padding (5,0);
475 range_mark_label.hide();
476 range_mark_label.set_no_show_all();
478 transport_mark_label.set_name ("EditorRulerLabel");
479 transport_mark_label.set_size_request (-1, (int)timebar_height);
480 transport_mark_label.set_alignment (1.0, 0.5);
481 transport_mark_label.set_padding (5,0);
482 transport_mark_label.hide();
483 transport_mark_label.set_no_show_all();
485 initialize_canvas ();
487 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
489 _summary = new EditorSummary (this);
491 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
492 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
494 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
496 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
497 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
499 edit_controls_vbox.set_spacing (0);
500 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
501 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
503 HBox* h = manage (new HBox);
504 _group_tabs = new EditorGroupTabs (this);
505 if (!ARDOUR::Profile->get_trx()) {
506 h->pack_start (*_group_tabs, PACK_SHRINK);
508 h->pack_start (edit_controls_vbox);
509 controls_layout.add (*h);
511 controls_layout.set_name ("EditControlsBase");
512 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
513 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
514 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
516 _cursors = new MouseCursors;
517 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
518 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
520 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
522 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
523 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
524 pad_line_1->set_outline_color (0xFF0000FF);
530 edit_packer.set_col_spacings (0);
531 edit_packer.set_row_spacings (0);
532 edit_packer.set_homogeneous (false);
533 edit_packer.set_border_width (0);
534 edit_packer.set_name ("EditorWindow");
536 time_bars_event_box.add (time_bars_vbox);
537 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
538 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
540 /* labels for the time bars */
541 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
543 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
545 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
547 bottom_hbox.set_border_width (2);
548 bottom_hbox.set_spacing (3);
550 _route_groups = new EditorRouteGroups (this);
551 _routes = new EditorRoutes (this);
552 _regions = new EditorRegions (this);
553 _snapshots = new EditorSnapshots (this);
554 _locations = new EditorLocations (this);
556 /* these are static location signals */
558 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
559 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
560 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
562 add_notebook_page (_("Regions"), _regions->widget ());
563 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
564 add_notebook_page (_("Snapshots"), _snapshots->widget ());
565 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
566 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
568 _the_notebook.set_show_tabs (true);
569 _the_notebook.set_scrollable (true);
570 _the_notebook.popup_disable ();
571 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
572 _the_notebook.show_all ();
574 _notebook_shrunk = false;
576 editor_summary_pane.pack1(edit_packer);
578 Button* summary_arrows_left_left = manage (new Button);
579 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
580 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
581 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
583 Button* summary_arrows_left_right = manage (new Button);
584 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
585 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
586 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
588 VBox* summary_arrows_left = manage (new VBox);
589 summary_arrows_left->pack_start (*summary_arrows_left_left);
590 summary_arrows_left->pack_start (*summary_arrows_left_right);
592 Button* summary_arrows_right_up = manage (new Button);
593 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
594 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
595 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
597 Button* summary_arrows_right_down = manage (new Button);
598 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
599 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
600 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
602 VBox* summary_arrows_right = manage (new VBox);
603 summary_arrows_right->pack_start (*summary_arrows_right_up);
604 summary_arrows_right->pack_start (*summary_arrows_right_down);
606 Frame* summary_frame = manage (new Frame);
607 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
609 summary_frame->add (*_summary);
610 summary_frame->show ();
612 _summary_hbox.pack_start (*summary_arrows_left, false, false);
613 _summary_hbox.pack_start (*summary_frame, true, true);
614 _summary_hbox.pack_start (*summary_arrows_right, false, false);
616 if (!ARDOUR::Profile->get_trx()) {
617 editor_summary_pane.pack2 (_summary_hbox);
620 edit_pane.pack1 (editor_summary_pane, true, true);
621 if (!ARDOUR::Profile->get_trx()) {
622 edit_pane.pack2 (_the_notebook, false, true);
625 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
627 /* XXX: editor_summary_pane might need similar to the edit_pane */
629 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
631 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
632 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
634 top_hbox.pack_start (toolbar_frame);
636 HBox *hbox = manage (new HBox);
637 hbox->pack_start (edit_pane, true, true);
639 global_vpacker.pack_start (top_hbox, false, false);
640 global_vpacker.pack_start (*hbox, true, true);
642 global_hpacker.pack_start (global_vpacker, true, true);
644 set_name ("EditorWindow");
645 add_accel_group (ActionManager::ui_manager->get_accel_group());
647 status_bar_hpacker.show ();
649 vpacker.pack_end (status_bar_hpacker, false, false);
650 vpacker.pack_end (global_hpacker, true, true);
652 /* register actions now so that set_state() can find them and set toggles/checks etc */
655 /* when we start using our own keybinding system for the editor, this
656 * will be uncommented
662 set_zoom_focus (zoom_focus);
663 set_visible_track_count (_visible_track_count);
664 _snap_type = SnapToBeat;
665 set_snap_to (_snap_type);
666 _snap_mode = SnapOff;
667 set_snap_mode (_snap_mode);
668 set_mouse_mode (MouseObject, true);
669 pre_internal_mouse_mode = MouseObject;
670 pre_internal_snap_type = _snap_type;
671 pre_internal_snap_mode = _snap_mode;
672 internal_snap_type = _snap_type;
673 internal_snap_mode = _snap_mode;
674 set_edit_point_preference (EditAtMouse, true);
676 _playlist_selector = new PlaylistSelector();
677 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
679 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
683 nudge_forward_button.set_name ("nudge button");
684 nudge_forward_button.set_image(::get_icon("nudge_right"));
686 nudge_backward_button.set_name ("nudge button");
687 nudge_backward_button.set_image(::get_icon("nudge_left"));
689 fade_context_menu.set_name ("ArdourContextMenu");
691 /* icons, titles, WM stuff */
693 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
694 Glib::RefPtr<Gdk::Pixbuf> icon;
696 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
697 window_icons.push_back (icon);
699 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
700 window_icons.push_back (icon);
702 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
703 window_icons.push_back (icon);
705 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
706 window_icons.push_back (icon);
708 if (!window_icons.empty()) {
709 // set_icon_list (window_icons);
710 set_default_icon_list (window_icons);
713 WindowTitle title(Glib::get_application_name());
714 title += _("Editor");
715 set_title (title.get_string());
716 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
719 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
721 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
722 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
724 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
726 /* allow external control surfaces/protocols to do various things */
728 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
729 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
730 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
731 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
732 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
733 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
734 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
735 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
736 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
737 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
738 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
739 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
740 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
741 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
743 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
744 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
745 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
746 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
747 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
749 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
751 /* problematic: has to return a value and thus cannot be x-thread */
753 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
755 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
756 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
758 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
760 _ignore_region_action = false;
761 _last_region_menu_was_main = false;
762 _popup_region_menu_item = 0;
764 _ignore_follow_edits = false;
766 _show_marker_lines = false;
768 /* Button bindings */
770 button_bindings = new Bindings;
772 XMLNode* node = button_settings();
774 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
775 button_bindings->load (**i);
781 /* grab current parameter state */
782 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
783 ARDOUR_UI::config()->map_parameters (pc);
785 setup_fade_images ();
792 delete button_bindings;
794 delete _route_groups;
795 delete _track_canvas_viewport;
801 Editor::button_settings () const
803 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
804 XMLNode* node = find_named_node (*settings, X_("Buttons"));
807 node = new XMLNode (X_("Buttons"));
814 Editor::add_toplevel_menu (Container& cont)
816 vpacker.pack_start (cont, false, false);
821 Editor::add_transport_frame (Container& cont)
823 if(ARDOUR::Profile->get_mixbus()) {
824 global_vpacker.pack_start (cont, false, false);
825 global_vpacker.reorder_child (cont, 0);
828 vpacker.pack_start (cont, false, false);
833 Editor::get_smart_mode () const
835 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
839 Editor::catch_vanishing_regionview (RegionView *rv)
841 /* note: the selection will take care of the vanishing
842 audioregionview by itself.
845 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
849 if (clicked_regionview == rv) {
850 clicked_regionview = 0;
853 if (entered_regionview == rv) {
854 set_entered_regionview (0);
857 if (!_all_region_actions_sensitized) {
858 sensitize_all_region_actions (true);
863 Editor::set_entered_regionview (RegionView* rv)
865 if (rv == entered_regionview) {
869 if (entered_regionview) {
870 entered_regionview->exited ();
873 entered_regionview = rv;
875 if (entered_regionview != 0) {
876 entered_regionview->entered (internal_editing ());
879 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
880 /* This RegionView entry might have changed what region actions
881 are allowed, so sensitize them all in case a key is pressed.
883 sensitize_all_region_actions (true);
888 Editor::set_entered_track (TimeAxisView* tav)
891 entered_track->exited ();
897 entered_track->entered ();
902 Editor::show_window ()
904 if (!is_visible ()) {
908 /* XXX: this is a bit unfortunate; it would probably
909 be nicer if we could just call show () above rather
910 than needing the show_all ()
913 /* re-hide stuff if necessary */
914 editor_list_button_toggled ();
915 parameter_changed ("show-summary");
916 parameter_changed ("show-group-tabs");
917 parameter_changed ("show-zoom-tools");
919 /* now reset all audio_time_axis heights, because widgets might need
925 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
926 tv = (static_cast<TimeAxisView*>(*i));
930 if (current_mixer_strip) {
931 current_mixer_strip->hide_things ();
932 current_mixer_strip->parameter_changed ("mixer-element-visibility");
940 Editor::instant_save ()
942 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
947 _session->add_instant_xml(get_state());
949 Config->add_instant_xml(get_state());
954 Editor::control_vertical_zoom_in_all ()
956 tav_zoom_smooth (false, true);
960 Editor::control_vertical_zoom_out_all ()
962 tav_zoom_smooth (true, true);
966 Editor::control_vertical_zoom_in_selected ()
968 tav_zoom_smooth (false, false);
972 Editor::control_vertical_zoom_out_selected ()
974 tav_zoom_smooth (true, false);
978 Editor::control_view (uint32_t view)
980 goto_visual_state (view);
984 Editor::control_unselect ()
986 selection->clear_tracks ();
990 Editor::control_select (uint32_t rid, Selection::Operation op)
992 /* handles the (static) signal from the ControlProtocol class that
993 * requests setting the selected track to a given RID
1000 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1006 TimeAxisView* tav = axis_view_from_route (r);
1010 case Selection::Add:
1011 selection->add (tav);
1013 case Selection::Toggle:
1014 selection->toggle (tav);
1016 case Selection::Extend:
1018 case Selection::Set:
1019 selection->set (tav);
1023 selection->clear_tracks ();
1028 Editor::control_step_tracks_up ()
1030 scroll_tracks_up_line ();
1034 Editor::control_step_tracks_down ()
1036 scroll_tracks_down_line ();
1040 Editor::control_scroll (float fraction)
1042 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1048 double step = fraction * current_page_samples();
1051 _control_scroll_target is an optional<T>
1053 it acts like a pointer to an framepos_t, with
1054 a operator conversion to boolean to check
1055 that it has a value could possibly use
1056 playhead_cursor->current_frame to store the
1057 value and a boolean in the class to know
1058 when it's out of date
1061 if (!_control_scroll_target) {
1062 _control_scroll_target = _session->transport_frame();
1063 _dragging_playhead = true;
1066 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1067 *_control_scroll_target = 0;
1068 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1069 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1071 *_control_scroll_target += (framepos_t) floor (step);
1074 /* move visuals, we'll catch up with it later */
1076 playhead_cursor->set_position (*_control_scroll_target);
1077 UpdateAllTransportClocks (*_control_scroll_target);
1079 if (*_control_scroll_target > (current_page_samples() / 2)) {
1080 /* try to center PH in window */
1081 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1087 Now we do a timeout to actually bring the session to the right place
1088 according to the playhead. This is to avoid reading disk buffers on every
1089 call to control_scroll, which is driven by ScrollTimeline and therefore
1090 probably by a control surface wheel which can generate lots of events.
1092 /* cancel the existing timeout */
1094 control_scroll_connection.disconnect ();
1096 /* add the next timeout */
1098 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1102 Editor::deferred_control_scroll (framepos_t /*target*/)
1104 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1105 // reset for next stream
1106 _control_scroll_target = boost::none;
1107 _dragging_playhead = false;
1112 Editor::access_action (std::string action_group, std::string action_item)
1118 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1121 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1129 Editor::on_realize ()
1131 Window::on_realize ();
1134 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1135 start_lock_event_timing ();
1138 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1142 Editor::start_lock_event_timing ()
1144 /* check if we should lock the GUI every 30 seconds */
1146 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1150 Editor::generic_event_handler (GdkEvent* ev)
1153 case GDK_BUTTON_PRESS:
1154 case GDK_BUTTON_RELEASE:
1155 case GDK_MOTION_NOTIFY:
1157 case GDK_KEY_RELEASE:
1158 gettimeofday (&last_event_time, 0);
1161 case GDK_LEAVE_NOTIFY:
1162 switch (ev->crossing.detail) {
1163 case GDK_NOTIFY_UNKNOWN:
1164 case GDK_NOTIFY_INFERIOR:
1165 case GDK_NOTIFY_ANCESTOR:
1167 case GDK_NOTIFY_VIRTUAL:
1168 case GDK_NOTIFY_NONLINEAR:
1169 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1170 /* leaving window, so reset focus, thus ending any and
1171 all text entry operations.
1186 Editor::lock_timeout_callback ()
1188 struct timeval now, delta;
1190 gettimeofday (&now, 0);
1192 timersub (&now, &last_event_time, &delta);
1194 if (delta.tv_sec > (time_t) ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1196 /* don't call again. Returning false will effectively
1197 disconnect us from the timer callback.
1199 unlock() will call start_lock_event_timing() to get things
1209 Editor::map_position_change (framepos_t frame)
1211 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1213 if (_session == 0) {
1217 if (_follow_playhead) {
1218 center_screen (frame);
1221 playhead_cursor->set_position (frame);
1225 Editor::center_screen (framepos_t frame)
1227 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1229 /* if we're off the page, then scroll.
1232 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1233 center_screen_internal (frame, page);
1238 Editor::center_screen_internal (framepos_t frame, float page)
1243 frame -= (framepos_t) page;
1248 reset_x_origin (frame);
1253 Editor::update_title ()
1255 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1258 bool dirty = _session->dirty();
1260 string session_name;
1262 if (_session->snap_name() != _session->name()) {
1263 session_name = _session->snap_name();
1265 session_name = _session->name();
1269 session_name = "*" + session_name;
1272 WindowTitle title(session_name);
1273 title += Glib::get_application_name();
1274 set_title (title.get_string());
1276 /* ::session_going_away() will have taken care of it */
1281 Editor::set_session (Session *t)
1283 SessionHandlePtr::set_session (t);
1289 _playlist_selector->set_session (_session);
1290 nudge_clock->set_session (_session);
1291 _summary->set_session (_session);
1292 _group_tabs->set_session (_session);
1293 _route_groups->set_session (_session);
1294 _regions->set_session (_session);
1295 _snapshots->set_session (_session);
1296 _routes->set_session (_session);
1297 _locations->set_session (_session);
1299 if (rhythm_ferret) {
1300 rhythm_ferret->set_session (_session);
1303 if (analysis_window) {
1304 analysis_window->set_session (_session);
1308 sfbrowser->set_session (_session);
1311 compute_fixed_ruler_scale ();
1313 /* Make sure we have auto loop and auto punch ranges */
1315 Location* loc = _session->locations()->auto_loop_location();
1317 loc->set_name (_("Loop"));
1320 loc = _session->locations()->auto_punch_location();
1323 loc->set_name (_("Punch"));
1326 refresh_location_display ();
1328 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1329 the selected Marker; this needs the LocationMarker list to be available.
1331 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1332 set_state (*node, Stateful::loading_state_version);
1334 /* catch up with the playhead */
1336 _session->request_locate (playhead_cursor->current_frame ());
1337 _pending_initial_locate = true;
1341 /* These signals can all be emitted by a non-GUI thread. Therefore the
1342 handlers for them must not attempt to directly interact with the GUI,
1343 but use PBD::Signal<T>::connect() which accepts an event loop
1344 ("context") where the handler will be asked to run.
1347 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1348 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1349 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1350 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1351 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1352 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1353 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1354 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1355 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1356 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1357 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1358 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1359 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1361 playhead_cursor->show ();
1363 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1364 Config->map_parameters (pc);
1365 _session->config.map_parameters (pc);
1367 restore_ruler_visibility ();
1368 //tempo_map_changed (PropertyChange (0));
1369 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1371 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1372 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1375 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1376 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1379 switch (_snap_type) {
1380 case SnapToRegionStart:
1381 case SnapToRegionEnd:
1382 case SnapToRegionSync:
1383 case SnapToRegionBoundary:
1384 build_region_boundary_cache ();
1391 /* register for undo history */
1392 _session->register_with_memento_command_factory(id(), this);
1394 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1396 start_updating_meters ();
1400 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1402 if (a->get_name() == "RegionMenu") {
1403 /* When the main menu's region menu is opened, we setup the actions so that they look right
1404 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1405 so we resensitize all region actions when the entered regionview or the region selection
1406 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1407 happens after the region context menu is opened. So we set a flag here, too.
1411 sensitize_the_right_region_actions ();
1412 _last_region_menu_was_main = true;
1417 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1419 using namespace Menu_Helpers;
1421 void (Editor::*emf)(FadeShape);
1422 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1425 images = &_xfade_in_images;
1426 emf = &Editor::set_fade_in_shape;
1428 images = &_xfade_out_images;
1429 emf = &Editor::set_fade_out_shape;
1434 _("Linear (for highly correlated material)"),
1435 *(*images)[FadeLinear],
1436 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1440 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1444 _("Constant power"),
1445 *(*images)[FadeConstantPower],
1446 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1449 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1454 *(*images)[FadeSymmetric],
1455 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1459 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1464 *(*images)[FadeSlow],
1465 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1468 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1473 *(*images)[FadeFast],
1474 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1477 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1480 /** Pop up a context menu for when the user clicks on a start crossfade */
1482 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1484 using namespace Menu_Helpers;
1485 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1488 MenuList& items (xfade_in_context_menu.items());
1491 if (arv->audio_region()->fade_in_active()) {
1492 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1494 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1497 items.push_back (SeparatorElem());
1498 fill_xfade_menu (items, true);
1500 xfade_in_context_menu.popup (button, time);
1503 /** Pop up a context menu for when the user clicks on an end crossfade */
1505 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1507 using namespace Menu_Helpers;
1508 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1511 MenuList& items (xfade_out_context_menu.items());
1514 if (arv->audio_region()->fade_out_active()) {
1515 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1517 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1520 items.push_back (SeparatorElem());
1521 fill_xfade_menu (items, false);
1523 xfade_out_context_menu.popup (button, time);
1527 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1529 using namespace Menu_Helpers;
1530 Menu* (Editor::*build_menu_function)();
1533 switch (item_type) {
1535 case RegionViewName:
1536 case RegionViewNameHighlight:
1537 case LeftFrameHandle:
1538 case RightFrameHandle:
1539 if (with_selection) {
1540 build_menu_function = &Editor::build_track_selection_context_menu;
1542 build_menu_function = &Editor::build_track_region_context_menu;
1547 if (with_selection) {
1548 build_menu_function = &Editor::build_track_selection_context_menu;
1550 build_menu_function = &Editor::build_track_context_menu;
1555 if (clicked_routeview->track()) {
1556 build_menu_function = &Editor::build_track_context_menu;
1558 build_menu_function = &Editor::build_track_bus_context_menu;
1563 /* probably shouldn't happen but if it does, we don't care */
1567 menu = (this->*build_menu_function)();
1568 menu->set_name ("ArdourContextMenu");
1570 /* now handle specific situations */
1572 switch (item_type) {
1574 case RegionViewName:
1575 case RegionViewNameHighlight:
1576 case LeftFrameHandle:
1577 case RightFrameHandle:
1578 if (!with_selection) {
1579 if (region_edit_menu_split_item) {
1580 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1581 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1583 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1586 if (region_edit_menu_split_multichannel_item) {
1587 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1588 region_edit_menu_split_multichannel_item->set_sensitive (true);
1590 region_edit_menu_split_multichannel_item->set_sensitive (false);
1603 /* probably shouldn't happen but if it does, we don't care */
1607 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1609 /* Bounce to disk */
1611 using namespace Menu_Helpers;
1612 MenuList& edit_items = menu->items();
1614 edit_items.push_back (SeparatorElem());
1616 switch (clicked_routeview->audio_track()->freeze_state()) {
1617 case AudioTrack::NoFreeze:
1618 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1621 case AudioTrack::Frozen:
1622 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1625 case AudioTrack::UnFrozen:
1626 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1632 if (item_type == StreamItem && clicked_routeview) {
1633 clicked_routeview->build_underlay_menu(menu);
1636 /* When the region menu is opened, we setup the actions so that they look right
1639 sensitize_the_right_region_actions ();
1640 _last_region_menu_was_main = false;
1642 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1643 menu->popup (button, time);
1647 Editor::build_track_context_menu ()
1649 using namespace Menu_Helpers;
1651 MenuList& edit_items = track_context_menu.items();
1654 add_dstream_context_items (edit_items);
1655 return &track_context_menu;
1659 Editor::build_track_bus_context_menu ()
1661 using namespace Menu_Helpers;
1663 MenuList& edit_items = track_context_menu.items();
1666 add_bus_context_items (edit_items);
1667 return &track_context_menu;
1671 Editor::build_track_region_context_menu ()
1673 using namespace Menu_Helpers;
1674 MenuList& edit_items = track_region_context_menu.items();
1677 /* we've just cleared the track region context menu, so the menu that these
1678 two items were on will have disappeared; stop them dangling.
1680 region_edit_menu_split_item = 0;
1681 region_edit_menu_split_multichannel_item = 0;
1683 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1686 boost::shared_ptr<Track> tr;
1687 boost::shared_ptr<Playlist> pl;
1689 if ((tr = rtv->track())) {
1690 add_region_context_items (edit_items, tr);
1694 add_dstream_context_items (edit_items);
1696 return &track_region_context_menu;
1700 Editor::analyze_region_selection ()
1702 if (analysis_window == 0) {
1703 analysis_window = new AnalysisWindow();
1706 analysis_window->set_session(_session);
1708 analysis_window->show_all();
1711 analysis_window->set_regionmode();
1712 analysis_window->analyze();
1714 analysis_window->present();
1718 Editor::analyze_range_selection()
1720 if (analysis_window == 0) {
1721 analysis_window = new AnalysisWindow();
1724 analysis_window->set_session(_session);
1726 analysis_window->show_all();
1729 analysis_window->set_rangemode();
1730 analysis_window->analyze();
1732 analysis_window->present();
1736 Editor::build_track_selection_context_menu ()
1738 using namespace Menu_Helpers;
1739 MenuList& edit_items = track_selection_context_menu.items();
1740 edit_items.clear ();
1742 add_selection_context_items (edit_items);
1743 // edit_items.push_back (SeparatorElem());
1744 // add_dstream_context_items (edit_items);
1746 return &track_selection_context_menu;
1750 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1752 using namespace Menu_Helpers;
1754 /* OK, stick the region submenu at the top of the list, and then add
1758 RegionSelection rs = get_regions_from_selection_and_entered ();
1760 string::size_type pos = 0;
1761 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1763 /* we have to hack up the region name because "_" has a special
1764 meaning for menu titles.
1767 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1768 menu_item_name.replace (pos, 1, "__");
1772 if (_popup_region_menu_item == 0) {
1773 _popup_region_menu_item = new MenuItem (menu_item_name);
1774 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1775 _popup_region_menu_item->show ();
1777 _popup_region_menu_item->set_label (menu_item_name);
1780 const framepos_t position = get_preferred_edit_position (false, true);
1782 edit_items.push_back (*_popup_region_menu_item);
1783 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1784 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1786 edit_items.push_back (SeparatorElem());
1789 /** Add context menu items relevant to selection ranges.
1790 * @param edit_items List to add the items to.
1793 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1795 using namespace Menu_Helpers;
1797 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1798 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1800 edit_items.push_back (SeparatorElem());
1801 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1803 edit_items.push_back (SeparatorElem());
1804 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1806 edit_items.push_back (SeparatorElem());
1808 edit_items.push_back (
1810 _("Move Range Start to Previous Region Boundary"),
1811 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1815 edit_items.push_back (
1817 _("Move Range Start to Next Region Boundary"),
1818 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1822 edit_items.push_back (
1824 _("Move Range End to Previous Region Boundary"),
1825 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1829 edit_items.push_back (
1831 _("Move Range End to Next Region Boundary"),
1832 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1836 edit_items.push_back (SeparatorElem());
1837 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1838 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1840 edit_items.push_back (SeparatorElem());
1841 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1843 edit_items.push_back (SeparatorElem());
1844 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1845 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1847 edit_items.push_back (SeparatorElem());
1848 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1850 edit_items.push_back (SeparatorElem());
1851 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1852 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1853 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1855 edit_items.push_back (SeparatorElem());
1856 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1857 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1858 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1859 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1860 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1861 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1862 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1868 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1870 using namespace Menu_Helpers;
1874 Menu *play_menu = manage (new Menu);
1875 MenuList& play_items = play_menu->items();
1876 play_menu->set_name ("ArdourContextMenu");
1878 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1879 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1880 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1881 play_items.push_back (SeparatorElem());
1882 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1884 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1888 Menu *select_menu = manage (new Menu);
1889 MenuList& select_items = select_menu->items();
1890 select_menu->set_name ("ArdourContextMenu");
1892 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1893 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1894 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1895 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1896 select_items.push_back (SeparatorElem());
1897 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1898 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1899 select_items.push_back (SeparatorElem());
1900 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1901 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1902 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1903 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1904 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1905 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1906 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1908 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1912 Menu *cutnpaste_menu = manage (new Menu);
1913 MenuList& cutnpaste_items = cutnpaste_menu->items();
1914 cutnpaste_menu->set_name ("ArdourContextMenu");
1916 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1917 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1918 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1920 cutnpaste_items.push_back (SeparatorElem());
1922 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1923 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1925 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1927 /* Adding new material */
1929 edit_items.push_back (SeparatorElem());
1930 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1931 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1935 Menu *nudge_menu = manage (new Menu());
1936 MenuList& nudge_items = nudge_menu->items();
1937 nudge_menu->set_name ("ArdourContextMenu");
1939 edit_items.push_back (SeparatorElem());
1940 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1941 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1942 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1943 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1945 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1949 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1951 using namespace Menu_Helpers;
1955 Menu *play_menu = manage (new Menu);
1956 MenuList& play_items = play_menu->items();
1957 play_menu->set_name ("ArdourContextMenu");
1959 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1960 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1961 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1965 Menu *select_menu = manage (new Menu);
1966 MenuList& select_items = select_menu->items();
1967 select_menu->set_name ("ArdourContextMenu");
1969 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1970 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1971 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1972 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1973 select_items.push_back (SeparatorElem());
1974 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1975 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1976 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1977 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1979 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1983 Menu *cutnpaste_menu = manage (new Menu);
1984 MenuList& cutnpaste_items = cutnpaste_menu->items();
1985 cutnpaste_menu->set_name ("ArdourContextMenu");
1987 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1988 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1989 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1991 Menu *nudge_menu = manage (new Menu());
1992 MenuList& nudge_items = nudge_menu->items();
1993 nudge_menu->set_name ("ArdourContextMenu");
1995 edit_items.push_back (SeparatorElem());
1996 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1997 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1998 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1999 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2001 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2005 Editor::snap_type() const
2011 Editor::snap_mode() const
2017 Editor::set_snap_to (SnapType st)
2019 unsigned int snap_ind = (unsigned int)st;
2023 if (snap_ind > snap_type_strings.size() - 1) {
2025 _snap_type = (SnapType)snap_ind;
2028 string str = snap_type_strings[snap_ind];
2030 if (str != snap_type_selector.get_text()) {
2031 snap_type_selector.set_text (str);
2036 switch (_snap_type) {
2037 case SnapToBeatDiv128:
2038 case SnapToBeatDiv64:
2039 case SnapToBeatDiv32:
2040 case SnapToBeatDiv28:
2041 case SnapToBeatDiv24:
2042 case SnapToBeatDiv20:
2043 case SnapToBeatDiv16:
2044 case SnapToBeatDiv14:
2045 case SnapToBeatDiv12:
2046 case SnapToBeatDiv10:
2047 case SnapToBeatDiv8:
2048 case SnapToBeatDiv7:
2049 case SnapToBeatDiv6:
2050 case SnapToBeatDiv5:
2051 case SnapToBeatDiv4:
2052 case SnapToBeatDiv3:
2053 case SnapToBeatDiv2: {
2054 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2055 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2057 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2058 current_bbt_points_begin, current_bbt_points_end);
2059 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2060 current_bbt_points_begin, current_bbt_points_end);
2061 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2065 case SnapToRegionStart:
2066 case SnapToRegionEnd:
2067 case SnapToRegionSync:
2068 case SnapToRegionBoundary:
2069 build_region_boundary_cache ();
2077 SnapChanged (); /* EMIT SIGNAL */
2081 Editor::set_snap_mode (SnapMode mode)
2083 string str = snap_mode_strings[(int)mode];
2085 if (_internal_editing) {
2086 internal_snap_mode = mode;
2088 pre_internal_snap_mode = mode;
2093 if (str != snap_mode_selector.get_text ()) {
2094 snap_mode_selector.set_text (str);
2100 Editor::set_edit_point_preference (EditPoint ep, bool force)
2102 bool changed = (_edit_point != ep);
2105 string str = edit_point_strings[(int)ep];
2107 if (Profile->get_mixbus())
2108 if (ep == EditAtSelectedMarker)
2109 ep = EditAtPlayhead;
2111 if (str != edit_point_selector.get_text ()) {
2112 edit_point_selector.set_text (str);
2115 reset_canvas_cursor ();
2117 if (!force && !changed) {
2121 const char* action=NULL;
2123 switch (_edit_point) {
2124 case EditAtPlayhead:
2125 action = "edit-at-playhead";
2127 case EditAtSelectedMarker:
2128 action = "edit-at-marker";
2131 action = "edit-at-mouse";
2135 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2137 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2141 bool in_track_canvas;
2143 if (!mouse_frame (foo, in_track_canvas)) {
2144 in_track_canvas = false;
2147 reset_canvas_action_sensitivity (in_track_canvas);
2153 Editor::set_state (const XMLNode& node, int /*version*/)
2155 const XMLProperty* prop;
2162 g.base_width = default_width;
2163 g.base_height = default_height;
2167 if ((geometry = find_named_node (node, "geometry")) != 0) {
2171 if ((prop = geometry->property("x_size")) == 0) {
2172 prop = geometry->property ("x-size");
2175 g.base_width = atoi(prop->value());
2177 if ((prop = geometry->property("y_size")) == 0) {
2178 prop = geometry->property ("y-size");
2181 g.base_height = atoi(prop->value());
2184 if ((prop = geometry->property ("x_pos")) == 0) {
2185 prop = geometry->property ("x-pos");
2188 x = atoi (prop->value());
2191 if ((prop = geometry->property ("y_pos")) == 0) {
2192 prop = geometry->property ("y-pos");
2195 y = atoi (prop->value());
2199 set_default_size (g.base_width, g.base_height);
2202 if (_session && (prop = node.property ("playhead"))) {
2204 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2206 playhead_cursor->set_position (pos);
2208 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2209 playhead_cursor->set_position (0);
2212 playhead_cursor->set_position (0);
2215 if ((prop = node.property ("mixer-width"))) {
2216 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2219 if ((prop = node.property ("zoom-focus"))) {
2220 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2223 if ((prop = node.property ("zoom"))) {
2224 /* older versions of ardour used floating point samples_per_pixel */
2225 double f = PBD::atof (prop->value());
2226 reset_zoom (llrintf (f));
2228 reset_zoom (samples_per_pixel);
2231 if ((prop = node.property ("visible-track-count"))) {
2232 set_visible_track_count (PBD::atoi (prop->value()));
2235 if ((prop = node.property ("snap-to"))) {
2236 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2239 if ((prop = node.property ("snap-mode"))) {
2240 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2243 if ((prop = node.property ("internal-snap-to"))) {
2244 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2247 if ((prop = node.property ("internal-snap-mode"))) {
2248 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2251 if ((prop = node.property ("pre-internal-snap-to"))) {
2252 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2256 if ((prop = node.property ("pre-internal-snap-mode"))) {
2257 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2260 if ((prop = node.property ("mouse-mode"))) {
2261 MouseMode m = str2mousemode(prop->value());
2262 set_mouse_mode (m, true);
2264 set_mouse_mode (MouseObject, true);
2267 if ((prop = node.property ("left-frame")) != 0) {
2269 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2273 reset_x_origin (pos);
2277 if ((prop = node.property ("y-origin")) != 0) {
2278 reset_y_origin (atof (prop->value ()));
2281 if ((prop = node.property ("internal-edit"))) {
2282 bool yn = string_is_affirmative (prop->value());
2283 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2285 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2286 tact->set_active (!yn);
2287 tact->set_active (yn);
2291 if ((prop = node.property ("join-object-range"))) {
2292 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2293 bool yn = string_is_affirmative (prop->value());
2295 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2296 tact->set_active (!yn);
2297 tact->set_active (yn);
2299 set_mouse_mode(mouse_mode, true);
2302 if ((prop = node.property ("edit-point"))) {
2303 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2306 if ((prop = node.property ("show-measures"))) {
2307 bool yn = string_is_affirmative (prop->value());
2308 _show_measures = yn;
2309 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2311 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2312 /* do it twice to force the change */
2313 tact->set_active (!yn);
2314 tact->set_active (yn);
2318 if ((prop = node.property ("follow-playhead"))) {
2319 bool yn = string_is_affirmative (prop->value());
2320 set_follow_playhead (yn);
2321 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2323 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2324 if (tact->get_active() != yn) {
2325 tact->set_active (yn);
2330 if ((prop = node.property ("stationary-playhead"))) {
2331 bool yn = string_is_affirmative (prop->value());
2332 set_stationary_playhead (yn);
2333 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2335 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2336 if (tact->get_active() != yn) {
2337 tact->set_active (yn);
2342 if ((prop = node.property ("region-list-sort-type"))) {
2343 RegionListSortType st;
2344 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2347 if ((prop = node.property ("show-editor-mixer"))) {
2349 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2352 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2353 bool yn = string_is_affirmative (prop->value());
2355 /* do it twice to force the change */
2357 tact->set_active (!yn);
2358 tact->set_active (yn);
2361 if ((prop = node.property ("show-editor-list"))) {
2363 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2366 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2367 bool yn = string_is_affirmative (prop->value());
2369 /* do it twice to force the change */
2371 tact->set_active (!yn);
2372 tact->set_active (yn);
2375 if ((prop = node.property (X_("editor-list-page")))) {
2376 _the_notebook.set_current_page (atoi (prop->value ()));
2379 if ((prop = node.property (X_("show-marker-lines")))) {
2380 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2382 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2383 bool yn = string_is_affirmative (prop->value ());
2385 tact->set_active (!yn);
2386 tact->set_active (yn);
2389 XMLNodeList children = node.children ();
2390 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2391 selection->set_state (**i, Stateful::current_state_version);
2392 _regions->set_state (**i);
2395 if ((prop = node.property ("maximised"))) {
2396 bool yn = string_is_affirmative (prop->value());
2397 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2399 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2400 bool fs = tact && tact->get_active();
2402 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2406 if ((prop = node.property ("nudge-clock-value"))) {
2408 sscanf (prop->value().c_str(), "%" PRId64, &f);
2409 nudge_clock->set (f);
2411 nudge_clock->set_mode (AudioClock::Timecode);
2412 nudge_clock->set (_session->frame_rate() * 5, true);
2419 Editor::get_state ()
2421 XMLNode* node = new XMLNode ("Editor");
2424 id().print (buf, sizeof (buf));
2425 node->add_property ("id", buf);
2427 if (is_realized()) {
2428 Glib::RefPtr<Gdk::Window> win = get_window();
2430 int x, y, width, height;
2431 win->get_root_origin(x, y);
2432 win->get_size(width, height);
2434 XMLNode* geometry = new XMLNode ("geometry");
2436 snprintf(buf, sizeof(buf), "%d", width);
2437 geometry->add_property("x-size", string(buf));
2438 snprintf(buf, sizeof(buf), "%d", height);
2439 geometry->add_property("y-size", string(buf));
2440 snprintf(buf, sizeof(buf), "%d", x);
2441 geometry->add_property("x-pos", string(buf));
2442 snprintf(buf, sizeof(buf), "%d", y);
2443 geometry->add_property("y-pos", string(buf));
2444 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2445 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2446 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2447 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2448 geometry->add_property("edit-vertical-pane-pos", string(buf));
2450 node->add_child_nocopy (*geometry);
2453 maybe_add_mixer_strip_width (*node);
2455 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2457 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2458 node->add_property ("zoom", buf);
2459 node->add_property ("snap-to", enum_2_string (_snap_type));
2460 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2461 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2462 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2463 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2464 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2465 node->add_property ("edit-point", enum_2_string (_edit_point));
2466 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2467 node->add_property ("visible-track-count", buf);
2469 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2470 node->add_property ("playhead", buf);
2471 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2472 node->add_property ("left-frame", buf);
2473 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2474 node->add_property ("y-origin", buf);
2476 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2477 node->add_property ("maximised", _maximised ? "yes" : "no");
2478 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2479 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2480 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2481 node->add_property ("mouse-mode", enum2str(mouse_mode));
2482 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2483 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2485 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2487 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2488 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2491 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2493 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2494 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2497 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2498 node->add_property (X_("editor-list-page"), buf);
2500 if (button_bindings) {
2501 XMLNode* bb = new XMLNode (X_("Buttons"));
2502 button_bindings->save (*bb);
2503 node->add_child_nocopy (*bb);
2506 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2508 node->add_child_nocopy (selection->get_state ());
2509 node->add_child_nocopy (_regions->get_state ());
2511 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2512 node->add_property ("nudge-clock-value", buf);
2517 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2518 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2520 * @return pair: TimeAxisView that y is over, layer index.
2522 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2523 * in stacked or expanded region display mode, otherwise 0.
2525 std::pair<TimeAxisView *, double>
2526 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2528 if (!trackview_relative_offset) {
2529 y -= _trackview_group->canvas_origin().y;
2533 return std::make_pair ( (TimeAxisView *) 0, 0);
2536 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2538 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2545 return std::make_pair ( (TimeAxisView *) 0, 0);
2548 /** Snap a position to the grid, if appropriate, taking into account current
2549 * grid settings and also the state of any snap modifier keys that may be pressed.
2550 * @param start Position to snap.
2551 * @param event Event to get current key modifier information from, or 0.
2554 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2556 if (!_session || !event) {
2560 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2561 if (_snap_mode == SnapOff) {
2562 snap_to_internal (start, direction, for_mark);
2565 if (_snap_mode != SnapOff) {
2566 snap_to_internal (start, direction, for_mark);
2572 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2574 if (!_session || _snap_mode == SnapOff) {
2578 snap_to_internal (start, direction, for_mark);
2582 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2584 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2585 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2587 switch (_snap_type) {
2588 case SnapToTimecodeFrame:
2589 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2590 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2592 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2596 case SnapToTimecodeSeconds:
2597 if (_session->config.get_timecode_offset_negative()) {
2598 start += _session->config.get_timecode_offset ();
2600 start -= _session->config.get_timecode_offset ();
2602 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2603 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2605 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2608 if (_session->config.get_timecode_offset_negative()) {
2609 start -= _session->config.get_timecode_offset ();
2611 start += _session->config.get_timecode_offset ();
2615 case SnapToTimecodeMinutes:
2616 if (_session->config.get_timecode_offset_negative()) {
2617 start += _session->config.get_timecode_offset ();
2619 start -= _session->config.get_timecode_offset ();
2621 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2622 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2624 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2626 if (_session->config.get_timecode_offset_negative()) {
2627 start -= _session->config.get_timecode_offset ();
2629 start += _session->config.get_timecode_offset ();
2633 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2639 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2641 const framepos_t one_second = _session->frame_rate();
2642 const framepos_t one_minute = _session->frame_rate() * 60;
2643 framepos_t presnap = start;
2647 switch (_snap_type) {
2648 case SnapToTimecodeFrame:
2649 case SnapToTimecodeSeconds:
2650 case SnapToTimecodeMinutes:
2651 return timecode_snap_to_internal (start, direction, for_mark);
2654 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2655 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2657 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2662 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2663 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2665 start = (framepos_t) floor ((double) start / one_second) * one_second;
2670 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2671 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2673 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2678 start = _session->tempo_map().round_to_bar (start, direction);
2682 start = _session->tempo_map().round_to_beat (start, direction);
2685 case SnapToBeatDiv128:
2686 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2688 case SnapToBeatDiv64:
2689 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2691 case SnapToBeatDiv32:
2692 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2694 case SnapToBeatDiv28:
2695 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2697 case SnapToBeatDiv24:
2698 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2700 case SnapToBeatDiv20:
2701 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2703 case SnapToBeatDiv16:
2704 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2706 case SnapToBeatDiv14:
2707 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2709 case SnapToBeatDiv12:
2710 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2712 case SnapToBeatDiv10:
2713 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2715 case SnapToBeatDiv8:
2716 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2718 case SnapToBeatDiv7:
2719 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2721 case SnapToBeatDiv6:
2722 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2724 case SnapToBeatDiv5:
2725 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2727 case SnapToBeatDiv4:
2728 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2730 case SnapToBeatDiv3:
2731 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2733 case SnapToBeatDiv2:
2734 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2742 _session->locations()->marks_either_side (start, before, after);
2744 if (before == max_framepos && after == max_framepos) {
2745 /* No marks to snap to, so just don't snap */
2747 } else if (before == max_framepos) {
2749 } else if (after == max_framepos) {
2751 } else if (before != max_framepos && after != max_framepos) {
2752 /* have before and after */
2753 if ((start - before) < (after - start)) {
2762 case SnapToRegionStart:
2763 case SnapToRegionEnd:
2764 case SnapToRegionSync:
2765 case SnapToRegionBoundary:
2766 if (!region_boundary_cache.empty()) {
2768 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2769 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2771 if (direction > 0) {
2772 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2774 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2777 if (next != region_boundary_cache.begin ()) {
2782 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2783 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2785 if (start > (p + n) / 2) {
2794 switch (_snap_mode) {
2800 if (presnap > start) {
2801 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2805 } else if (presnap < start) {
2806 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2812 /* handled at entry */
2820 Editor::setup_toolbar ()
2822 HBox* mode_box = manage(new HBox);
2823 mode_box->set_border_width (2);
2824 mode_box->set_spacing(2);
2826 HBox* mouse_mode_box = manage (new HBox);
2827 HBox* mouse_mode_hbox = manage (new HBox);
2828 VBox* mouse_mode_vbox = manage (new VBox);
2829 Alignment* mouse_mode_align = manage (new Alignment);
2831 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2832 mouse_mode_size_group->add_widget (smart_mode_button);
2833 mouse_mode_size_group->add_widget (mouse_move_button);
2834 mouse_mode_size_group->add_widget (mouse_cut_button);
2835 mouse_mode_size_group->add_widget (mouse_select_button);
2836 mouse_mode_size_group->add_widget (mouse_gain_button);
2837 mouse_mode_size_group->add_widget (mouse_timefx_button);
2838 mouse_mode_size_group->add_widget (mouse_audition_button);
2839 mouse_mode_size_group->add_widget (mouse_draw_button);
2840 mouse_mode_size_group->add_widget (internal_edit_button);
2842 mouse_mode_size_group->add_widget (zoom_in_button);
2843 mouse_mode_size_group->add_widget (zoom_out_button);
2844 mouse_mode_size_group->add_widget (zoom_preset_selector);
2845 mouse_mode_size_group->add_widget (zoom_out_full_button);
2846 mouse_mode_size_group->add_widget (zoom_focus_selector);
2848 mouse_mode_size_group->add_widget (tav_shrink_button);
2849 mouse_mode_size_group->add_widget (tav_expand_button);
2850 mouse_mode_size_group->add_widget (visible_tracks_selector);
2852 mouse_mode_size_group->add_widget (snap_type_selector);
2853 mouse_mode_size_group->add_widget (snap_mode_selector);
2855 mouse_mode_size_group->add_widget (edit_point_selector);
2856 mouse_mode_size_group->add_widget (edit_mode_selector);
2858 mouse_mode_size_group->add_widget (*nudge_clock);
2859 mouse_mode_size_group->add_widget (nudge_forward_button);
2860 mouse_mode_size_group->add_widget (nudge_backward_button);
2862 mouse_mode_hbox->set_spacing (2);
2864 if (!ARDOUR::Profile->get_trx()) {
2865 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2868 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2869 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2871 if (!ARDOUR::Profile->get_mixbus()) {
2872 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2875 if (!ARDOUR::Profile->get_trx()) {
2876 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2877 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2878 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2879 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2880 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 0);
2883 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2885 mouse_mode_align->add (*mouse_mode_vbox);
2886 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2888 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2890 edit_mode_selector.set_name ("mouse mode button");
2892 if (!ARDOUR::Profile->get_trx()) {
2893 mode_box->pack_start (edit_mode_selector, false, false);
2895 mode_box->pack_start (*mouse_mode_box, false, false);
2897 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2898 _mouse_mode_tearoff->set_name ("MouseModeBase");
2899 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2901 if (Profile->get_sae() || Profile->get_mixbus() ) {
2902 _mouse_mode_tearoff->set_can_be_torn_off (false);
2905 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2906 &_mouse_mode_tearoff->tearoff_window()));
2907 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2908 &_mouse_mode_tearoff->tearoff_window(), 1));
2909 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2910 &_mouse_mode_tearoff->tearoff_window()));
2911 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2912 &_mouse_mode_tearoff->tearoff_window(), 1));
2916 _zoom_box.set_spacing (2);
2917 _zoom_box.set_border_width (2);
2921 zoom_preset_selector.set_name ("zoom button");
2922 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2923 zoom_preset_selector.set_size_request (42, -1);
2925 zoom_in_button.set_name ("zoom button");
2926 zoom_in_button.set_image(::get_icon ("zoom_in"));
2927 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2928 zoom_in_button.set_related_action (act);
2930 zoom_out_button.set_name ("zoom button");
2931 zoom_out_button.set_image(::get_icon ("zoom_out"));
2932 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2933 zoom_out_button.set_related_action (act);
2935 zoom_out_full_button.set_name ("zoom button");
2936 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2937 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2938 zoom_out_full_button.set_related_action (act);
2940 zoom_focus_selector.set_name ("zoom button");
2942 if (ARDOUR::Profile->get_mixbus()) {
2943 _zoom_box.pack_start (zoom_preset_selector, false, false);
2944 } else if (ARDOUR::Profile->get_trx()) {
2945 mode_box->pack_start (zoom_out_button, false, false);
2946 mode_box->pack_start (zoom_in_button, false, false);
2948 _zoom_box.pack_start (zoom_out_button, false, false);
2949 _zoom_box.pack_start (zoom_in_button, false, false);
2950 _zoom_box.pack_start (zoom_out_full_button, false, false);
2951 _zoom_box.pack_start (zoom_focus_selector, false, false);
2954 /* Track zoom buttons */
2955 visible_tracks_selector.set_name ("zoom button");
2956 if (Profile->get_mixbus()) {
2957 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2958 visible_tracks_selector.set_size_request (42, -1);
2960 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2963 tav_expand_button.set_name ("zoom button");
2964 tav_expand_button.set_image(::get_icon ("tav_exp"));
2965 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2966 tav_expand_button.set_related_action (act);
2968 tav_shrink_button.set_name ("zoom button");
2969 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2970 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2971 tav_shrink_button.set_related_action (act);
2973 if (ARDOUR::Profile->get_mixbus()) {
2974 _zoom_box.pack_start (visible_tracks_selector);
2975 } else if (ARDOUR::Profile->get_trx()) {
2976 _zoom_box.pack_start (tav_shrink_button);
2977 _zoom_box.pack_start (tav_expand_button);
2979 _zoom_box.pack_start (visible_tracks_selector);
2980 _zoom_box.pack_start (tav_shrink_button);
2981 _zoom_box.pack_start (tav_expand_button);
2984 if (!ARDOUR::Profile->get_trx()) {
2985 _zoom_tearoff = manage (new TearOff (_zoom_box));
2987 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2988 &_zoom_tearoff->tearoff_window()));
2989 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2990 &_zoom_tearoff->tearoff_window(), 0));
2991 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2992 &_zoom_tearoff->tearoff_window()));
2993 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2994 &_zoom_tearoff->tearoff_window(), 0));
2997 if (Profile->get_sae() || Profile->get_mixbus() ) {
2998 _zoom_tearoff->set_can_be_torn_off (false);
3001 snap_box.set_spacing (2);
3002 snap_box.set_border_width (2);
3004 snap_type_selector.set_name ("mouse mode button");
3006 snap_mode_selector.set_name ("mouse mode button");
3008 edit_point_selector.set_name ("mouse mode button");
3010 snap_box.pack_start (snap_mode_selector, false, false);
3011 snap_box.pack_start (snap_type_selector, false, false);
3012 snap_box.pack_start (edit_point_selector, false, false);
3016 HBox *nudge_box = manage (new HBox);
3017 nudge_box->set_spacing (2);
3018 nudge_box->set_border_width (2);
3020 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3021 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3023 nudge_box->pack_start (nudge_backward_button, false, false);
3024 nudge_box->pack_start (nudge_forward_button, false, false);
3025 nudge_box->pack_start (*nudge_clock, false, false);
3028 /* Pack everything in... */
3030 HBox* hbox = manage (new HBox);
3031 hbox->set_spacing(2);
3033 _tools_tearoff = manage (new TearOff (*hbox));
3034 _tools_tearoff->set_name ("MouseModeBase");
3035 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3037 if (Profile->get_sae() || Profile->get_mixbus()) {
3038 _tools_tearoff->set_can_be_torn_off (false);
3041 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3042 &_tools_tearoff->tearoff_window()));
3043 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3044 &_tools_tearoff->tearoff_window(), 0));
3045 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3046 &_tools_tearoff->tearoff_window()));
3047 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3048 &_tools_tearoff->tearoff_window(), 0));
3050 toolbar_hbox.set_spacing (2);
3051 toolbar_hbox.set_border_width (1);
3053 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3054 if (!ARDOUR::Profile->get_trx()) {
3055 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3056 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3059 if (!ARDOUR::Profile->get_trx()) {
3060 hbox->pack_start (snap_box, false, false);
3061 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3062 hbox->pack_start (*nudge_box, false, false);
3064 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3067 hbox->pack_start (panic_box, false, false);
3071 toolbar_base.set_name ("ToolBarBase");
3072 toolbar_base.add (toolbar_hbox);
3074 _toolbar_viewport.add (toolbar_base);
3075 /* stick to the required height but allow width to vary if there's not enough room */
3076 _toolbar_viewport.set_size_request (1, -1);
3078 toolbar_frame.set_shadow_type (SHADOW_OUT);
3079 toolbar_frame.set_name ("BaseFrame");
3080 toolbar_frame.add (_toolbar_viewport);
3084 Editor::build_edit_point_menu ()
3086 using namespace Menu_Helpers;
3088 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3089 if(!Profile->get_mixbus())
3090 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3091 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3093 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3097 Editor::build_edit_mode_menu ()
3099 using namespace Menu_Helpers;
3101 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3102 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3103 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3104 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3106 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3110 Editor::build_snap_mode_menu ()
3112 using namespace Menu_Helpers;
3114 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3115 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3116 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3118 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3122 Editor::build_snap_type_menu ()
3124 using namespace Menu_Helpers;
3126 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3127 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3128 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3129 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3130 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3131 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3132 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3133 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3134 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3135 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3136 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3137 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3138 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3139 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3140 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3141 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3142 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3143 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3144 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3145 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3146 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3147 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3148 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3149 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3150 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3151 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3152 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3153 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3154 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3155 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3157 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3162 Editor::setup_tooltips ()
3164 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3165 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3166 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3167 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3168 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3169 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3170 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3171 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3172 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3173 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3174 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3175 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3176 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3177 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3178 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3179 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3180 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3181 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3182 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3183 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3184 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3185 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3186 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3187 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3188 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3192 Editor::convert_drop_to_paths (
3193 vector<string>& paths,
3194 const RefPtr<Gdk::DragContext>& /*context*/,
3197 const SelectionData& data,
3201 if (_session == 0) {
3205 vector<string> uris = data.get_uris();
3209 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3210 are actually URI lists. So do it by hand.
3213 if (data.get_target() != "text/plain") {
3217 /* Parse the "uri-list" format that Nautilus provides,
3218 where each pathname is delimited by \r\n.
3220 THERE MAY BE NO NULL TERMINATING CHAR!!!
3223 string txt = data.get_text();
3227 p = (char *) malloc (txt.length() + 1);
3228 txt.copy (p, txt.length(), 0);
3229 p[txt.length()] = '\0';
3235 while (g_ascii_isspace (*p))
3239 while (*q && (*q != '\n') && (*q != '\r')) {
3246 while (q > p && g_ascii_isspace (*q))
3251 uris.push_back (string (p, q - p + 1));
3255 p = strchr (p, '\n');
3267 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3268 if ((*i).substr (0,7) == "file://") {
3269 paths.push_back (Glib::filename_from_uri (*i));
3277 Editor::new_tempo_section ()
3282 Editor::map_transport_state ()
3284 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3286 if (_session && _session->transport_stopped()) {
3287 have_pending_keyboard_selection = false;
3290 update_loop_range_view ();
3296 Editor::begin_reversible_command (string name)
3299 _session->begin_reversible_command (name);
3304 Editor::begin_reversible_command (GQuark q)
3307 _session->begin_reversible_command (q);
3312 Editor::commit_reversible_command ()
3315 _session->commit_reversible_command ();
3320 Editor::history_changed ()
3324 if (undo_action && _session) {
3325 if (_session->undo_depth() == 0) {
3326 label = S_("Command|Undo");
3328 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3330 undo_action->property_label() = label;
3333 if (redo_action && _session) {
3334 if (_session->redo_depth() == 0) {
3337 label = string_compose(_("Redo (%1)"), _session->next_redo());
3339 redo_action->property_label() = label;
3344 Editor::duplicate_range (bool with_dialog)
3348 RegionSelection rs = get_regions_from_selection_and_entered ();
3350 if ( selection->time.length() == 0 && rs.empty()) {
3356 ArdourDialog win (_("Duplicate"));
3357 Label label (_("Number of duplications:"));
3358 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3359 SpinButton spinner (adjustment, 0.0, 1);
3362 win.get_vbox()->set_spacing (12);
3363 win.get_vbox()->pack_start (hbox);
3364 hbox.set_border_width (6);
3365 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3367 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3368 place, visually. so do this by hand.
3371 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3372 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3373 spinner.grab_focus();
3379 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3380 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3381 win.set_default_response (RESPONSE_ACCEPT);
3383 spinner.grab_focus ();
3385 switch (win.run ()) {
3386 case RESPONSE_ACCEPT:
3392 times = adjustment.get_value();
3395 if ((current_mouse_mode() == Editing::MouseRange)) {
3396 if (selection->time.length()) {
3397 duplicate_selection (times);
3399 } else if (get_smart_mode()) {
3400 if (selection->time.length()) {
3401 duplicate_selection (times);
3403 duplicate_some_regions (rs, times);
3405 duplicate_some_regions (rs, times);
3410 Editor::set_edit_mode (EditMode m)
3412 Config->set_edit_mode (m);
3416 Editor::cycle_edit_mode ()
3418 switch (Config->get_edit_mode()) {
3420 if (Profile->get_sae()) {
3421 Config->set_edit_mode (Lock);
3423 Config->set_edit_mode (Ripple);
3428 Config->set_edit_mode (Lock);
3431 Config->set_edit_mode (Slide);
3437 Editor::edit_mode_selection_done ( EditMode m )
3439 Config->set_edit_mode ( m );
3443 Editor::snap_type_selection_done (SnapType snaptype)
3445 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3447 ract->set_active ();
3452 Editor::snap_mode_selection_done (SnapMode mode)
3454 RefPtr<RadioAction> ract = snap_mode_action (mode);
3457 ract->set_active (true);
3462 Editor::cycle_edit_point (bool with_marker)
3464 if(Profile->get_mixbus())
3465 with_marker = false;
3467 switch (_edit_point) {
3469 set_edit_point_preference (EditAtPlayhead);
3471 case EditAtPlayhead:
3473 set_edit_point_preference (EditAtSelectedMarker);
3475 set_edit_point_preference (EditAtMouse);
3478 case EditAtSelectedMarker:
3479 set_edit_point_preference (EditAtMouse);
3485 Editor::edit_point_selection_done (EditPoint ep)
3487 set_edit_point_preference ( ep );
3491 Editor::build_zoom_focus_menu ()
3493 using namespace Menu_Helpers;
3495 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3496 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3497 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3498 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3499 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3500 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3502 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3506 Editor::zoom_focus_selection_done ( ZoomFocus f )
3508 RefPtr<RadioAction> ract = zoom_focus_action (f);
3510 ract->set_active ();
3515 Editor::build_track_count_menu ()
3517 using namespace Menu_Helpers;
3519 if (!Profile->get_mixbus()) {
3520 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3521 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3522 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3523 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3524 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3525 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3526 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3527 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3528 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3529 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3530 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3531 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3532 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3534 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3535 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3536 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3537 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3538 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3539 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3540 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3541 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3542 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3543 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3545 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3546 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3547 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3548 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3549 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3550 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3551 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3552 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3553 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3554 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3555 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3560 Editor::set_zoom_preset (int64_t ms)
3563 temporal_zoom_session();
3567 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3568 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3572 Editor::set_visible_track_count (int32_t n)
3574 _visible_track_count = n;
3576 /* if the canvas hasn't really been allocated any size yet, just
3577 record the desired number of visible tracks and return. when canvas
3578 allocation happens, we will get called again and then we can do the
3582 if (_visible_canvas_height <= 1) {
3589 if (_visible_track_count > 0) {
3590 h = trackviews_height() / _visible_track_count;
3591 std::ostringstream s;
3592 s << _visible_track_count;
3594 } else if (_visible_track_count == 0) {
3596 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3597 if ((*i)->marked_for_display()) {
3601 h = trackviews_height() / n;
3604 /* negative value means that the visible track count has
3605 been overridden by explicit track height changes.
3607 visible_tracks_selector.set_text (X_("*"));
3611 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3612 (*i)->set_height (h);
3615 if (str != visible_tracks_selector.get_text()) {
3616 visible_tracks_selector.set_text (str);
3621 Editor::override_visible_track_count ()
3623 _visible_track_count = -1;
3624 visible_tracks_selector.set_text ( _("*") );
3628 Editor::edit_controls_button_release (GdkEventButton* ev)
3630 if (Keyboard::is_context_menu_event (ev)) {
3631 ARDOUR_UI::instance()->add_route (this);
3632 } else if (ev->button == 1) {
3633 selection->clear_tracks ();
3640 Editor::mouse_select_button_release (GdkEventButton* ev)
3642 /* this handles just right-clicks */
3644 if (ev->button != 3) {
3652 Editor::set_zoom_focus (ZoomFocus f)
3654 string str = zoom_focus_strings[(int)f];
3656 if (str != zoom_focus_selector.get_text()) {
3657 zoom_focus_selector.set_text (str);
3660 if (zoom_focus != f) {
3667 Editor::cycle_zoom_focus ()
3669 switch (zoom_focus) {
3671 set_zoom_focus (ZoomFocusRight);
3673 case ZoomFocusRight:
3674 set_zoom_focus (ZoomFocusCenter);
3676 case ZoomFocusCenter:
3677 set_zoom_focus (ZoomFocusPlayhead);
3679 case ZoomFocusPlayhead:
3680 set_zoom_focus (ZoomFocusMouse);
3682 case ZoomFocusMouse:
3683 set_zoom_focus (ZoomFocusEdit);
3686 set_zoom_focus (ZoomFocusLeft);
3692 Editor::ensure_float (Window& win)
3694 win.set_transient_for (*this);
3698 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3700 /* recover or initialize pane positions. do this here rather than earlier because
3701 we don't want the positions to change the child allocations, which they seem to do.
3707 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3716 XMLNode* geometry = find_named_node (*node, "geometry");
3718 if (which == static_cast<Paned*> (&edit_pane)) {
3720 if (done & Horizontal) {
3724 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3725 _notebook_shrunk = string_is_affirmative (prop->value ());
3728 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3729 /* initial allocation is 90% to canvas, 10% to notebook */
3730 pos = (int) floor (alloc.get_width() * 0.90f);
3731 snprintf (buf, sizeof(buf), "%d", pos);
3733 pos = atoi (prop->value());
3736 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3737 edit_pane.set_position (pos);
3740 done = (Pane) (done | Horizontal);
3742 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3744 if (done & Vertical) {
3748 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3749 /* initial allocation is 90% to canvas, 10% to summary */
3750 pos = (int) floor (alloc.get_height() * 0.90f);
3751 snprintf (buf, sizeof(buf), "%d", pos);
3754 pos = atoi (prop->value());
3757 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3758 editor_summary_pane.set_position (pos);
3761 done = (Pane) (done | Vertical);
3766 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3768 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3769 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3770 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3771 top_hbox.remove (toolbar_frame);
3776 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3778 if (toolbar_frame.get_parent() == 0) {
3779 top_hbox.pack_end (toolbar_frame);
3784 Editor::set_show_measures (bool yn)
3786 if (_show_measures != yn) {
3789 if ((_show_measures = yn) == true) {
3791 tempo_lines->show();
3794 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3795 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3797 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3798 draw_measures (begin, end);
3806 Editor::toggle_follow_playhead ()
3808 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3810 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3811 set_follow_playhead (tact->get_active());
3815 /** @param yn true to follow playhead, otherwise false.
3816 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3819 Editor::set_follow_playhead (bool yn, bool catch_up)
3821 if (_follow_playhead != yn) {
3822 if ((_follow_playhead = yn) == true && catch_up) {
3824 reset_x_origin_to_follow_playhead ();
3831 Editor::toggle_stationary_playhead ()
3833 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3835 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3836 set_stationary_playhead (tact->get_active());
3841 Editor::set_stationary_playhead (bool yn)
3843 if (_stationary_playhead != yn) {
3844 if ((_stationary_playhead = yn) == true) {
3846 // FIXME need a 3.0 equivalent of this 2.X call
3847 // update_current_screen ();
3854 Editor::playlist_selector () const
3856 return *_playlist_selector;
3860 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3864 switch (_snap_type) {
3869 case SnapToBeatDiv128:
3872 case SnapToBeatDiv64:
3875 case SnapToBeatDiv32:
3878 case SnapToBeatDiv28:
3881 case SnapToBeatDiv24:
3884 case SnapToBeatDiv20:
3887 case SnapToBeatDiv16:
3890 case SnapToBeatDiv14:
3893 case SnapToBeatDiv12:
3896 case SnapToBeatDiv10:
3899 case SnapToBeatDiv8:
3902 case SnapToBeatDiv7:
3905 case SnapToBeatDiv6:
3908 case SnapToBeatDiv5:
3911 case SnapToBeatDiv4:
3914 case SnapToBeatDiv3:
3917 case SnapToBeatDiv2:
3923 return _session->tempo_map().meter_at (position).divisions_per_bar();
3928 case SnapToTimecodeFrame:
3929 case SnapToTimecodeSeconds:
3930 case SnapToTimecodeMinutes:
3933 case SnapToRegionStart:
3934 case SnapToRegionEnd:
3935 case SnapToRegionSync:
3936 case SnapToRegionBoundary:
3946 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3950 ret = nudge_clock->current_duration (pos);
3951 next = ret + 1; /* XXXX fix me */
3957 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3959 ArdourDialog dialog (_("Playlist Deletion"));
3960 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3961 "If it is kept, its audio files will not be cleaned.\n"
3962 "If it is deleted, audio files used by it alone will be cleaned."),
3965 dialog.set_position (WIN_POS_CENTER);
3966 dialog.get_vbox()->pack_start (label);
3970 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3971 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3972 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3974 switch (dialog.run ()) {
3975 case RESPONSE_ACCEPT:
3976 /* delete the playlist */
3980 case RESPONSE_REJECT:
3981 /* keep the playlist */
3993 Editor::audio_region_selection_covers (framepos_t where)
3995 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3996 if ((*a)->region()->covers (where)) {
4005 Editor::prepare_for_cleanup ()
4007 cut_buffer->clear_regions ();
4008 cut_buffer->clear_playlists ();
4010 selection->clear_regions ();
4011 selection->clear_playlists ();
4013 _regions->suspend_redisplay ();
4017 Editor::finish_cleanup ()
4019 _regions->resume_redisplay ();
4023 Editor::transport_loop_location()
4026 return _session->locations()->auto_loop_location();
4033 Editor::transport_punch_location()
4036 return _session->locations()->auto_punch_location();
4043 Editor::control_layout_scroll (GdkEventScroll* ev)
4045 /* Just forward to the normal canvas scroll method. The coordinate
4046 systems are different but since the canvas is always larger than the
4047 track headers, and aligned with the trackview area, this will work.
4049 In the not too distant future this layout is going away anyway and
4050 headers will be on the canvas.
4052 return canvas_scroll_event (ev, false);
4056 Editor::session_state_saved (string)
4059 _snapshots->redisplay ();
4063 Editor::update_tearoff_visibility()
4065 bool visible = Config->get_keep_tearoffs();
4066 _mouse_mode_tearoff->set_visible (visible);
4067 _tools_tearoff->set_visible (visible);
4068 if (_zoom_tearoff) {
4069 _zoom_tearoff->set_visible (visible);
4074 Editor::reattach_all_tearoffs ()
4076 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4077 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4078 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4082 Editor::maximise_editing_space ()
4094 Editor::restore_editing_space ()
4106 * Make new playlists for a given track and also any others that belong
4107 * to the same active route group with the `select' property.
4112 Editor::new_playlists (TimeAxisView* v)
4114 begin_reversible_command (_("new playlists"));
4115 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4116 _session->playlists->get (playlists);
4117 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4118 commit_reversible_command ();
4122 * Use a copy of the current playlist for a given track and also any others that belong
4123 * to the same active route group with the `select' property.
4128 Editor::copy_playlists (TimeAxisView* v)
4130 begin_reversible_command (_("copy playlists"));
4131 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4132 _session->playlists->get (playlists);
4133 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4134 commit_reversible_command ();
4137 /** Clear the current playlist for a given track and also any others that belong
4138 * to the same active route group with the `select' property.
4143 Editor::clear_playlists (TimeAxisView* v)
4145 begin_reversible_command (_("clear playlists"));
4146 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4147 _session->playlists->get (playlists);
4148 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4149 commit_reversible_command ();
4153 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4155 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4159 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4161 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4165 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4167 atv.clear_playlist ();
4171 Editor::on_key_press_event (GdkEventKey* ev)
4173 return key_press_focus_accelerator_handler (*this, ev);
4177 Editor::on_key_release_event (GdkEventKey* ev)
4179 return Gtk::Window::on_key_release_event (ev);
4180 // return key_press_focus_accelerator_handler (*this, ev);
4183 /** Queue up a change to the viewport x origin.
4184 * @param frame New x origin.
4187 Editor::reset_x_origin (framepos_t frame)
4189 pending_visual_change.add (VisualChange::TimeOrigin);
4190 pending_visual_change.time_origin = frame;
4191 ensure_visual_change_idle_handler ();
4195 Editor::reset_y_origin (double y)
4197 pending_visual_change.add (VisualChange::YOrigin);
4198 pending_visual_change.y_origin = y;
4199 ensure_visual_change_idle_handler ();
4203 Editor::reset_zoom (framecnt_t spp)
4205 if (spp == samples_per_pixel) {
4209 pending_visual_change.add (VisualChange::ZoomLevel);
4210 pending_visual_change.samples_per_pixel = spp;
4211 ensure_visual_change_idle_handler ();
4215 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4217 reset_x_origin (frame);
4220 if (!no_save_visual) {
4221 undo_visual_stack.push_back (current_visual_state(false));
4225 Editor::VisualState::VisualState (bool with_tracks)
4226 : gui_state (with_tracks ? new GUIObjectState : 0)
4230 Editor::VisualState::~VisualState ()
4235 Editor::VisualState*
4236 Editor::current_visual_state (bool with_tracks)
4238 VisualState* vs = new VisualState (with_tracks);
4239 vs->y_position = vertical_adjustment.get_value();
4240 vs->samples_per_pixel = samples_per_pixel;
4241 vs->leftmost_frame = leftmost_frame;
4242 vs->zoom_focus = zoom_focus;
4245 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4252 Editor::undo_visual_state ()
4254 if (undo_visual_stack.empty()) {
4258 VisualState* vs = undo_visual_stack.back();
4259 undo_visual_stack.pop_back();
4262 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4264 use_visual_state (*vs);
4268 Editor::redo_visual_state ()
4270 if (redo_visual_stack.empty()) {
4274 VisualState* vs = redo_visual_stack.back();
4275 redo_visual_stack.pop_back();
4277 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4279 use_visual_state (*vs);
4283 Editor::swap_visual_state ()
4285 if (undo_visual_stack.empty()) {
4286 redo_visual_state ();
4288 undo_visual_state ();
4293 Editor::use_visual_state (VisualState& vs)
4295 PBD::Unwinder<bool> nsv (no_save_visual, true);
4296 DisplaySuspender ds;
4298 vertical_adjustment.set_value (vs.y_position);
4300 set_zoom_focus (vs.zoom_focus);
4301 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4304 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4306 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4307 (*i)->reset_visual_state ();
4311 _routes->update_visibility ();
4314 /** This is the core function that controls the zoom level of the canvas. It is called
4315 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4316 * @param spp new number of samples per pixel
4319 Editor::set_samples_per_pixel (framecnt_t spp)
4325 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4326 const framecnt_t lots_of_pixels = 4000;
4328 /* if the zoom level is greater than what you'd get trying to display 3
4329 * days of audio on a really big screen, then it's too big.
4332 if (spp * lots_of_pixels > three_days) {
4336 samples_per_pixel = spp;
4339 tempo_lines->tempo_map_changed();
4342 bool const showing_time_selection = selection->time.length() > 0;
4344 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4345 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4346 (*i)->reshow_selection (selection->time);
4350 ZoomChanged (); /* EMIT_SIGNAL */
4352 ArdourCanvas::GtkCanvasViewport* c;
4354 c = get_track_canvas();
4356 c->canvas()->zoomed ();
4359 if (playhead_cursor) {
4360 playhead_cursor->set_position (playhead_cursor->current_frame ());
4363 refresh_location_display();
4364 _summary->set_overlays_dirty ();
4366 update_marker_labels ();
4372 Editor::queue_visual_videotimeline_update ()
4375 * pending_visual_change.add (VisualChange::VideoTimeline);
4376 * or maybe even more specific: which videotimeline-image
4377 * currently it calls update_video_timeline() to update
4378 * _all outdated_ images on the video-timeline.
4379 * see 'exposeimg()' in video_image_frame.cc
4381 ensure_visual_change_idle_handler ();
4385 Editor::ensure_visual_change_idle_handler ()
4387 if (pending_visual_change.idle_handler_id < 0) {
4388 // see comment in add_to_idle_resize above.
4389 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4390 pending_visual_change.being_handled = false;
4395 Editor::_idle_visual_changer (void* arg)
4397 return static_cast<Editor*>(arg)->idle_visual_changer ();
4401 Editor::idle_visual_changer ()
4403 /* set_horizontal_position() below (and maybe other calls) call
4404 gtk_main_iteration(), so it's possible that a signal will be handled
4405 half-way through this method. If this signal wants an
4406 idle_visual_changer we must schedule another one after this one, so
4407 mark the idle_handler_id as -1 here to allow that. Also make a note
4408 that we are doing the visual change, so that changes in response to
4409 super-rapid-screen-update can be dropped if we are still processing
4413 pending_visual_change.idle_handler_id = -1;
4414 pending_visual_change.being_handled = true;
4416 VisualChange vc = pending_visual_change;
4418 pending_visual_change.pending = (VisualChange::Type) 0;
4420 visual_changer (vc);
4422 pending_visual_change.being_handled = false;
4424 return 0; /* this is always a one-shot call */
4428 Editor::visual_changer (const VisualChange& vc)
4430 double const last_time_origin = horizontal_position ();
4432 if (vc.pending & VisualChange::ZoomLevel) {
4433 set_samples_per_pixel (vc.samples_per_pixel);
4435 compute_fixed_ruler_scale ();
4437 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4438 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4440 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4441 current_bbt_points_begin, current_bbt_points_end);
4442 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4443 current_bbt_points_begin, current_bbt_points_end);
4444 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4446 update_video_timeline();
4449 if (vc.pending & VisualChange::TimeOrigin) {
4450 set_horizontal_position (vc.time_origin / samples_per_pixel);
4453 if (vc.pending & VisualChange::YOrigin) {
4454 vertical_adjustment.set_value (vc.y_origin);
4457 if (last_time_origin == horizontal_position ()) {
4458 /* changed signal not emitted */
4459 update_fixed_rulers ();
4460 redisplay_tempo (true);
4463 if (!(vc.pending & VisualChange::ZoomLevel)) {
4464 update_video_timeline();
4467 _summary->set_overlays_dirty ();
4470 struct EditorOrderTimeAxisSorter {
4471 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4472 return a->order () < b->order ();
4477 Editor::sort_track_selection (TrackViewList& sel)
4479 EditorOrderTimeAxisSorter cmp;
4484 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4487 framepos_t where = 0;
4488 EditPoint ep = _edit_point;
4490 if(Profile->get_mixbus())
4491 if (ep == EditAtSelectedMarker)
4494 if (from_context_menu && (ep == EditAtMouse)) {
4495 return canvas_event_sample (&context_click_event, 0, 0);
4498 if (entered_marker) {
4499 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4500 return entered_marker->position();
4503 if (ignore_playhead && ep == EditAtPlayhead) {
4504 ep = EditAtSelectedMarker;
4508 case EditAtPlayhead:
4509 where = _session->audible_frame();
4510 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4513 case EditAtSelectedMarker:
4514 if (!selection->markers.empty()) {
4516 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4519 where = loc->start();
4523 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4531 if (!mouse_frame (where, ignored)) {
4532 /* XXX not right but what can we do ? */
4536 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4544 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4546 if (!_session) return;
4548 begin_reversible_command (cmd);
4552 if ((tll = transport_loop_location()) == 0) {
4553 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4554 XMLNode &before = _session->locations()->get_state();
4555 _session->locations()->add (loc, true);
4556 _session->set_auto_loop_location (loc);
4557 XMLNode &after = _session->locations()->get_state();
4558 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4560 XMLNode &before = tll->get_state();
4561 tll->set_hidden (false, this);
4562 tll->set (start, end);
4563 XMLNode &after = tll->get_state();
4564 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4567 commit_reversible_command ();
4571 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4573 if (!_session) return;
4575 begin_reversible_command (cmd);
4579 if ((tpl = transport_punch_location()) == 0) {
4580 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4581 XMLNode &before = _session->locations()->get_state();
4582 _session->locations()->add (loc, true);
4583 _session->set_auto_punch_location (loc);
4584 XMLNode &after = _session->locations()->get_state();
4585 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4588 XMLNode &before = tpl->get_state();
4589 tpl->set_hidden (false, this);
4590 tpl->set (start, end);
4591 XMLNode &after = tpl->get_state();
4592 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4595 commit_reversible_command ();
4598 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4599 * @param rs List to which found regions are added.
4600 * @param where Time to look at.
4601 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4604 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4606 const TrackViewList* tracks;
4609 tracks = &track_views;
4614 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4616 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4619 boost::shared_ptr<Track> tr;
4620 boost::shared_ptr<Playlist> pl;
4622 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4624 boost::shared_ptr<RegionList> regions = pl->regions_at (
4625 (framepos_t) floor ( (double) where * tr->speed()));
4627 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4628 RegionView* rv = rtv->view()->find_view (*i);
4639 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4641 const TrackViewList* tracks;
4644 tracks = &track_views;
4649 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4650 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4652 boost::shared_ptr<Track> tr;
4653 boost::shared_ptr<Playlist> pl;
4655 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4657 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4658 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4660 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4662 RegionView* rv = rtv->view()->find_view (*i);
4673 /** Get regions using the following method:
4675 * Make a region list using:
4676 * (a) any selected regions
4677 * (b) the intersection of any selected tracks and the edit point(*)
4678 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4680 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4682 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4686 Editor::get_regions_from_selection_and_edit_point ()
4688 RegionSelection regions;
4690 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4691 regions.add (entered_regionview);
4693 regions = selection->regions;
4696 if ( regions.empty() ) {
4697 TrackViewList tracks = selection->tracks;
4699 if (!tracks.empty()) {
4700 /* no region selected or entered, but some selected tracks:
4701 * act on all regions on the selected tracks at the edit point
4703 framepos_t const where = get_preferred_edit_position ();
4704 get_regions_at(regions, where, tracks);
4711 /** Get regions using the following method:
4713 * Make a region list using:
4714 * (a) any selected regions
4715 * (b) the intersection of any selected tracks and the edit point(*)
4716 * (c) if neither exists, then whatever region is under the mouse
4718 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4720 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4723 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4725 RegionSelection regions;
4727 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4728 regions.add (entered_regionview);
4730 regions = selection->regions;
4733 if ( regions.empty() ) {
4734 TrackViewList tracks = selection->tracks;
4736 if (!tracks.empty()) {
4737 /* no region selected or entered, but some selected tracks:
4738 * act on all regions on the selected tracks at the edit point
4740 get_regions_at(regions, pos, tracks);
4747 /** Start with regions that are selected, or the entered regionview if none are selected.
4748 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4749 * of the regions that we started with.
4753 Editor::get_regions_from_selection_and_entered ()
4755 RegionSelection regions = selection->regions;
4757 if (regions.empty() && entered_regionview) {
4758 regions.add (entered_regionview);
4765 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4767 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4769 RouteTimeAxisView* tatv;
4771 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4773 boost::shared_ptr<Playlist> pl;
4774 vector<boost::shared_ptr<Region> > results;
4776 boost::shared_ptr<Track> tr;
4778 if ((tr = tatv->track()) == 0) {
4783 if ((pl = (tr->playlist())) != 0) {
4784 if (src_comparison) {
4785 pl->get_source_equivalent_regions (region, results);
4787 pl->get_region_list_equivalent_regions (region, results);
4791 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4792 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4793 regions.push_back (marv);
4802 Editor::show_rhythm_ferret ()
4804 if (rhythm_ferret == 0) {
4805 rhythm_ferret = new RhythmFerret(*this);
4808 rhythm_ferret->set_session (_session);
4809 rhythm_ferret->show ();
4810 rhythm_ferret->present ();
4814 Editor::first_idle ()
4816 MessageDialog* dialog = 0;
4818 if (track_views.size() > 1) {
4819 dialog = new MessageDialog (
4821 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4825 ARDOUR_UI::instance()->flush_pending ();
4828 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4832 // first idle adds route children (automation tracks), so we need to redisplay here
4833 _routes->redisplay ();
4840 Editor::_idle_resize (gpointer arg)
4842 return ((Editor*)arg)->idle_resize ();
4846 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4848 if (resize_idle_id < 0) {
4849 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
4850 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
4851 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
4853 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
4854 _pending_resize_amount = 0;
4857 /* make a note of the smallest resulting height, so that we can clamp the
4858 lower limit at TimeAxisView::hSmall */
4860 int32_t min_resulting = INT32_MAX;
4862 _pending_resize_amount += h;
4863 _pending_resize_view = view;
4865 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4867 if (selection->tracks.contains (_pending_resize_view)) {
4868 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4869 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4873 if (min_resulting < 0) {
4878 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4879 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4883 /** Handle pending resizing of tracks */
4885 Editor::idle_resize ()
4887 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4889 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4890 selection->tracks.contains (_pending_resize_view)) {
4892 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4893 if (*i != _pending_resize_view) {
4894 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4899 _pending_resize_amount = 0;
4900 _group_tabs->set_dirty ();
4901 resize_idle_id = -1;
4909 ENSURE_GUI_THREAD (*this, &Editor::located);
4912 playhead_cursor->set_position (_session->audible_frame ());
4913 if (_follow_playhead && !_pending_initial_locate) {
4914 reset_x_origin_to_follow_playhead ();
4918 _pending_locate_request = false;
4919 _pending_initial_locate = false;
4923 Editor::region_view_added (RegionView *)
4925 _summary->set_background_dirty ();
4929 Editor::region_view_removed ()
4931 _summary->set_background_dirty ();
4935 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4937 TrackViewList::const_iterator j = track_views.begin ();
4938 while (j != track_views.end()) {
4939 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4940 if (rtv && rtv->route() == r) {
4951 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4955 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4956 TimeAxisView* tv = axis_view_from_route (*i);
4966 Editor::suspend_route_redisplay ()
4969 _routes->suspend_redisplay();
4974 Editor::resume_route_redisplay ()
4977 _routes->resume_redisplay();
4982 Editor::add_routes (RouteList& routes)
4984 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4986 RouteTimeAxisView *rtv;
4987 list<RouteTimeAxisView*> new_views;
4989 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4990 boost::shared_ptr<Route> route = (*x);
4992 if (route->is_auditioner() || route->is_monitor()) {
4996 DataType dt = route->input()->default_type();
4998 if (dt == ARDOUR::DataType::AUDIO) {
4999 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5000 rtv->set_route (route);
5001 } else if (dt == ARDOUR::DataType::MIDI) {
5002 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5003 rtv->set_route (route);
5005 throw unknown_type();
5008 new_views.push_back (rtv);
5009 track_views.push_back (rtv);
5011 rtv->effective_gain_display ();
5013 if (internal_editing()) {
5014 rtv->enter_internal_edit_mode ();
5016 rtv->leave_internal_edit_mode ();
5019 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5020 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5023 if (new_views.size() > 0) {
5024 _routes->routes_added (new_views);
5025 _summary->routes_added (new_views);
5028 if (show_editor_mixer_when_tracks_arrive) {
5029 show_editor_mixer (true);
5032 editor_list_button.set_sensitive (true);
5036 Editor::timeaxisview_deleted (TimeAxisView *tv)
5038 if (tv == entered_track) {
5042 if (_session && _session->deletion_in_progress()) {
5043 /* the situation is under control */
5047 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5049 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5051 _routes->route_removed (tv);
5053 TimeAxisView::Children c = tv->get_child_list ();
5054 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5055 if (entered_track == i->get()) {
5060 /* remove it from the list of track views */
5062 TrackViewList::iterator i;
5064 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5065 i = track_views.erase (i);
5068 /* update whatever the current mixer strip is displaying, if revelant */
5070 boost::shared_ptr<Route> route;
5073 route = rtav->route ();
5076 if (current_mixer_strip && current_mixer_strip->route() == route) {
5078 TimeAxisView* next_tv;
5080 if (track_views.empty()) {
5082 } else if (i == track_views.end()) {
5083 next_tv = track_views.front();
5090 set_selected_mixer_strip (*next_tv);
5092 /* make the editor mixer strip go away setting the
5093 * button to inactive (which also unticks the menu option)
5096 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5102 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5104 if (apply_to_selection) {
5105 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5107 TrackSelection::iterator j = i;
5110 hide_track_in_display (*i, false);
5115 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5117 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5118 // this will hide the mixer strip
5119 set_selected_mixer_strip (*tv);
5122 _routes->hide_track_in_display (*tv);
5127 Editor::sync_track_view_list_and_routes ()
5129 track_views = TrackViewList (_routes->views ());
5131 _summary->set_dirty ();
5132 _group_tabs->set_dirty ();
5134 return false; // do not call again (until needed)
5138 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5140 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5145 /** Find a RouteTimeAxisView by the ID of its route */
5147 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5149 RouteTimeAxisView* v;
5151 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5152 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5153 if(v->route()->id() == id) {
5163 Editor::fit_route_group (RouteGroup *g)
5165 TrackViewList ts = axis_views_from_routes (g->route_list ());
5170 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5172 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5175 _session->cancel_audition ();
5179 if (_session->is_auditioning()) {
5180 _session->cancel_audition ();
5181 if (r == last_audition_region) {
5186 _session->audition_region (r);
5187 last_audition_region = r;
5192 Editor::hide_a_region (boost::shared_ptr<Region> r)
5194 r->set_hidden (true);
5198 Editor::show_a_region (boost::shared_ptr<Region> r)
5200 r->set_hidden (false);
5204 Editor::audition_region_from_region_list ()
5206 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5210 Editor::hide_region_from_region_list ()
5212 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5216 Editor::show_region_in_region_list ()
5218 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5222 Editor::step_edit_status_change (bool yn)
5225 start_step_editing ();
5227 stop_step_editing ();
5232 Editor::start_step_editing ()
5234 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5238 Editor::stop_step_editing ()
5240 step_edit_connection.disconnect ();
5244 Editor::check_step_edit ()
5246 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5247 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5249 mtv->check_step_edit ();
5253 return true; // do it again, till we stop
5257 Editor::scroll_press (Direction dir)
5259 ++_scroll_callbacks;
5261 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5262 /* delay the first auto-repeat */
5268 scroll_backward (1);
5276 scroll_up_one_track ();
5280 scroll_down_one_track ();
5284 /* do hacky auto-repeat */
5285 if (!_scroll_connection.connected ()) {
5287 _scroll_connection = Glib::signal_timeout().connect (
5288 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5291 _scroll_callbacks = 0;
5298 Editor::scroll_release ()
5300 _scroll_connection.disconnect ();
5303 /** Queue a change for the Editor viewport x origin to follow the playhead */
5305 Editor::reset_x_origin_to_follow_playhead ()
5307 framepos_t const frame = playhead_cursor->current_frame ();
5309 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5311 if (_session->transport_speed() < 0) {
5313 if (frame > (current_page_samples() / 2)) {
5314 center_screen (frame-(current_page_samples()/2));
5316 center_screen (current_page_samples()/2);
5323 if (frame < leftmost_frame) {
5325 if (_session->transport_rolling()) {
5326 /* rolling; end up with the playhead at the right of the page */
5327 l = frame - current_page_samples ();
5329 /* not rolling: end up with the playhead 1/4 of the way along the page */
5330 l = frame - current_page_samples() / 4;
5334 if (_session->transport_rolling()) {
5335 /* rolling: end up with the playhead on the left of the page */
5338 /* not rolling: end up with the playhead 3/4 of the way along the page */
5339 l = frame - 3 * current_page_samples() / 4;
5347 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5353 Editor::super_rapid_screen_update ()
5355 if (!_session || !_session->engine().running()) {
5359 /* METERING / MIXER STRIPS */
5361 /* update track meters, if required */
5362 if (is_mapped() && meters_running) {
5363 RouteTimeAxisView* rtv;
5364 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5365 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5366 rtv->fast_update ();
5371 /* and any current mixer strip */
5372 if (current_mixer_strip) {
5373 current_mixer_strip->fast_update ();
5376 /* PLAYHEAD AND VIEWPORT */
5378 framepos_t const frame = _session->audible_frame();
5380 /* There are a few reasons why we might not update the playhead / viewport stuff:
5382 * 1. we don't update things when there's a pending locate request, otherwise
5383 * when the editor requests a locate there is a chance that this method
5384 * will move the playhead before the locate request is processed, causing
5386 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5387 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5390 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5392 last_update_frame = frame;
5394 if (!_dragging_playhead) {
5395 playhead_cursor->set_position (frame);
5398 if (!_stationary_playhead) {
5400 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5401 /* We only do this if we aren't already
5402 handling a visual change (ie if
5403 pending_visual_change.being_handled is
5404 false) so that these requests don't stack
5405 up there are too many of them to handle in
5408 reset_x_origin_to_follow_playhead ();
5413 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5417 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5418 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5419 if (target <= 0.0) {
5422 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5423 target = (target * 0.15) + (current * 0.85);
5429 set_horizontal_position (current);
5438 Editor::session_going_away ()
5440 _have_idled = false;
5442 _session_connections.drop_connections ();
5444 super_rapid_screen_update_connection.disconnect ();
5446 selection->clear ();
5447 cut_buffer->clear ();
5449 clicked_regionview = 0;
5450 clicked_axisview = 0;
5451 clicked_routeview = 0;
5452 entered_regionview = 0;
5454 last_update_frame = 0;
5457 playhead_cursor->hide ();
5459 /* rip everything out of the list displays */
5463 _route_groups->clear ();
5465 /* do this first so that deleting a track doesn't reset cms to null
5466 and thus cause a leak.
5469 if (current_mixer_strip) {
5470 if (current_mixer_strip->get_parent() != 0) {
5471 global_hpacker.remove (*current_mixer_strip);
5473 delete current_mixer_strip;
5474 current_mixer_strip = 0;
5477 /* delete all trackviews */
5479 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5482 track_views.clear ();
5484 nudge_clock->set_session (0);
5486 editor_list_button.set_active(false);
5487 editor_list_button.set_sensitive(false);
5489 /* clear tempo/meter rulers */
5490 remove_metric_marks ();
5492 clear_marker_display ();
5494 stop_step_editing ();
5496 /* get rid of any existing editor mixer strip */
5498 WindowTitle title(Glib::get_application_name());
5499 title += _("Editor");
5501 set_title (title.get_string());
5503 SessionHandlePtr::session_going_away ();
5508 Editor::show_editor_list (bool yn)
5511 _the_notebook.show ();
5513 _the_notebook.hide ();
5518 Editor::change_region_layering_order (bool from_context_menu)
5520 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5522 if (!clicked_routeview) {
5523 if (layering_order_editor) {
5524 layering_order_editor->hide ();
5529 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5535 boost::shared_ptr<Playlist> pl = track->playlist();
5541 if (layering_order_editor == 0) {
5542 layering_order_editor = new RegionLayeringOrderEditor (*this);
5545 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5546 layering_order_editor->maybe_present ();
5550 Editor::update_region_layering_order_editor ()
5552 if (layering_order_editor && layering_order_editor->is_visible ()) {
5553 change_region_layering_order (true);
5558 Editor::setup_fade_images ()
5560 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5561 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5562 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5563 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5564 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5566 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5567 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5568 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5569 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5570 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5572 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5573 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5574 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5575 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5576 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5578 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5579 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5580 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5581 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5582 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5586 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5588 Editor::action_menu_item (std::string const & name)
5590 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5593 return *manage (a->create_menu_item ());
5597 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5599 EventBox* b = manage (new EventBox);
5600 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5601 Label* l = manage (new Label (name));
5605 _the_notebook.append_page (widget, *b);
5609 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5611 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5612 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5615 if (ev->type == GDK_2BUTTON_PRESS) {
5617 /* double-click on a notebook tab shrinks or expands the notebook */
5619 if (_notebook_shrunk) {
5620 if (pre_notebook_shrink_pane_width) {
5621 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5623 _notebook_shrunk = false;
5625 pre_notebook_shrink_pane_width = edit_pane.get_position();
5627 /* this expands the LHS of the edit pane to cover the notebook
5628 PAGE but leaves the tabs visible.
5630 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5631 _notebook_shrunk = true;
5639 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5641 using namespace Menu_Helpers;
5643 MenuList& items = _control_point_context_menu.items ();
5646 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5647 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5648 if (!can_remove_control_point (item)) {
5649 items.back().set_sensitive (false);
5652 _control_point_context_menu.popup (event->button.button, event->button.time);
5656 Editor::zoom_vertical_modifier_released()
5658 _stepping_axis_view = 0;
5662 Editor::ui_parameter_changed (string parameter)
5664 if (parameter == "icon-set") {
5665 while (!_cursor_stack.empty()) {
5666 _cursor_stack.pop();
5668 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5669 } else if (parameter == "draggable-playhead") {
5670 if (_verbose_cursor) {
5671 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());