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_selector.set_name ("mouse mode button");
2829 edit_mode_selector.set_size_request (65, -1);
2830 edit_mode_selector.add_elements (ArdourButton::Inset);
2832 if (!ARDOUR::Profile->get_trx()) {
2833 mode_box->pack_start (edit_mode_selector, false, false);
2835 mode_box->pack_start (*mouse_mode_box, false, false);
2837 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2838 _mouse_mode_tearoff->set_name ("MouseModeBase");
2839 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2841 if (Profile->get_sae()) {
2842 _mouse_mode_tearoff->set_can_be_torn_off (false);
2845 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2846 &_mouse_mode_tearoff->tearoff_window()));
2847 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2848 &_mouse_mode_tearoff->tearoff_window(), 1));
2849 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2850 &_mouse_mode_tearoff->tearoff_window()));
2851 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2852 &_mouse_mode_tearoff->tearoff_window(), 1));
2856 _zoom_box.set_spacing (2);
2857 _zoom_box.set_border_width (2);
2861 zoom_in_button.set_name ("zoom button");
2862 // zoom_in_button.add_elements ( ArdourButton::Inset );
2863 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2864 zoom_in_button.set_image(::get_icon ("zoom_in"));
2865 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2866 zoom_in_button.set_related_action (act);
2868 zoom_out_button.set_name ("zoom button");
2869 // zoom_out_button.add_elements ( ArdourButton::Inset );
2870 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2871 zoom_out_button.set_image(::get_icon ("zoom_out"));
2872 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2873 zoom_out_button.set_related_action (act);
2875 zoom_out_full_button.set_name ("zoom button");
2876 // zoom_out_full_button.add_elements ( ArdourButton::Inset );
2877 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2878 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2879 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2880 zoom_out_full_button.set_related_action (act);
2882 zoom_focus_selector.set_name ("zoom button");
2883 zoom_focus_selector.set_size_request (80, -1);
2884 // zoom_focus_selector.add_elements (ArdourButton::Inset);
2886 if (!ARDOUR::Profile->get_trx()) {
2887 _zoom_box.pack_start (zoom_out_button, false, false);
2888 _zoom_box.pack_start (zoom_in_button, false, false);
2889 _zoom_box.pack_start (zoom_out_full_button, false, false);
2890 _zoom_box.pack_start (zoom_focus_selector, false, false);
2892 mode_box->pack_start (zoom_out_button, false, false);
2893 mode_box->pack_start (zoom_in_button, false, false);
2896 /* Track zoom buttons */
2897 visible_tracks_selector.set_name ("zoom button");
2898 // visible_tracks_selector.add_elements ( ArdourButton::Inset );
2899 set_size_request_to_display_given_text (visible_tracks_selector, _("all"), 40, 2);
2901 tav_expand_button.set_name ("zoom button");
2902 // tav_expand_button.add_elements ( ArdourButton::FlatFace );
2903 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2904 tav_expand_button.set_size_request (-1, 20);
2905 tav_expand_button.set_image(::get_icon ("tav_exp"));
2906 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2907 tav_expand_button.set_related_action (act);
2909 tav_shrink_button.set_name ("zoom button");
2910 // tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2911 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2912 tav_shrink_button.set_size_request (-1, 20);
2913 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2914 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2915 tav_shrink_button.set_related_action (act);
2917 if (!ARDOUR::Profile->get_trx()) {
2918 _zoom_box.pack_start (visible_tracks_selector);
2920 _zoom_box.pack_start (tav_shrink_button);
2921 _zoom_box.pack_start (tav_expand_button);
2923 if (!ARDOUR::Profile->get_trx()) {
2924 _zoom_tearoff = manage (new TearOff (_zoom_box));
2926 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2927 &_zoom_tearoff->tearoff_window()));
2928 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2929 &_zoom_tearoff->tearoff_window(), 0));
2930 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2931 &_zoom_tearoff->tearoff_window()));
2932 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2933 &_zoom_tearoff->tearoff_window(), 0));
2936 snap_box.set_spacing (2);
2937 snap_box.set_border_width (2);
2939 snap_type_selector.set_name ("mouse mode button");
2940 snap_type_selector.set_size_request (140, -1);
2941 snap_type_selector.add_elements (ArdourButton::Inset);
2943 snap_mode_selector.set_name ("mouse mode button");
2944 snap_mode_selector.set_size_request (85, -1);
2945 snap_mode_selector.add_elements (ArdourButton::Inset);
2947 edit_point_selector.set_name ("mouse mode button");
2948 edit_point_selector.set_size_request (85, -1);
2949 edit_point_selector.add_elements (ArdourButton::Inset);
2951 snap_box.pack_start (snap_mode_selector, false, false);
2952 snap_box.pack_start (snap_type_selector, false, false);
2953 snap_box.pack_start (edit_point_selector, false, false);
2957 HBox *nudge_box = manage (new HBox);
2958 nudge_box->set_spacing (2);
2959 nudge_box->set_border_width (2);
2961 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2962 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2964 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2965 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2967 nudge_box->pack_start (nudge_backward_button, false, false);
2968 nudge_box->pack_start (nudge_forward_button, false, false);
2969 nudge_box->pack_start (*nudge_clock, false, false);
2972 /* Pack everything in... */
2974 HBox* hbox = manage (new HBox);
2975 hbox->set_spacing(10);
2977 _tools_tearoff = manage (new TearOff (*hbox));
2978 _tools_tearoff->set_name ("MouseModeBase");
2979 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2981 if (Profile->get_sae()) {
2982 _tools_tearoff->set_can_be_torn_off (false);
2985 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2986 &_tools_tearoff->tearoff_window()));
2987 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2988 &_tools_tearoff->tearoff_window(), 0));
2989 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2990 &_tools_tearoff->tearoff_window()));
2991 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2992 &_tools_tearoff->tearoff_window(), 0));
2994 toolbar_hbox.set_spacing (10);
2995 toolbar_hbox.set_border_width (1);
2997 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2998 if (!ARDOUR::Profile->get_trx()) {
2999 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3000 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3003 if (!ARDOUR::Profile->get_trx()) {
3004 hbox->pack_start (snap_box, false, false);
3005 if (!Profile->get_small_screen()) {
3006 hbox->pack_start (*nudge_box, false, false);
3008 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3011 hbox->pack_start (panic_box, false, false);
3015 toolbar_base.set_name ("ToolBarBase");
3016 toolbar_base.add (toolbar_hbox);
3018 _toolbar_viewport.add (toolbar_base);
3019 /* stick to the required height but allow width to vary if there's not enough room */
3020 _toolbar_viewport.set_size_request (1, -1);
3022 toolbar_frame.set_shadow_type (SHADOW_OUT);
3023 toolbar_frame.set_name ("BaseFrame");
3024 toolbar_frame.add (_toolbar_viewport);
3028 Editor::build_edit_point_menu ()
3030 using namespace Menu_Helpers;
3032 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3033 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3034 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3038 Editor::build_edit_mode_menu ()
3040 using namespace Menu_Helpers;
3042 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Slide), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3043 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Splice), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3044 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Ripple), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3045 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Lock), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3049 Editor::build_snap_mode_menu ()
3051 using namespace Menu_Helpers;
3053 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3054 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3055 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3059 Editor::build_snap_type_menu ()
3061 using namespace Menu_Helpers;
3063 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3064 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3065 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3066 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3067 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3068 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3069 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3070 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3071 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3072 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3073 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3074 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3075 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3076 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3077 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3078 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3079 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3080 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3081 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3082 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3083 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3084 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3085 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3086 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3087 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3088 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3089 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3090 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3091 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3092 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3096 Editor::setup_tooltips ()
3098 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3099 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3100 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3101 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3102 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3103 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3104 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3105 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3106 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3107 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3108 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3109 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3110 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3111 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3112 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3113 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3114 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3115 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3116 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3117 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3118 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3119 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3120 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3121 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3125 Editor::convert_drop_to_paths (
3126 vector<string>& paths,
3127 const RefPtr<Gdk::DragContext>& /*context*/,
3130 const SelectionData& data,
3134 if (_session == 0) {
3138 vector<string> uris = data.get_uris();
3142 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3143 are actually URI lists. So do it by hand.
3146 if (data.get_target() != "text/plain") {
3150 /* Parse the "uri-list" format that Nautilus provides,
3151 where each pathname is delimited by \r\n.
3153 THERE MAY BE NO NULL TERMINATING CHAR!!!
3156 string txt = data.get_text();
3160 p = (char *) malloc (txt.length() + 1);
3161 txt.copy (p, txt.length(), 0);
3162 p[txt.length()] = '\0';
3168 while (g_ascii_isspace (*p))
3172 while (*q && (*q != '\n') && (*q != '\r')) {
3179 while (q > p && g_ascii_isspace (*q))
3184 uris.push_back (string (p, q - p + 1));
3188 p = strchr (p, '\n');
3200 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3201 if ((*i).substr (0,7) == "file://") {
3202 paths.push_back (Glib::filename_from_uri (*i));
3210 Editor::new_tempo_section ()
3215 Editor::map_transport_state ()
3217 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3219 if (_session && _session->transport_stopped()) {
3220 have_pending_keyboard_selection = false;
3223 update_loop_range_view ();
3229 Editor::begin_reversible_command (string name)
3232 _session->begin_reversible_command (name);
3237 Editor::begin_reversible_command (GQuark q)
3240 _session->begin_reversible_command (q);
3245 Editor::commit_reversible_command ()
3248 _session->commit_reversible_command ();
3253 Editor::history_changed ()
3257 if (undo_action && _session) {
3258 if (_session->undo_depth() == 0) {
3259 label = S_("Command|Undo");
3261 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3263 undo_action->property_label() = label;
3266 if (redo_action && _session) {
3267 if (_session->redo_depth() == 0) {
3270 label = string_compose(_("Redo (%1)"), _session->next_redo());
3272 redo_action->property_label() = label;
3277 Editor::duplicate_range (bool with_dialog)
3281 RegionSelection rs = get_regions_from_selection_and_entered ();
3283 if ( selection->time.length() == 0 && rs.empty()) {
3289 ArdourDialog win (_("Duplicate"));
3290 Label label (_("Number of duplications:"));
3291 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3292 SpinButton spinner (adjustment, 0.0, 1);
3295 win.get_vbox()->set_spacing (12);
3296 win.get_vbox()->pack_start (hbox);
3297 hbox.set_border_width (6);
3298 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3300 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3301 place, visually. so do this by hand.
3304 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3305 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3306 spinner.grab_focus();
3312 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3313 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3314 win.set_default_response (RESPONSE_ACCEPT);
3316 spinner.grab_focus ();
3318 switch (win.run ()) {
3319 case RESPONSE_ACCEPT:
3325 times = adjustment.get_value();
3328 if ((current_mouse_mode() == Editing::MouseRange)) {
3329 if (selection->time.length()) {
3330 duplicate_selection (times);
3332 } else if (get_smart_mode()) {
3333 if (selection->time.length()) {
3334 duplicate_selection (times);
3336 duplicate_some_regions (rs, times);
3338 duplicate_some_regions (rs, times);
3343 Editor::set_edit_mode (EditMode m)
3345 Config->set_edit_mode (m);
3349 Editor::cycle_edit_mode ()
3351 switch (Config->get_edit_mode()) {
3353 if (Profile->get_sae()) {
3354 Config->set_edit_mode (Lock);
3356 Config->set_edit_mode (Ripple);
3361 Config->set_edit_mode (Lock);
3364 Config->set_edit_mode (Slide);
3370 Editor::edit_mode_selection_done ( EditMode m )
3372 Config->set_edit_mode ( m );
3376 Editor::snap_type_selection_done (SnapType snaptype)
3378 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3380 ract->set_active ();
3385 Editor::snap_mode_selection_done (SnapMode mode)
3387 RefPtr<RadioAction> ract = snap_mode_action (mode);
3390 ract->set_active (true);
3395 Editor::cycle_edit_point (bool with_marker)
3397 switch (_edit_point) {
3399 set_edit_point_preference (EditAtPlayhead);
3401 case EditAtPlayhead:
3403 set_edit_point_preference (EditAtSelectedMarker);
3405 set_edit_point_preference (EditAtMouse);
3408 case EditAtSelectedMarker:
3409 set_edit_point_preference (EditAtMouse);
3415 Editor::edit_point_selection_done (EditPoint ep)
3417 set_edit_point_preference ( ep );
3421 Editor::build_zoom_focus_menu ()
3423 using namespace Menu_Helpers;
3425 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3426 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3427 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3428 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3429 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3430 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3434 Editor::zoom_focus_selection_done ( ZoomFocus f )
3436 RefPtr<RadioAction> ract = zoom_focus_action (f);
3438 ract->set_active ();
3443 Editor::build_track_count_menu ()
3445 using namespace Menu_Helpers;
3447 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3448 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3449 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3450 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3451 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3452 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3453 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3454 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3455 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3456 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3457 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3458 visible_tracks_selector.AddMenuElem (MenuElem (_("all"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3462 Editor::set_visible_track_count (int32_t n)
3464 _visible_track_count = n;
3466 /* if the canvas hasn't really been allocated any size yet, just
3467 record the desired number of visible tracks and return. when canvas
3468 allocation happens, we will get called again and then we can do the
3472 if (_visible_canvas_height <= 1) {
3479 if (_visible_track_count > 0) {
3480 h = _visible_canvas_height / _visible_track_count;
3481 std::ostringstream s;
3482 s << _visible_track_count;
3484 } else if (_visible_track_count == 0) {
3485 h = _visible_canvas_height / track_views.size();
3488 /* negative value means that the visible track count has
3489 been overridden by explicit track height changes.
3491 visible_tracks_selector.set_text (X_("*"));
3495 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3496 (*i)->set_height (h);
3499 if (str != visible_tracks_selector.get_text()) {
3500 visible_tracks_selector.set_text (str);
3505 Editor::override_visible_track_count ()
3507 _visible_track_count = -_visible_track_count;
3511 Editor::edit_controls_button_release (GdkEventButton* ev)
3513 if (Keyboard::is_context_menu_event (ev)) {
3514 ARDOUR_UI::instance()->add_route (this);
3515 } else if (ev->button == 1) {
3516 selection->clear_tracks ();
3523 Editor::mouse_select_button_release (GdkEventButton* ev)
3525 /* this handles just right-clicks */
3527 if (ev->button != 3) {
3535 Editor::set_zoom_focus (ZoomFocus f)
3537 string str = zoom_focus_strings[(int)f];
3539 if (str != zoom_focus_selector.get_text()) {
3540 zoom_focus_selector.set_text (str);
3543 if (zoom_focus != f) {
3550 Editor::cycle_zoom_focus ()
3552 switch (zoom_focus) {
3554 set_zoom_focus (ZoomFocusRight);
3556 case ZoomFocusRight:
3557 set_zoom_focus (ZoomFocusCenter);
3559 case ZoomFocusCenter:
3560 set_zoom_focus (ZoomFocusPlayhead);
3562 case ZoomFocusPlayhead:
3563 set_zoom_focus (ZoomFocusMouse);
3565 case ZoomFocusMouse:
3566 set_zoom_focus (ZoomFocusEdit);
3569 set_zoom_focus (ZoomFocusLeft);
3575 Editor::ensure_float (Window& win)
3577 win.set_transient_for (*this);
3581 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3583 /* recover or initialize pane positions. do this here rather than earlier because
3584 we don't want the positions to change the child allocations, which they seem to do.
3590 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3599 XMLNode* geometry = find_named_node (*node, "geometry");
3601 if (which == static_cast<Paned*> (&edit_pane)) {
3603 if (done & Horizontal) {
3607 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3608 _notebook_shrunk = string_is_affirmative (prop->value ());
3611 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3612 /* initial allocation is 90% to canvas, 10% to notebook */
3613 pos = (int) floor (alloc.get_width() * 0.90f);
3614 snprintf (buf, sizeof(buf), "%d", pos);
3616 pos = atoi (prop->value());
3619 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3620 edit_pane.set_position (pos);
3623 done = (Pane) (done | Horizontal);
3625 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3627 if (done & Vertical) {
3631 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3632 /* initial allocation is 90% to canvas, 10% to summary */
3633 pos = (int) floor (alloc.get_height() * 0.90f);
3634 snprintf (buf, sizeof(buf), "%d", pos);
3637 pos = atoi (prop->value());
3640 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3641 editor_summary_pane.set_position (pos);
3644 done = (Pane) (done | Vertical);
3649 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3651 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3652 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3653 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3654 top_hbox.remove (toolbar_frame);
3659 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3661 if (toolbar_frame.get_parent() == 0) {
3662 top_hbox.pack_end (toolbar_frame);
3667 Editor::set_show_measures (bool yn)
3669 if (_show_measures != yn) {
3672 if ((_show_measures = yn) == true) {
3674 tempo_lines->show();
3677 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3678 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3680 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3681 draw_measures (begin, end);
3689 Editor::toggle_follow_playhead ()
3691 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3693 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3694 set_follow_playhead (tact->get_active());
3698 /** @param yn true to follow playhead, otherwise false.
3699 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3702 Editor::set_follow_playhead (bool yn, bool catch_up)
3704 if (_follow_playhead != yn) {
3705 if ((_follow_playhead = yn) == true && catch_up) {
3707 reset_x_origin_to_follow_playhead ();
3714 Editor::toggle_stationary_playhead ()
3716 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3718 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3719 set_stationary_playhead (tact->get_active());
3724 Editor::set_stationary_playhead (bool yn)
3726 if (_stationary_playhead != yn) {
3727 if ((_stationary_playhead = yn) == true) {
3729 // FIXME need a 3.0 equivalent of this 2.X call
3730 // update_current_screen ();
3737 Editor::playlist_selector () const
3739 return *_playlist_selector;
3743 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3747 switch (_snap_type) {
3752 case SnapToBeatDiv128:
3755 case SnapToBeatDiv64:
3758 case SnapToBeatDiv32:
3761 case SnapToBeatDiv28:
3764 case SnapToBeatDiv24:
3767 case SnapToBeatDiv20:
3770 case SnapToBeatDiv16:
3773 case SnapToBeatDiv14:
3776 case SnapToBeatDiv12:
3779 case SnapToBeatDiv10:
3782 case SnapToBeatDiv8:
3785 case SnapToBeatDiv7:
3788 case SnapToBeatDiv6:
3791 case SnapToBeatDiv5:
3794 case SnapToBeatDiv4:
3797 case SnapToBeatDiv3:
3800 case SnapToBeatDiv2:
3806 return _session->tempo_map().meter_at (position).divisions_per_bar();
3811 case SnapToTimecodeFrame:
3812 case SnapToTimecodeSeconds:
3813 case SnapToTimecodeMinutes:
3816 case SnapToRegionStart:
3817 case SnapToRegionEnd:
3818 case SnapToRegionSync:
3819 case SnapToRegionBoundary:
3829 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3833 ret = nudge_clock->current_duration (pos);
3834 next = ret + 1; /* XXXX fix me */
3840 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3842 ArdourDialog dialog (_("Playlist Deletion"));
3843 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3844 "If it is kept, its audio files will not be cleaned.\n"
3845 "If it is deleted, audio files used by it alone will be cleaned."),
3848 dialog.set_position (WIN_POS_CENTER);
3849 dialog.get_vbox()->pack_start (label);
3853 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3854 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3855 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3857 switch (dialog.run ()) {
3858 case RESPONSE_ACCEPT:
3859 /* delete the playlist */
3863 case RESPONSE_REJECT:
3864 /* keep the playlist */
3876 Editor::audio_region_selection_covers (framepos_t where)
3878 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3879 if ((*a)->region()->covers (where)) {
3888 Editor::prepare_for_cleanup ()
3890 cut_buffer->clear_regions ();
3891 cut_buffer->clear_playlists ();
3893 selection->clear_regions ();
3894 selection->clear_playlists ();
3896 _regions->suspend_redisplay ();
3900 Editor::finish_cleanup ()
3902 _regions->resume_redisplay ();
3906 Editor::transport_loop_location()
3909 return _session->locations()->auto_loop_location();
3916 Editor::transport_punch_location()
3919 return _session->locations()->auto_punch_location();
3926 Editor::control_layout_scroll (GdkEventScroll* ev)
3928 /* Just forward to the normal canvas scroll method. The coordinate
3929 systems are different but since the canvas is always larger than the
3930 track headers, and aligned with the trackview area, this will work.
3932 In the not too distant future this layout is going away anyway and
3933 headers will be on the canvas.
3935 return canvas_scroll_event (ev, false);
3939 Editor::session_state_saved (string)
3942 _snapshots->redisplay ();
3946 Editor::update_tearoff_visibility()
3948 bool visible = Config->get_keep_tearoffs();
3949 _mouse_mode_tearoff->set_visible (visible);
3950 _tools_tearoff->set_visible (visible);
3951 if (_zoom_tearoff) {
3952 _zoom_tearoff->set_visible (visible);
3957 Editor::maximise_editing_space ()
3969 Editor::restore_editing_space ()
3981 * Make new playlists for a given track and also any others that belong
3982 * to the same active route group with the `select' property.
3987 Editor::new_playlists (TimeAxisView* v)
3989 begin_reversible_command (_("new playlists"));
3990 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3991 _session->playlists->get (playlists);
3992 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
3993 commit_reversible_command ();
3997 * Use a copy of the current playlist for a given track and also any others that belong
3998 * to the same active route group with the `select' property.
4003 Editor::copy_playlists (TimeAxisView* v)
4005 begin_reversible_command (_("copy playlists"));
4006 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4007 _session->playlists->get (playlists);
4008 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4009 commit_reversible_command ();
4012 /** Clear the current playlist for a given track and also any others that belong
4013 * to the same active route group with the `select' property.
4018 Editor::clear_playlists (TimeAxisView* v)
4020 begin_reversible_command (_("clear playlists"));
4021 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4022 _session->playlists->get (playlists);
4023 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4024 commit_reversible_command ();
4028 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4030 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4034 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4036 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4040 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4042 atv.clear_playlist ();
4046 Editor::on_key_press_event (GdkEventKey* ev)
4048 return key_press_focus_accelerator_handler (*this, ev);
4052 Editor::on_key_release_event (GdkEventKey* ev)
4054 return Gtk::Window::on_key_release_event (ev);
4055 // return key_press_focus_accelerator_handler (*this, ev);
4058 /** Queue up a change to the viewport x origin.
4059 * @param frame New x origin.
4062 Editor::reset_x_origin (framepos_t frame)
4064 pending_visual_change.add (VisualChange::TimeOrigin);
4065 pending_visual_change.time_origin = frame;
4066 ensure_visual_change_idle_handler ();
4070 Editor::reset_y_origin (double y)
4072 pending_visual_change.add (VisualChange::YOrigin);
4073 pending_visual_change.y_origin = y;
4074 ensure_visual_change_idle_handler ();
4078 Editor::reset_zoom (framecnt_t spp)
4080 clamp_samples_per_pixel (spp);
4082 if (spp == samples_per_pixel) {
4086 pending_visual_change.add (VisualChange::ZoomLevel);
4087 pending_visual_change.samples_per_pixel = spp;
4088 ensure_visual_change_idle_handler ();
4092 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4094 reset_x_origin (frame);
4097 if (!no_save_visual) {
4098 undo_visual_stack.push_back (current_visual_state(false));
4102 Editor::VisualState::VisualState (bool with_tracks)
4103 : gui_state (with_tracks ? new GUIObjectState : 0)
4107 Editor::VisualState::~VisualState ()
4112 Editor::VisualState*
4113 Editor::current_visual_state (bool with_tracks)
4115 VisualState* vs = new VisualState (with_tracks);
4116 vs->y_position = vertical_adjustment.get_value();
4117 vs->samples_per_pixel = samples_per_pixel;
4118 vs->leftmost_frame = leftmost_frame;
4119 vs->zoom_focus = zoom_focus;
4122 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4129 Editor::undo_visual_state ()
4131 if (undo_visual_stack.empty()) {
4135 VisualState* vs = undo_visual_stack.back();
4136 undo_visual_stack.pop_back();
4139 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4141 use_visual_state (*vs);
4145 Editor::redo_visual_state ()
4147 if (redo_visual_stack.empty()) {
4151 VisualState* vs = redo_visual_stack.back();
4152 redo_visual_stack.pop_back();
4154 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4156 use_visual_state (*vs);
4160 Editor::swap_visual_state ()
4162 if (undo_visual_stack.empty()) {
4163 redo_visual_state ();
4165 undo_visual_state ();
4170 Editor::use_visual_state (VisualState& vs)
4172 PBD::Unwinder<bool> nsv (no_save_visual, true);
4173 DisplaySuspender ds;
4175 vertical_adjustment.set_value (vs.y_position);
4177 set_zoom_focus (vs.zoom_focus);
4178 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4181 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4183 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4184 (*i)->reset_visual_state ();
4188 _routes->update_visibility ();
4191 /** This is the core function that controls the zoom level of the canvas. It is called
4192 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4193 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4196 Editor::set_samples_per_pixel (framecnt_t spp)
4198 clamp_samples_per_pixel (spp);
4199 samples_per_pixel = spp;
4202 tempo_lines->tempo_map_changed();
4205 /* convert fpu to frame count */
4207 framepos_t frames = samples_per_pixel * _visible_canvas_width;
4209 if (samples_per_pixel != zoom_range_clock->current_duration()) {
4210 zoom_range_clock->set (frames);
4213 bool const showing_time_selection = selection->time.length() > 0;
4215 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4216 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4217 (*i)->reshow_selection (selection->time);
4221 ZoomChanged (); /* EMIT_SIGNAL */
4223 ArdourCanvas::GtkCanvasViewport* c;
4225 c = get_track_canvas();
4227 c->canvas()->zoomed ();
4230 if (playhead_cursor) {
4231 playhead_cursor->set_position (playhead_cursor->current_frame ());
4234 refresh_location_display();
4235 _summary->set_overlays_dirty ();
4237 update_marker_labels ();
4243 Editor::queue_visual_videotimeline_update ()
4246 * pending_visual_change.add (VisualChange::VideoTimeline);
4247 * or maybe even more specific: which videotimeline-image
4248 * currently it calls update_video_timeline() to update
4249 * _all outdated_ images on the video-timeline.
4250 * see 'exposeimg()' in video_image_frame.cc
4252 ensure_visual_change_idle_handler ();
4256 Editor::ensure_visual_change_idle_handler ()
4258 if (pending_visual_change.idle_handler_id < 0) {
4259 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4260 pending_visual_change.being_handled = false;
4265 Editor::_idle_visual_changer (void* arg)
4267 return static_cast<Editor*>(arg)->idle_visual_changer ();
4271 Editor::idle_visual_changer ()
4273 /* set_horizontal_position() below (and maybe other calls) call
4274 gtk_main_iteration(), so it's possible that a signal will be handled
4275 half-way through this method. If this signal wants an
4276 idle_visual_changer we must schedule another one after this one, so
4277 mark the idle_handler_id as -1 here to allow that. Also make a note
4278 that we are doing the visual change, so that changes in response to
4279 super-rapid-screen-update can be dropped if we are still processing
4283 pending_visual_change.idle_handler_id = -1;
4284 pending_visual_change.being_handled = true;
4286 VisualChange vc = pending_visual_change;
4288 pending_visual_change.pending = (VisualChange::Type) 0;
4290 visual_changer (vc);
4292 pending_visual_change.being_handled = false;
4294 return 0; /* this is always a one-shot call */
4298 Editor::visual_changer (const VisualChange& vc)
4300 double const last_time_origin = horizontal_position ();
4302 if (vc.pending & VisualChange::ZoomLevel) {
4303 set_samples_per_pixel (vc.samples_per_pixel);
4305 compute_fixed_ruler_scale ();
4307 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4308 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4310 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4311 current_bbt_points_begin, current_bbt_points_end);
4312 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4313 current_bbt_points_begin, current_bbt_points_end);
4314 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4316 update_video_timeline();
4319 if (vc.pending & VisualChange::TimeOrigin) {
4320 set_horizontal_position (vc.time_origin / samples_per_pixel);
4323 if (vc.pending & VisualChange::YOrigin) {
4324 vertical_adjustment.set_value (vc.y_origin);
4327 if (last_time_origin == horizontal_position ()) {
4328 /* changed signal not emitted */
4329 update_fixed_rulers ();
4330 redisplay_tempo (true);
4333 if (!(vc.pending & VisualChange::ZoomLevel)) {
4334 update_video_timeline();
4337 _summary->set_overlays_dirty ();
4340 struct EditorOrderTimeAxisSorter {
4341 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4342 return a->order () < b->order ();
4347 Editor::sort_track_selection (TrackViewList& sel)
4349 EditorOrderTimeAxisSorter cmp;
4354 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4357 framepos_t where = 0;
4358 EditPoint ep = _edit_point;
4360 if (from_context_menu && (ep == EditAtMouse)) {
4361 return canvas_event_sample (&context_click_event, 0, 0);
4364 if (entered_marker) {
4365 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4366 return entered_marker->position();
4369 if (ignore_playhead && ep == EditAtPlayhead) {
4370 ep = EditAtSelectedMarker;
4374 case EditAtPlayhead:
4375 where = _session->audible_frame();
4376 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4379 case EditAtSelectedMarker:
4380 if (!selection->markers.empty()) {
4382 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4385 where = loc->start();
4389 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4397 if (!mouse_frame (where, ignored)) {
4398 /* XXX not right but what can we do ? */
4402 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4410 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4412 if (!_session) return;
4414 begin_reversible_command (cmd);
4418 if ((tll = transport_loop_location()) == 0) {
4419 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4420 XMLNode &before = _session->locations()->get_state();
4421 _session->locations()->add (loc, true);
4422 _session->set_auto_loop_location (loc);
4423 XMLNode &after = _session->locations()->get_state();
4424 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4426 XMLNode &before = tll->get_state();
4427 tll->set_hidden (false, this);
4428 tll->set (start, end);
4429 XMLNode &after = tll->get_state();
4430 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4433 commit_reversible_command ();
4437 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4439 if (!_session) return;
4441 begin_reversible_command (cmd);
4445 if ((tpl = transport_punch_location()) == 0) {
4446 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4447 XMLNode &before = _session->locations()->get_state();
4448 _session->locations()->add (loc, true);
4449 _session->set_auto_punch_location (loc);
4450 XMLNode &after = _session->locations()->get_state();
4451 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4454 XMLNode &before = tpl->get_state();
4455 tpl->set_hidden (false, this);
4456 tpl->set (start, end);
4457 XMLNode &after = tpl->get_state();
4458 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4461 commit_reversible_command ();
4464 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4465 * @param rs List to which found regions are added.
4466 * @param where Time to look at.
4467 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4470 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4472 const TrackViewList* tracks;
4475 tracks = &track_views;
4480 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4482 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4485 boost::shared_ptr<Track> tr;
4486 boost::shared_ptr<Playlist> pl;
4488 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4490 boost::shared_ptr<RegionList> regions = pl->regions_at (
4491 (framepos_t) floor ( (double) where * tr->speed()));
4493 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4494 RegionView* rv = rtv->view()->find_view (*i);
4505 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4507 const TrackViewList* tracks;
4510 tracks = &track_views;
4515 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4516 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4518 boost::shared_ptr<Track> tr;
4519 boost::shared_ptr<Playlist> pl;
4521 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4523 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4524 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4526 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4528 RegionView* rv = rtv->view()->find_view (*i);
4539 /** Get regions using the following method:
4541 * Make a region list using the selected regions, unless
4542 * the edit point is `mouse' and the mouse is over an unselected
4543 * region. In this case, use just that region.
4545 * If the edit point is not 'mouse', and there are no regions selected,
4546 * search the list of selected tracks and return regions that are under
4547 * the edit point on these tracks. If there are no selected tracks and
4548 * 'No Selection = All Tracks' is active, search all tracks,
4550 * The rationale here is that the mouse edit point is special in that
4551 * its position describes both a time and a track; the other edit
4552 * modes only describe a time. Hence if the edit point is `mouse' we
4553 * ignore selected tracks, as we assume the user means something by
4554 * pointing at a particular track. Also in this case we take note of
4555 * the region directly under the edit point, as there is always just one
4556 * (rather than possibly several with non-mouse edit points).
4560 Editor::get_regions_from_selection_and_edit_point ()
4562 RegionSelection regions;
4564 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4565 regions.add (entered_regionview);
4567 regions = selection->regions;
4571 if (regions.empty() && _edit_point != EditAtMouse) {
4572 TrackViewList tracks = selection->tracks;
4574 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4575 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4576 * is enabled, so consider all tracks
4578 tracks = track_views;
4581 if (!tracks.empty()) {
4582 /* no region selected or entered, but some selected tracks:
4583 * act on all regions on the selected tracks at the edit point
4585 framepos_t const where = get_preferred_edit_position ();
4586 get_regions_at(regions, where, tracks);
4592 /** Start with regions that are selected, or the entered regionview if none are selected.
4593 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4594 * of the regions that we started with.
4598 Editor::get_regions_from_selection_and_entered ()
4600 RegionSelection regions = selection->regions;
4602 if (regions.empty() && entered_regionview) {
4603 regions.add (entered_regionview);
4610 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4612 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4614 RouteTimeAxisView* tatv;
4616 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4618 boost::shared_ptr<Playlist> pl;
4619 vector<boost::shared_ptr<Region> > results;
4621 boost::shared_ptr<Track> tr;
4623 if ((tr = tatv->track()) == 0) {
4628 if ((pl = (tr->playlist())) != 0) {
4629 if (src_comparison) {
4630 pl->get_source_equivalent_regions (region, results);
4632 pl->get_region_list_equivalent_regions (region, results);
4636 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4637 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4638 regions.push_back (marv);
4647 Editor::show_rhythm_ferret ()
4649 if (rhythm_ferret == 0) {
4650 rhythm_ferret = new RhythmFerret(*this);
4653 rhythm_ferret->set_session (_session);
4654 rhythm_ferret->show ();
4655 rhythm_ferret->present ();
4659 Editor::first_idle ()
4661 MessageDialog* dialog = 0;
4663 if (track_views.size() > 1) {
4664 dialog = new MessageDialog (
4666 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4670 ARDOUR_UI::instance()->flush_pending ();
4673 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4677 // first idle adds route children (automation tracks), so we need to redisplay here
4678 _routes->redisplay ();
4685 Editor::_idle_resize (gpointer arg)
4687 return ((Editor*)arg)->idle_resize ();
4691 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4693 if (resize_idle_id < 0) {
4694 resize_idle_id = g_idle_add (_idle_resize, this);
4695 _pending_resize_amount = 0;
4698 /* make a note of the smallest resulting height, so that we can clamp the
4699 lower limit at TimeAxisView::hSmall */
4701 int32_t min_resulting = INT32_MAX;
4703 _pending_resize_amount += h;
4704 _pending_resize_view = view;
4706 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4708 if (selection->tracks.contains (_pending_resize_view)) {
4709 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4710 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4714 if (min_resulting < 0) {
4719 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4720 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4724 /** Handle pending resizing of tracks */
4726 Editor::idle_resize ()
4728 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4730 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4731 selection->tracks.contains (_pending_resize_view)) {
4733 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4734 if (*i != _pending_resize_view) {
4735 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4740 _pending_resize_amount = 0;
4741 _group_tabs->set_dirty ();
4742 resize_idle_id = -1;
4750 ENSURE_GUI_THREAD (*this, &Editor::located);
4753 playhead_cursor->set_position (_session->audible_frame ());
4754 if (_follow_playhead && !_pending_initial_locate) {
4755 reset_x_origin_to_follow_playhead ();
4759 _pending_locate_request = false;
4760 _pending_initial_locate = false;
4764 Editor::region_view_added (RegionView *)
4766 _summary->set_background_dirty ();
4770 Editor::region_view_removed ()
4772 _summary->set_background_dirty ();
4776 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4778 TrackViewList::const_iterator j = track_views.begin ();
4779 while (j != track_views.end()) {
4780 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4781 if (rtv && rtv->route() == r) {
4792 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4796 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4797 TimeAxisView* tv = axis_view_from_route (*i);
4807 Editor::suspend_route_redisplay ()
4810 _routes->suspend_redisplay();
4815 Editor::resume_route_redisplay ()
4818 _routes->resume_redisplay();
4823 Editor::add_routes (RouteList& routes)
4825 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4827 RouteTimeAxisView *rtv;
4828 list<RouteTimeAxisView*> new_views;
4830 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4831 boost::shared_ptr<Route> route = (*x);
4833 if (route->is_auditioner() || route->is_monitor()) {
4837 DataType dt = route->input()->default_type();
4839 if (dt == ARDOUR::DataType::AUDIO) {
4840 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4841 rtv->set_route (route);
4842 } else if (dt == ARDOUR::DataType::MIDI) {
4843 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4844 rtv->set_route (route);
4846 throw unknown_type();
4849 new_views.push_back (rtv);
4850 track_views.push_back (rtv);
4852 rtv->effective_gain_display ();
4854 if (internal_editing()) {
4855 rtv->enter_internal_edit_mode ();
4857 rtv->leave_internal_edit_mode ();
4860 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4861 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4864 if (new_views.size() > 0) {
4865 _routes->routes_added (new_views);
4866 _summary->routes_added (new_views);
4869 if (show_editor_mixer_when_tracks_arrive) {
4870 show_editor_mixer (true);
4873 editor_list_button.set_sensitive (true);
4877 Editor::timeaxisview_deleted (TimeAxisView *tv)
4879 if (tv == entered_track) {
4883 if (_session && _session->deletion_in_progress()) {
4884 /* the situation is under control */
4888 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4890 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4892 _routes->route_removed (tv);
4894 TimeAxisView::Children c = tv->get_child_list ();
4895 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4896 if (entered_track == i->get()) {
4901 /* remove it from the list of track views */
4903 TrackViewList::iterator i;
4905 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4906 i = track_views.erase (i);
4909 /* update whatever the current mixer strip is displaying, if revelant */
4911 boost::shared_ptr<Route> route;
4914 route = rtav->route ();
4917 if (current_mixer_strip && current_mixer_strip->route() == route) {
4919 TimeAxisView* next_tv;
4921 if (track_views.empty()) {
4923 } else if (i == track_views.end()) {
4924 next_tv = track_views.front();
4931 set_selected_mixer_strip (*next_tv);
4933 /* make the editor mixer strip go away setting the
4934 * button to inactive (which also unticks the menu option)
4937 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4943 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4945 if (apply_to_selection) {
4946 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4948 TrackSelection::iterator j = i;
4951 hide_track_in_display (*i, false);
4956 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4958 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4959 // this will hide the mixer strip
4960 set_selected_mixer_strip (*tv);
4963 _routes->hide_track_in_display (*tv);
4968 Editor::sync_track_view_list_and_routes ()
4970 track_views = TrackViewList (_routes->views ());
4972 _summary->set_dirty ();
4973 _group_tabs->set_dirty ();
4975 return false; // do not call again (until needed)
4979 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4981 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4986 /** Find a RouteTimeAxisView by the ID of its route */
4988 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4990 RouteTimeAxisView* v;
4992 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4993 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4994 if(v->route()->id() == id) {
5004 Editor::fit_route_group (RouteGroup *g)
5006 TrackViewList ts = axis_views_from_routes (g->route_list ());
5011 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5013 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5016 _session->cancel_audition ();
5020 if (_session->is_auditioning()) {
5021 _session->cancel_audition ();
5022 if (r == last_audition_region) {
5027 _session->audition_region (r);
5028 last_audition_region = r;
5033 Editor::hide_a_region (boost::shared_ptr<Region> r)
5035 r->set_hidden (true);
5039 Editor::show_a_region (boost::shared_ptr<Region> r)
5041 r->set_hidden (false);
5045 Editor::audition_region_from_region_list ()
5047 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5051 Editor::hide_region_from_region_list ()
5053 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5057 Editor::show_region_in_region_list ()
5059 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5063 Editor::step_edit_status_change (bool yn)
5066 start_step_editing ();
5068 stop_step_editing ();
5073 Editor::start_step_editing ()
5075 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5079 Editor::stop_step_editing ()
5081 step_edit_connection.disconnect ();
5085 Editor::check_step_edit ()
5087 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5088 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5090 mtv->check_step_edit ();
5094 return true; // do it again, till we stop
5098 Editor::scroll_press (Direction dir)
5100 ++_scroll_callbacks;
5102 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5103 /* delay the first auto-repeat */
5109 scroll_backward (1);
5117 scroll_tracks_up_line ();
5121 scroll_tracks_down_line ();
5125 /* do hacky auto-repeat */
5126 if (!_scroll_connection.connected ()) {
5128 _scroll_connection = Glib::signal_timeout().connect (
5129 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5132 _scroll_callbacks = 0;
5139 Editor::scroll_release ()
5141 _scroll_connection.disconnect ();
5144 /** Queue a change for the Editor viewport x origin to follow the playhead */
5146 Editor::reset_x_origin_to_follow_playhead ()
5148 framepos_t const frame = playhead_cursor->current_frame ();
5150 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5152 if (_session->transport_speed() < 0) {
5154 if (frame > (current_page_samples() / 2)) {
5155 center_screen (frame-(current_page_samples()/2));
5157 center_screen (current_page_samples()/2);
5164 if (frame < leftmost_frame) {
5166 if (_session->transport_rolling()) {
5167 /* rolling; end up with the playhead at the right of the page */
5168 l = frame - current_page_samples ();
5170 /* not rolling: end up with the playhead 1/4 of the way along the page */
5171 l = frame - current_page_samples() / 4;
5175 if (_session->transport_rolling()) {
5176 /* rolling: end up with the playhead on the left of the page */
5179 /* not rolling: end up with the playhead 3/4 of the way along the page */
5180 l = frame - 3 * current_page_samples() / 4;
5188 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5194 Editor::super_rapid_screen_update ()
5196 if (!_session || !_session->engine().running()) {
5200 /* METERING / MIXER STRIPS */
5202 /* update track meters, if required */
5203 if (is_mapped() && meters_running) {
5204 RouteTimeAxisView* rtv;
5205 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5206 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5207 rtv->fast_update ();
5212 /* and any current mixer strip */
5213 if (current_mixer_strip) {
5214 current_mixer_strip->fast_update ();
5217 /* PLAYHEAD AND VIEWPORT */
5219 framepos_t const frame = _session->audible_frame();
5221 /* There are a few reasons why we might not update the playhead / viewport stuff:
5223 * 1. we don't update things when there's a pending locate request, otherwise
5224 * when the editor requests a locate there is a chance that this method
5225 * will move the playhead before the locate request is processed, causing
5227 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5228 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5231 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5233 last_update_frame = frame;
5235 if (!_dragging_playhead) {
5236 playhead_cursor->set_position (frame);
5239 if (!_stationary_playhead) {
5241 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5242 /* We only do this if we aren't already
5243 handling a visual change (ie if
5244 pending_visual_change.being_handled is
5245 false) so that these requests don't stack
5246 up there are too many of them to handle in
5249 reset_x_origin_to_follow_playhead ();
5254 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5258 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5259 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5260 if (target <= 0.0) {
5263 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5264 target = (target * 0.15) + (current * 0.85);
5270 set_horizontal_position (current);
5279 Editor::session_going_away ()
5281 _have_idled = false;
5283 _session_connections.drop_connections ();
5285 super_rapid_screen_update_connection.disconnect ();
5287 selection->clear ();
5288 cut_buffer->clear ();
5290 clicked_regionview = 0;
5291 clicked_axisview = 0;
5292 clicked_routeview = 0;
5293 entered_regionview = 0;
5295 last_update_frame = 0;
5298 playhead_cursor->hide ();
5300 /* rip everything out of the list displays */
5304 _route_groups->clear ();
5306 /* do this first so that deleting a track doesn't reset cms to null
5307 and thus cause a leak.
5310 if (current_mixer_strip) {
5311 if (current_mixer_strip->get_parent() != 0) {
5312 global_hpacker.remove (*current_mixer_strip);
5314 delete current_mixer_strip;
5315 current_mixer_strip = 0;
5318 /* delete all trackviews */
5320 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5323 track_views.clear ();
5325 zoom_range_clock->set_session (0);
5326 nudge_clock->set_session (0);
5328 editor_list_button.set_active(false);
5329 editor_list_button.set_sensitive(false);
5331 /* clear tempo/meter rulers */
5332 remove_metric_marks ();
5334 clear_marker_display ();
5336 stop_step_editing ();
5338 /* get rid of any existing editor mixer strip */
5340 WindowTitle title(Glib::get_application_name());
5341 title += _("Editor");
5343 set_title (title.get_string());
5345 SessionHandlePtr::session_going_away ();
5350 Editor::show_editor_list (bool yn)
5353 _the_notebook.show ();
5355 _the_notebook.hide ();
5360 Editor::change_region_layering_order (bool from_context_menu)
5362 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5364 if (!clicked_routeview) {
5365 if (layering_order_editor) {
5366 layering_order_editor->hide ();
5371 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5377 boost::shared_ptr<Playlist> pl = track->playlist();
5383 if (layering_order_editor == 0) {
5384 layering_order_editor = new RegionLayeringOrderEditor (*this);
5387 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5388 layering_order_editor->maybe_present ();
5392 Editor::update_region_layering_order_editor ()
5394 if (layering_order_editor && layering_order_editor->is_visible ()) {
5395 change_region_layering_order (true);
5400 Editor::setup_fade_images ()
5402 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5403 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5404 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5405 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5406 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5408 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5409 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5410 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5411 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5412 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5414 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5415 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5416 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5417 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5418 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5420 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5421 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5422 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5423 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5424 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5428 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5430 Editor::action_menu_item (std::string const & name)
5432 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5435 return *manage (a->create_menu_item ());
5439 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5441 EventBox* b = manage (new EventBox);
5442 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5443 Label* l = manage (new Label (name));
5447 _the_notebook.append_page (widget, *b);
5451 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5453 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5454 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5457 if (ev->type == GDK_2BUTTON_PRESS) {
5459 /* double-click on a notebook tab shrinks or expands the notebook */
5461 if (_notebook_shrunk) {
5462 if (pre_notebook_shrink_pane_width) {
5463 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5465 _notebook_shrunk = false;
5467 pre_notebook_shrink_pane_width = edit_pane.get_position();
5469 /* this expands the LHS of the edit pane to cover the notebook
5470 PAGE but leaves the tabs visible.
5472 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5473 _notebook_shrunk = true;
5481 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5483 using namespace Menu_Helpers;
5485 MenuList& items = _control_point_context_menu.items ();
5488 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5489 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5490 if (!can_remove_control_point (item)) {
5491 items.back().set_sensitive (false);
5494 _control_point_context_menu.popup (event->button.button, event->button.time);
5498 Editor::zoom_vertical_modifier_released()
5500 _stepping_axis_view = 0;
5504 Editor::ui_parameter_changed (string parameter)
5506 if (parameter == "icon-set") {
5507 while (!_cursor_stack.empty()) {
5508 _cursor_stack.pop();
5510 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5511 } else if (parameter == "draggable-playhead") {
5512 if (_verbose_cursor) {
5513 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());