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"
49 #include <glibmm/miscutils.h>
50 #include <gtkmm/image.h>
51 #include <gdkmm/color.h>
52 #include <gdkmm/bitmap.h>
54 #include "gtkmm2ext/bindings.h"
55 #include "gtkmm2ext/grouped_buttons.h"
56 #include "gtkmm2ext/gtk_ui.h"
57 #include "gtkmm2ext/tearoff.h"
58 #include "gtkmm2ext/utils.h"
59 #include "gtkmm2ext/window_title.h"
60 #include "gtkmm2ext/choice.h"
61 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
63 #include "ardour/audio_track.h"
64 #include "ardour/audioengine.h"
65 #include "ardour/audioregion.h"
66 #include "ardour/location.h"
67 #include "ardour/profile.h"
68 #include "ardour/route_group.h"
69 #include "ardour/session_playlists.h"
70 #include "ardour/tempo.h"
71 #include "ardour/utils.h"
73 #include "canvas/debug.h"
74 #include "canvas/text.h"
76 #include "control_protocol/control_protocol.h"
80 #include "analysis_window.h"
81 #include "audio_clock.h"
82 #include "audio_region_view.h"
83 #include "audio_streamview.h"
84 #include "audio_time_axis.h"
85 #include "automation_time_axis.h"
86 #include "bundle_manager.h"
87 #include "crossfade_edit.h"
91 #include "editor_cursors.h"
92 #include "editor_drag.h"
93 #include "editor_group_tabs.h"
94 #include "editor_locations.h"
95 #include "editor_regions.h"
96 #include "editor_route_groups.h"
97 #include "editor_routes.h"
98 #include "editor_snapshots.h"
99 #include "editor_summary.h"
100 #include "global_port_matrix.h"
101 #include "gui_object.h"
102 #include "gui_thread.h"
103 #include "keyboard.h"
105 #include "midi_time_axis.h"
106 #include "mixer_strip.h"
107 #include "mixer_ui.h"
108 #include "mouse_cursors.h"
109 #include "playlist_selector.h"
110 #include "public_editor.h"
111 #include "region_layering_order_editor.h"
112 #include "rgb_macros.h"
113 #include "rhythm_ferret.h"
114 #include "selection.h"
116 #include "tempo_lines.h"
117 #include "time_axis_view.h"
123 #include "imageframe_socket_handler.h"
127 using namespace ARDOUR;
130 using namespace Glib;
131 using namespace Gtkmm2ext;
132 using namespace Editing;
134 using PBD::internationalize;
136 using Gtkmm2ext::Keyboard;
138 const double Editor::timebar_height = 15.0;
140 static const gchar *_snap_type_strings[] = {
142 N_("Timecode Frames"),
143 N_("Timecode Seconds"),
144 N_("Timecode Minutes"),
174 static const gchar *_snap_mode_strings[] = {
181 static const gchar *_edit_point_strings[] = {
188 static const gchar *_zoom_focus_strings[] = {
198 #ifdef USE_RUBBERBAND
199 static const gchar *_rb_opt_strings[] = {
202 N_("Balanced multitimbral mixture"),
203 N_("Unpitched percussion with stable notes"),
204 N_("Crisp monophonic instrumental"),
205 N_("Unpitched solo percussion"),
206 N_("Resample without preserving pitch"),
212 pane_size_watcher (Paned* pane)
214 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
218 Quartz: impossible to access
220 so stop that by preventing it from ever getting too narrow. 35
221 pixels is basically a rough guess at the tab width.
226 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
228 gint pos = pane->get_position ();
230 if (pos > max_width_of_lhs) {
231 pane->set_position (max_width_of_lhs);
236 : VisibilityTracker (*((Gtk::Window*) this))
237 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
239 /* time display buttons */
240 , minsec_label (_("Mins:Secs"))
241 , bbt_label (_("Bars:Beats"))
242 , timecode_label (_("Timecode"))
243 , samples_label (_("Samples"))
244 , tempo_label (_("Tempo"))
245 , meter_label (_("Meter"))
246 , mark_label (_("Location Markers"))
247 , range_mark_label (_("Range Markers"))
248 , transport_mark_label (_("Loop/Punch Ranges"))
249 , cd_mark_label (_("CD Markers"))
250 , videotl_label (_("Video Timeline"))
251 , edit_packer (4, 4, true)
253 /* the values here don't matter: layout widgets
254 reset them as needed.
257 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
258 , horizontal_adjustment (0.0, 0.0, 1e16)
259 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
261 , controls_layout (unused_adjustment, vertical_adjustment)
263 /* tool bar related */
265 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
267 , toolbar_selection_clock_table (2,3)
269 , automation_mode_button (_("mode"))
271 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
274 , image_socket_listener(0)
279 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
280 , meters_running(false)
281 , _pending_locate_request (false)
282 , _pending_initial_locate (false)
283 , _last_cut_copy_source_track (0)
285 , _region_selection_change_updates_region_list (true)
286 , _following_mixer_selection (false)
287 , _control_point_toggled_on_press (false)
288 , _stepping_axis_view (0)
292 /* we are a singleton */
294 PublicEditor::_instance = this;
298 selection = new Selection (this);
299 cut_buffer = new Selection (this);
301 clicked_regionview = 0;
302 clicked_axisview = 0;
303 clicked_routeview = 0;
304 clicked_control_point = 0;
305 last_update_frame = 0;
306 pre_press_cursor = 0;
307 _drags = new DragManager (this);
308 current_mixer_strip = 0;
311 snap_type_strings = I18N (_snap_type_strings);
312 snap_mode_strings = I18N (_snap_mode_strings);
313 zoom_focus_strings = I18N (_zoom_focus_strings);
314 edit_point_strings = I18N (_edit_point_strings);
315 #ifdef USE_RUBBERBAND
316 rb_opt_strings = I18N (_rb_opt_strings);
320 snap_threshold = 5.0;
321 bbt_beat_subdivision = 4;
322 _visible_canvas_width = 0;
323 _visible_canvas_height = 0;
324 last_autoscroll_x = 0;
325 last_autoscroll_y = 0;
326 autoscroll_active = false;
327 autoscroll_timeout_tag = -1;
332 current_interthread_info = 0;
333 _show_measures = true;
335 show_gain_after_trim = false;
337 have_pending_keyboard_selection = false;
338 _follow_playhead = true;
339 _stationary_playhead = false;
340 editor_ruler_menu = 0;
341 no_ruler_shown_update = false;
343 range_marker_menu = 0;
344 marker_menu_item = 0;
345 tempo_or_meter_marker_menu = 0;
346 transport_marker_menu = 0;
347 new_transport_marker_menu = 0;
348 editor_mixer_strip_width = Wide;
349 show_editor_mixer_when_tracks_arrive = false;
350 region_edit_menu_split_multichannel_item = 0;
351 region_edit_menu_split_item = 0;
354 current_stepping_trackview = 0;
356 entered_regionview = 0;
358 clear_entered_track = false;
361 button_release_can_deselect = true;
362 _dragging_playhead = false;
363 _dragging_edit_point = false;
364 select_new_marker = false;
366 layering_order_editor = 0;
367 no_save_visual = false;
369 within_track_canvas = false;
371 scrubbing_direction = 0;
375 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
376 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
377 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
378 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
379 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
381 _edit_point = EditAtMouse;
382 _internal_editing = false;
383 current_canvas_cursor = 0;
385 samples_per_pixel = 2048; /* too early to use reset_zoom () */
387 _scroll_callbacks = 0;
389 zoom_focus = ZoomFocusLeft;
390 set_zoom_focus (ZoomFocusLeft);
391 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
393 bbt_label.set_name ("EditorRulerLabel");
394 bbt_label.set_size_request (-1, (int)timebar_height);
395 bbt_label.set_alignment (1.0, 0.5);
396 bbt_label.set_padding (5,0);
398 bbt_label.set_no_show_all();
399 minsec_label.set_name ("EditorRulerLabel");
400 minsec_label.set_size_request (-1, (int)timebar_height);
401 minsec_label.set_alignment (1.0, 0.5);
402 minsec_label.set_padding (5,0);
403 minsec_label.hide ();
404 minsec_label.set_no_show_all();
405 timecode_label.set_name ("EditorRulerLabel");
406 timecode_label.set_size_request (-1, (int)timebar_height);
407 timecode_label.set_alignment (1.0, 0.5);
408 timecode_label.set_padding (5,0);
409 timecode_label.hide ();
410 timecode_label.set_no_show_all();
411 samples_label.set_name ("EditorRulerLabel");
412 samples_label.set_size_request (-1, (int)timebar_height);
413 samples_label.set_alignment (1.0, 0.5);
414 samples_label.set_padding (5,0);
415 samples_label.hide ();
416 samples_label.set_no_show_all();
418 tempo_label.set_name ("EditorRulerLabel");
419 tempo_label.set_size_request (-1, (int)timebar_height);
420 tempo_label.set_alignment (1.0, 0.5);
421 tempo_label.set_padding (5,0);
423 tempo_label.set_no_show_all();
425 meter_label.set_name ("EditorRulerLabel");
426 meter_label.set_size_request (-1, (int)timebar_height);
427 meter_label.set_alignment (1.0, 0.5);
428 meter_label.set_padding (5,0);
430 meter_label.set_no_show_all();
432 mark_label.set_name ("EditorRulerLabel");
433 mark_label.set_size_request (-1, (int)timebar_height);
434 mark_label.set_alignment (1.0, 0.5);
435 mark_label.set_padding (5,0);
437 mark_label.set_no_show_all();
439 cd_mark_label.set_name ("EditorRulerLabel");
440 cd_mark_label.set_size_request (-1, (int)timebar_height);
441 cd_mark_label.set_alignment (1.0, 0.5);
442 cd_mark_label.set_padding (5,0);
443 cd_mark_label.hide();
444 cd_mark_label.set_no_show_all();
446 videotl_bar_height = 4;
447 videotl_label.set_name ("EditorRulerLabel");
448 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
449 videotl_label.set_alignment (1.0, 0.5);
450 videotl_label.set_padding (5,0);
451 videotl_label.hide();
452 videotl_label.set_no_show_all();
454 range_mark_label.set_name ("EditorRulerLabel");
455 range_mark_label.set_size_request (-1, (int)timebar_height);
456 range_mark_label.set_alignment (1.0, 0.5);
457 range_mark_label.set_padding (5,0);
458 range_mark_label.hide();
459 range_mark_label.set_no_show_all();
461 transport_mark_label.set_name ("EditorRulerLabel");
462 transport_mark_label.set_size_request (-1, (int)timebar_height);
463 transport_mark_label.set_alignment (1.0, 0.5);
464 transport_mark_label.set_padding (5,0);
465 transport_mark_label.hide();
466 transport_mark_label.set_no_show_all();
468 initialize_rulers ();
469 initialize_canvas ();
471 _summary = new EditorSummary (this);
473 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
474 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
476 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
478 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
479 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
481 edit_controls_vbox.set_spacing (0);
482 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
483 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
485 HBox* h = manage (new HBox);
486 _group_tabs = new EditorGroupTabs (this);
487 h->pack_start (*_group_tabs, PACK_SHRINK);
488 h->pack_start (edit_controls_vbox);
489 controls_layout.add (*h);
491 controls_layout.set_name ("EditControlsBase");
492 controls_layout.add_events (Gdk::SCROLL_MASK);
493 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
495 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
496 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
498 _cursors = new MouseCursors;
500 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
502 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
503 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
504 pad_line_1->set_outline_color (0xFF0000FF);
510 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
511 time_canvas_vbox.set_size_request (-1, -1);
513 ruler_label_event_box.add (ruler_label_vbox);
514 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
515 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
517 time_bars_event_box.add (time_bars_vbox);
518 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
519 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
521 time_canvas_event_box.add (time_canvas_vbox);
522 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
524 edit_packer.set_col_spacings (0);
525 edit_packer.set_row_spacings (0);
526 edit_packer.set_homogeneous (false);
527 edit_packer.set_border_width (0);
528 edit_packer.set_name ("EditorWindow");
530 /* labels for the rulers */
531 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
532 /* labels for the marker "tracks" (time bars) */
533 edit_packer.attach (time_bars_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
535 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
537 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
538 /* time bars canvas */
539 edit_packer.attach (*_time_bars_canvas_viewport, 2, 3, 1, 2, FILL, FILL, 0, 0);
541 edit_packer.attach (*_track_canvas_viewport, 2, 3, 2, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
543 bottom_hbox.set_border_width (2);
544 bottom_hbox.set_spacing (3);
546 _route_groups = new EditorRouteGroups (this);
547 _routes = new EditorRoutes (this);
548 _regions = new EditorRegions (this);
549 _snapshots = new EditorSnapshots (this);
550 _locations = new EditorLocations (this);
552 add_notebook_page (_("Regions"), _regions->widget ());
553 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
554 add_notebook_page (_("Snapshots"), _snapshots->widget ());
555 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
556 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
558 _the_notebook.set_show_tabs (true);
559 _the_notebook.set_scrollable (true);
560 _the_notebook.popup_disable ();
561 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
562 _the_notebook.show_all ();
564 _notebook_shrunk = false;
566 editor_summary_pane.pack1(edit_packer);
568 Button* summary_arrows_left_left = manage (new Button);
569 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
570 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
571 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
573 Button* summary_arrows_left_right = manage (new Button);
574 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
575 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
576 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
578 VBox* summary_arrows_left = manage (new VBox);
579 summary_arrows_left->pack_start (*summary_arrows_left_left);
580 summary_arrows_left->pack_start (*summary_arrows_left_right);
582 Button* summary_arrows_right_up = manage (new Button);
583 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
584 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
585 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
587 Button* summary_arrows_right_down = manage (new Button);
588 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
589 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
590 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
592 VBox* summary_arrows_right = manage (new VBox);
593 summary_arrows_right->pack_start (*summary_arrows_right_up);
594 summary_arrows_right->pack_start (*summary_arrows_right_down);
596 Frame* summary_frame = manage (new Frame);
597 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
599 summary_frame->add (*_summary);
600 summary_frame->show ();
602 _summary_hbox.pack_start (*summary_arrows_left, false, false);
603 _summary_hbox.pack_start (*summary_frame, true, true);
604 _summary_hbox.pack_start (*summary_arrows_right, false, false);
606 editor_summary_pane.pack2 (_summary_hbox);
608 edit_pane.pack1 (editor_summary_pane, true, true);
609 edit_pane.pack2 (_the_notebook, false, true);
611 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
613 /* XXX: editor_summary_pane might need similar to the edit_pane */
615 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
617 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
618 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
620 top_hbox.pack_start (toolbar_frame);
622 HBox *hbox = manage (new HBox);
623 hbox->pack_start (edit_pane, true, true);
625 global_vpacker.pack_start (top_hbox, false, false);
626 global_vpacker.pack_start (*hbox, true, true);
628 global_hpacker.pack_start (global_vpacker, true, true);
630 set_name ("EditorWindow");
631 add_accel_group (ActionManager::ui_manager->get_accel_group());
633 status_bar_hpacker.show ();
635 vpacker.pack_end (status_bar_hpacker, false, false);
636 vpacker.pack_end (global_hpacker, true, true);
638 /* register actions now so that set_state() can find them and set toggles/checks etc */
641 /* when we start using our own keybinding system for the editor, this
642 * will be uncommented
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 ("zoom button");
668 nudge_forward_button.add_elements (ArdourButton::FlatFace);
669 nudge_forward_button.set_image(::get_icon("nudge_right"));
671 nudge_backward_button.set_name ("zoom button");
672 nudge_backward_button.add_elements (ArdourButton::FlatFace);
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().ShiftReleased.connect (sigc::mem_fun (*this, &Editor::shift_key_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());
743 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
745 _ignore_region_action = false;
746 _last_region_menu_was_main = false;
747 _popup_region_menu_item = 0;
749 _show_marker_lines = false;
750 _over_region_trim_target = 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);
766 setup_fade_images ();
772 if(image_socket_listener) {
773 if(image_socket_listener->is_connected())
775 image_socket_listener->close_connection() ;
778 delete image_socket_listener ;
779 image_socket_listener = 0 ;
783 delete button_bindings;
785 delete _route_groups;
786 delete _time_bars_canvas_viewport;
787 delete _track_canvas_viewport;
792 Editor::button_settings () const
794 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
795 XMLNode* node = find_named_node (*settings, X_("Buttons"));
798 node = new XMLNode (X_("Buttons"));
805 Editor::add_toplevel_controls (Container& cont)
807 vpacker.pack_start (cont, false, false);
812 Editor::get_smart_mode () const
814 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
818 Editor::catch_vanishing_regionview (RegionView *rv)
820 /* note: the selection will take care of the vanishing
821 audioregionview by itself.
824 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
828 if (clicked_regionview == rv) {
829 clicked_regionview = 0;
832 if (entered_regionview == rv) {
833 set_entered_regionview (0);
836 if (!_all_region_actions_sensitized) {
837 sensitize_all_region_actions (true);
840 _over_region_trim_target = false;
844 Editor::set_entered_regionview (RegionView* rv)
846 if (rv == entered_regionview) {
850 if (entered_regionview) {
851 entered_regionview->exited ();
854 if ((entered_regionview = rv) != 0) {
855 entered_regionview->entered (internal_editing ());
858 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
859 /* This RegionView entry might have changed what region actions
860 are allowed, so sensitize them all in case a key is pressed.
862 sensitize_all_region_actions (true);
867 Editor::set_entered_track (TimeAxisView* tav)
870 entered_track->exited ();
873 if ((entered_track = tav) != 0) {
874 entered_track->entered ();
879 Editor::show_window ()
881 if (!is_visible ()) {
884 /* XXX: this is a bit unfortunate; it would probably
885 be nicer if we could just call show () above rather
886 than needing the show_all ()
889 /* re-hide stuff if necessary */
890 editor_list_button_toggled ();
891 parameter_changed ("show-summary");
892 parameter_changed ("show-group-tabs");
893 parameter_changed ("show-zoom-tools");
895 /* now reset all audio_time_axis heights, because widgets might need
901 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
902 tv = (static_cast<TimeAxisView*>(*i));
906 if (current_mixer_strip) {
907 current_mixer_strip->hide_things ();
908 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
916 Editor::instant_save ()
918 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
923 _session->add_instant_xml(get_state());
925 Config->add_instant_xml(get_state());
930 Editor::zoom_adjustment_changed ()
936 double fpu = zoom_range_clock->current_duration() / _visible_canvas_width;
937 bool clamped = clamp_samples_per_pixel (fpu);
940 zoom_range_clock->set ((framepos_t) floor (fpu * _visible_canvas_width));
947 Editor::control_vertical_zoom_in_all ()
949 tav_zoom_smooth (false, true);
953 Editor::control_vertical_zoom_out_all ()
955 tav_zoom_smooth (true, true);
959 Editor::control_vertical_zoom_in_selected ()
961 tav_zoom_smooth (false, false);
965 Editor::control_vertical_zoom_out_selected ()
967 tav_zoom_smooth (true, false);
971 Editor::control_view (uint32_t view)
973 goto_visual_state (view);
977 Editor::control_unselect ()
979 selection->clear_tracks ();
983 Editor::control_select (uint32_t rid, Selection::Operation op)
985 /* handles the (static) signal from the ControlProtocol class that
986 * requests setting the selected track to a given RID
993 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
999 TimeAxisView* tav = axis_view_from_route (r);
1003 case Selection::Add:
1004 selection->add (tav);
1006 case Selection::Toggle:
1007 selection->toggle (tav);
1009 case Selection::Extend:
1011 case Selection::Set:
1012 selection->set (tav);
1016 selection->clear_tracks ();
1021 Editor::control_step_tracks_up ()
1023 scroll_tracks_up_line ();
1027 Editor::control_step_tracks_down ()
1029 scroll_tracks_down_line ();
1033 Editor::control_scroll (float fraction)
1035 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1041 double step = fraction * current_page_samples();
1044 _control_scroll_target is an optional<T>
1046 it acts like a pointer to an framepos_t, with
1047 a operator conversion to boolean to check
1048 that it has a value could possibly use
1049 playhead_cursor->current_frame to store the
1050 value and a boolean in the class to know
1051 when it's out of date
1054 if (!_control_scroll_target) {
1055 _control_scroll_target = _session->transport_frame();
1056 _dragging_playhead = true;
1059 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1060 *_control_scroll_target = 0;
1061 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1062 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1064 *_control_scroll_target += (framepos_t) floor (step);
1067 /* move visuals, we'll catch up with it later */
1069 playhead_cursor->set_position (*_control_scroll_target);
1070 UpdateAllTransportClocks (*_control_scroll_target);
1072 if (*_control_scroll_target > (current_page_samples() / 2)) {
1073 /* try to center PH in window */
1074 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1080 Now we do a timeout to actually bring the session to the right place
1081 according to the playhead. This is to avoid reading disk buffers on every
1082 call to control_scroll, which is driven by ScrollTimeline and therefore
1083 probably by a control surface wheel which can generate lots of events.
1085 /* cancel the existing timeout */
1087 control_scroll_connection.disconnect ();
1089 /* add the next timeout */
1091 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1095 Editor::deferred_control_scroll (framepos_t /*target*/)
1097 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1098 // reset for next stream
1099 _control_scroll_target = boost::none;
1100 _dragging_playhead = false;
1105 Editor::access_action (std::string action_group, std::string action_item)
1111 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1114 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1122 Editor::on_realize ()
1124 Window::on_realize ();
1129 Editor::map_position_change (framepos_t frame)
1131 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1133 if (_session == 0) {
1137 if (_follow_playhead) {
1138 center_screen (frame);
1141 playhead_cursor->set_position (frame);
1145 Editor::center_screen (framepos_t frame)
1147 double const page = _visible_canvas_width * samples_per_pixel;
1149 /* if we're off the page, then scroll.
1152 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1153 center_screen_internal (frame, page);
1158 Editor::center_screen_internal (framepos_t frame, float page)
1163 frame -= (framepos_t) page;
1168 reset_x_origin (frame);
1173 Editor::update_title ()
1175 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1178 bool dirty = _session->dirty();
1180 string session_name;
1182 if (_session->snap_name() != _session->name()) {
1183 session_name = _session->snap_name();
1185 session_name = _session->name();
1189 session_name = "*" + session_name;
1192 WindowTitle title(session_name);
1193 title += Glib::get_application_name();
1194 set_title (title.get_string());
1196 /* ::session_going_away() will have taken care of it */
1201 Editor::set_session (Session *t)
1203 SessionHandlePtr::set_session (t);
1209 zoom_range_clock->set_session (_session);
1210 _playlist_selector->set_session (_session);
1211 nudge_clock->set_session (_session);
1212 _summary->set_session (_session);
1213 _group_tabs->set_session (_session);
1214 _route_groups->set_session (_session);
1215 _regions->set_session (_session);
1216 _snapshots->set_session (_session);
1217 _routes->set_session (_session);
1218 _locations->set_session (_session);
1220 if (rhythm_ferret) {
1221 rhythm_ferret->set_session (_session);
1224 if (analysis_window) {
1225 analysis_window->set_session (_session);
1229 sfbrowser->set_session (_session);
1232 compute_fixed_ruler_scale ();
1234 /* Make sure we have auto loop and auto punch ranges */
1236 Location* loc = _session->locations()->auto_loop_location();
1238 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1240 if (loc->start() == loc->end()) {
1241 loc->set_end (loc->start() + 1);
1244 _session->locations()->add (loc, false);
1245 _session->set_auto_loop_location (loc);
1248 loc->set_name (_("Loop"));
1251 loc = _session->locations()->auto_punch_location();
1254 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1256 if (loc->start() == loc->end()) {
1257 loc->set_end (loc->start() + 1);
1260 _session->locations()->add (loc, false);
1261 _session->set_auto_punch_location (loc);
1264 loc->set_name (_("Punch"));
1267 refresh_location_display ();
1269 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1270 the selected Marker; this needs the LocationMarker list to be available.
1272 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1273 set_state (*node, Stateful::loading_state_version);
1275 /* catch up with the playhead */
1277 _session->request_locate (playhead_cursor->current_frame ());
1278 _pending_initial_locate = true;
1282 /* These signals can all be emitted by a non-GUI thread. Therefore the
1283 handlers for them must not attempt to directly interact with the GUI,
1284 but use Gtkmm2ext::UI::instance()->call_slot();
1287 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1288 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1289 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1290 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1291 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1292 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1293 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1294 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1295 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1296 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1297 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1298 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1299 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1300 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1302 playhead_cursor->show ();
1304 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1305 Config->map_parameters (pc);
1306 _session->config.map_parameters (pc);
1308 restore_ruler_visibility ();
1309 //tempo_map_changed (PropertyChange (0));
1310 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1312 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1313 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1316 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1317 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1320 switch (_snap_type) {
1321 case SnapToRegionStart:
1322 case SnapToRegionEnd:
1323 case SnapToRegionSync:
1324 case SnapToRegionBoundary:
1325 build_region_boundary_cache ();
1332 /* register for undo history */
1333 _session->register_with_memento_command_factory(id(), this);
1335 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1337 start_updating_meters ();
1341 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1343 if (a->get_name() == "RegionMenu") {
1344 /* When the main menu's region menu is opened, we setup the actions so that they look right
1345 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1346 so we resensitize all region actions when the entered regionview or the region selection
1347 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1348 happens after the region context menu is opened. So we set a flag here, too.
1352 sensitize_the_right_region_actions ();
1353 _last_region_menu_was_main = true;
1358 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1360 using namespace Menu_Helpers;
1362 void (Editor::*emf)(FadeShape);
1363 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1366 images = &_xfade_in_images;
1367 emf = &Editor::set_fade_in_shape;
1369 images = &_xfade_out_images;
1370 emf = &Editor::set_fade_out_shape;
1375 _("Linear (for highly correlated material)"),
1376 *(*images)[FadeLinear],
1377 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1381 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1385 _("Constant power"),
1386 *(*images)[FadeConstantPower],
1387 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1390 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1395 *(*images)[FadeSymmetric],
1396 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1400 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1405 *(*images)[FadeSlow],
1406 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1409 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1414 *(*images)[FadeFast],
1415 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1418 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1421 /** Pop up a context menu for when the user clicks on a start crossfade */
1423 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1425 using namespace Menu_Helpers;
1427 MenuList& items (xfade_in_context_menu.items());
1429 if (items.empty()) {
1430 fill_xfade_menu (items, true);
1433 xfade_in_context_menu.popup (button, time);
1436 /** Pop up a context menu for when the user clicks on an end crossfade */
1438 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1440 using namespace Menu_Helpers;
1442 MenuList& items (xfade_out_context_menu.items());
1444 if (items.empty()) {
1445 fill_xfade_menu (items, false);
1448 xfade_out_context_menu.popup (button, time);
1452 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1454 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1456 using namespace Menu_Helpers;
1457 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1460 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1464 MenuList& items (fade_context_menu.items());
1467 switch (item_type) {
1469 case FadeInHandleItem:
1470 if (arv->audio_region()->fade_in_active()) {
1471 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1473 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1476 items.push_back (SeparatorElem());
1478 if (Profile->get_sae()) {
1480 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1481 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1488 *_fade_in_images[FadeLinear],
1489 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1493 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1498 *_fade_in_images[FadeSlow],
1499 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1502 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1507 *_fade_in_images[FadeFast],
1508 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1511 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1516 *_fade_in_images[FadeSymmetric],
1517 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1522 _("Constant power"),
1523 *_fade_in_images[FadeConstantPower],
1524 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1527 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1533 case FadeOutHandleItem:
1534 if (arv->audio_region()->fade_out_active()) {
1535 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1537 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1540 items.push_back (SeparatorElem());
1542 if (Profile->get_sae()) {
1543 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1544 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1550 *_fade_out_images[FadeLinear],
1551 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1555 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1560 *_fade_out_images[FadeSlow],
1561 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1564 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1569 *_fade_out_images[FadeFast],
1570 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1573 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1578 *_fade_out_images[FadeSymmetric],
1579 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1584 _("Constant power"),
1585 *_fade_out_images[FadeConstantPower],
1586 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1589 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1595 fatal << _("programming error: ")
1596 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1601 fade_context_menu.popup (button, time);
1605 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1607 using namespace Menu_Helpers;
1608 Menu* (Editor::*build_menu_function)();
1611 switch (item_type) {
1613 case RegionViewName:
1614 case RegionViewNameHighlight:
1615 case LeftFrameHandle:
1616 case RightFrameHandle:
1617 if (with_selection) {
1618 build_menu_function = &Editor::build_track_selection_context_menu;
1620 build_menu_function = &Editor::build_track_region_context_menu;
1625 if (with_selection) {
1626 build_menu_function = &Editor::build_track_selection_context_menu;
1628 build_menu_function = &Editor::build_track_context_menu;
1633 if (clicked_routeview->track()) {
1634 build_menu_function = &Editor::build_track_context_menu;
1636 build_menu_function = &Editor::build_track_bus_context_menu;
1641 /* probably shouldn't happen but if it does, we don't care */
1645 menu = (this->*build_menu_function)();
1646 menu->set_name ("ArdourContextMenu");
1648 /* now handle specific situations */
1650 switch (item_type) {
1652 case RegionViewName:
1653 case RegionViewNameHighlight:
1654 case LeftFrameHandle:
1655 case RightFrameHandle:
1656 if (!with_selection) {
1657 if (region_edit_menu_split_item) {
1658 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1659 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1661 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1664 if (region_edit_menu_split_multichannel_item) {
1665 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1666 region_edit_menu_split_multichannel_item->set_sensitive (true);
1668 region_edit_menu_split_multichannel_item->set_sensitive (false);
1681 /* probably shouldn't happen but if it does, we don't care */
1685 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1687 /* Bounce to disk */
1689 using namespace Menu_Helpers;
1690 MenuList& edit_items = menu->items();
1692 edit_items.push_back (SeparatorElem());
1694 switch (clicked_routeview->audio_track()->freeze_state()) {
1695 case AudioTrack::NoFreeze:
1696 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1699 case AudioTrack::Frozen:
1700 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1703 case AudioTrack::UnFrozen:
1704 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1710 if (item_type == StreamItem && clicked_routeview) {
1711 clicked_routeview->build_underlay_menu(menu);
1714 /* When the region menu is opened, we setup the actions so that they look right
1717 sensitize_the_right_region_actions ();
1718 _last_region_menu_was_main = false;
1720 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1721 menu->popup (button, time);
1725 Editor::build_track_context_menu ()
1727 using namespace Menu_Helpers;
1729 MenuList& edit_items = track_context_menu.items();
1732 add_dstream_context_items (edit_items);
1733 return &track_context_menu;
1737 Editor::build_track_bus_context_menu ()
1739 using namespace Menu_Helpers;
1741 MenuList& edit_items = track_context_menu.items();
1744 add_bus_context_items (edit_items);
1745 return &track_context_menu;
1749 Editor::build_track_region_context_menu ()
1751 using namespace Menu_Helpers;
1752 MenuList& edit_items = track_region_context_menu.items();
1755 /* we've just cleared the track region context menu, so the menu that these
1756 two items were on will have disappeared; stop them dangling.
1758 region_edit_menu_split_item = 0;
1759 region_edit_menu_split_multichannel_item = 0;
1761 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1764 boost::shared_ptr<Track> tr;
1765 boost::shared_ptr<Playlist> pl;
1767 if ((tr = rtv->track())) {
1768 add_region_context_items (edit_items, tr);
1772 add_dstream_context_items (edit_items);
1774 return &track_region_context_menu;
1778 Editor::analyze_region_selection ()
1780 if (analysis_window == 0) {
1781 analysis_window = new AnalysisWindow();
1784 analysis_window->set_session(_session);
1786 analysis_window->show_all();
1789 analysis_window->set_regionmode();
1790 analysis_window->analyze();
1792 analysis_window->present();
1796 Editor::analyze_range_selection()
1798 if (analysis_window == 0) {
1799 analysis_window = new AnalysisWindow();
1802 analysis_window->set_session(_session);
1804 analysis_window->show_all();
1807 analysis_window->set_rangemode();
1808 analysis_window->analyze();
1810 analysis_window->present();
1814 Editor::build_track_selection_context_menu ()
1816 using namespace Menu_Helpers;
1817 MenuList& edit_items = track_selection_context_menu.items();
1818 edit_items.clear ();
1820 add_selection_context_items (edit_items);
1821 // edit_items.push_back (SeparatorElem());
1822 // add_dstream_context_items (edit_items);
1824 return &track_selection_context_menu;
1828 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1830 using namespace Menu_Helpers;
1832 /* OK, stick the region submenu at the top of the list, and then add
1836 RegionSelection rs = get_regions_from_selection_and_entered ();
1838 string::size_type pos = 0;
1839 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1841 /* we have to hack up the region name because "_" has a special
1842 meaning for menu titles.
1845 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1846 menu_item_name.replace (pos, 1, "__");
1850 if (_popup_region_menu_item == 0) {
1851 _popup_region_menu_item = new MenuItem (menu_item_name);
1852 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1853 _popup_region_menu_item->show ();
1855 _popup_region_menu_item->set_label (menu_item_name);
1858 const framepos_t position = get_preferred_edit_position (false, true);
1860 edit_items.push_back (*_popup_region_menu_item);
1861 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1862 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1864 edit_items.push_back (SeparatorElem());
1867 /** Add context menu items relevant to selection ranges.
1868 * @param edit_items List to add the items to.
1871 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1873 using namespace Menu_Helpers;
1875 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1876 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1878 edit_items.push_back (SeparatorElem());
1879 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1881 edit_items.push_back (SeparatorElem());
1883 edit_items.push_back (
1885 _("Move Range Start to Previous Region Boundary"),
1886 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1890 edit_items.push_back (
1892 _("Move Range Start to Next Region Boundary"),
1893 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1897 edit_items.push_back (
1899 _("Move Range End to Previous Region Boundary"),
1900 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1904 edit_items.push_back (
1906 _("Move Range End to Next Region Boundary"),
1907 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1911 edit_items.push_back (SeparatorElem());
1912 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1913 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1915 edit_items.push_back (SeparatorElem());
1916 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1918 edit_items.push_back (SeparatorElem());
1919 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1920 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1922 edit_items.push_back (SeparatorElem());
1923 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1925 edit_items.push_back (SeparatorElem());
1926 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1927 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1928 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1930 edit_items.push_back (SeparatorElem());
1931 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1932 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1933 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1934 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1935 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1940 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1942 using namespace Menu_Helpers;
1946 Menu *play_menu = manage (new Menu);
1947 MenuList& play_items = play_menu->items();
1948 play_menu->set_name ("ArdourContextMenu");
1950 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1951 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1952 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1953 play_items.push_back (SeparatorElem());
1954 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1956 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1960 Menu *select_menu = manage (new Menu);
1961 MenuList& select_items = select_menu->items();
1962 select_menu->set_name ("ArdourContextMenu");
1964 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1965 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1966 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1967 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1968 select_items.push_back (SeparatorElem());
1969 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1970 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1971 select_items.push_back (SeparatorElem());
1972 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1973 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1974 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1975 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1976 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1977 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1978 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1980 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1984 Menu *cutnpaste_menu = manage (new Menu);
1985 MenuList& cutnpaste_items = cutnpaste_menu->items();
1986 cutnpaste_menu->set_name ("ArdourContextMenu");
1988 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1989 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1990 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1992 cutnpaste_items.push_back (SeparatorElem());
1994 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1995 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1997 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1999 /* Adding new material */
2001 edit_items.push_back (SeparatorElem());
2002 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2003 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2007 Menu *nudge_menu = manage (new Menu());
2008 MenuList& nudge_items = nudge_menu->items();
2009 nudge_menu->set_name ("ArdourContextMenu");
2011 edit_items.push_back (SeparatorElem());
2012 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2013 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2014 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2015 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2017 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2021 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2023 using namespace Menu_Helpers;
2027 Menu *play_menu = manage (new Menu);
2028 MenuList& play_items = play_menu->items();
2029 play_menu->set_name ("ArdourContextMenu");
2031 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2032 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2033 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2037 Menu *select_menu = manage (new Menu);
2038 MenuList& select_items = select_menu->items();
2039 select_menu->set_name ("ArdourContextMenu");
2041 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2042 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2043 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2044 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2045 select_items.push_back (SeparatorElem());
2046 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2047 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2048 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2049 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2051 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2055 Menu *cutnpaste_menu = manage (new Menu);
2056 MenuList& cutnpaste_items = cutnpaste_menu->items();
2057 cutnpaste_menu->set_name ("ArdourContextMenu");
2059 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2060 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2061 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2063 Menu *nudge_menu = manage (new Menu());
2064 MenuList& nudge_items = nudge_menu->items();
2065 nudge_menu->set_name ("ArdourContextMenu");
2067 edit_items.push_back (SeparatorElem());
2068 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2069 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2070 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2071 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2073 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2077 Editor::snap_type() const
2083 Editor::snap_mode() const
2089 Editor::set_snap_to (SnapType st)
2091 unsigned int snap_ind = (unsigned int)st;
2095 if (snap_ind > snap_type_strings.size() - 1) {
2097 _snap_type = (SnapType)snap_ind;
2100 string str = snap_type_strings[snap_ind];
2102 if (str != snap_type_selector.get_active_text()) {
2103 snap_type_selector.set_active_text (str);
2108 switch (_snap_type) {
2109 case SnapToBeatDiv128:
2110 case SnapToBeatDiv64:
2111 case SnapToBeatDiv32:
2112 case SnapToBeatDiv28:
2113 case SnapToBeatDiv24:
2114 case SnapToBeatDiv20:
2115 case SnapToBeatDiv16:
2116 case SnapToBeatDiv14:
2117 case SnapToBeatDiv12:
2118 case SnapToBeatDiv10:
2119 case SnapToBeatDiv8:
2120 case SnapToBeatDiv7:
2121 case SnapToBeatDiv6:
2122 case SnapToBeatDiv5:
2123 case SnapToBeatDiv4:
2124 case SnapToBeatDiv3:
2125 case SnapToBeatDiv2: {
2126 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2127 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2129 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2130 current_bbt_points_begin, current_bbt_points_end);
2131 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2132 current_bbt_points_begin, current_bbt_points_end);
2133 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2137 case SnapToRegionStart:
2138 case SnapToRegionEnd:
2139 case SnapToRegionSync:
2140 case SnapToRegionBoundary:
2141 build_region_boundary_cache ();
2149 SnapChanged (); /* EMIT SIGNAL */
2153 Editor::set_snap_mode (SnapMode mode)
2155 string str = snap_mode_strings[(int)mode];
2157 if (_internal_editing) {
2158 internal_snap_mode = mode;
2160 pre_internal_snap_mode = mode;
2165 if (str != snap_mode_selector.get_active_text ()) {
2166 snap_mode_selector.set_active_text (str);
2172 Editor::set_edit_point_preference (EditPoint ep, bool force)
2174 bool changed = (_edit_point != ep);
2177 string str = edit_point_strings[(int)ep];
2179 if (str != edit_point_selector.get_active_text ()) {
2180 edit_point_selector.set_active_text (str);
2183 set_canvas_cursor ();
2185 if (!force && !changed) {
2189 const char* action=NULL;
2191 switch (_edit_point) {
2192 case EditAtPlayhead:
2193 action = "edit-at-playhead";
2195 case EditAtSelectedMarker:
2196 action = "edit-at-marker";
2199 action = "edit-at-mouse";
2203 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2205 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2209 bool in_track_canvas;
2211 if (!mouse_frame (foo, in_track_canvas)) {
2212 in_track_canvas = false;
2215 reset_canvas_action_sensitivity (in_track_canvas);
2221 Editor::set_state (const XMLNode& node, int /*version*/)
2223 const XMLProperty* prop;
2230 g.base_width = default_width;
2231 g.base_height = default_height;
2235 if ((geometry = find_named_node (node, "geometry")) != 0) {
2239 if ((prop = geometry->property("x_size")) == 0) {
2240 prop = geometry->property ("x-size");
2243 g.base_width = atoi(prop->value());
2245 if ((prop = geometry->property("y_size")) == 0) {
2246 prop = geometry->property ("y-size");
2249 g.base_height = atoi(prop->value());
2252 if ((prop = geometry->property ("x_pos")) == 0) {
2253 prop = geometry->property ("x-pos");
2256 x = atoi (prop->value());
2259 if ((prop = geometry->property ("y_pos")) == 0) {
2260 prop = geometry->property ("y-pos");
2263 y = atoi (prop->value());
2267 set_default_size (g.base_width, g.base_height);
2270 if (_session && (prop = node.property ("playhead"))) {
2272 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2273 playhead_cursor->set_position (pos);
2275 playhead_cursor->set_position (0);
2278 if ((prop = node.property ("mixer-width"))) {
2279 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2282 if ((prop = node.property ("zoom-focus"))) {
2283 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2286 if ((prop = node.property ("zoom"))) {
2287 reset_zoom (PBD::atof (prop->value()));
2289 reset_zoom (samples_per_pixel);
2292 if ((prop = node.property ("snap-to"))) {
2293 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2296 if ((prop = node.property ("snap-mode"))) {
2297 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2300 if ((prop = node.property ("internal-snap-to"))) {
2301 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2304 if ((prop = node.property ("internal-snap-mode"))) {
2305 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2308 if ((prop = node.property ("pre-internal-snap-to"))) {
2309 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2313 if ((prop = node.property ("pre-internal-snap-mode"))) {
2314 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2317 if ((prop = node.property ("mouse-mode"))) {
2318 MouseMode m = str2mousemode(prop->value());
2319 set_mouse_mode (m, true);
2321 set_mouse_mode (MouseObject, true);
2324 if ((prop = node.property ("left-frame")) != 0) {
2326 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2330 reset_x_origin (pos);
2334 if ((prop = node.property ("y-origin")) != 0) {
2335 reset_y_origin (atof (prop->value ()));
2338 if ((prop = node.property ("internal-edit"))) {
2339 bool yn = string_is_affirmative (prop->value());
2340 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2342 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2343 tact->set_active (!yn);
2344 tact->set_active (yn);
2348 if ((prop = node.property ("join-object-range"))) {
2349 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2350 bool yn = string_is_affirmative (prop->value());
2352 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2353 tact->set_active (!yn);
2354 tact->set_active (yn);
2356 set_mouse_mode(mouse_mode, true);
2359 if ((prop = node.property ("edit-point"))) {
2360 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2363 if ((prop = node.property ("show-measures"))) {
2364 bool yn = string_is_affirmative (prop->value());
2365 _show_measures = yn;
2366 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2368 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2369 /* do it twice to force the change */
2370 tact->set_active (!yn);
2371 tact->set_active (yn);
2375 if ((prop = node.property ("follow-playhead"))) {
2376 bool yn = string_is_affirmative (prop->value());
2377 set_follow_playhead (yn);
2378 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2380 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2381 if (tact->get_active() != yn) {
2382 tact->set_active (yn);
2387 if ((prop = node.property ("stationary-playhead"))) {
2388 bool yn = string_is_affirmative (prop->value());
2389 set_stationary_playhead (yn);
2390 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2392 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2393 if (tact->get_active() != yn) {
2394 tact->set_active (yn);
2399 if ((prop = node.property ("region-list-sort-type"))) {
2400 RegionListSortType st;
2401 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2404 if ((prop = node.property ("show-editor-mixer"))) {
2406 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2409 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2410 bool yn = string_is_affirmative (prop->value());
2412 /* do it twice to force the change */
2414 tact->set_active (!yn);
2415 tact->set_active (yn);
2418 if ((prop = node.property ("show-editor-list"))) {
2420 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2423 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2424 bool yn = string_is_affirmative (prop->value());
2426 /* do it twice to force the change */
2428 tact->set_active (!yn);
2429 tact->set_active (yn);
2432 if ((prop = node.property (X_("editor-list-page")))) {
2433 _the_notebook.set_current_page (atoi (prop->value ()));
2436 if ((prop = node.property (X_("show-marker-lines")))) {
2437 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2439 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2440 bool yn = string_is_affirmative (prop->value ());
2442 tact->set_active (!yn);
2443 tact->set_active (yn);
2446 XMLNodeList children = node.children ();
2447 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2448 selection->set_state (**i, Stateful::current_state_version);
2449 _regions->set_state (**i);
2452 if ((prop = node.property ("maximised"))) {
2453 bool yn = string_is_affirmative (prop->value());
2455 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2459 if ((prop = node.property ("nudge-clock-value"))) {
2461 sscanf (prop->value().c_str(), "%" PRId64, &f);
2462 nudge_clock->set (f);
2464 nudge_clock->set_mode (AudioClock::Timecode);
2465 nudge_clock->set (_session->frame_rate() * 5, true);
2472 Editor::get_state ()
2474 XMLNode* node = new XMLNode ("Editor");
2477 id().print (buf, sizeof (buf));
2478 node->add_property ("id", buf);
2480 if (is_realized()) {
2481 Glib::RefPtr<Gdk::Window> win = get_window();
2483 int x, y, width, height;
2484 win->get_root_origin(x, y);
2485 win->get_size(width, height);
2487 XMLNode* geometry = new XMLNode ("geometry");
2489 snprintf(buf, sizeof(buf), "%d", width);
2490 geometry->add_property("x-size", string(buf));
2491 snprintf(buf, sizeof(buf), "%d", height);
2492 geometry->add_property("y-size", string(buf));
2493 snprintf(buf, sizeof(buf), "%d", x);
2494 geometry->add_property("x-pos", string(buf));
2495 snprintf(buf, sizeof(buf), "%d", y);
2496 geometry->add_property("y-pos", string(buf));
2497 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2498 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2499 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2500 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2501 geometry->add_property("edit-vertical-pane-pos", string(buf));
2503 node->add_child_nocopy (*geometry);
2506 maybe_add_mixer_strip_width (*node);
2508 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2509 snprintf (buf, sizeof(buf), "%f", samples_per_pixel);
2510 node->add_property ("zoom", buf);
2511 node->add_property ("snap-to", enum_2_string (_snap_type));
2512 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2513 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2514 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2515 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2516 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2517 node->add_property ("edit-point", enum_2_string (_edit_point));
2519 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2520 node->add_property ("playhead", buf);
2521 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2522 node->add_property ("left-frame", buf);
2523 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2524 node->add_property ("y-origin", buf);
2526 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2527 node->add_property ("maximised", _maximised ? "yes" : "no");
2528 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2529 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2530 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2531 node->add_property ("mouse-mode", enum2str(mouse_mode));
2532 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2533 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2535 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2537 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2538 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2541 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2543 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2544 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2547 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2548 node->add_property (X_("editor-list-page"), buf);
2550 if (button_bindings) {
2551 XMLNode* bb = new XMLNode (X_("Buttons"));
2552 button_bindings->save (*bb);
2553 node->add_child_nocopy (*bb);
2556 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2558 node->add_child_nocopy (selection->get_state ());
2559 node->add_child_nocopy (_regions->get_state ());
2561 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2562 node->add_property ("nudge-clock-value", buf);
2569 /** @param y y offset from the top of all trackviews.
2570 * @return pair: TimeAxisView that y is over, layer index.
2571 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2572 * in stacked or expanded region display mode, otherwise 0.
2574 std::pair<TimeAxisView *, double>
2575 Editor::trackview_by_y_position (double y)
2577 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2579 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2585 return std::make_pair ( (TimeAxisView *) 0, 0);
2588 /** Snap a position to the grid, if appropriate, taking into account current
2589 * grid settings and also the state of any snap modifier keys that may be pressed.
2590 * @param start Position to snap.
2591 * @param event Event to get current key modifier information from, or 0.
2594 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2596 if (!_session || !event) {
2600 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2601 if (_snap_mode == SnapOff) {
2602 snap_to_internal (start, direction, for_mark);
2605 if (_snap_mode != SnapOff) {
2606 snap_to_internal (start, direction, for_mark);
2612 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2614 if (!_session || _snap_mode == SnapOff) {
2618 snap_to_internal (start, direction, for_mark);
2622 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2624 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2625 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2627 switch (_snap_type) {
2628 case SnapToTimecodeFrame:
2629 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2630 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2632 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2636 case SnapToTimecodeSeconds:
2637 if (_session->config.get_timecode_offset_negative()) {
2638 start += _session->config.get_timecode_offset ();
2640 start -= _session->config.get_timecode_offset ();
2642 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2643 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2645 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2648 if (_session->config.get_timecode_offset_negative()) {
2649 start -= _session->config.get_timecode_offset ();
2651 start += _session->config.get_timecode_offset ();
2655 case SnapToTimecodeMinutes:
2656 if (_session->config.get_timecode_offset_negative()) {
2657 start += _session->config.get_timecode_offset ();
2659 start -= _session->config.get_timecode_offset ();
2661 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2662 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2664 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2666 if (_session->config.get_timecode_offset_negative()) {
2667 start -= _session->config.get_timecode_offset ();
2669 start += _session->config.get_timecode_offset ();
2673 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2679 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2681 const framepos_t one_second = _session->frame_rate();
2682 const framepos_t one_minute = _session->frame_rate() * 60;
2683 framepos_t presnap = start;
2687 switch (_snap_type) {
2688 case SnapToTimecodeFrame:
2689 case SnapToTimecodeSeconds:
2690 case SnapToTimecodeMinutes:
2691 return timecode_snap_to_internal (start, direction, for_mark);
2694 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2695 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2697 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2702 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2703 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2705 start = (framepos_t) floor ((double) start / one_second) * one_second;
2710 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2711 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2713 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2718 start = _session->tempo_map().round_to_bar (start, direction);
2722 start = _session->tempo_map().round_to_beat (start, direction);
2725 case SnapToBeatDiv128:
2726 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2728 case SnapToBeatDiv64:
2729 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2731 case SnapToBeatDiv32:
2732 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2734 case SnapToBeatDiv28:
2735 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2737 case SnapToBeatDiv24:
2738 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2740 case SnapToBeatDiv20:
2741 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2743 case SnapToBeatDiv16:
2744 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2746 case SnapToBeatDiv14:
2747 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2749 case SnapToBeatDiv12:
2750 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2752 case SnapToBeatDiv10:
2753 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2755 case SnapToBeatDiv8:
2756 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2758 case SnapToBeatDiv7:
2759 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2761 case SnapToBeatDiv6:
2762 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2764 case SnapToBeatDiv5:
2765 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2767 case SnapToBeatDiv4:
2768 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2770 case SnapToBeatDiv3:
2771 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2773 case SnapToBeatDiv2:
2774 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2782 _session->locations()->marks_either_side (start, before, after);
2784 if (before == max_framepos && after == max_framepos) {
2785 /* No marks to snap to, so just don't snap */
2787 } else if (before == max_framepos) {
2789 } else if (after == max_framepos) {
2791 } else if (before != max_framepos && after != max_framepos) {
2792 /* have before and after */
2793 if ((start - before) < (after - start)) {
2802 case SnapToRegionStart:
2803 case SnapToRegionEnd:
2804 case SnapToRegionSync:
2805 case SnapToRegionBoundary:
2806 if (!region_boundary_cache.empty()) {
2808 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2809 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2811 if (direction > 0) {
2812 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2814 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2817 if (next != region_boundary_cache.begin ()) {
2822 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2823 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2825 if (start > (p + n) / 2) {
2834 switch (_snap_mode) {
2840 if (presnap > start) {
2841 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2845 } else if (presnap < start) {
2846 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2852 /* handled at entry */
2860 Editor::setup_toolbar ()
2862 HBox* mode_box = manage(new HBox);
2863 mode_box->set_border_width (2);
2864 mode_box->set_spacing(4);
2866 HBox* mouse_mode_box = manage (new HBox);
2867 HBox* mouse_mode_hbox = manage (new HBox);
2868 VBox* mouse_mode_vbox = manage (new VBox);
2869 Alignment* mouse_mode_align = manage (new Alignment);
2871 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2872 // mouse_mode_size_group->add_widget (smart_mode_button);
2873 mouse_mode_size_group->add_widget (mouse_move_button);
2874 mouse_mode_size_group->add_widget (mouse_select_button);
2875 mouse_mode_size_group->add_widget (mouse_zoom_button);
2876 mouse_mode_size_group->add_widget (mouse_gain_button);
2877 mouse_mode_size_group->add_widget (mouse_timefx_button);
2878 mouse_mode_size_group->add_widget (mouse_audition_button);
2879 mouse_mode_size_group->add_widget (mouse_draw_button);
2880 mouse_mode_size_group->add_widget (internal_edit_button);
2882 /* make them just a bit bigger */
2883 mouse_move_button.set_size_request (-1, 30);
2885 mouse_mode_hbox->set_spacing (2);
2887 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2888 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2889 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2890 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2891 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2892 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2893 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2894 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2895 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2897 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2899 mouse_mode_align->add (*mouse_mode_vbox);
2900 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2902 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2904 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2905 if (!Profile->get_sae()) {
2906 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2908 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2910 edit_mode_selector.set_name ("EditModeSelector");
2911 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2912 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2914 mode_box->pack_start (edit_mode_selector, false, false);
2915 mode_box->pack_start (*mouse_mode_box, false, false);
2917 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2918 _mouse_mode_tearoff->set_name ("MouseModeBase");
2919 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2921 if (Profile->get_sae()) {
2922 _mouse_mode_tearoff->set_can_be_torn_off (false);
2925 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2926 &_mouse_mode_tearoff->tearoff_window()));
2927 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2928 &_mouse_mode_tearoff->tearoff_window(), 1));
2929 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2930 &_mouse_mode_tearoff->tearoff_window()));
2931 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2932 &_mouse_mode_tearoff->tearoff_window(), 1));
2936 _zoom_box.set_spacing (2);
2937 _zoom_box.set_border_width (2);
2941 zoom_in_button.set_name ("zoom button");
2942 zoom_in_button.add_elements ( ArdourButton::FlatFace );
2943 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2944 zoom_in_button.set_image(::get_icon ("zoom_in"));
2945 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2946 zoom_in_button.set_related_action (act);
2948 zoom_out_button.set_name ("zoom button");
2949 zoom_out_button.add_elements ( ArdourButton::FlatFace );
2950 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2951 zoom_out_button.set_image(::get_icon ("zoom_out"));
2952 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2953 zoom_out_button.set_related_action (act);
2955 zoom_out_full_button.set_name ("zoom button");
2956 zoom_out_full_button.add_elements ( ArdourButton::FlatFace );
2957 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2958 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2959 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2960 zoom_out_full_button.set_related_action (act);
2962 zoom_focus_selector.set_name ("ZoomFocusSelector");
2963 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2964 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2966 _zoom_box.pack_start (zoom_out_button, false, false);
2967 _zoom_box.pack_start (zoom_in_button, false, false);
2968 _zoom_box.pack_start (zoom_out_full_button, false, false);
2970 _zoom_box.pack_start (zoom_focus_selector, false, false);
2972 /* Track zoom buttons */
2973 tav_expand_button.set_name ("zoom button");
2974 tav_expand_button.add_elements ( ArdourButton::FlatFace );
2975 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2976 tav_expand_button.set_size_request (-1, 20);
2977 tav_expand_button.set_image(::get_icon ("tav_exp"));
2978 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2979 tav_expand_button.set_related_action (act);
2981 tav_shrink_button.set_name ("zoom button");
2982 tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2983 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2984 tav_shrink_button.set_size_request (-1, 20);
2985 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2986 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2987 tav_shrink_button.set_related_action (act);
2989 _zoom_box.pack_start (tav_shrink_button);
2990 _zoom_box.pack_start (tav_expand_button);
2992 _zoom_tearoff = manage (new TearOff (_zoom_box));
2994 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2995 &_zoom_tearoff->tearoff_window()));
2996 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2997 &_zoom_tearoff->tearoff_window(), 0));
2998 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2999 &_zoom_tearoff->tearoff_window()));
3000 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3001 &_zoom_tearoff->tearoff_window(), 0));
3003 snap_box.set_spacing (2);
3004 snap_box.set_border_width (2);
3006 snap_type_selector.set_name ("SnapTypeSelector");
3007 set_popdown_strings (snap_type_selector, snap_type_strings);
3008 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
3010 snap_mode_selector.set_name ("SnapModeSelector");
3011 set_popdown_strings (snap_mode_selector, snap_mode_strings);
3012 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
3014 edit_point_selector.set_name ("EditPointSelector");
3015 set_popdown_strings (edit_point_selector, edit_point_strings);
3016 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
3018 snap_box.pack_start (snap_mode_selector, false, false);
3019 snap_box.pack_start (snap_type_selector, false, false);
3020 snap_box.pack_start (edit_point_selector, false, false);
3024 HBox *nudge_box = manage (new HBox);
3025 nudge_box->set_spacing (2);
3026 nudge_box->set_border_width (2);
3028 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3029 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3031 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3032 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3034 nudge_box->pack_start (nudge_backward_button, false, false);
3035 nudge_box->pack_start (nudge_forward_button, false, false);
3036 nudge_box->pack_start (*nudge_clock, false, false);
3039 /* Pack everything in... */
3041 HBox* hbox = manage (new HBox);
3042 hbox->set_spacing(10);
3044 _tools_tearoff = manage (new TearOff (*hbox));
3045 _tools_tearoff->set_name ("MouseModeBase");
3046 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3048 if (Profile->get_sae()) {
3049 _tools_tearoff->set_can_be_torn_off (false);
3052 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3053 &_tools_tearoff->tearoff_window()));
3054 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3055 &_tools_tearoff->tearoff_window(), 0));
3056 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3057 &_tools_tearoff->tearoff_window()));
3058 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3059 &_tools_tearoff->tearoff_window(), 0));
3061 toolbar_hbox.set_spacing (10);
3062 toolbar_hbox.set_border_width (1);
3064 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3065 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3066 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3068 hbox->pack_start (snap_box, false, false);
3069 if (!Profile->get_small_screen()) {
3070 hbox->pack_start (*nudge_box, false, false);
3072 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3074 hbox->pack_start (panic_box, false, false);
3078 toolbar_base.set_name ("ToolBarBase");
3079 toolbar_base.add (toolbar_hbox);
3081 _toolbar_viewport.add (toolbar_base);
3082 /* stick to the required height but allow width to vary if there's not enough room */
3083 _toolbar_viewport.set_size_request (1, -1);
3085 toolbar_frame.set_shadow_type (SHADOW_OUT);
3086 toolbar_frame.set_name ("BaseFrame");
3087 toolbar_frame.add (_toolbar_viewport);
3091 Editor::setup_tooltips ()
3093 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3094 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3095 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3096 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3097 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3098 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3099 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3100 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3101 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3102 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3103 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3104 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3105 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3106 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3107 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3108 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3109 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3110 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3111 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3112 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3113 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3114 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3115 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3119 Editor::convert_drop_to_paths (
3120 vector<string>& paths,
3121 const RefPtr<Gdk::DragContext>& /*context*/,
3124 const SelectionData& data,
3128 if (_session == 0) {
3132 vector<string> uris = data.get_uris();
3136 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3137 are actually URI lists. So do it by hand.
3140 if (data.get_target() != "text/plain") {
3144 /* Parse the "uri-list" format that Nautilus provides,
3145 where each pathname is delimited by \r\n.
3147 THERE MAY BE NO NULL TERMINATING CHAR!!!
3150 string txt = data.get_text();
3154 p = (const char *) malloc (txt.length() + 1);
3155 txt.copy (const_cast<char *> (p), txt.length(), 0);
3156 const_cast<char*>(p)[txt.length()] = '\0';
3162 while (g_ascii_isspace (*p))
3166 while (*q && (*q != '\n') && (*q != '\r')) {
3173 while (q > p && g_ascii_isspace (*q))
3178 uris.push_back (string (p, q - p + 1));
3182 p = strchr (p, '\n');
3194 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3196 if ((*i).substr (0,7) == "file://") {
3198 string const p = PBD::url_decode (*i);
3200 // scan forward past three slashes
3202 string::size_type slashcnt = 0;
3203 string::size_type n = 0;
3204 string::const_iterator x = p.begin();
3206 while (slashcnt < 3 && x != p.end()) {
3209 } else if (slashcnt == 3) {
3216 if (slashcnt != 3 || x == p.end()) {
3217 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3221 paths.push_back (p.substr (n - 1));
3229 Editor::new_tempo_section ()
3235 Editor::map_transport_state ()
3237 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3239 if (_session && _session->transport_stopped()) {
3240 have_pending_keyboard_selection = false;
3243 update_loop_range_view (true);
3249 Editor::begin_reversible_command (string name)
3252 _session->begin_reversible_command (name);
3257 Editor::begin_reversible_command (GQuark q)
3260 _session->begin_reversible_command (q);
3265 Editor::commit_reversible_command ()
3268 _session->commit_reversible_command ();
3273 Editor::history_changed ()
3277 if (undo_action && _session) {
3278 if (_session->undo_depth() == 0) {
3279 label = S_("Command|Undo");
3281 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3283 undo_action->property_label() = label;
3286 if (redo_action && _session) {
3287 if (_session->redo_depth() == 0) {
3290 label = string_compose(_("Redo (%1)"), _session->next_redo());
3292 redo_action->property_label() = label;
3297 Editor::duplicate_range (bool with_dialog)
3301 RegionSelection rs = get_regions_from_selection_and_entered ();
3303 if ( selection->time.length() == 0 && rs.empty()) {
3309 ArdourDialog win (_("Duplicate"));
3310 Label label (_("Number of duplications:"));
3311 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3312 SpinButton spinner (adjustment, 0.0, 1);
3315 win.get_vbox()->set_spacing (12);
3316 win.get_vbox()->pack_start (hbox);
3317 hbox.set_border_width (6);
3318 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3320 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3321 place, visually. so do this by hand.
3324 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3325 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3326 spinner.grab_focus();
3332 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3333 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3334 win.set_default_response (RESPONSE_ACCEPT);
3336 win.set_position (WIN_POS_MOUSE);
3338 spinner.grab_focus ();
3340 switch (win.run ()) {
3341 case RESPONSE_ACCEPT:
3347 times = adjustment.get_value();
3350 if ((current_mouse_mode() == Editing::MouseRange)) {
3351 if (selection->time.length()) {
3352 duplicate_selection (times);
3354 } else if (get_smart_mode()) {
3355 if (selection->time.length()) {
3356 duplicate_selection (times);
3358 duplicate_some_regions (rs, times);
3360 duplicate_some_regions (rs, times);
3365 Editor::set_edit_mode (EditMode m)
3367 Config->set_edit_mode (m);
3371 Editor::cycle_edit_mode ()
3373 switch (Config->get_edit_mode()) {
3375 if (Profile->get_sae()) {
3376 Config->set_edit_mode (Lock);
3378 Config->set_edit_mode (Splice);
3382 Config->set_edit_mode (Lock);
3385 Config->set_edit_mode (Slide);
3391 Editor::edit_mode_selection_done ()
3393 string s = edit_mode_selector.get_active_text ();
3396 Config->set_edit_mode (string_to_edit_mode (s));
3401 Editor::snap_type_selection_done ()
3403 string choice = snap_type_selector.get_active_text();
3404 SnapType snaptype = SnapToBeat;
3406 if (choice == _("Beats/2")) {
3407 snaptype = SnapToBeatDiv2;
3408 } else if (choice == _("Beats/3")) {
3409 snaptype = SnapToBeatDiv3;
3410 } else if (choice == _("Beats/4")) {
3411 snaptype = SnapToBeatDiv4;
3412 } else if (choice == _("Beats/5")) {
3413 snaptype = SnapToBeatDiv5;
3414 } else if (choice == _("Beats/6")) {
3415 snaptype = SnapToBeatDiv6;
3416 } else if (choice == _("Beats/7")) {
3417 snaptype = SnapToBeatDiv7;
3418 } else if (choice == _("Beats/8")) {
3419 snaptype = SnapToBeatDiv8;
3420 } else if (choice == _("Beats/10")) {
3421 snaptype = SnapToBeatDiv10;
3422 } else if (choice == _("Beats/12")) {
3423 snaptype = SnapToBeatDiv12;
3424 } else if (choice == _("Beats/14")) {
3425 snaptype = SnapToBeatDiv14;
3426 } else if (choice == _("Beats/16")) {
3427 snaptype = SnapToBeatDiv16;
3428 } else if (choice == _("Beats/20")) {
3429 snaptype = SnapToBeatDiv20;
3430 } else if (choice == _("Beats/24")) {
3431 snaptype = SnapToBeatDiv24;
3432 } else if (choice == _("Beats/28")) {
3433 snaptype = SnapToBeatDiv28;
3434 } else if (choice == _("Beats/32")) {
3435 snaptype = SnapToBeatDiv32;
3436 } else if (choice == _("Beats/64")) {
3437 snaptype = SnapToBeatDiv64;
3438 } else if (choice == _("Beats/128")) {
3439 snaptype = SnapToBeatDiv128;
3440 } else if (choice == _("Beats")) {
3441 snaptype = SnapToBeat;
3442 } else if (choice == _("Bars")) {
3443 snaptype = SnapToBar;
3444 } else if (choice == _("Marks")) {
3445 snaptype = SnapToMark;
3446 } else if (choice == _("Region starts")) {
3447 snaptype = SnapToRegionStart;
3448 } else if (choice == _("Region ends")) {
3449 snaptype = SnapToRegionEnd;
3450 } else if (choice == _("Region bounds")) {
3451 snaptype = SnapToRegionBoundary;
3452 } else if (choice == _("Region syncs")) {
3453 snaptype = SnapToRegionSync;
3454 } else if (choice == _("CD Frames")) {
3455 snaptype = SnapToCDFrame;
3456 } else if (choice == _("Timecode Frames")) {
3457 snaptype = SnapToTimecodeFrame;
3458 } else if (choice == _("Timecode Seconds")) {
3459 snaptype = SnapToTimecodeSeconds;
3460 } else if (choice == _("Timecode Minutes")) {
3461 snaptype = SnapToTimecodeMinutes;
3462 } else if (choice == _("Seconds")) {
3463 snaptype = SnapToSeconds;
3464 } else if (choice == _("Minutes")) {
3465 snaptype = SnapToMinutes;
3468 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3470 ract->set_active ();
3475 Editor::snap_mode_selection_done ()
3477 string choice = snap_mode_selector.get_active_text();
3478 SnapMode mode = SnapNormal;
3480 if (choice == _("No Grid")) {
3482 } else if (choice == _("Grid")) {
3484 } else if (choice == _("Magnetic")) {
3485 mode = SnapMagnetic;
3488 RefPtr<RadioAction> ract = snap_mode_action (mode);
3491 ract->set_active (true);
3496 Editor::cycle_edit_point (bool with_marker)
3498 switch (_edit_point) {
3500 set_edit_point_preference (EditAtPlayhead);
3502 case EditAtPlayhead:
3504 set_edit_point_preference (EditAtSelectedMarker);
3506 set_edit_point_preference (EditAtMouse);
3509 case EditAtSelectedMarker:
3510 set_edit_point_preference (EditAtMouse);
3516 Editor::edit_point_selection_done ()
3518 string choice = edit_point_selector.get_active_text();
3519 EditPoint ep = EditAtSelectedMarker;
3521 if (choice == _("Marker")) {
3522 set_edit_point_preference (EditAtSelectedMarker);
3523 } else if (choice == _("Playhead")) {
3524 set_edit_point_preference (EditAtPlayhead);
3526 set_edit_point_preference (EditAtMouse);
3529 RefPtr<RadioAction> ract = edit_point_action (ep);
3532 ract->set_active (true);
3537 Editor::zoom_focus_selection_done ()
3539 string choice = zoom_focus_selector.get_active_text();
3540 ZoomFocus focus_type = ZoomFocusLeft;
3542 if (choice == _("Left")) {
3543 focus_type = ZoomFocusLeft;
3544 } else if (choice == _("Right")) {
3545 focus_type = ZoomFocusRight;
3546 } else if (choice == _("Center")) {
3547 focus_type = ZoomFocusCenter;
3548 } else if (choice == _("Playhead")) {
3549 focus_type = ZoomFocusPlayhead;
3550 } else if (choice == _("Mouse")) {
3551 focus_type = ZoomFocusMouse;
3552 } else if (choice == _("Edit point")) {
3553 focus_type = ZoomFocusEdit;
3556 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3559 ract->set_active ();
3564 Editor::edit_controls_button_release (GdkEventButton* ev)
3566 if (Keyboard::is_context_menu_event (ev)) {
3567 ARDOUR_UI::instance()->add_route (this);
3568 } else if (ev->button == 1) {
3569 selection->clear_tracks ();
3576 Editor::mouse_select_button_release (GdkEventButton* ev)
3578 /* this handles just right-clicks */
3580 if (ev->button != 3) {
3588 Editor::set_zoom_focus (ZoomFocus f)
3590 string str = zoom_focus_strings[(int)f];
3592 if (str != zoom_focus_selector.get_active_text()) {
3593 zoom_focus_selector.set_active_text (str);
3596 if (zoom_focus != f) {
3603 Editor::cycle_zoom_focus ()
3605 switch (zoom_focus) {
3607 set_zoom_focus (ZoomFocusRight);
3609 case ZoomFocusRight:
3610 set_zoom_focus (ZoomFocusCenter);
3612 case ZoomFocusCenter:
3613 set_zoom_focus (ZoomFocusPlayhead);
3615 case ZoomFocusPlayhead:
3616 set_zoom_focus (ZoomFocusMouse);
3618 case ZoomFocusMouse:
3619 set_zoom_focus (ZoomFocusEdit);
3622 set_zoom_focus (ZoomFocusLeft);
3628 Editor::ensure_float (Window& win)
3630 win.set_transient_for (*this);
3634 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3636 /* recover or initialize pane positions. do this here rather than earlier because
3637 we don't want the positions to change the child allocations, which they seem to do.
3643 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3652 XMLNode* geometry = find_named_node (*node, "geometry");
3654 if (which == static_cast<Paned*> (&edit_pane)) {
3656 if (done & Horizontal) {
3660 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3661 _notebook_shrunk = string_is_affirmative (prop->value ());
3664 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3665 /* initial allocation is 90% to canvas, 10% to notebook */
3666 pos = (int) floor (alloc.get_width() * 0.90f);
3667 snprintf (buf, sizeof(buf), "%d", pos);
3669 pos = atoi (prop->value());
3672 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3673 edit_pane.set_position (pos);
3676 done = (Pane) (done | Horizontal);
3678 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3680 if (done & Vertical) {
3684 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3685 /* initial allocation is 90% to canvas, 10% to summary */
3686 pos = (int) floor (alloc.get_height() * 0.90f);
3687 snprintf (buf, sizeof(buf), "%d", pos);
3690 pos = atoi (prop->value());
3693 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3694 editor_summary_pane.set_position (pos);
3697 done = (Pane) (done | Vertical);
3702 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3704 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3705 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3706 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3707 top_hbox.remove (toolbar_frame);
3712 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3714 if (toolbar_frame.get_parent() == 0) {
3715 top_hbox.pack_end (toolbar_frame);
3720 Editor::set_show_measures (bool yn)
3722 if (_show_measures != yn) {
3725 if ((_show_measures = yn) == true) {
3727 tempo_lines->show();
3730 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3731 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3733 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3734 draw_measures (begin, end);
3742 Editor::toggle_follow_playhead ()
3744 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3746 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3747 set_follow_playhead (tact->get_active());
3751 /** @param yn true to follow playhead, otherwise false.
3752 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3755 Editor::set_follow_playhead (bool yn, bool catch_up)
3757 if (_follow_playhead != yn) {
3758 if ((_follow_playhead = yn) == true && catch_up) {
3760 reset_x_origin_to_follow_playhead ();
3767 Editor::toggle_stationary_playhead ()
3769 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3771 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3772 set_stationary_playhead (tact->get_active());
3777 Editor::set_stationary_playhead (bool yn)
3779 if (_stationary_playhead != yn) {
3780 if ((_stationary_playhead = yn) == true) {
3782 // FIXME need a 3.0 equivalent of this 2.X call
3783 // update_current_screen ();
3790 Editor::playlist_selector () const
3792 return *_playlist_selector;
3796 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3800 switch (_snap_type) {
3805 case SnapToBeatDiv128:
3808 case SnapToBeatDiv64:
3811 case SnapToBeatDiv32:
3814 case SnapToBeatDiv28:
3817 case SnapToBeatDiv24:
3820 case SnapToBeatDiv20:
3823 case SnapToBeatDiv16:
3826 case SnapToBeatDiv14:
3829 case SnapToBeatDiv12:
3832 case SnapToBeatDiv10:
3835 case SnapToBeatDiv8:
3838 case SnapToBeatDiv7:
3841 case SnapToBeatDiv6:
3844 case SnapToBeatDiv5:
3847 case SnapToBeatDiv4:
3850 case SnapToBeatDiv3:
3853 case SnapToBeatDiv2:
3859 return _session->tempo_map().meter_at (position).divisions_per_bar();
3864 case SnapToTimecodeFrame:
3865 case SnapToTimecodeSeconds:
3866 case SnapToTimecodeMinutes:
3869 case SnapToRegionStart:
3870 case SnapToRegionEnd:
3871 case SnapToRegionSync:
3872 case SnapToRegionBoundary:
3882 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3886 ret = nudge_clock->current_duration (pos);
3887 next = ret + 1; /* XXXX fix me */
3893 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3895 ArdourDialog dialog (_("Playlist Deletion"));
3896 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3897 "If it is kept, its audio files will not be cleaned.\n"
3898 "If it is deleted, audio files used by it alone will be cleaned."),
3901 dialog.set_position (WIN_POS_CENTER);
3902 dialog.get_vbox()->pack_start (label);
3906 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3907 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3908 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3910 switch (dialog.run ()) {
3911 case RESPONSE_ACCEPT:
3912 /* delete the playlist */
3916 case RESPONSE_REJECT:
3917 /* keep the playlist */
3929 Editor::audio_region_selection_covers (framepos_t where)
3931 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3932 if ((*a)->region()->covers (where)) {
3941 Editor::prepare_for_cleanup ()
3943 cut_buffer->clear_regions ();
3944 cut_buffer->clear_playlists ();
3946 selection->clear_regions ();
3947 selection->clear_playlists ();
3949 _regions->suspend_redisplay ();
3953 Editor::finish_cleanup ()
3955 _regions->resume_redisplay ();
3959 Editor::transport_loop_location()
3962 return _session->locations()->auto_loop_location();
3969 Editor::transport_punch_location()
3972 return _session->locations()->auto_punch_location();
3979 Editor::control_layout_scroll (GdkEventScroll* ev)
3981 if (Keyboard::some_magic_widget_has_focus()) {
3985 switch (ev->direction) {
3987 scroll_tracks_up_line ();
3991 case GDK_SCROLL_DOWN:
3992 scroll_tracks_down_line ();
3996 /* no left/right handling yet */
4004 Editor::session_state_saved (string)
4007 _snapshots->redisplay ();
4011 Editor::update_tearoff_visibility()
4013 bool visible = Config->get_keep_tearoffs();
4014 _mouse_mode_tearoff->set_visible (visible);
4015 _tools_tearoff->set_visible (visible);
4016 _zoom_tearoff->set_visible (visible);
4020 Editor::maximise_editing_space ()
4032 Editor::restore_editing_space ()
4044 * Make new playlists for a given track and also any others that belong
4045 * to the same active route group with the `select' property.
4050 Editor::new_playlists (TimeAxisView* v)
4052 begin_reversible_command (_("new playlists"));
4053 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4054 _session->playlists->get (playlists);
4055 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4056 commit_reversible_command ();
4060 * Use a copy of the current playlist for a given track and also any others that belong
4061 * to the same active route group with the `select' property.
4066 Editor::copy_playlists (TimeAxisView* v)
4068 begin_reversible_command (_("copy playlists"));
4069 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4070 _session->playlists->get (playlists);
4071 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4072 commit_reversible_command ();
4075 /** Clear the current playlist for a given track and also any others that belong
4076 * to the same active route group with the `select' property.
4081 Editor::clear_playlists (TimeAxisView* v)
4083 begin_reversible_command (_("clear playlists"));
4084 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4085 _session->playlists->get (playlists);
4086 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4087 commit_reversible_command ();
4091 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4093 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4097 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4099 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4103 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4105 atv.clear_playlist ();
4109 Editor::on_key_press_event (GdkEventKey* ev)
4111 return key_press_focus_accelerator_handler (*this, ev);
4115 Editor::on_key_release_event (GdkEventKey* ev)
4117 return Gtk::Window::on_key_release_event (ev);
4118 // return key_press_focus_accelerator_handler (*this, ev);
4121 /** Queue up a change to the viewport x origin.
4122 * @param frame New x origin.
4125 Editor::reset_x_origin (framepos_t frame)
4127 pending_visual_change.add (VisualChange::TimeOrigin);
4128 pending_visual_change.time_origin = frame;
4129 ensure_visual_change_idle_handler ();
4133 Editor::reset_y_origin (double y)
4135 pending_visual_change.add (VisualChange::YOrigin);
4136 pending_visual_change.y_origin = y;
4137 ensure_visual_change_idle_handler ();
4141 Editor::reset_zoom (double fpp)
4143 clamp_samples_per_pixel (fpp);
4145 if (fpp == samples_per_pixel) {
4149 pending_visual_change.add (VisualChange::ZoomLevel);
4150 pending_visual_change.samples_per_pixel = fpp;
4151 ensure_visual_change_idle_handler ();
4155 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4157 reset_x_origin (frame);
4160 if (!no_save_visual) {
4161 undo_visual_stack.push_back (current_visual_state(false));
4165 Editor::VisualState::VisualState (bool with_tracks)
4166 : gui_state (with_tracks ? new GUIObjectState : 0)
4170 Editor::VisualState::~VisualState ()
4175 Editor::VisualState*
4176 Editor::current_visual_state (bool with_tracks)
4178 VisualState* vs = new VisualState (with_tracks);
4179 vs->y_position = vertical_adjustment.get_value();
4180 vs->samples_per_pixel = samples_per_pixel;
4181 vs->leftmost_frame = leftmost_frame;
4182 vs->zoom_focus = zoom_focus;
4185 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4192 Editor::undo_visual_state ()
4194 if (undo_visual_stack.empty()) {
4198 VisualState* vs = undo_visual_stack.back();
4199 undo_visual_stack.pop_back();
4202 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4204 use_visual_state (*vs);
4208 Editor::redo_visual_state ()
4210 if (redo_visual_stack.empty()) {
4214 VisualState* vs = redo_visual_stack.back();
4215 redo_visual_stack.pop_back();
4217 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4219 use_visual_state (*vs);
4223 Editor::swap_visual_state ()
4225 if (undo_visual_stack.empty()) {
4226 redo_visual_state ();
4228 undo_visual_state ();
4233 Editor::use_visual_state (VisualState& vs)
4235 PBD::Unwinder<bool> nsv (no_save_visual, true);
4237 _routes->suspend_redisplay ();
4239 vertical_adjustment.set_value (vs.y_position);
4241 set_zoom_focus (vs.zoom_focus);
4242 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4245 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4247 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4248 (*i)->reset_visual_state ();
4252 _routes->update_visibility ();
4253 _routes->resume_redisplay ();
4256 /** This is the core function that controls the zoom level of the canvas. It is called
4257 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4258 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4261 Editor::set_samples_per_pixel (double fpp)
4264 tempo_lines->tempo_map_changed();
4267 samples_per_pixel = fpp;
4269 /* convert fpu to frame count */
4271 framepos_t frames = (framepos_t) floor (samples_per_pixel * _visible_canvas_width);
4273 if (samples_per_pixel != zoom_range_clock->current_duration()) {
4274 zoom_range_clock->set (frames);
4277 bool const showing_time_selection = selection->time.length() > 0;
4279 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4280 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4281 (*i)->reshow_selection (selection->time);
4285 ZoomChanged (); /* EMIT_SIGNAL */
4287 //reset_scrolling_region ();
4289 if (playhead_cursor) {
4290 playhead_cursor->set_position (playhead_cursor->current_frame ());
4293 refresh_location_display();
4294 _summary->set_overlays_dirty ();
4296 update_marker_labels ();
4302 Editor::queue_visual_videotimeline_update ()
4305 * pending_visual_change.add (VisualChange::VideoTimeline);
4306 * or maybe even more specific: which videotimeline-image
4307 * currently it calls update_video_timeline() to update
4308 * _all outdated_ images on the video-timeline.
4309 * see 'exposeimg()' in video_image_frame.cc
4311 ensure_visual_change_idle_handler ();
4315 Editor::ensure_visual_change_idle_handler ()
4317 if (pending_visual_change.idle_handler_id < 0) {
4318 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4319 pending_visual_change.being_handled = false;
4324 Editor::_idle_visual_changer (void* arg)
4326 return static_cast<Editor*>(arg)->idle_visual_changer ();
4330 Editor::idle_visual_changer ()
4332 /* set_horizontal_position() below (and maybe other calls) call
4333 gtk_main_iteration(), so it's possible that a signal will be handled
4334 half-way through this method. If this signal wants an
4335 idle_visual_changer we must schedule another one after this one, so
4336 mark the idle_handler_id as -1 here to allow that. Also make a note
4337 that we are doing the visual change, so that changes in response to
4338 super-rapid-screen-update can be dropped if we are still processing
4342 pending_visual_change.idle_handler_id = -1;
4343 pending_visual_change.being_handled = true;
4345 VisualChange::Type p = pending_visual_change.pending;
4346 pending_visual_change.pending = (VisualChange::Type) 0;
4348 double const last_time_origin = horizontal_position ();
4350 if (p & VisualChange::ZoomLevel) {
4351 set_samples_per_pixel (pending_visual_change.samples_per_pixel);
4353 compute_fixed_ruler_scale ();
4355 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4356 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4358 compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_samples(),
4359 current_bbt_points_begin, current_bbt_points_end);
4360 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_samples(),
4361 current_bbt_points_begin, current_bbt_points_end);
4362 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4365 if (p & VisualChange::ZoomLevel) {
4366 update_video_timeline();
4369 if (p & VisualChange::TimeOrigin) {
4370 set_horizontal_position (pending_visual_change.time_origin / samples_per_pixel);
4373 if (p & VisualChange::YOrigin) {
4374 vertical_adjustment.set_value (pending_visual_change.y_origin);
4377 if (last_time_origin == horizontal_position ()) {
4378 /* changed signal not emitted */
4379 update_fixed_rulers ();
4380 redisplay_tempo (true);
4383 if (!(p & VisualChange::ZoomLevel)) {
4384 update_video_timeline();
4387 _summary->set_overlays_dirty ();
4389 pending_visual_change.being_handled = false;
4390 return 0; /* this is always a one-shot call */
4393 struct EditorOrderTimeAxisSorter {
4394 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4395 return a->order () < b->order ();
4400 Editor::sort_track_selection (TrackViewList& sel)
4402 EditorOrderTimeAxisSorter cmp;
4407 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4410 framepos_t where = 0;
4411 EditPoint ep = _edit_point;
4413 if (from_context_menu && (ep == EditAtMouse)) {
4414 return window_event_frame (&context_click_event, 0, 0);
4417 if (entered_marker) {
4418 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4419 return entered_marker->position();
4422 if (ignore_playhead && ep == EditAtPlayhead) {
4423 ep = EditAtSelectedMarker;
4427 case EditAtPlayhead:
4428 where = _session->audible_frame();
4429 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4432 case EditAtSelectedMarker:
4433 if (!selection->markers.empty()) {
4435 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4438 where = loc->start();
4442 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4450 if (!mouse_frame (where, ignored)) {
4451 /* XXX not right but what can we do ? */
4455 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4463 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4465 if (!_session) return;
4467 begin_reversible_command (cmd);
4471 if ((tll = transport_loop_location()) == 0) {
4472 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4473 XMLNode &before = _session->locations()->get_state();
4474 _session->locations()->add (loc, true);
4475 _session->set_auto_loop_location (loc);
4476 XMLNode &after = _session->locations()->get_state();
4477 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4479 XMLNode &before = tll->get_state();
4480 tll->set_hidden (false, this);
4481 tll->set (start, end);
4482 XMLNode &after = tll->get_state();
4483 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4486 commit_reversible_command ();
4490 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4492 if (!_session) return;
4494 begin_reversible_command (cmd);
4498 if ((tpl = transport_punch_location()) == 0) {
4499 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4500 XMLNode &before = _session->locations()->get_state();
4501 _session->locations()->add (loc, true);
4502 _session->set_auto_loop_location (loc);
4503 XMLNode &after = _session->locations()->get_state();
4504 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4507 XMLNode &before = tpl->get_state();
4508 tpl->set_hidden (false, this);
4509 tpl->set (start, end);
4510 XMLNode &after = tpl->get_state();
4511 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4514 commit_reversible_command ();
4517 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4518 * @param rs List to which found regions are added.
4519 * @param where Time to look at.
4520 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4523 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4525 const TrackViewList* tracks;
4528 tracks = &track_views;
4533 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4535 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4538 boost::shared_ptr<Track> tr;
4539 boost::shared_ptr<Playlist> pl;
4541 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4543 boost::shared_ptr<RegionList> regions = pl->regions_at (
4544 (framepos_t) floor ( (double) where * tr->speed()));
4546 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4547 RegionView* rv = rtv->view()->find_view (*i);
4558 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4560 const TrackViewList* tracks;
4563 tracks = &track_views;
4568 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4569 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4571 boost::shared_ptr<Track> tr;
4572 boost::shared_ptr<Playlist> pl;
4574 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4576 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4577 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4579 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4581 RegionView* rv = rtv->view()->find_view (*i);
4592 /** Get regions using the following method:
4594 * Make a region list using the selected regions, unless
4595 * the edit point is `mouse' and the mouse is over an unselected
4596 * region. In this case, use just that region.
4598 * If the edit point is not 'mouse', and there are no regions selected,
4599 * search the list of selected tracks and return regions that are under
4600 * the edit point on these tracks. If there are no selected tracks and
4601 * 'No Selection = All Tracks' is active, search all tracks,
4603 * The rationale here is that the mouse edit point is special in that
4604 * its position describes both a time and a track; the other edit
4605 * modes only describe a time. Hence if the edit point is `mouse' we
4606 * ignore selected tracks, as we assume the user means something by
4607 * pointing at a particular track. Also in this case we take note of
4608 * the region directly under the edit point, as there is always just one
4609 * (rather than possibly several with non-mouse edit points).
4613 Editor::get_regions_from_selection_and_edit_point ()
4615 RegionSelection regions;
4617 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4618 regions.add (entered_regionview);
4620 regions = selection->regions;
4624 if (regions.empty() && _edit_point != EditAtMouse) {
4625 TrackViewList tracks = selection->tracks;
4627 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4628 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4629 * is enabled, so consider all tracks
4631 tracks = track_views;
4634 if (!tracks.empty()) {
4635 /* no region selected or entered, but some selected tracks:
4636 * act on all regions on the selected tracks at the edit point
4638 framepos_t const where = get_preferred_edit_position ();
4639 get_regions_at(regions, where, tracks);
4645 /** Start with regions that are selected, or the entered regionview if none are selected.
4646 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4647 * of the regions that we started with.
4651 Editor::get_regions_from_selection_and_entered ()
4653 RegionSelection regions = selection->regions;
4655 if (regions.empty() && entered_regionview) {
4656 regions.add (entered_regionview);
4663 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4665 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4667 RouteTimeAxisView* tatv;
4669 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4671 boost::shared_ptr<Playlist> pl;
4672 vector<boost::shared_ptr<Region> > results;
4674 boost::shared_ptr<Track> tr;
4676 if ((tr = tatv->track()) == 0) {
4681 if ((pl = (tr->playlist())) != 0) {
4682 if (src_comparison) {
4683 pl->get_source_equivalent_regions (region, results);
4685 pl->get_region_list_equivalent_regions (region, results);
4689 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4690 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4691 regions.push_back (marv);
4700 Editor::show_rhythm_ferret ()
4702 if (rhythm_ferret == 0) {
4703 rhythm_ferret = new RhythmFerret(*this);
4706 rhythm_ferret->set_session (_session);
4707 rhythm_ferret->show ();
4708 rhythm_ferret->present ();
4712 Editor::first_idle ()
4714 MessageDialog* dialog = 0;
4716 if (track_views.size() > 1) {
4717 dialog = new MessageDialog (
4719 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4723 ARDOUR_UI::instance()->flush_pending ();
4726 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4730 // first idle adds route children (automation tracks), so we need to redisplay here
4731 _routes->redisplay ();
4738 Editor::_idle_resize (gpointer arg)
4740 return ((Editor*)arg)->idle_resize ();
4744 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4746 if (resize_idle_id < 0) {
4747 resize_idle_id = g_idle_add (_idle_resize, this);
4748 _pending_resize_amount = 0;
4751 /* make a note of the smallest resulting height, so that we can clamp the
4752 lower limit at TimeAxisView::hSmall */
4754 int32_t min_resulting = INT32_MAX;
4756 _pending_resize_amount += h;
4757 _pending_resize_view = view;
4759 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4761 if (selection->tracks.contains (_pending_resize_view)) {
4762 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4763 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4767 if (min_resulting < 0) {
4772 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4773 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4777 /** Handle pending resizing of tracks */
4779 Editor::idle_resize ()
4781 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4783 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4784 selection->tracks.contains (_pending_resize_view)) {
4786 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4787 if (*i != _pending_resize_view) {
4788 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4793 _pending_resize_amount = 0;
4794 _group_tabs->set_dirty ();
4795 resize_idle_id = -1;
4803 ENSURE_GUI_THREAD (*this, &Editor::located);
4806 playhead_cursor->set_position (_session->audible_frame ());
4807 if (_follow_playhead && !_pending_initial_locate) {
4808 reset_x_origin_to_follow_playhead ();
4812 _pending_locate_request = false;
4813 _pending_initial_locate = false;
4817 Editor::region_view_added (RegionView *)
4819 _summary->set_dirty ();
4823 Editor::region_view_removed ()
4825 _summary->set_dirty ();
4829 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4831 TrackViewList::const_iterator j = track_views.begin ();
4832 while (j != track_views.end()) {
4833 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4834 if (rtv && rtv->route() == r) {
4845 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4849 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4850 TimeAxisView* tv = axis_view_from_route (*i);
4860 Editor::add_routes (RouteList& routes)
4862 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4864 RouteTimeAxisView *rtv;
4865 list<RouteTimeAxisView*> new_views;
4867 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4868 boost::shared_ptr<Route> route = (*x);
4870 if (route->is_auditioner() || route->is_monitor()) {
4874 DataType dt = route->input()->default_type();
4876 if (dt == ARDOUR::DataType::AUDIO) {
4877 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4878 rtv->set_route (route);
4879 } else if (dt == ARDOUR::DataType::MIDI) {
4880 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4881 rtv->set_route (route);
4883 throw unknown_type();
4886 new_views.push_back (rtv);
4887 track_views.push_back (rtv);
4889 rtv->effective_gain_display ();
4891 if (internal_editing()) {
4892 rtv->enter_internal_edit_mode ();
4894 rtv->leave_internal_edit_mode ();
4897 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4898 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4901 _routes->routes_added (new_views);
4902 _summary->routes_added (new_views);
4904 if (show_editor_mixer_when_tracks_arrive) {
4905 show_editor_mixer (true);
4908 editor_list_button.set_sensitive (true);
4912 Editor::timeaxisview_deleted (TimeAxisView *tv)
4914 if (_session && _session->deletion_in_progress()) {
4915 /* the situation is under control */
4919 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4921 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4923 _routes->route_removed (tv);
4925 if (tv == entered_track) {
4929 TimeAxisView::Children c = tv->get_child_list ();
4930 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4931 if (entered_track == i->get()) {
4936 /* remove it from the list of track views */
4938 TrackViewList::iterator i;
4940 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4941 i = track_views.erase (i);
4944 /* update whatever the current mixer strip is displaying, if revelant */
4946 boost::shared_ptr<Route> route;
4949 route = rtav->route ();
4952 if (current_mixer_strip && current_mixer_strip->route() == route) {
4954 TimeAxisView* next_tv;
4956 if (track_views.empty()) {
4958 } else if (i == track_views.end()) {
4959 next_tv = track_views.front();
4966 set_selected_mixer_strip (*next_tv);
4968 /* make the editor mixer strip go away setting the
4969 * button to inactive (which also unticks the menu option)
4972 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4978 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4980 if (apply_to_selection) {
4981 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4983 TrackSelection::iterator j = i;
4986 hide_track_in_display (*i, false);
4991 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4993 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4994 // this will hide the mixer strip
4995 set_selected_mixer_strip (*tv);
4998 _routes->hide_track_in_display (*tv);
5003 Editor::sync_track_view_list_and_routes ()
5005 track_views = TrackViewList (_routes->views ());
5007 _summary->set_dirty ();
5008 _group_tabs->set_dirty ();
5010 return false; // do not call again (until needed)
5014 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5016 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5021 /** Find a RouteTimeAxisView by the ID of its route */
5023 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5025 RouteTimeAxisView* v;
5027 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5028 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5029 if(v->route()->id() == id) {
5039 Editor::fit_route_group (RouteGroup *g)
5041 TrackViewList ts = axis_views_from_routes (g->route_list ());
5046 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5048 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5051 _session->cancel_audition ();
5055 if (_session->is_auditioning()) {
5056 _session->cancel_audition ();
5057 if (r == last_audition_region) {
5062 _session->audition_region (r);
5063 last_audition_region = r;
5068 Editor::hide_a_region (boost::shared_ptr<Region> r)
5070 r->set_hidden (true);
5074 Editor::show_a_region (boost::shared_ptr<Region> r)
5076 r->set_hidden (false);
5080 Editor::audition_region_from_region_list ()
5082 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5086 Editor::hide_region_from_region_list ()
5088 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5092 Editor::show_region_in_region_list ()
5094 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5098 Editor::step_edit_status_change (bool yn)
5101 start_step_editing ();
5103 stop_step_editing ();
5108 Editor::start_step_editing ()
5110 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5114 Editor::stop_step_editing ()
5116 step_edit_connection.disconnect ();
5120 Editor::check_step_edit ()
5122 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5123 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5125 mtv->check_step_edit ();
5129 return true; // do it again, till we stop
5133 Editor::scroll_press (Direction dir)
5135 ++_scroll_callbacks;
5137 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5138 /* delay the first auto-repeat */
5144 scroll_backward (1);
5152 scroll_tracks_up_line ();
5156 scroll_tracks_down_line ();
5160 /* do hacky auto-repeat */
5161 if (!_scroll_connection.connected ()) {
5163 _scroll_connection = Glib::signal_timeout().connect (
5164 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5167 _scroll_callbacks = 0;
5174 Editor::scroll_release ()
5176 _scroll_connection.disconnect ();
5179 /** Queue a change for the Editor viewport x origin to follow the playhead */
5181 Editor::reset_x_origin_to_follow_playhead ()
5183 framepos_t const frame = playhead_cursor->current_frame ();
5185 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5187 if (_session->transport_speed() < 0) {
5189 if (frame > (current_page_samples() / 2)) {
5190 center_screen (frame-(current_page_samples()/2));
5192 center_screen (current_page_samples()/2);
5199 if (frame < leftmost_frame) {
5201 if (_session->transport_rolling()) {
5202 /* rolling; end up with the playhead at the right of the page */
5203 l = frame - current_page_samples ();
5205 /* not rolling: end up with the playhead 1/4 of the way along the page */
5206 l = frame - current_page_samples() / 4;
5210 if (_session->transport_rolling()) {
5211 /* rolling: end up with the playhead on the left of the page */
5214 /* not rolling: end up with the playhead 3/4 of the way along the page */
5215 l = frame - 3 * current_page_samples() / 4;
5223 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5229 Editor::super_rapid_screen_update ()
5231 if (!_session || !_session->engine().running()) {
5235 /* METERING / MIXER STRIPS */
5237 /* update track meters, if required */
5238 if (is_mapped() && meters_running) {
5239 RouteTimeAxisView* rtv;
5240 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5241 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5242 rtv->fast_update ();
5247 /* and any current mixer strip */
5248 if (current_mixer_strip) {
5249 current_mixer_strip->fast_update ();
5252 /* PLAYHEAD AND VIEWPORT */
5254 framepos_t const frame = _session->audible_frame();
5256 /* There are a few reasons why we might not update the playhead / viewport stuff:
5258 * 1. we don't update things when there's a pending locate request, otherwise
5259 * when the editor requests a locate there is a chance that this method
5260 * will move the playhead before the locate request is processed, causing
5262 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5263 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5266 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5268 last_update_frame = frame;
5270 if (!_dragging_playhead) {
5271 playhead_cursor->set_position (frame);
5274 if (!_stationary_playhead) {
5276 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5277 /* We only do this if we aren't already
5278 handling a visual change (ie if
5279 pending_visual_change.being_handled is
5280 false) so that these requests don't stack
5281 up there are too many of them to handle in
5284 reset_x_origin_to_follow_playhead ();
5289 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5293 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5294 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5295 if (target <= 0.0) {
5298 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5299 target = (target * 0.15) + (current * 0.85);
5305 set_horizontal_position (current);
5314 Editor::session_going_away ()
5316 _have_idled = false;
5318 _session_connections.drop_connections ();
5320 super_rapid_screen_update_connection.disconnect ();
5322 selection->clear ();
5323 cut_buffer->clear ();
5325 clicked_regionview = 0;
5326 clicked_axisview = 0;
5327 clicked_routeview = 0;
5328 entered_regionview = 0;
5330 last_update_frame = 0;
5333 playhead_cursor->hide ();
5335 /* rip everything out of the list displays */
5339 _route_groups->clear ();
5341 /* do this first so that deleting a track doesn't reset cms to null
5342 and thus cause a leak.
5345 if (current_mixer_strip) {
5346 if (current_mixer_strip->get_parent() != 0) {
5347 global_hpacker.remove (*current_mixer_strip);
5349 delete current_mixer_strip;
5350 current_mixer_strip = 0;
5353 /* delete all trackviews */
5355 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5358 track_views.clear ();
5360 zoom_range_clock->set_session (0);
5361 nudge_clock->set_session (0);
5363 editor_list_button.set_active(false);
5364 editor_list_button.set_sensitive(false);
5366 /* clear tempo/meter rulers */
5367 remove_metric_marks ();
5369 clear_marker_display ();
5371 stop_step_editing ();
5373 /* get rid of any existing editor mixer strip */
5375 WindowTitle title(Glib::get_application_name());
5376 title += _("Editor");
5378 set_title (title.get_string());
5380 SessionHandlePtr::session_going_away ();
5385 Editor::show_editor_list (bool yn)
5388 _the_notebook.show ();
5390 _the_notebook.hide ();
5395 Editor::change_region_layering_order (bool from_context_menu)
5397 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5399 if (!clicked_routeview) {
5400 if (layering_order_editor) {
5401 layering_order_editor->hide ();
5406 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5412 boost::shared_ptr<Playlist> pl = track->playlist();
5418 if (layering_order_editor == 0) {
5419 layering_order_editor = new RegionLayeringOrderEditor (*this);
5420 layering_order_editor->set_position (WIN_POS_MOUSE);
5423 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5424 layering_order_editor->maybe_present ();
5428 Editor::update_region_layering_order_editor ()
5430 if (layering_order_editor && layering_order_editor->is_visible ()) {
5431 change_region_layering_order (true);
5436 Editor::setup_fade_images ()
5438 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5439 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5440 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5441 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5442 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5444 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5445 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5446 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5447 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5448 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5450 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5451 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5452 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5453 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5454 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5456 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5457 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5458 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5459 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5460 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5464 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5466 Editor::action_menu_item (std::string const & name)
5468 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5471 return *manage (a->create_menu_item ());
5475 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5477 EventBox* b = manage (new EventBox);
5478 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5479 Label* l = manage (new Label (name));
5483 _the_notebook.append_page (widget, *b);
5487 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5489 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5490 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5493 if (ev->type == GDK_2BUTTON_PRESS) {
5495 /* double-click on a notebook tab shrinks or expands the notebook */
5497 if (_notebook_shrunk) {
5498 if (pre_notebook_shrink_pane_width) {
5499 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5501 _notebook_shrunk = false;
5503 pre_notebook_shrink_pane_width = edit_pane.get_position();
5505 /* this expands the LHS of the edit pane to cover the notebook
5506 PAGE but leaves the tabs visible.
5508 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5509 _notebook_shrunk = true;
5517 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5519 using namespace Menu_Helpers;
5521 MenuList& items = _control_point_context_menu.items ();
5524 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5525 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5526 if (!can_remove_control_point (item)) {
5527 items.back().set_sensitive (false);
5530 _control_point_context_menu.popup (event->button.button, event->button.time);
5534 Editor::shift_key_released ()
5536 _stepping_axis_view = 0;