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[] = {
145 N_("Timecode Frames"),
146 N_("Timecode Seconds"),
147 N_("Timecode Minutes"),
177 static const gchar *_snap_mode_strings[] = {
184 static const gchar *_edit_point_strings[] = {
191 static const gchar *_zoom_focus_strings[] = {
201 #ifdef USE_RUBBERBAND
202 static const gchar *_rb_opt_strings[] = {
205 N_("Balanced multitimbral mixture"),
206 N_("Unpitched percussion with stable notes"),
207 N_("Crisp monophonic instrumental"),
208 N_("Unpitched solo percussion"),
209 N_("Resample without preserving pitch"),
215 pane_size_watcher (Paned* pane)
217 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
221 Quartz: impossible to access
223 so stop that by preventing it from ever getting too narrow. 35
224 pixels is basically a rough guess at the tab width.
229 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
231 gint pos = pane->get_position ();
233 if (pos > max_width_of_lhs) {
234 pane->set_position (max_width_of_lhs);
239 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
241 /* time display buttons */
242 , minsec_label (_("Mins:Secs"))
243 , bbt_label (_("Bars:Beats"))
244 , timecode_label (_("Timecode"))
245 , samples_label (_("Samples"))
246 , tempo_label (_("Tempo"))
247 , meter_label (_("Meter"))
248 , mark_label (_("Location Markers"))
249 , range_mark_label (_("Range Markers"))
250 , transport_mark_label (_("Loop/Punch Ranges"))
251 , cd_mark_label (_("CD Markers"))
252 , videotl_label (_("Video Timeline"))
253 , edit_packer (4, 4, true)
255 /* the values here don't matter: layout widgets
256 reset them as needed.
259 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
260 , horizontal_adjustment (0.0, 0.0, 1e16)
261 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
263 , controls_layout (unused_adjustment, vertical_adjustment)
265 /* tool bar related */
267 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
268 , toolbar_selection_clock_table (2,3)
269 , _mouse_mode_tearoff (0)
270 , automation_mode_button (_("mode"))
274 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
278 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
279 , meters_running(false)
280 , _pending_locate_request (false)
281 , _pending_initial_locate (false)
282 , _last_cut_copy_source_track (0)
284 , _region_selection_change_updates_region_list (true)
285 , _following_mixer_selection (false)
286 , _control_point_toggled_on_press (false)
287 , _stepping_axis_view (0)
291 /* we are a singleton */
293 PublicEditor::_instance = this;
297 selection = new Selection (this);
298 cut_buffer = new Selection (this);
300 clicked_regionview = 0;
301 clicked_axisview = 0;
302 clicked_routeview = 0;
303 clicked_control_point = 0;
304 last_update_frame = 0;
305 pre_press_cursor = 0;
306 _drags = new DragManager (this);
309 current_mixer_strip = 0;
312 snap_type_strings = I18N (_snap_type_strings);
313 snap_mode_strings = I18N (_snap_mode_strings);
314 zoom_focus_strings = I18N (_zoom_focus_strings);
315 edit_point_strings = I18N (_edit_point_strings);
316 #ifdef USE_RUBBERBAND
317 rb_opt_strings = I18N (_rb_opt_strings);
321 build_edit_mode_menu();
322 build_zoom_focus_menu();
323 build_track_count_menu();
324 build_snap_mode_menu();
325 build_snap_type_menu();
326 build_edit_point_menu();
328 snap_threshold = 5.0;
329 bbt_beat_subdivision = 4;
330 _visible_canvas_width = 0;
331 _visible_canvas_height = 0;
332 autoscroll_horizontal_allowed = false;
333 autoscroll_vertical_allowed = false;
338 current_interthread_info = 0;
339 _show_measures = true;
341 show_gain_after_trim = false;
343 have_pending_keyboard_selection = false;
344 _follow_playhead = true;
345 _stationary_playhead = false;
346 editor_ruler_menu = 0;
347 no_ruler_shown_update = false;
349 range_marker_menu = 0;
350 marker_menu_item = 0;
351 tempo_or_meter_marker_menu = 0;
352 transport_marker_menu = 0;
353 new_transport_marker_menu = 0;
354 editor_mixer_strip_width = Wide;
355 show_editor_mixer_when_tracks_arrive = false;
356 region_edit_menu_split_multichannel_item = 0;
357 region_edit_menu_split_item = 0;
360 current_stepping_trackview = 0;
362 entered_regionview = 0;
364 clear_entered_track = false;
367 button_release_can_deselect = true;
368 _dragging_playhead = false;
369 _dragging_edit_point = false;
370 select_new_marker = false;
372 layering_order_editor = 0;
373 no_save_visual = false;
375 within_track_canvas = false;
377 scrubbing_direction = 0;
381 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
382 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
383 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
384 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
385 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
387 zoom_focus = ZoomFocusLeft;
388 _edit_point = EditAtMouse;
389 _internal_editing = false;
390 current_canvas_cursor = 0;
391 _visible_track_count = 16;
393 samples_per_pixel = 2048; /* too early to use reset_zoom () */
395 _scroll_callbacks = 0;
397 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
399 bbt_label.set_name ("EditorRulerLabel");
400 bbt_label.set_size_request (-1, (int)timebar_height);
401 bbt_label.set_alignment (1.0, 0.5);
402 bbt_label.set_padding (5,0);
404 bbt_label.set_no_show_all();
405 minsec_label.set_name ("EditorRulerLabel");
406 minsec_label.set_size_request (-1, (int)timebar_height);
407 minsec_label.set_alignment (1.0, 0.5);
408 minsec_label.set_padding (5,0);
409 minsec_label.hide ();
410 minsec_label.set_no_show_all();
411 timecode_label.set_name ("EditorRulerLabel");
412 timecode_label.set_size_request (-1, (int)timebar_height);
413 timecode_label.set_alignment (1.0, 0.5);
414 timecode_label.set_padding (5,0);
415 timecode_label.hide ();
416 timecode_label.set_no_show_all();
417 samples_label.set_name ("EditorRulerLabel");
418 samples_label.set_size_request (-1, (int)timebar_height);
419 samples_label.set_alignment (1.0, 0.5);
420 samples_label.set_padding (5,0);
421 samples_label.hide ();
422 samples_label.set_no_show_all();
424 tempo_label.set_name ("EditorRulerLabel");
425 tempo_label.set_size_request (-1, (int)timebar_height);
426 tempo_label.set_alignment (1.0, 0.5);
427 tempo_label.set_padding (5,0);
429 tempo_label.set_no_show_all();
431 meter_label.set_name ("EditorRulerLabel");
432 meter_label.set_size_request (-1, (int)timebar_height);
433 meter_label.set_alignment (1.0, 0.5);
434 meter_label.set_padding (5,0);
436 meter_label.set_no_show_all();
438 if (Profile->get_trx()) {
439 mark_label.set_text (_("Markers"));
441 mark_label.set_name ("EditorRulerLabel");
442 mark_label.set_size_request (-1, (int)timebar_height);
443 mark_label.set_alignment (1.0, 0.5);
444 mark_label.set_padding (5,0);
446 mark_label.set_no_show_all();
448 cd_mark_label.set_name ("EditorRulerLabel");
449 cd_mark_label.set_size_request (-1, (int)timebar_height);
450 cd_mark_label.set_alignment (1.0, 0.5);
451 cd_mark_label.set_padding (5,0);
452 cd_mark_label.hide();
453 cd_mark_label.set_no_show_all();
455 videotl_bar_height = 4;
456 videotl_label.set_name ("EditorRulerLabel");
457 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
458 videotl_label.set_alignment (1.0, 0.5);
459 videotl_label.set_padding (5,0);
460 videotl_label.hide();
461 videotl_label.set_no_show_all();
463 range_mark_label.set_name ("EditorRulerLabel");
464 range_mark_label.set_size_request (-1, (int)timebar_height);
465 range_mark_label.set_alignment (1.0, 0.5);
466 range_mark_label.set_padding (5,0);
467 range_mark_label.hide();
468 range_mark_label.set_no_show_all();
470 transport_mark_label.set_name ("EditorRulerLabel");
471 transport_mark_label.set_size_request (-1, (int)timebar_height);
472 transport_mark_label.set_alignment (1.0, 0.5);
473 transport_mark_label.set_padding (5,0);
474 transport_mark_label.hide();
475 transport_mark_label.set_no_show_all();
477 initialize_canvas ();
479 _summary = new EditorSummary (this);
481 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
482 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
484 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
486 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
487 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
489 edit_controls_vbox.set_spacing (0);
490 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
491 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
493 HBox* h = manage (new HBox);
494 _group_tabs = new EditorGroupTabs (this);
495 if (!ARDOUR::Profile->get_trx()) {
496 h->pack_start (*_group_tabs, PACK_SHRINK);
498 h->pack_start (edit_controls_vbox);
499 controls_layout.add (*h);
501 controls_layout.set_name ("EditControlsBase");
502 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
503 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
504 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
506 _cursors = new MouseCursors;
507 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
508 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
510 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
512 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
513 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
514 pad_line_1->set_outline_color (0xFF0000FF);
520 edit_packer.set_col_spacings (0);
521 edit_packer.set_row_spacings (0);
522 edit_packer.set_homogeneous (false);
523 edit_packer.set_border_width (0);
524 edit_packer.set_name ("EditorWindow");
526 time_bars_event_box.add (time_bars_vbox);
527 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
528 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
530 /* labels for the time bars */
531 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
533 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
535 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
537 bottom_hbox.set_border_width (2);
538 bottom_hbox.set_spacing (3);
540 _route_groups = new EditorRouteGroups (this);
541 _routes = new EditorRoutes (this);
542 _regions = new EditorRegions (this);
543 _snapshots = new EditorSnapshots (this);
544 _locations = new EditorLocations (this);
546 add_notebook_page (_("Regions"), _regions->widget ());
547 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
548 add_notebook_page (_("Snapshots"), _snapshots->widget ());
549 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
550 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
552 _the_notebook.set_show_tabs (true);
553 _the_notebook.set_scrollable (true);
554 _the_notebook.popup_disable ();
555 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
556 _the_notebook.show_all ();
558 _notebook_shrunk = false;
560 editor_summary_pane.pack1(edit_packer);
562 Button* summary_arrows_left_left = manage (new Button);
563 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
564 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
565 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
567 Button* summary_arrows_left_right = manage (new Button);
568 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
569 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
570 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
572 VBox* summary_arrows_left = manage (new VBox);
573 summary_arrows_left->pack_start (*summary_arrows_left_left);
574 summary_arrows_left->pack_start (*summary_arrows_left_right);
576 Button* summary_arrows_right_up = manage (new Button);
577 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
578 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
579 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
581 Button* summary_arrows_right_down = manage (new Button);
582 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
583 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
584 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
586 VBox* summary_arrows_right = manage (new VBox);
587 summary_arrows_right->pack_start (*summary_arrows_right_up);
588 summary_arrows_right->pack_start (*summary_arrows_right_down);
590 Frame* summary_frame = manage (new Frame);
591 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
593 summary_frame->add (*_summary);
594 summary_frame->show ();
596 _summary_hbox.pack_start (*summary_arrows_left, false, false);
597 _summary_hbox.pack_start (*summary_frame, true, true);
598 _summary_hbox.pack_start (*summary_arrows_right, false, false);
600 if (!ARDOUR::Profile->get_trx()) {
601 editor_summary_pane.pack2 (_summary_hbox);
604 edit_pane.pack1 (editor_summary_pane, true, true);
605 if (!ARDOUR::Profile->get_trx()) {
606 edit_pane.pack2 (_the_notebook, false, true);
609 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
611 /* XXX: editor_summary_pane might need similar to the edit_pane */
613 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
615 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
616 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
618 top_hbox.pack_start (toolbar_frame);
620 HBox *hbox = manage (new HBox);
621 hbox->pack_start (edit_pane, true, true);
623 global_vpacker.pack_start (top_hbox, false, false);
624 global_vpacker.pack_start (*hbox, true, true);
626 global_hpacker.pack_start (global_vpacker, true, true);
628 set_name ("EditorWindow");
629 add_accel_group (ActionManager::ui_manager->get_accel_group());
631 status_bar_hpacker.show ();
633 vpacker.pack_end (status_bar_hpacker, false, false);
634 vpacker.pack_end (global_hpacker, true, true);
636 /* register actions now so that set_state() can find them and set toggles/checks etc */
639 /* when we start using our own keybinding system for the editor, this
640 * will be uncommented
646 set_zoom_focus (zoom_focus);
647 set_visible_track_count (_visible_track_count);
648 _snap_type = SnapToBeat;
649 set_snap_to (_snap_type);
650 _snap_mode = SnapOff;
651 set_snap_mode (_snap_mode);
652 set_mouse_mode (MouseObject, true);
653 pre_internal_mouse_mode = MouseObject;
654 pre_internal_snap_type = _snap_type;
655 pre_internal_snap_mode = _snap_mode;
656 internal_snap_type = _snap_type;
657 internal_snap_mode = _snap_mode;
658 set_edit_point_preference (EditAtMouse, true);
660 _playlist_selector = new PlaylistSelector();
661 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
663 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
667 nudge_forward_button.set_name ("nudge button");
668 // nudge_forward_button.add_elements (ArdourButton::Inset);
669 nudge_forward_button.set_image(::get_icon("nudge_right"));
671 nudge_backward_button.set_name ("nudge button");
672 // nudge_backward_button.add_elements (ArdourButton::Inset);
673 nudge_backward_button.set_image(::get_icon("nudge_left"));
675 fade_context_menu.set_name ("ArdourContextMenu");
677 /* icons, titles, WM stuff */
679 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
680 Glib::RefPtr<Gdk::Pixbuf> icon;
682 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
683 window_icons.push_back (icon);
685 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
686 window_icons.push_back (icon);
688 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
689 window_icons.push_back (icon);
691 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
692 window_icons.push_back (icon);
694 if (!window_icons.empty()) {
695 // set_icon_list (window_icons);
696 set_default_icon_list (window_icons);
699 WindowTitle title(Glib::get_application_name());
700 title += _("Editor");
701 set_title (title.get_string());
702 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
705 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
707 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
708 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
710 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
712 /* allow external control surfaces/protocols to do various things */
714 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
715 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
716 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
717 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
718 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
719 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
720 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
721 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
722 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
723 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
724 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
725 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
726 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
727 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
729 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
730 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
731 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
732 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
733 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
735 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
737 /* problematic: has to return a value and thus cannot be x-thread */
739 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
741 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
742 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
744 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
746 _ignore_region_action = false;
747 _last_region_menu_was_main = false;
748 _popup_region_menu_item = 0;
750 _show_marker_lines = false;
752 /* Button bindings */
754 button_bindings = new Bindings;
756 XMLNode* node = button_settings();
758 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
759 button_bindings->load (**i);
765 /* grab current parameter state */
766 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
767 ARDOUR_UI::config()->map_parameters (pc);
769 setup_fade_images ();
776 delete button_bindings;
778 delete _route_groups;
779 delete _track_canvas_viewport;
784 Editor::button_settings () const
786 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
787 XMLNode* node = find_named_node (*settings, X_("Buttons"));
790 node = new XMLNode (X_("Buttons"));
797 Editor::add_toplevel_controls (Container& cont)
799 vpacker.pack_start (cont, false, false);
804 Editor::get_smart_mode () const
806 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
810 Editor::catch_vanishing_regionview (RegionView *rv)
812 /* note: the selection will take care of the vanishing
813 audioregionview by itself.
816 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
820 if (clicked_regionview == rv) {
821 clicked_regionview = 0;
824 if (entered_regionview == rv) {
825 set_entered_regionview (0);
828 if (!_all_region_actions_sensitized) {
829 sensitize_all_region_actions (true);
834 Editor::set_entered_regionview (RegionView* rv)
836 if (rv == entered_regionview) {
840 if (entered_regionview) {
841 entered_regionview->exited ();
844 entered_regionview = rv;
846 if (entered_regionview != 0) {
847 entered_regionview->entered (internal_editing ());
850 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
851 /* This RegionView entry might have changed what region actions
852 are allowed, so sensitize them all in case a key is pressed.
854 sensitize_all_region_actions (true);
859 Editor::set_entered_track (TimeAxisView* tav)
862 entered_track->exited ();
868 entered_track->entered ();
873 Editor::show_window ()
875 if (!is_visible ()) {
878 /* XXX: this is a bit unfortunate; it would probably
879 be nicer if we could just call show () above rather
880 than needing the show_all ()
883 /* re-hide stuff if necessary */
884 editor_list_button_toggled ();
885 parameter_changed ("show-summary");
886 parameter_changed ("show-group-tabs");
887 parameter_changed ("show-zoom-tools");
889 /* now reset all audio_time_axis heights, because widgets might need
895 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
896 tv = (static_cast<TimeAxisView*>(*i));
900 if (current_mixer_strip) {
901 current_mixer_strip->hide_things ();
902 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
910 Editor::instant_save ()
912 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
917 _session->add_instant_xml(get_state());
919 Config->add_instant_xml(get_state());
924 Editor::zoom_adjustment_changed ()
930 framecnt_t fpu = llrintf (zoom_range_clock->current_duration() / _visible_canvas_width);
931 bool clamped = clamp_samples_per_pixel (fpu);
934 zoom_range_clock->set ((framepos_t) floor (fpu * _visible_canvas_width));
941 Editor::control_vertical_zoom_in_all ()
943 tav_zoom_smooth (false, true);
947 Editor::control_vertical_zoom_out_all ()
949 tav_zoom_smooth (true, true);
953 Editor::control_vertical_zoom_in_selected ()
955 tav_zoom_smooth (false, false);
959 Editor::control_vertical_zoom_out_selected ()
961 tav_zoom_smooth (true, false);
965 Editor::control_view (uint32_t view)
967 goto_visual_state (view);
971 Editor::control_unselect ()
973 selection->clear_tracks ();
977 Editor::control_select (uint32_t rid, Selection::Operation op)
979 /* handles the (static) signal from the ControlProtocol class that
980 * requests setting the selected track to a given RID
987 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
993 TimeAxisView* tav = axis_view_from_route (r);
998 selection->add (tav);
1000 case Selection::Toggle:
1001 selection->toggle (tav);
1003 case Selection::Extend:
1005 case Selection::Set:
1006 selection->set (tav);
1010 selection->clear_tracks ();
1015 Editor::control_step_tracks_up ()
1017 scroll_tracks_up_line ();
1021 Editor::control_step_tracks_down ()
1023 scroll_tracks_down_line ();
1027 Editor::control_scroll (float fraction)
1029 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1035 double step = fraction * current_page_samples();
1038 _control_scroll_target is an optional<T>
1040 it acts like a pointer to an framepos_t, with
1041 a operator conversion to boolean to check
1042 that it has a value could possibly use
1043 playhead_cursor->current_frame to store the
1044 value and a boolean in the class to know
1045 when it's out of date
1048 if (!_control_scroll_target) {
1049 _control_scroll_target = _session->transport_frame();
1050 _dragging_playhead = true;
1053 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1054 *_control_scroll_target = 0;
1055 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1056 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1058 *_control_scroll_target += (framepos_t) floor (step);
1061 /* move visuals, we'll catch up with it later */
1063 playhead_cursor->set_position (*_control_scroll_target);
1064 UpdateAllTransportClocks (*_control_scroll_target);
1066 if (*_control_scroll_target > (current_page_samples() / 2)) {
1067 /* try to center PH in window */
1068 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1074 Now we do a timeout to actually bring the session to the right place
1075 according to the playhead. This is to avoid reading disk buffers on every
1076 call to control_scroll, which is driven by ScrollTimeline and therefore
1077 probably by a control surface wheel which can generate lots of events.
1079 /* cancel the existing timeout */
1081 control_scroll_connection.disconnect ();
1083 /* add the next timeout */
1085 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1089 Editor::deferred_control_scroll (framepos_t /*target*/)
1091 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1092 // reset for next stream
1093 _control_scroll_target = boost::none;
1094 _dragging_playhead = false;
1099 Editor::access_action (std::string action_group, std::string action_item)
1105 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1108 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1116 Editor::on_realize ()
1118 Window::on_realize ();
1121 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1122 start_lock_event_timing ();
1125 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1129 Editor::start_lock_event_timing ()
1131 /* check if we should lock the GUI every 30 seconds */
1133 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1137 Editor::generic_event_handler (GdkEvent* ev)
1140 case GDK_BUTTON_PRESS:
1141 case GDK_BUTTON_RELEASE:
1142 case GDK_MOTION_NOTIFY:
1144 case GDK_KEY_RELEASE:
1145 gettimeofday (&last_event_time, 0);
1154 Editor::lock_timeout_callback ()
1156 struct timeval now, delta;
1158 gettimeofday (&now, 0);
1160 timersub (&now, &last_event_time, &delta);
1162 if (delta.tv_sec > ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1164 /* don't call again. Returning false will effectively
1165 disconnect us from the timer callback.
1167 unlock() will call start_lock_event_timing() to get things
1177 Editor::map_position_change (framepos_t frame)
1179 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1181 if (_session == 0) {
1185 if (_follow_playhead) {
1186 center_screen (frame);
1189 playhead_cursor->set_position (frame);
1193 Editor::center_screen (framepos_t frame)
1195 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1197 /* if we're off the page, then scroll.
1200 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1201 center_screen_internal (frame, page);
1206 Editor::center_screen_internal (framepos_t frame, float page)
1211 frame -= (framepos_t) page;
1216 reset_x_origin (frame);
1221 Editor::update_title ()
1223 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1226 bool dirty = _session->dirty();
1228 string session_name;
1230 if (_session->snap_name() != _session->name()) {
1231 session_name = _session->snap_name();
1233 session_name = _session->name();
1237 session_name = "*" + session_name;
1240 WindowTitle title(session_name);
1241 title += Glib::get_application_name();
1242 set_title (title.get_string());
1244 /* ::session_going_away() will have taken care of it */
1249 Editor::set_session (Session *t)
1251 SessionHandlePtr::set_session (t);
1257 zoom_range_clock->set_session (_session);
1258 _playlist_selector->set_session (_session);
1259 nudge_clock->set_session (_session);
1260 _summary->set_session (_session);
1261 _group_tabs->set_session (_session);
1262 _route_groups->set_session (_session);
1263 _regions->set_session (_session);
1264 _snapshots->set_session (_session);
1265 _routes->set_session (_session);
1266 _locations->set_session (_session);
1268 if (rhythm_ferret) {
1269 rhythm_ferret->set_session (_session);
1272 if (analysis_window) {
1273 analysis_window->set_session (_session);
1277 sfbrowser->set_session (_session);
1280 compute_fixed_ruler_scale ();
1282 /* Make sure we have auto loop and auto punch ranges */
1284 Location* loc = _session->locations()->auto_loop_location();
1286 loc->set_name (_("Loop"));
1289 loc = _session->locations()->auto_punch_location();
1292 loc->set_name (_("Punch"));
1295 refresh_location_display ();
1297 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1298 the selected Marker; this needs the LocationMarker list to be available.
1300 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1301 set_state (*node, Stateful::loading_state_version);
1303 /* catch up with the playhead */
1305 _session->request_locate (playhead_cursor->current_frame ());
1306 _pending_initial_locate = true;
1310 /* These signals can all be emitted by a non-GUI thread. Therefore the
1311 handlers for them must not attempt to directly interact with the GUI,
1312 but use PBD::Signal<T>::connect() which accepts an event loop
1313 ("context") where the handler will be asked to run.
1316 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1317 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1318 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1319 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1320 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1321 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1322 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1323 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1324 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1325 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1326 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1327 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1328 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1329 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1331 playhead_cursor->show ();
1333 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1334 Config->map_parameters (pc);
1335 _session->config.map_parameters (pc);
1337 restore_ruler_visibility ();
1338 //tempo_map_changed (PropertyChange (0));
1339 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1341 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1342 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1345 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1346 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1349 switch (_snap_type) {
1350 case SnapToRegionStart:
1351 case SnapToRegionEnd:
1352 case SnapToRegionSync:
1353 case SnapToRegionBoundary:
1354 build_region_boundary_cache ();
1361 /* register for undo history */
1362 _session->register_with_memento_command_factory(id(), this);
1364 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1366 start_updating_meters ();
1370 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1372 if (a->get_name() == "RegionMenu") {
1373 /* When the main menu's region menu is opened, we setup the actions so that they look right
1374 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1375 so we resensitize all region actions when the entered regionview or the region selection
1376 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1377 happens after the region context menu is opened. So we set a flag here, too.
1381 sensitize_the_right_region_actions ();
1382 _last_region_menu_was_main = true;
1387 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1389 using namespace Menu_Helpers;
1391 void (Editor::*emf)(FadeShape);
1392 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1395 images = &_xfade_in_images;
1396 emf = &Editor::set_fade_in_shape;
1398 images = &_xfade_out_images;
1399 emf = &Editor::set_fade_out_shape;
1404 _("Linear (for highly correlated material)"),
1405 *(*images)[FadeLinear],
1406 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1410 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1414 _("Constant power"),
1415 *(*images)[FadeConstantPower],
1416 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1419 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1424 *(*images)[FadeSymmetric],
1425 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1429 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1434 *(*images)[FadeSlow],
1435 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1438 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1443 *(*images)[FadeFast],
1444 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1447 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1450 /** Pop up a context menu for when the user clicks on a start crossfade */
1452 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1454 using namespace Menu_Helpers;
1455 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1458 MenuList& items (xfade_in_context_menu.items());
1461 if (arv->audio_region()->fade_in_active()) {
1462 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1464 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1467 items.push_back (SeparatorElem());
1468 fill_xfade_menu (items, true);
1470 xfade_in_context_menu.popup (button, time);
1473 /** Pop up a context menu for when the user clicks on an end crossfade */
1475 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1477 using namespace Menu_Helpers;
1478 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1481 MenuList& items (xfade_out_context_menu.items());
1484 if (arv->audio_region()->fade_out_active()) {
1485 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1487 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1490 items.push_back (SeparatorElem());
1491 fill_xfade_menu (items, false);
1493 xfade_out_context_menu.popup (button, time);
1497 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1499 using namespace Menu_Helpers;
1500 Menu* (Editor::*build_menu_function)();
1503 switch (item_type) {
1505 case RegionViewName:
1506 case RegionViewNameHighlight:
1507 case LeftFrameHandle:
1508 case RightFrameHandle:
1509 if (with_selection) {
1510 build_menu_function = &Editor::build_track_selection_context_menu;
1512 build_menu_function = &Editor::build_track_region_context_menu;
1517 if (with_selection) {
1518 build_menu_function = &Editor::build_track_selection_context_menu;
1520 build_menu_function = &Editor::build_track_context_menu;
1525 if (clicked_routeview->track()) {
1526 build_menu_function = &Editor::build_track_context_menu;
1528 build_menu_function = &Editor::build_track_bus_context_menu;
1533 /* probably shouldn't happen but if it does, we don't care */
1537 menu = (this->*build_menu_function)();
1538 menu->set_name ("ArdourContextMenu");
1540 /* now handle specific situations */
1542 switch (item_type) {
1544 case RegionViewName:
1545 case RegionViewNameHighlight:
1546 case LeftFrameHandle:
1547 case RightFrameHandle:
1548 if (!with_selection) {
1549 if (region_edit_menu_split_item) {
1550 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1551 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1553 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1556 if (region_edit_menu_split_multichannel_item) {
1557 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1558 region_edit_menu_split_multichannel_item->set_sensitive (true);
1560 region_edit_menu_split_multichannel_item->set_sensitive (false);
1573 /* probably shouldn't happen but if it does, we don't care */
1577 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1579 /* Bounce to disk */
1581 using namespace Menu_Helpers;
1582 MenuList& edit_items = menu->items();
1584 edit_items.push_back (SeparatorElem());
1586 switch (clicked_routeview->audio_track()->freeze_state()) {
1587 case AudioTrack::NoFreeze:
1588 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1591 case AudioTrack::Frozen:
1592 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1595 case AudioTrack::UnFrozen:
1596 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1602 if (item_type == StreamItem && clicked_routeview) {
1603 clicked_routeview->build_underlay_menu(menu);
1606 /* When the region menu is opened, we setup the actions so that they look right
1609 sensitize_the_right_region_actions ();
1610 _last_region_menu_was_main = false;
1612 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1613 menu->popup (button, time);
1617 Editor::build_track_context_menu ()
1619 using namespace Menu_Helpers;
1621 MenuList& edit_items = track_context_menu.items();
1624 add_dstream_context_items (edit_items);
1625 return &track_context_menu;
1629 Editor::build_track_bus_context_menu ()
1631 using namespace Menu_Helpers;
1633 MenuList& edit_items = track_context_menu.items();
1636 add_bus_context_items (edit_items);
1637 return &track_context_menu;
1641 Editor::build_track_region_context_menu ()
1643 using namespace Menu_Helpers;
1644 MenuList& edit_items = track_region_context_menu.items();
1647 /* we've just cleared the track region context menu, so the menu that these
1648 two items were on will have disappeared; stop them dangling.
1650 region_edit_menu_split_item = 0;
1651 region_edit_menu_split_multichannel_item = 0;
1653 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1656 boost::shared_ptr<Track> tr;
1657 boost::shared_ptr<Playlist> pl;
1659 if ((tr = rtv->track())) {
1660 add_region_context_items (edit_items, tr);
1664 add_dstream_context_items (edit_items);
1666 return &track_region_context_menu;
1670 Editor::analyze_region_selection ()
1672 if (analysis_window == 0) {
1673 analysis_window = new AnalysisWindow();
1676 analysis_window->set_session(_session);
1678 analysis_window->show_all();
1681 analysis_window->set_regionmode();
1682 analysis_window->analyze();
1684 analysis_window->present();
1688 Editor::analyze_range_selection()
1690 if (analysis_window == 0) {
1691 analysis_window = new AnalysisWindow();
1694 analysis_window->set_session(_session);
1696 analysis_window->show_all();
1699 analysis_window->set_rangemode();
1700 analysis_window->analyze();
1702 analysis_window->present();
1706 Editor::build_track_selection_context_menu ()
1708 using namespace Menu_Helpers;
1709 MenuList& edit_items = track_selection_context_menu.items();
1710 edit_items.clear ();
1712 add_selection_context_items (edit_items);
1713 // edit_items.push_back (SeparatorElem());
1714 // add_dstream_context_items (edit_items);
1716 return &track_selection_context_menu;
1720 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1722 using namespace Menu_Helpers;
1724 /* OK, stick the region submenu at the top of the list, and then add
1728 RegionSelection rs = get_regions_from_selection_and_entered ();
1730 string::size_type pos = 0;
1731 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1733 /* we have to hack up the region name because "_" has a special
1734 meaning for menu titles.
1737 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1738 menu_item_name.replace (pos, 1, "__");
1742 if (_popup_region_menu_item == 0) {
1743 _popup_region_menu_item = new MenuItem (menu_item_name);
1744 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1745 _popup_region_menu_item->show ();
1747 _popup_region_menu_item->set_label (menu_item_name);
1750 const framepos_t position = get_preferred_edit_position (false, true);
1752 edit_items.push_back (*_popup_region_menu_item);
1753 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1754 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1756 edit_items.push_back (SeparatorElem());
1759 /** Add context menu items relevant to selection ranges.
1760 * @param edit_items List to add the items to.
1763 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1765 using namespace Menu_Helpers;
1767 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1768 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1770 edit_items.push_back (SeparatorElem());
1771 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1773 edit_items.push_back (SeparatorElem());
1775 edit_items.push_back (
1777 _("Move Range Start to Previous Region Boundary"),
1778 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1782 edit_items.push_back (
1784 _("Move Range Start to Next Region Boundary"),
1785 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1789 edit_items.push_back (
1791 _("Move Range End to Previous Region Boundary"),
1792 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1796 edit_items.push_back (
1798 _("Move Range End to Next Region Boundary"),
1799 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1803 edit_items.push_back (SeparatorElem());
1804 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1805 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1807 edit_items.push_back (SeparatorElem());
1808 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1810 edit_items.push_back (SeparatorElem());
1811 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1812 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1814 edit_items.push_back (SeparatorElem());
1815 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1817 edit_items.push_back (SeparatorElem());
1818 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1819 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1820 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1822 edit_items.push_back (SeparatorElem());
1823 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1824 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1825 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1826 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1827 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1828 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1829 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1835 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1837 using namespace Menu_Helpers;
1841 Menu *play_menu = manage (new Menu);
1842 MenuList& play_items = play_menu->items();
1843 play_menu->set_name ("ArdourContextMenu");
1845 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1846 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1847 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1848 play_items.push_back (SeparatorElem());
1849 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1851 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1855 Menu *select_menu = manage (new Menu);
1856 MenuList& select_items = select_menu->items();
1857 select_menu->set_name ("ArdourContextMenu");
1859 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1860 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1861 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1862 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1863 select_items.push_back (SeparatorElem());
1864 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1865 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1866 select_items.push_back (SeparatorElem());
1867 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1868 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1869 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1870 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1871 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1872 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1873 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1875 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1879 Menu *cutnpaste_menu = manage (new Menu);
1880 MenuList& cutnpaste_items = cutnpaste_menu->items();
1881 cutnpaste_menu->set_name ("ArdourContextMenu");
1883 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1884 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1885 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1887 cutnpaste_items.push_back (SeparatorElem());
1889 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1890 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1892 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1894 /* Adding new material */
1896 edit_items.push_back (SeparatorElem());
1897 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1898 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1902 Menu *nudge_menu = manage (new Menu());
1903 MenuList& nudge_items = nudge_menu->items();
1904 nudge_menu->set_name ("ArdourContextMenu");
1906 edit_items.push_back (SeparatorElem());
1907 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1908 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1909 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1910 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1912 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1916 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1918 using namespace Menu_Helpers;
1922 Menu *play_menu = manage (new Menu);
1923 MenuList& play_items = play_menu->items();
1924 play_menu->set_name ("ArdourContextMenu");
1926 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1927 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1928 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1932 Menu *select_menu = manage (new Menu);
1933 MenuList& select_items = select_menu->items();
1934 select_menu->set_name ("ArdourContextMenu");
1936 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1937 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1938 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1939 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1940 select_items.push_back (SeparatorElem());
1941 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1942 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1943 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1944 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1946 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1950 Menu *cutnpaste_menu = manage (new Menu);
1951 MenuList& cutnpaste_items = cutnpaste_menu->items();
1952 cutnpaste_menu->set_name ("ArdourContextMenu");
1954 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1955 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1956 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1958 Menu *nudge_menu = manage (new Menu());
1959 MenuList& nudge_items = nudge_menu->items();
1960 nudge_menu->set_name ("ArdourContextMenu");
1962 edit_items.push_back (SeparatorElem());
1963 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1964 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1965 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1966 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1968 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1972 Editor::snap_type() const
1978 Editor::snap_mode() const
1984 Editor::set_snap_to (SnapType st)
1986 unsigned int snap_ind = (unsigned int)st;
1990 if (snap_ind > snap_type_strings.size() - 1) {
1992 _snap_type = (SnapType)snap_ind;
1995 string str = snap_type_strings[snap_ind];
1997 if (str != snap_type_selector.get_text()) {
1998 snap_type_selector.set_text (str);
2003 switch (_snap_type) {
2004 case SnapToBeatDiv128:
2005 case SnapToBeatDiv64:
2006 case SnapToBeatDiv32:
2007 case SnapToBeatDiv28:
2008 case SnapToBeatDiv24:
2009 case SnapToBeatDiv20:
2010 case SnapToBeatDiv16:
2011 case SnapToBeatDiv14:
2012 case SnapToBeatDiv12:
2013 case SnapToBeatDiv10:
2014 case SnapToBeatDiv8:
2015 case SnapToBeatDiv7:
2016 case SnapToBeatDiv6:
2017 case SnapToBeatDiv5:
2018 case SnapToBeatDiv4:
2019 case SnapToBeatDiv3:
2020 case SnapToBeatDiv2: {
2021 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2022 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2024 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2025 current_bbt_points_begin, current_bbt_points_end);
2026 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2027 current_bbt_points_begin, current_bbt_points_end);
2028 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2032 case SnapToRegionStart:
2033 case SnapToRegionEnd:
2034 case SnapToRegionSync:
2035 case SnapToRegionBoundary:
2036 build_region_boundary_cache ();
2044 SnapChanged (); /* EMIT SIGNAL */
2048 Editor::set_snap_mode (SnapMode mode)
2050 string str = snap_mode_strings[(int)mode];
2052 if (_internal_editing) {
2053 internal_snap_mode = mode;
2055 pre_internal_snap_mode = mode;
2060 if (str != snap_mode_selector.get_text ()) {
2061 snap_mode_selector.set_text (str);
2067 Editor::set_edit_point_preference (EditPoint ep, bool force)
2069 bool changed = (_edit_point != ep);
2072 string str = edit_point_strings[(int)ep];
2074 if (str != edit_point_selector.get_text ()) {
2075 edit_point_selector.set_text (str);
2078 reset_canvas_cursor ();
2080 if (!force && !changed) {
2084 const char* action=NULL;
2086 switch (_edit_point) {
2087 case EditAtPlayhead:
2088 action = "edit-at-playhead";
2090 case EditAtSelectedMarker:
2091 action = "edit-at-marker";
2094 action = "edit-at-mouse";
2098 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2100 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2104 bool in_track_canvas;
2106 if (!mouse_frame (foo, in_track_canvas)) {
2107 in_track_canvas = false;
2110 reset_canvas_action_sensitivity (in_track_canvas);
2116 Editor::set_state (const XMLNode& node, int /*version*/)
2118 const XMLProperty* prop;
2125 g.base_width = default_width;
2126 g.base_height = default_height;
2130 if ((geometry = find_named_node (node, "geometry")) != 0) {
2134 if ((prop = geometry->property("x_size")) == 0) {
2135 prop = geometry->property ("x-size");
2138 g.base_width = atoi(prop->value());
2140 if ((prop = geometry->property("y_size")) == 0) {
2141 prop = geometry->property ("y-size");
2144 g.base_height = atoi(prop->value());
2147 if ((prop = geometry->property ("x_pos")) == 0) {
2148 prop = geometry->property ("x-pos");
2151 x = atoi (prop->value());
2154 if ((prop = geometry->property ("y_pos")) == 0) {
2155 prop = geometry->property ("y-pos");
2158 y = atoi (prop->value());
2162 set_default_size (g.base_width, g.base_height);
2165 if (_session && (prop = node.property ("playhead"))) {
2167 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2168 playhead_cursor->set_position (pos);
2170 playhead_cursor->set_position (0);
2173 if ((prop = node.property ("mixer-width"))) {
2174 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2177 if ((prop = node.property ("zoom-focus"))) {
2178 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2181 if ((prop = node.property ("zoom"))) {
2182 /* older versions of ardour used floating point samples_per_pixel */
2183 double f = PBD::atof (prop->value());
2184 reset_zoom (llrintf (f));
2186 reset_zoom (samples_per_pixel);
2189 if ((prop = node.property ("visible-track-count"))) {
2190 set_visible_track_count (PBD::atoi (prop->value()));
2193 if ((prop = node.property ("snap-to"))) {
2194 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2197 if ((prop = node.property ("snap-mode"))) {
2198 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2201 if ((prop = node.property ("internal-snap-to"))) {
2202 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2205 if ((prop = node.property ("internal-snap-mode"))) {
2206 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2209 if ((prop = node.property ("pre-internal-snap-to"))) {
2210 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2214 if ((prop = node.property ("pre-internal-snap-mode"))) {
2215 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2218 if ((prop = node.property ("mouse-mode"))) {
2219 MouseMode m = str2mousemode(prop->value());
2220 set_mouse_mode (m, true);
2222 set_mouse_mode (MouseObject, true);
2225 if ((prop = node.property ("left-frame")) != 0) {
2227 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2231 reset_x_origin (pos);
2235 if ((prop = node.property ("y-origin")) != 0) {
2236 reset_y_origin (atof (prop->value ()));
2239 if ((prop = node.property ("internal-edit"))) {
2240 bool yn = string_is_affirmative (prop->value());
2241 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2243 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2244 tact->set_active (!yn);
2245 tact->set_active (yn);
2249 if ((prop = node.property ("join-object-range"))) {
2250 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2251 bool yn = string_is_affirmative (prop->value());
2253 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2254 tact->set_active (!yn);
2255 tact->set_active (yn);
2257 set_mouse_mode(mouse_mode, true);
2260 if ((prop = node.property ("edit-point"))) {
2261 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2264 if ((prop = node.property ("show-measures"))) {
2265 bool yn = string_is_affirmative (prop->value());
2266 _show_measures = yn;
2267 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2269 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2270 /* do it twice to force the change */
2271 tact->set_active (!yn);
2272 tact->set_active (yn);
2276 if ((prop = node.property ("follow-playhead"))) {
2277 bool yn = string_is_affirmative (prop->value());
2278 set_follow_playhead (yn);
2279 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2281 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2282 if (tact->get_active() != yn) {
2283 tact->set_active (yn);
2288 if ((prop = node.property ("stationary-playhead"))) {
2289 bool yn = string_is_affirmative (prop->value());
2290 set_stationary_playhead (yn);
2291 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2293 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2294 if (tact->get_active() != yn) {
2295 tact->set_active (yn);
2300 if ((prop = node.property ("region-list-sort-type"))) {
2301 RegionListSortType st;
2302 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2305 if ((prop = node.property ("show-editor-mixer"))) {
2307 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2310 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2311 bool yn = string_is_affirmative (prop->value());
2313 /* do it twice to force the change */
2315 tact->set_active (!yn);
2316 tact->set_active (yn);
2319 if ((prop = node.property ("show-editor-list"))) {
2321 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2324 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2325 bool yn = string_is_affirmative (prop->value());
2327 /* do it twice to force the change */
2329 tact->set_active (!yn);
2330 tact->set_active (yn);
2333 if ((prop = node.property (X_("editor-list-page")))) {
2334 _the_notebook.set_current_page (atoi (prop->value ()));
2337 if ((prop = node.property (X_("show-marker-lines")))) {
2338 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2340 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2341 bool yn = string_is_affirmative (prop->value ());
2343 tact->set_active (!yn);
2344 tact->set_active (yn);
2347 XMLNodeList children = node.children ();
2348 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2349 selection->set_state (**i, Stateful::current_state_version);
2350 _regions->set_state (**i);
2353 if ((prop = node.property ("maximised"))) {
2354 bool yn = string_is_affirmative (prop->value());
2355 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2357 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2358 bool fs = tact && tact->get_active();
2360 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2364 if ((prop = node.property ("nudge-clock-value"))) {
2366 sscanf (prop->value().c_str(), "%" PRId64, &f);
2367 nudge_clock->set (f);
2369 nudge_clock->set_mode (AudioClock::Timecode);
2370 nudge_clock->set (_session->frame_rate() * 5, true);
2377 Editor::get_state ()
2379 XMLNode* node = new XMLNode ("Editor");
2382 id().print (buf, sizeof (buf));
2383 node->add_property ("id", buf);
2385 if (is_realized()) {
2386 Glib::RefPtr<Gdk::Window> win = get_window();
2388 int x, y, width, height;
2389 win->get_root_origin(x, y);
2390 win->get_size(width, height);
2392 XMLNode* geometry = new XMLNode ("geometry");
2394 snprintf(buf, sizeof(buf), "%d", width);
2395 geometry->add_property("x-size", string(buf));
2396 snprintf(buf, sizeof(buf), "%d", height);
2397 geometry->add_property("y-size", string(buf));
2398 snprintf(buf, sizeof(buf), "%d", x);
2399 geometry->add_property("x-pos", string(buf));
2400 snprintf(buf, sizeof(buf), "%d", y);
2401 geometry->add_property("y-pos", string(buf));
2402 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2403 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2404 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2405 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2406 geometry->add_property("edit-vertical-pane-pos", string(buf));
2408 node->add_child_nocopy (*geometry);
2411 maybe_add_mixer_strip_width (*node);
2413 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2415 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2416 node->add_property ("zoom", buf);
2417 node->add_property ("snap-to", enum_2_string (_snap_type));
2418 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2419 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2420 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2421 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2422 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2423 node->add_property ("edit-point", enum_2_string (_edit_point));
2424 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2425 node->add_property ("visible-track-count", buf);
2427 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2428 node->add_property ("playhead", buf);
2429 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2430 node->add_property ("left-frame", buf);
2431 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2432 node->add_property ("y-origin", buf);
2434 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2435 node->add_property ("maximised", _maximised ? "yes" : "no");
2436 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2437 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2438 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2439 node->add_property ("mouse-mode", enum2str(mouse_mode));
2440 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2441 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2443 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2445 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2446 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2449 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2451 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2452 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2455 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2456 node->add_property (X_("editor-list-page"), buf);
2458 if (button_bindings) {
2459 XMLNode* bb = new XMLNode (X_("Buttons"));
2460 button_bindings->save (*bb);
2461 node->add_child_nocopy (*bb);
2464 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2466 node->add_child_nocopy (selection->get_state ());
2467 node->add_child_nocopy (_regions->get_state ());
2469 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2470 node->add_property ("nudge-clock-value", buf);
2475 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2476 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2478 * @return pair: TimeAxisView that y is over, layer index.
2480 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2481 * in stacked or expanded region display mode, otherwise 0.
2483 std::pair<TimeAxisView *, double>
2484 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2486 if (!trackview_relative_offset) {
2487 y -= _trackview_group->canvas_origin().y;
2491 return std::make_pair ( (TimeAxisView *) 0, 0);
2494 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2496 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2503 return std::make_pair ( (TimeAxisView *) 0, 0);
2506 /** Snap a position to the grid, if appropriate, taking into account current
2507 * grid settings and also the state of any snap modifier keys that may be pressed.
2508 * @param start Position to snap.
2509 * @param event Event to get current key modifier information from, or 0.
2512 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2514 if (!_session || !event) {
2518 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2519 if (_snap_mode == SnapOff) {
2520 snap_to_internal (start, direction, for_mark);
2523 if (_snap_mode != SnapOff) {
2524 snap_to_internal (start, direction, for_mark);
2530 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2532 if (!_session || _snap_mode == SnapOff) {
2536 snap_to_internal (start, direction, for_mark);
2540 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2542 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2543 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2545 switch (_snap_type) {
2546 case SnapToTimecodeFrame:
2547 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2548 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2550 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2554 case SnapToTimecodeSeconds:
2555 if (_session->config.get_timecode_offset_negative()) {
2556 start += _session->config.get_timecode_offset ();
2558 start -= _session->config.get_timecode_offset ();
2560 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2561 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2563 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2566 if (_session->config.get_timecode_offset_negative()) {
2567 start -= _session->config.get_timecode_offset ();
2569 start += _session->config.get_timecode_offset ();
2573 case SnapToTimecodeMinutes:
2574 if (_session->config.get_timecode_offset_negative()) {
2575 start += _session->config.get_timecode_offset ();
2577 start -= _session->config.get_timecode_offset ();
2579 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2580 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2582 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2584 if (_session->config.get_timecode_offset_negative()) {
2585 start -= _session->config.get_timecode_offset ();
2587 start += _session->config.get_timecode_offset ();
2591 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2597 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2599 const framepos_t one_second = _session->frame_rate();
2600 const framepos_t one_minute = _session->frame_rate() * 60;
2601 framepos_t presnap = start;
2605 switch (_snap_type) {
2606 case SnapToTimecodeFrame:
2607 case SnapToTimecodeSeconds:
2608 case SnapToTimecodeMinutes:
2609 return timecode_snap_to_internal (start, direction, for_mark);
2612 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2613 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2615 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2620 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2621 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2623 start = (framepos_t) floor ((double) start / one_second) * one_second;
2628 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2629 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2631 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2636 start = _session->tempo_map().round_to_bar (start, direction);
2640 start = _session->tempo_map().round_to_beat (start, direction);
2643 case SnapToBeatDiv128:
2644 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2646 case SnapToBeatDiv64:
2647 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2649 case SnapToBeatDiv32:
2650 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2652 case SnapToBeatDiv28:
2653 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2655 case SnapToBeatDiv24:
2656 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2658 case SnapToBeatDiv20:
2659 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2661 case SnapToBeatDiv16:
2662 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2664 case SnapToBeatDiv14:
2665 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2667 case SnapToBeatDiv12:
2668 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2670 case SnapToBeatDiv10:
2671 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2673 case SnapToBeatDiv8:
2674 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2676 case SnapToBeatDiv7:
2677 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2679 case SnapToBeatDiv6:
2680 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2682 case SnapToBeatDiv5:
2683 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2685 case SnapToBeatDiv4:
2686 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2688 case SnapToBeatDiv3:
2689 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2691 case SnapToBeatDiv2:
2692 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2700 _session->locations()->marks_either_side (start, before, after);
2702 if (before == max_framepos && after == max_framepos) {
2703 /* No marks to snap to, so just don't snap */
2705 } else if (before == max_framepos) {
2707 } else if (after == max_framepos) {
2709 } else if (before != max_framepos && after != max_framepos) {
2710 /* have before and after */
2711 if ((start - before) < (after - start)) {
2720 case SnapToRegionStart:
2721 case SnapToRegionEnd:
2722 case SnapToRegionSync:
2723 case SnapToRegionBoundary:
2724 if (!region_boundary_cache.empty()) {
2726 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2727 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2729 if (direction > 0) {
2730 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2732 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2735 if (next != region_boundary_cache.begin ()) {
2740 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2741 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2743 if (start > (p + n) / 2) {
2752 switch (_snap_mode) {
2758 if (presnap > start) {
2759 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2763 } else if (presnap < start) {
2764 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2770 /* handled at entry */
2778 Editor::setup_toolbar ()
2780 HBox* mode_box = manage(new HBox);
2781 mode_box->set_border_width (2);
2782 mode_box->set_spacing(4);
2784 HBox* mouse_mode_box = manage (new HBox);
2785 HBox* mouse_mode_hbox = manage (new HBox);
2786 VBox* mouse_mode_vbox = manage (new VBox);
2787 Alignment* mouse_mode_align = manage (new Alignment);
2789 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2790 // mouse_mode_size_group->add_widget (smart_mode_button);
2791 mouse_mode_size_group->add_widget (mouse_move_button);
2792 mouse_mode_size_group->add_widget (mouse_select_button);
2793 mouse_mode_size_group->add_widget (mouse_zoom_button);
2794 mouse_mode_size_group->add_widget (mouse_gain_button);
2795 mouse_mode_size_group->add_widget (mouse_timefx_button);
2796 mouse_mode_size_group->add_widget (mouse_audition_button);
2797 mouse_mode_size_group->add_widget (mouse_draw_button);
2798 mouse_mode_size_group->add_widget (internal_edit_button);
2800 /* make them just a bit bigger */
2801 mouse_move_button.set_size_request (-1, 30);
2803 mouse_mode_hbox->set_spacing (2);
2805 if (!ARDOUR::Profile->get_trx()) {
2806 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2809 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2810 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2811 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2813 if (!ARDOUR::Profile->get_trx()) {
2814 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2815 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2816 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2817 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2818 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2821 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2823 mouse_mode_align->add (*mouse_mode_vbox);
2824 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2826 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2828 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2829 if (!Profile->get_sae()) {
2830 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2832 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2834 edit_mode_selector.set_name ("mouse mode button");
2835 edit_mode_selector.set_size_request (65, -1);
2836 edit_mode_selector.add_elements (ArdourButton::Inset);
2838 if (!ARDOUR::Profile->get_trx()) {
2839 mode_box->pack_start (edit_mode_selector, false, false);
2841 mode_box->pack_start (*mouse_mode_box, false, false);
2843 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2844 _mouse_mode_tearoff->set_name ("MouseModeBase");
2845 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2847 if (Profile->get_sae()) {
2848 _mouse_mode_tearoff->set_can_be_torn_off (false);
2851 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2852 &_mouse_mode_tearoff->tearoff_window()));
2853 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2854 &_mouse_mode_tearoff->tearoff_window(), 1));
2855 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2856 &_mouse_mode_tearoff->tearoff_window()));
2857 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2858 &_mouse_mode_tearoff->tearoff_window(), 1));
2862 _zoom_box.set_spacing (2);
2863 _zoom_box.set_border_width (2);
2867 zoom_in_button.set_name ("zoom button");
2868 // zoom_in_button.add_elements ( ArdourButton::Inset );
2869 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2870 zoom_in_button.set_image(::get_icon ("zoom_in"));
2871 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2872 zoom_in_button.set_related_action (act);
2874 zoom_out_button.set_name ("zoom button");
2875 // zoom_out_button.add_elements ( ArdourButton::Inset );
2876 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2877 zoom_out_button.set_image(::get_icon ("zoom_out"));
2878 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2879 zoom_out_button.set_related_action (act);
2881 zoom_out_full_button.set_name ("zoom button");
2882 // zoom_out_full_button.add_elements ( ArdourButton::Inset );
2883 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2884 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2885 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2886 zoom_out_full_button.set_related_action (act);
2888 zoom_focus_selector.set_name ("zoom button");
2889 zoom_focus_selector.set_size_request (80, -1);
2890 // zoom_focus_selector.add_elements (ArdourButton::Inset);
2892 if (!ARDOUR::Profile->get_trx()) {
2893 _zoom_box.pack_start (zoom_out_button, false, false);
2894 _zoom_box.pack_start (zoom_in_button, false, false);
2895 _zoom_box.pack_start (zoom_out_full_button, false, false);
2896 _zoom_box.pack_start (zoom_focus_selector, false, false);
2898 mode_box->pack_start (zoom_out_button, false, false);
2899 mode_box->pack_start (zoom_in_button, false, false);
2902 /* Track zoom buttons */
2903 visible_tracks_selector.set_name ("zoom button");
2904 // visible_tracks_selector.add_elements ( ArdourButton::Inset );
2905 set_size_request_to_display_given_text (visible_tracks_selector, _("all"), 40, 2);
2907 tav_expand_button.set_name ("zoom button");
2908 // tav_expand_button.add_elements ( ArdourButton::FlatFace );
2909 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2910 tav_expand_button.set_size_request (-1, 20);
2911 tav_expand_button.set_image(::get_icon ("tav_exp"));
2912 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2913 tav_expand_button.set_related_action (act);
2915 tav_shrink_button.set_name ("zoom button");
2916 // tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2917 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2918 tav_shrink_button.set_size_request (-1, 20);
2919 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2920 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2921 tav_shrink_button.set_related_action (act);
2923 if (!ARDOUR::Profile->get_trx()) {
2924 _zoom_box.pack_start (visible_tracks_selector);
2926 _zoom_box.pack_start (tav_shrink_button);
2927 _zoom_box.pack_start (tav_expand_button);
2929 if (!ARDOUR::Profile->get_trx()) {
2930 _zoom_tearoff = manage (new TearOff (_zoom_box));
2932 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2933 &_zoom_tearoff->tearoff_window()));
2934 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2935 &_zoom_tearoff->tearoff_window(), 0));
2936 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2937 &_zoom_tearoff->tearoff_window()));
2938 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2939 &_zoom_tearoff->tearoff_window(), 0));
2942 snap_box.set_spacing (2);
2943 snap_box.set_border_width (2);
2945 snap_type_selector.set_name ("mouse mode button");
2946 snap_type_selector.set_size_request (140, -1);
2947 snap_type_selector.add_elements (ArdourButton::Inset);
2949 snap_mode_selector.set_name ("mouse mode button");
2950 snap_mode_selector.set_size_request (85, -1);
2951 snap_mode_selector.add_elements (ArdourButton::Inset);
2953 edit_point_selector.set_name ("mouse mode button");
2954 edit_point_selector.set_size_request (85, -1);
2955 edit_point_selector.add_elements (ArdourButton::Inset);
2957 snap_box.pack_start (snap_mode_selector, false, false);
2958 snap_box.pack_start (snap_type_selector, false, false);
2959 snap_box.pack_start (edit_point_selector, false, false);
2963 HBox *nudge_box = manage (new HBox);
2964 nudge_box->set_spacing (2);
2965 nudge_box->set_border_width (2);
2967 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2968 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2970 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2971 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2973 nudge_box->pack_start (nudge_backward_button, false, false);
2974 nudge_box->pack_start (nudge_forward_button, false, false);
2975 nudge_box->pack_start (*nudge_clock, false, false);
2978 /* Pack everything in... */
2980 HBox* hbox = manage (new HBox);
2981 hbox->set_spacing(10);
2983 _tools_tearoff = manage (new TearOff (*hbox));
2984 _tools_tearoff->set_name ("MouseModeBase");
2985 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2987 if (Profile->get_sae()) {
2988 _tools_tearoff->set_can_be_torn_off (false);
2991 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2992 &_tools_tearoff->tearoff_window()));
2993 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2994 &_tools_tearoff->tearoff_window(), 0));
2995 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2996 &_tools_tearoff->tearoff_window()));
2997 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2998 &_tools_tearoff->tearoff_window(), 0));
3000 toolbar_hbox.set_spacing (10);
3001 toolbar_hbox.set_border_width (1);
3003 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3004 if (!ARDOUR::Profile->get_trx()) {
3005 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3006 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3009 if (!ARDOUR::Profile->get_trx()) {
3010 hbox->pack_start (snap_box, false, false);
3011 if (!Profile->get_small_screen()) {
3012 hbox->pack_start (*nudge_box, false, false);
3014 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3017 hbox->pack_start (panic_box, false, false);
3021 toolbar_base.set_name ("ToolBarBase");
3022 toolbar_base.add (toolbar_hbox);
3024 _toolbar_viewport.add (toolbar_base);
3025 /* stick to the required height but allow width to vary if there's not enough room */
3026 _toolbar_viewport.set_size_request (1, -1);
3028 toolbar_frame.set_shadow_type (SHADOW_OUT);
3029 toolbar_frame.set_name ("BaseFrame");
3030 toolbar_frame.add (_toolbar_viewport);
3034 Editor::build_edit_point_menu ()
3036 using namespace Menu_Helpers;
3038 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3039 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3040 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3044 Editor::build_edit_mode_menu ()
3046 using namespace Menu_Helpers;
3048 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Slide), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3049 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Splice), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3050 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Lock), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3054 Editor::build_snap_mode_menu ()
3056 using namespace Menu_Helpers;
3058 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3059 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3060 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3064 Editor::build_snap_type_menu ()
3066 using namespace Menu_Helpers;
3068 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3069 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3070 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3071 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3072 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3073 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3074 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3075 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3076 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3077 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3078 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3079 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3080 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3081 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3082 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3083 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3084 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3085 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3086 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3087 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3088 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3089 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3090 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3091 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3092 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3093 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3094 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3095 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3096 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3097 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3101 Editor::setup_tooltips ()
3103 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3104 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3105 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3106 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3107 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3108 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3109 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3110 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3111 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3112 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3113 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3114 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3115 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3116 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3117 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3118 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3119 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3120 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3121 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3122 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3123 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3124 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3125 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3126 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3130 Editor::convert_drop_to_paths (
3131 vector<string>& paths,
3132 const RefPtr<Gdk::DragContext>& /*context*/,
3135 const SelectionData& data,
3139 if (_session == 0) {
3143 vector<string> uris = data.get_uris();
3147 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3148 are actually URI lists. So do it by hand.
3151 if (data.get_target() != "text/plain") {
3155 /* Parse the "uri-list" format that Nautilus provides,
3156 where each pathname is delimited by \r\n.
3158 THERE MAY BE NO NULL TERMINATING CHAR!!!
3161 string txt = data.get_text();
3165 p = (char *) malloc (txt.length() + 1);
3166 txt.copy (p, txt.length(), 0);
3167 p[txt.length()] = '\0';
3173 while (g_ascii_isspace (*p))
3177 while (*q && (*q != '\n') && (*q != '\r')) {
3184 while (q > p && g_ascii_isspace (*q))
3189 uris.push_back (string (p, q - p + 1));
3193 p = strchr (p, '\n');
3205 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3206 if ((*i).substr (0,7) == "file://") {
3207 paths.push_back (Glib::filename_from_uri (*i));
3215 Editor::new_tempo_section ()
3220 Editor::map_transport_state ()
3222 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3224 if (_session && _session->transport_stopped()) {
3225 have_pending_keyboard_selection = false;
3228 update_loop_range_view ();
3234 Editor::begin_reversible_command (string name)
3237 _session->begin_reversible_command (name);
3242 Editor::begin_reversible_command (GQuark q)
3245 _session->begin_reversible_command (q);
3250 Editor::commit_reversible_command ()
3253 _session->commit_reversible_command ();
3258 Editor::history_changed ()
3262 if (undo_action && _session) {
3263 if (_session->undo_depth() == 0) {
3264 label = S_("Command|Undo");
3266 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3268 undo_action->property_label() = label;
3271 if (redo_action && _session) {
3272 if (_session->redo_depth() == 0) {
3275 label = string_compose(_("Redo (%1)"), _session->next_redo());
3277 redo_action->property_label() = label;
3282 Editor::duplicate_range (bool with_dialog)
3286 RegionSelection rs = get_regions_from_selection_and_entered ();
3288 if ( selection->time.length() == 0 && rs.empty()) {
3294 ArdourDialog win (_("Duplicate"));
3295 Label label (_("Number of duplications:"));
3296 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3297 SpinButton spinner (adjustment, 0.0, 1);
3300 win.get_vbox()->set_spacing (12);
3301 win.get_vbox()->pack_start (hbox);
3302 hbox.set_border_width (6);
3303 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3305 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3306 place, visually. so do this by hand.
3309 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3310 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3311 spinner.grab_focus();
3317 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3318 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3319 win.set_default_response (RESPONSE_ACCEPT);
3321 spinner.grab_focus ();
3323 switch (win.run ()) {
3324 case RESPONSE_ACCEPT:
3330 times = adjustment.get_value();
3333 if ((current_mouse_mode() == Editing::MouseRange)) {
3334 if (selection->time.length()) {
3335 duplicate_selection (times);
3337 } else if (get_smart_mode()) {
3338 if (selection->time.length()) {
3339 duplicate_selection (times);
3341 duplicate_some_regions (rs, times);
3343 duplicate_some_regions (rs, times);
3348 Editor::set_edit_mode (EditMode m)
3350 Config->set_edit_mode (m);
3354 Editor::cycle_edit_mode ()
3356 switch (Config->get_edit_mode()) {
3358 if (Profile->get_sae()) {
3359 Config->set_edit_mode (Lock);
3361 Config->set_edit_mode (Splice);
3365 Config->set_edit_mode (Lock);
3368 Config->set_edit_mode (Slide);
3374 Editor::edit_mode_selection_done ( EditMode m )
3376 Config->set_edit_mode ( m );
3380 Editor::snap_type_selection_done (SnapType snaptype)
3382 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3384 ract->set_active ();
3389 Editor::snap_mode_selection_done (SnapMode mode)
3391 RefPtr<RadioAction> ract = snap_mode_action (mode);
3394 ract->set_active (true);
3399 Editor::cycle_edit_point (bool with_marker)
3401 switch (_edit_point) {
3403 set_edit_point_preference (EditAtPlayhead);
3405 case EditAtPlayhead:
3407 set_edit_point_preference (EditAtSelectedMarker);
3409 set_edit_point_preference (EditAtMouse);
3412 case EditAtSelectedMarker:
3413 set_edit_point_preference (EditAtMouse);
3419 Editor::edit_point_selection_done (EditPoint ep)
3421 set_edit_point_preference ( ep );
3425 Editor::build_zoom_focus_menu ()
3427 using namespace Menu_Helpers;
3429 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3430 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3431 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3432 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3433 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3434 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3438 Editor::zoom_focus_selection_done ( ZoomFocus f )
3440 RefPtr<RadioAction> ract = zoom_focus_action (f);
3442 ract->set_active ();
3447 Editor::build_track_count_menu ()
3449 using namespace Menu_Helpers;
3451 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3452 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3453 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3454 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3455 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3456 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3457 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3458 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3459 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3460 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3461 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3462 visible_tracks_selector.AddMenuElem (MenuElem (_("all"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3466 Editor::set_visible_track_count (int32_t n)
3468 _visible_track_count = n;
3470 /* if the canvas hasn't really been allocated any size yet, just
3471 record the desired number of visible tracks and return. when canvas
3472 allocation happens, we will get called again and then we can do the
3476 if (_visible_canvas_height <= 1) {
3483 if (_visible_track_count > 0) {
3484 h = _visible_canvas_height / _visible_track_count;
3485 std::ostringstream s;
3486 s << _visible_track_count;
3488 } else if (_visible_track_count == 0) {
3489 h = _visible_canvas_height / track_views.size();
3492 /* negative value means that the visible track count has
3493 been overridden by explicit track height changes.
3495 visible_tracks_selector.set_text (X_("*"));
3499 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3500 (*i)->set_height (h);
3503 if (str != visible_tracks_selector.get_text()) {
3504 visible_tracks_selector.set_text (str);
3509 Editor::override_visible_track_count ()
3511 _visible_track_count = -_visible_track_count;
3515 Editor::edit_controls_button_release (GdkEventButton* ev)
3517 if (Keyboard::is_context_menu_event (ev)) {
3518 ARDOUR_UI::instance()->add_route (this);
3519 } else if (ev->button == 1) {
3520 selection->clear_tracks ();
3527 Editor::mouse_select_button_release (GdkEventButton* ev)
3529 /* this handles just right-clicks */
3531 if (ev->button != 3) {
3539 Editor::set_zoom_focus (ZoomFocus f)
3541 string str = zoom_focus_strings[(int)f];
3543 if (str != zoom_focus_selector.get_text()) {
3544 zoom_focus_selector.set_text (str);
3547 if (zoom_focus != f) {
3554 Editor::cycle_zoom_focus ()
3556 switch (zoom_focus) {
3558 set_zoom_focus (ZoomFocusRight);
3560 case ZoomFocusRight:
3561 set_zoom_focus (ZoomFocusCenter);
3563 case ZoomFocusCenter:
3564 set_zoom_focus (ZoomFocusPlayhead);
3566 case ZoomFocusPlayhead:
3567 set_zoom_focus (ZoomFocusMouse);
3569 case ZoomFocusMouse:
3570 set_zoom_focus (ZoomFocusEdit);
3573 set_zoom_focus (ZoomFocusLeft);
3579 Editor::ensure_float (Window& win)
3581 win.set_transient_for (*this);
3585 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3587 /* recover or initialize pane positions. do this here rather than earlier because
3588 we don't want the positions to change the child allocations, which they seem to do.
3594 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3603 XMLNode* geometry = find_named_node (*node, "geometry");
3605 if (which == static_cast<Paned*> (&edit_pane)) {
3607 if (done & Horizontal) {
3611 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3612 _notebook_shrunk = string_is_affirmative (prop->value ());
3615 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3616 /* initial allocation is 90% to canvas, 10% to notebook */
3617 pos = (int) floor (alloc.get_width() * 0.90f);
3618 snprintf (buf, sizeof(buf), "%d", pos);
3620 pos = atoi (prop->value());
3623 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3624 edit_pane.set_position (pos);
3627 done = (Pane) (done | Horizontal);
3629 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3631 if (done & Vertical) {
3635 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3636 /* initial allocation is 90% to canvas, 10% to summary */
3637 pos = (int) floor (alloc.get_height() * 0.90f);
3638 snprintf (buf, sizeof(buf), "%d", pos);
3641 pos = atoi (prop->value());
3644 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3645 editor_summary_pane.set_position (pos);
3648 done = (Pane) (done | Vertical);
3653 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3655 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3656 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3657 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3658 top_hbox.remove (toolbar_frame);
3663 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3665 if (toolbar_frame.get_parent() == 0) {
3666 top_hbox.pack_end (toolbar_frame);
3671 Editor::set_show_measures (bool yn)
3673 if (_show_measures != yn) {
3676 if ((_show_measures = yn) == true) {
3678 tempo_lines->show();
3681 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3682 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3684 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3685 draw_measures (begin, end);
3693 Editor::toggle_follow_playhead ()
3695 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3697 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3698 set_follow_playhead (tact->get_active());
3702 /** @param yn true to follow playhead, otherwise false.
3703 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3706 Editor::set_follow_playhead (bool yn, bool catch_up)
3708 if (_follow_playhead != yn) {
3709 if ((_follow_playhead = yn) == true && catch_up) {
3711 reset_x_origin_to_follow_playhead ();
3718 Editor::toggle_stationary_playhead ()
3720 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3722 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3723 set_stationary_playhead (tact->get_active());
3728 Editor::set_stationary_playhead (bool yn)
3730 if (_stationary_playhead != yn) {
3731 if ((_stationary_playhead = yn) == true) {
3733 // FIXME need a 3.0 equivalent of this 2.X call
3734 // update_current_screen ();
3741 Editor::playlist_selector () const
3743 return *_playlist_selector;
3747 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3751 switch (_snap_type) {
3756 case SnapToBeatDiv128:
3759 case SnapToBeatDiv64:
3762 case SnapToBeatDiv32:
3765 case SnapToBeatDiv28:
3768 case SnapToBeatDiv24:
3771 case SnapToBeatDiv20:
3774 case SnapToBeatDiv16:
3777 case SnapToBeatDiv14:
3780 case SnapToBeatDiv12:
3783 case SnapToBeatDiv10:
3786 case SnapToBeatDiv8:
3789 case SnapToBeatDiv7:
3792 case SnapToBeatDiv6:
3795 case SnapToBeatDiv5:
3798 case SnapToBeatDiv4:
3801 case SnapToBeatDiv3:
3804 case SnapToBeatDiv2:
3810 return _session->tempo_map().meter_at (position).divisions_per_bar();
3815 case SnapToTimecodeFrame:
3816 case SnapToTimecodeSeconds:
3817 case SnapToTimecodeMinutes:
3820 case SnapToRegionStart:
3821 case SnapToRegionEnd:
3822 case SnapToRegionSync:
3823 case SnapToRegionBoundary:
3833 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3837 ret = nudge_clock->current_duration (pos);
3838 next = ret + 1; /* XXXX fix me */
3844 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3846 ArdourDialog dialog (_("Playlist Deletion"));
3847 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3848 "If it is kept, its audio files will not be cleaned.\n"
3849 "If it is deleted, audio files used by it alone will be cleaned."),
3852 dialog.set_position (WIN_POS_CENTER);
3853 dialog.get_vbox()->pack_start (label);
3857 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3858 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3859 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3861 switch (dialog.run ()) {
3862 case RESPONSE_ACCEPT:
3863 /* delete the playlist */
3867 case RESPONSE_REJECT:
3868 /* keep the playlist */
3880 Editor::audio_region_selection_covers (framepos_t where)
3882 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3883 if ((*a)->region()->covers (where)) {
3892 Editor::prepare_for_cleanup ()
3894 cut_buffer->clear_regions ();
3895 cut_buffer->clear_playlists ();
3897 selection->clear_regions ();
3898 selection->clear_playlists ();
3900 _regions->suspend_redisplay ();
3904 Editor::finish_cleanup ()
3906 _regions->resume_redisplay ();
3910 Editor::transport_loop_location()
3913 return _session->locations()->auto_loop_location();
3920 Editor::transport_punch_location()
3923 return _session->locations()->auto_punch_location();
3930 Editor::control_layout_scroll (GdkEventScroll* ev)
3932 /* Just forward to the normal canvas scroll method. The coordinate
3933 systems are different but since the canvas is always larger than the
3934 track headers, and aligned with the trackview area, this will work.
3936 In the not too distant future this layout is going away anyway and
3937 headers will be on the canvas.
3939 return canvas_scroll_event (ev, false);
3943 Editor::session_state_saved (string)
3946 _snapshots->redisplay ();
3950 Editor::update_tearoff_visibility()
3952 bool visible = Config->get_keep_tearoffs();
3953 _mouse_mode_tearoff->set_visible (visible);
3954 _tools_tearoff->set_visible (visible);
3955 if (_zoom_tearoff) {
3956 _zoom_tearoff->set_visible (visible);
3961 Editor::maximise_editing_space ()
3973 Editor::restore_editing_space ()
3985 * Make new playlists for a given track and also any others that belong
3986 * to the same active route group with the `select' property.
3991 Editor::new_playlists (TimeAxisView* v)
3993 begin_reversible_command (_("new playlists"));
3994 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3995 _session->playlists->get (playlists);
3996 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
3997 commit_reversible_command ();
4001 * Use a copy of the current playlist for a given track and also any others that belong
4002 * to the same active route group with the `select' property.
4007 Editor::copy_playlists (TimeAxisView* v)
4009 begin_reversible_command (_("copy playlists"));
4010 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4011 _session->playlists->get (playlists);
4012 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4013 commit_reversible_command ();
4016 /** Clear the current playlist for a given track and also any others that belong
4017 * to the same active route group with the `select' property.
4022 Editor::clear_playlists (TimeAxisView* v)
4024 begin_reversible_command (_("clear playlists"));
4025 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4026 _session->playlists->get (playlists);
4027 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4028 commit_reversible_command ();
4032 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4034 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4038 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4040 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4044 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4046 atv.clear_playlist ();
4050 Editor::on_key_press_event (GdkEventKey* ev)
4052 return key_press_focus_accelerator_handler (*this, ev);
4056 Editor::on_key_release_event (GdkEventKey* ev)
4058 return Gtk::Window::on_key_release_event (ev);
4059 // return key_press_focus_accelerator_handler (*this, ev);
4062 /** Queue up a change to the viewport x origin.
4063 * @param frame New x origin.
4066 Editor::reset_x_origin (framepos_t frame)
4068 pending_visual_change.add (VisualChange::TimeOrigin);
4069 pending_visual_change.time_origin = frame;
4070 ensure_visual_change_idle_handler ();
4074 Editor::reset_y_origin (double y)
4076 pending_visual_change.add (VisualChange::YOrigin);
4077 pending_visual_change.y_origin = y;
4078 ensure_visual_change_idle_handler ();
4082 Editor::reset_zoom (framecnt_t spp)
4084 clamp_samples_per_pixel (spp);
4086 if (spp == samples_per_pixel) {
4090 pending_visual_change.add (VisualChange::ZoomLevel);
4091 pending_visual_change.samples_per_pixel = spp;
4092 ensure_visual_change_idle_handler ();
4096 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4098 reset_x_origin (frame);
4101 if (!no_save_visual) {
4102 undo_visual_stack.push_back (current_visual_state(false));
4106 Editor::VisualState::VisualState (bool with_tracks)
4107 : gui_state (with_tracks ? new GUIObjectState : 0)
4111 Editor::VisualState::~VisualState ()
4116 Editor::VisualState*
4117 Editor::current_visual_state (bool with_tracks)
4119 VisualState* vs = new VisualState (with_tracks);
4120 vs->y_position = vertical_adjustment.get_value();
4121 vs->samples_per_pixel = samples_per_pixel;
4122 vs->leftmost_frame = leftmost_frame;
4123 vs->zoom_focus = zoom_focus;
4126 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4133 Editor::undo_visual_state ()
4135 if (undo_visual_stack.empty()) {
4139 VisualState* vs = undo_visual_stack.back();
4140 undo_visual_stack.pop_back();
4143 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4145 use_visual_state (*vs);
4149 Editor::redo_visual_state ()
4151 if (redo_visual_stack.empty()) {
4155 VisualState* vs = redo_visual_stack.back();
4156 redo_visual_stack.pop_back();
4158 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4160 use_visual_state (*vs);
4164 Editor::swap_visual_state ()
4166 if (undo_visual_stack.empty()) {
4167 redo_visual_state ();
4169 undo_visual_state ();
4174 Editor::use_visual_state (VisualState& vs)
4176 PBD::Unwinder<bool> nsv (no_save_visual, true);
4177 DisplaySuspender ds;
4179 vertical_adjustment.set_value (vs.y_position);
4181 set_zoom_focus (vs.zoom_focus);
4182 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4185 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4187 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4188 (*i)->reset_visual_state ();
4192 _routes->update_visibility ();
4195 /** This is the core function that controls the zoom level of the canvas. It is called
4196 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4197 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4200 Editor::set_samples_per_pixel (framecnt_t spp)
4202 clamp_samples_per_pixel (spp);
4203 samples_per_pixel = spp;
4206 tempo_lines->tempo_map_changed();
4209 /* convert fpu to frame count */
4211 framepos_t frames = samples_per_pixel * _visible_canvas_width;
4213 if (samples_per_pixel != zoom_range_clock->current_duration()) {
4214 zoom_range_clock->set (frames);
4217 bool const showing_time_selection = selection->time.length() > 0;
4219 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4220 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4221 (*i)->reshow_selection (selection->time);
4225 ZoomChanged (); /* EMIT_SIGNAL */
4227 ArdourCanvas::GtkCanvasViewport* c;
4229 c = get_track_canvas();
4231 c->canvas()->zoomed ();
4234 if (playhead_cursor) {
4235 playhead_cursor->set_position (playhead_cursor->current_frame ());
4238 refresh_location_display();
4239 _summary->set_overlays_dirty ();
4241 update_marker_labels ();
4247 Editor::queue_visual_videotimeline_update ()
4250 * pending_visual_change.add (VisualChange::VideoTimeline);
4251 * or maybe even more specific: which videotimeline-image
4252 * currently it calls update_video_timeline() to update
4253 * _all outdated_ images on the video-timeline.
4254 * see 'exposeimg()' in video_image_frame.cc
4256 ensure_visual_change_idle_handler ();
4260 Editor::ensure_visual_change_idle_handler ()
4262 if (pending_visual_change.idle_handler_id < 0) {
4263 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4264 pending_visual_change.being_handled = false;
4269 Editor::_idle_visual_changer (void* arg)
4271 return static_cast<Editor*>(arg)->idle_visual_changer ();
4275 Editor::idle_visual_changer ()
4277 /* set_horizontal_position() below (and maybe other calls) call
4278 gtk_main_iteration(), so it's possible that a signal will be handled
4279 half-way through this method. If this signal wants an
4280 idle_visual_changer we must schedule another one after this one, so
4281 mark the idle_handler_id as -1 here to allow that. Also make a note
4282 that we are doing the visual change, so that changes in response to
4283 super-rapid-screen-update can be dropped if we are still processing
4287 pending_visual_change.idle_handler_id = -1;
4288 pending_visual_change.being_handled = true;
4290 VisualChange vc = pending_visual_change;
4292 pending_visual_change.pending = (VisualChange::Type) 0;
4294 visual_changer (vc);
4296 pending_visual_change.being_handled = false;
4298 return 0; /* this is always a one-shot call */
4302 Editor::visual_changer (const VisualChange& vc)
4304 double const last_time_origin = horizontal_position ();
4306 if (vc.pending & VisualChange::ZoomLevel) {
4307 set_samples_per_pixel (vc.samples_per_pixel);
4309 compute_fixed_ruler_scale ();
4311 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4312 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4314 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4315 current_bbt_points_begin, current_bbt_points_end);
4316 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4317 current_bbt_points_begin, current_bbt_points_end);
4318 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4320 update_video_timeline();
4323 if (vc.pending & VisualChange::TimeOrigin) {
4324 set_horizontal_position (vc.time_origin / samples_per_pixel);
4327 if (vc.pending & VisualChange::YOrigin) {
4328 vertical_adjustment.set_value (vc.y_origin);
4331 if (last_time_origin == horizontal_position ()) {
4332 /* changed signal not emitted */
4333 update_fixed_rulers ();
4334 redisplay_tempo (true);
4337 if (!(vc.pending & VisualChange::ZoomLevel)) {
4338 update_video_timeline();
4341 _summary->set_overlays_dirty ();
4344 struct EditorOrderTimeAxisSorter {
4345 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4346 return a->order () < b->order ();
4351 Editor::sort_track_selection (TrackViewList& sel)
4353 EditorOrderTimeAxisSorter cmp;
4358 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4361 framepos_t where = 0;
4362 EditPoint ep = _edit_point;
4364 if (from_context_menu && (ep == EditAtMouse)) {
4365 return canvas_event_sample (&context_click_event, 0, 0);
4368 if (entered_marker) {
4369 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4370 return entered_marker->position();
4373 if (ignore_playhead && ep == EditAtPlayhead) {
4374 ep = EditAtSelectedMarker;
4378 case EditAtPlayhead:
4379 where = _session->audible_frame();
4380 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4383 case EditAtSelectedMarker:
4384 if (!selection->markers.empty()) {
4386 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4389 where = loc->start();
4393 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4401 if (!mouse_frame (where, ignored)) {
4402 /* XXX not right but what can we do ? */
4406 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4414 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4416 if (!_session) return;
4418 begin_reversible_command (cmd);
4422 if ((tll = transport_loop_location()) == 0) {
4423 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4424 XMLNode &before = _session->locations()->get_state();
4425 _session->locations()->add (loc, true);
4426 _session->set_auto_loop_location (loc);
4427 XMLNode &after = _session->locations()->get_state();
4428 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4430 XMLNode &before = tll->get_state();
4431 tll->set_hidden (false, this);
4432 tll->set (start, end);
4433 XMLNode &after = tll->get_state();
4434 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4437 commit_reversible_command ();
4441 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4443 if (!_session) return;
4445 begin_reversible_command (cmd);
4449 if ((tpl = transport_punch_location()) == 0) {
4450 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4451 XMLNode &before = _session->locations()->get_state();
4452 _session->locations()->add (loc, true);
4453 _session->set_auto_punch_location (loc);
4454 XMLNode &after = _session->locations()->get_state();
4455 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4458 XMLNode &before = tpl->get_state();
4459 tpl->set_hidden (false, this);
4460 tpl->set (start, end);
4461 XMLNode &after = tpl->get_state();
4462 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4465 commit_reversible_command ();
4468 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4469 * @param rs List to which found regions are added.
4470 * @param where Time to look at.
4471 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4474 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4476 const TrackViewList* tracks;
4479 tracks = &track_views;
4484 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4486 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4489 boost::shared_ptr<Track> tr;
4490 boost::shared_ptr<Playlist> pl;
4492 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4494 boost::shared_ptr<RegionList> regions = pl->regions_at (
4495 (framepos_t) floor ( (double) where * tr->speed()));
4497 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4498 RegionView* rv = rtv->view()->find_view (*i);
4509 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4511 const TrackViewList* tracks;
4514 tracks = &track_views;
4519 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4520 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4522 boost::shared_ptr<Track> tr;
4523 boost::shared_ptr<Playlist> pl;
4525 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4527 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4528 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4530 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4532 RegionView* rv = rtv->view()->find_view (*i);
4543 /** Get regions using the following method:
4545 * Make a region list using the selected regions, unless
4546 * the edit point is `mouse' and the mouse is over an unselected
4547 * region. In this case, use just that region.
4549 * If the edit point is not 'mouse', and there are no regions selected,
4550 * search the list of selected tracks and return regions that are under
4551 * the edit point on these tracks. If there are no selected tracks and
4552 * 'No Selection = All Tracks' is active, search all tracks,
4554 * The rationale here is that the mouse edit point is special in that
4555 * its position describes both a time and a track; the other edit
4556 * modes only describe a time. Hence if the edit point is `mouse' we
4557 * ignore selected tracks, as we assume the user means something by
4558 * pointing at a particular track. Also in this case we take note of
4559 * the region directly under the edit point, as there is always just one
4560 * (rather than possibly several with non-mouse edit points).
4564 Editor::get_regions_from_selection_and_edit_point ()
4566 RegionSelection regions;
4568 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4569 regions.add (entered_regionview);
4571 regions = selection->regions;
4575 if (regions.empty() && _edit_point != EditAtMouse) {
4576 TrackViewList tracks = selection->tracks;
4578 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4579 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4580 * is enabled, so consider all tracks
4582 tracks = track_views;
4585 if (!tracks.empty()) {
4586 /* no region selected or entered, but some selected tracks:
4587 * act on all regions on the selected tracks at the edit point
4589 framepos_t const where = get_preferred_edit_position ();
4590 get_regions_at(regions, where, tracks);
4596 /** Start with regions that are selected, or the entered regionview if none are selected.
4597 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4598 * of the regions that we started with.
4602 Editor::get_regions_from_selection_and_entered ()
4604 RegionSelection regions = selection->regions;
4606 if (regions.empty() && entered_regionview) {
4607 regions.add (entered_regionview);
4614 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4616 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4618 RouteTimeAxisView* tatv;
4620 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4622 boost::shared_ptr<Playlist> pl;
4623 vector<boost::shared_ptr<Region> > results;
4625 boost::shared_ptr<Track> tr;
4627 if ((tr = tatv->track()) == 0) {
4632 if ((pl = (tr->playlist())) != 0) {
4633 if (src_comparison) {
4634 pl->get_source_equivalent_regions (region, results);
4636 pl->get_region_list_equivalent_regions (region, results);
4640 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4641 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4642 regions.push_back (marv);
4651 Editor::show_rhythm_ferret ()
4653 if (rhythm_ferret == 0) {
4654 rhythm_ferret = new RhythmFerret(*this);
4657 rhythm_ferret->set_session (_session);
4658 rhythm_ferret->show ();
4659 rhythm_ferret->present ();
4663 Editor::first_idle ()
4665 MessageDialog* dialog = 0;
4667 if (track_views.size() > 1) {
4668 dialog = new MessageDialog (
4670 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4674 ARDOUR_UI::instance()->flush_pending ();
4677 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4681 // first idle adds route children (automation tracks), so we need to redisplay here
4682 _routes->redisplay ();
4689 Editor::_idle_resize (gpointer arg)
4691 return ((Editor*)arg)->idle_resize ();
4695 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4697 if (resize_idle_id < 0) {
4698 resize_idle_id = g_idle_add (_idle_resize, this);
4699 _pending_resize_amount = 0;
4702 /* make a note of the smallest resulting height, so that we can clamp the
4703 lower limit at TimeAxisView::hSmall */
4705 int32_t min_resulting = INT32_MAX;
4707 _pending_resize_amount += h;
4708 _pending_resize_view = view;
4710 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4712 if (selection->tracks.contains (_pending_resize_view)) {
4713 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4714 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4718 if (min_resulting < 0) {
4723 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4724 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4728 /** Handle pending resizing of tracks */
4730 Editor::idle_resize ()
4732 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4734 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4735 selection->tracks.contains (_pending_resize_view)) {
4737 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4738 if (*i != _pending_resize_view) {
4739 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4744 _pending_resize_amount = 0;
4745 _group_tabs->set_dirty ();
4746 resize_idle_id = -1;
4754 ENSURE_GUI_THREAD (*this, &Editor::located);
4757 playhead_cursor->set_position (_session->audible_frame ());
4758 if (_follow_playhead && !_pending_initial_locate) {
4759 reset_x_origin_to_follow_playhead ();
4763 _pending_locate_request = false;
4764 _pending_initial_locate = false;
4768 Editor::region_view_added (RegionView *)
4770 _summary->set_background_dirty ();
4774 Editor::region_view_removed ()
4776 _summary->set_background_dirty ();
4780 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4782 TrackViewList::const_iterator j = track_views.begin ();
4783 while (j != track_views.end()) {
4784 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4785 if (rtv && rtv->route() == r) {
4796 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4800 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4801 TimeAxisView* tv = axis_view_from_route (*i);
4811 Editor::suspend_route_redisplay ()
4814 _routes->suspend_redisplay();
4819 Editor::resume_route_redisplay ()
4822 _routes->resume_redisplay();
4827 Editor::add_routes (RouteList& routes)
4829 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4831 RouteTimeAxisView *rtv;
4832 list<RouteTimeAxisView*> new_views;
4834 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4835 boost::shared_ptr<Route> route = (*x);
4837 if (route->is_auditioner() || route->is_monitor()) {
4841 DataType dt = route->input()->default_type();
4843 if (dt == ARDOUR::DataType::AUDIO) {
4844 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4845 rtv->set_route (route);
4846 } else if (dt == ARDOUR::DataType::MIDI) {
4847 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4848 rtv->set_route (route);
4850 throw unknown_type();
4853 new_views.push_back (rtv);
4854 track_views.push_back (rtv);
4856 rtv->effective_gain_display ();
4858 if (internal_editing()) {
4859 rtv->enter_internal_edit_mode ();
4861 rtv->leave_internal_edit_mode ();
4864 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4865 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4868 if (new_views.size() > 0) {
4869 _routes->routes_added (new_views);
4870 _summary->routes_added (new_views);
4873 if (show_editor_mixer_when_tracks_arrive) {
4874 show_editor_mixer (true);
4877 editor_list_button.set_sensitive (true);
4881 Editor::timeaxisview_deleted (TimeAxisView *tv)
4883 if (tv == entered_track) {
4887 if (_session && _session->deletion_in_progress()) {
4888 /* the situation is under control */
4892 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4894 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4896 _routes->route_removed (tv);
4898 TimeAxisView::Children c = tv->get_child_list ();
4899 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4900 if (entered_track == i->get()) {
4905 /* remove it from the list of track views */
4907 TrackViewList::iterator i;
4909 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4910 i = track_views.erase (i);
4913 /* update whatever the current mixer strip is displaying, if revelant */
4915 boost::shared_ptr<Route> route;
4918 route = rtav->route ();
4921 if (current_mixer_strip && current_mixer_strip->route() == route) {
4923 TimeAxisView* next_tv;
4925 if (track_views.empty()) {
4927 } else if (i == track_views.end()) {
4928 next_tv = track_views.front();
4935 set_selected_mixer_strip (*next_tv);
4937 /* make the editor mixer strip go away setting the
4938 * button to inactive (which also unticks the menu option)
4941 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4947 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4949 if (apply_to_selection) {
4950 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4952 TrackSelection::iterator j = i;
4955 hide_track_in_display (*i, false);
4960 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4962 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4963 // this will hide the mixer strip
4964 set_selected_mixer_strip (*tv);
4967 _routes->hide_track_in_display (*tv);
4972 Editor::sync_track_view_list_and_routes ()
4974 track_views = TrackViewList (_routes->views ());
4976 _summary->set_dirty ();
4977 _group_tabs->set_dirty ();
4979 return false; // do not call again (until needed)
4983 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4985 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4990 /** Find a RouteTimeAxisView by the ID of its route */
4992 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4994 RouteTimeAxisView* v;
4996 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4997 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4998 if(v->route()->id() == id) {
5008 Editor::fit_route_group (RouteGroup *g)
5010 TrackViewList ts = axis_views_from_routes (g->route_list ());
5015 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5017 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5020 _session->cancel_audition ();
5024 if (_session->is_auditioning()) {
5025 _session->cancel_audition ();
5026 if (r == last_audition_region) {
5031 _session->audition_region (r);
5032 last_audition_region = r;
5037 Editor::hide_a_region (boost::shared_ptr<Region> r)
5039 r->set_hidden (true);
5043 Editor::show_a_region (boost::shared_ptr<Region> r)
5045 r->set_hidden (false);
5049 Editor::audition_region_from_region_list ()
5051 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5055 Editor::hide_region_from_region_list ()
5057 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5061 Editor::show_region_in_region_list ()
5063 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5067 Editor::step_edit_status_change (bool yn)
5070 start_step_editing ();
5072 stop_step_editing ();
5077 Editor::start_step_editing ()
5079 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5083 Editor::stop_step_editing ()
5085 step_edit_connection.disconnect ();
5089 Editor::check_step_edit ()
5091 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5092 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5094 mtv->check_step_edit ();
5098 return true; // do it again, till we stop
5102 Editor::scroll_press (Direction dir)
5104 ++_scroll_callbacks;
5106 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5107 /* delay the first auto-repeat */
5113 scroll_backward (1);
5121 scroll_tracks_up_line ();
5125 scroll_tracks_down_line ();
5129 /* do hacky auto-repeat */
5130 if (!_scroll_connection.connected ()) {
5132 _scroll_connection = Glib::signal_timeout().connect (
5133 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5136 _scroll_callbacks = 0;
5143 Editor::scroll_release ()
5145 _scroll_connection.disconnect ();
5148 /** Queue a change for the Editor viewport x origin to follow the playhead */
5150 Editor::reset_x_origin_to_follow_playhead ()
5152 framepos_t const frame = playhead_cursor->current_frame ();
5154 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5156 if (_session->transport_speed() < 0) {
5158 if (frame > (current_page_samples() / 2)) {
5159 center_screen (frame-(current_page_samples()/2));
5161 center_screen (current_page_samples()/2);
5168 if (frame < leftmost_frame) {
5170 if (_session->transport_rolling()) {
5171 /* rolling; end up with the playhead at the right of the page */
5172 l = frame - current_page_samples ();
5174 /* not rolling: end up with the playhead 1/4 of the way along the page */
5175 l = frame - current_page_samples() / 4;
5179 if (_session->transport_rolling()) {
5180 /* rolling: end up with the playhead on the left of the page */
5183 /* not rolling: end up with the playhead 3/4 of the way along the page */
5184 l = frame - 3 * current_page_samples() / 4;
5192 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5198 Editor::super_rapid_screen_update ()
5200 if (!_session || !_session->engine().running()) {
5204 /* METERING / MIXER STRIPS */
5206 /* update track meters, if required */
5207 if (is_mapped() && meters_running) {
5208 RouteTimeAxisView* rtv;
5209 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5210 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5211 rtv->fast_update ();
5216 /* and any current mixer strip */
5217 if (current_mixer_strip) {
5218 current_mixer_strip->fast_update ();
5221 /* PLAYHEAD AND VIEWPORT */
5223 framepos_t const frame = _session->audible_frame();
5225 /* There are a few reasons why we might not update the playhead / viewport stuff:
5227 * 1. we don't update things when there's a pending locate request, otherwise
5228 * when the editor requests a locate there is a chance that this method
5229 * will move the playhead before the locate request is processed, causing
5231 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5232 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5235 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5237 last_update_frame = frame;
5239 if (!_dragging_playhead) {
5240 playhead_cursor->set_position (frame);
5243 if (!_stationary_playhead) {
5245 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5246 /* We only do this if we aren't already
5247 handling a visual change (ie if
5248 pending_visual_change.being_handled is
5249 false) so that these requests don't stack
5250 up there are too many of them to handle in
5253 reset_x_origin_to_follow_playhead ();
5258 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5262 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5263 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5264 if (target <= 0.0) {
5267 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5268 target = (target * 0.15) + (current * 0.85);
5274 set_horizontal_position (current);
5283 Editor::session_going_away ()
5285 _have_idled = false;
5287 _session_connections.drop_connections ();
5289 super_rapid_screen_update_connection.disconnect ();
5291 selection->clear ();
5292 cut_buffer->clear ();
5294 clicked_regionview = 0;
5295 clicked_axisview = 0;
5296 clicked_routeview = 0;
5297 entered_regionview = 0;
5299 last_update_frame = 0;
5302 playhead_cursor->hide ();
5304 /* rip everything out of the list displays */
5308 _route_groups->clear ();
5310 /* do this first so that deleting a track doesn't reset cms to null
5311 and thus cause a leak.
5314 if (current_mixer_strip) {
5315 if (current_mixer_strip->get_parent() != 0) {
5316 global_hpacker.remove (*current_mixer_strip);
5318 delete current_mixer_strip;
5319 current_mixer_strip = 0;
5322 /* delete all trackviews */
5324 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5327 track_views.clear ();
5329 zoom_range_clock->set_session (0);
5330 nudge_clock->set_session (0);
5332 editor_list_button.set_active(false);
5333 editor_list_button.set_sensitive(false);
5335 /* clear tempo/meter rulers */
5336 remove_metric_marks ();
5338 clear_marker_display ();
5340 stop_step_editing ();
5342 /* get rid of any existing editor mixer strip */
5344 WindowTitle title(Glib::get_application_name());
5345 title += _("Editor");
5347 set_title (title.get_string());
5349 SessionHandlePtr::session_going_away ();
5354 Editor::show_editor_list (bool yn)
5357 _the_notebook.show ();
5359 _the_notebook.hide ();
5364 Editor::change_region_layering_order (bool from_context_menu)
5366 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5368 if (!clicked_routeview) {
5369 if (layering_order_editor) {
5370 layering_order_editor->hide ();
5375 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5381 boost::shared_ptr<Playlist> pl = track->playlist();
5387 if (layering_order_editor == 0) {
5388 layering_order_editor = new RegionLayeringOrderEditor (*this);
5391 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5392 layering_order_editor->maybe_present ();
5396 Editor::update_region_layering_order_editor ()
5398 if (layering_order_editor && layering_order_editor->is_visible ()) {
5399 change_region_layering_order (true);
5404 Editor::setup_fade_images ()
5406 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5407 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5408 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5409 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5410 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5412 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5413 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5414 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5415 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5416 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5418 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5419 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5420 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5421 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5422 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5424 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5425 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5426 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5427 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5428 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5432 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5434 Editor::action_menu_item (std::string const & name)
5436 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5439 return *manage (a->create_menu_item ());
5443 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5445 EventBox* b = manage (new EventBox);
5446 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5447 Label* l = manage (new Label (name));
5451 _the_notebook.append_page (widget, *b);
5455 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5457 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5458 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5461 if (ev->type == GDK_2BUTTON_PRESS) {
5463 /* double-click on a notebook tab shrinks or expands the notebook */
5465 if (_notebook_shrunk) {
5466 if (pre_notebook_shrink_pane_width) {
5467 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5469 _notebook_shrunk = false;
5471 pre_notebook_shrink_pane_width = edit_pane.get_position();
5473 /* this expands the LHS of the edit pane to cover the notebook
5474 PAGE but leaves the tabs visible.
5476 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5477 _notebook_shrunk = true;
5485 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5487 using namespace Menu_Helpers;
5489 MenuList& items = _control_point_context_menu.items ();
5492 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5493 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5494 if (!can_remove_control_point (item)) {
5495 items.back().set_sensitive (false);
5498 _control_point_context_menu.popup (event->button.button, event->button.time);
5502 Editor::zoom_vertical_modifier_released()
5504 _stepping_axis_view = 0;
5508 Editor::ui_parameter_changed (string parameter)
5510 if (parameter == "icon-set") {
5511 while (!_cursor_stack.empty()) {
5512 _cursor_stack.pop();
5514 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5515 } else if (parameter == "draggable-playhead") {
5516 if (_verbose_cursor) {
5517 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());