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 using namespace ARDOUR;
126 using namespace Glib;
127 using namespace Gtkmm2ext;
128 using namespace Editing;
130 using PBD::internationalize;
132 using Gtkmm2ext::Keyboard;
134 const double Editor::timebar_height = 15.0;
136 static const gchar *_snap_type_strings[] = {
138 N_("Timecode Frames"),
139 N_("Timecode Seconds"),
140 N_("Timecode Minutes"),
170 static const gchar *_snap_mode_strings[] = {
177 static const gchar *_edit_point_strings[] = {
184 static const gchar *_zoom_focus_strings[] = {
194 #ifdef USE_RUBBERBAND
195 static const gchar *_rb_opt_strings[] = {
198 N_("Balanced multitimbral mixture"),
199 N_("Unpitched percussion with stable notes"),
200 N_("Crisp monophonic instrumental"),
201 N_("Unpitched solo percussion"),
202 N_("Resample without preserving pitch"),
208 pane_size_watcher (Paned* pane)
210 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
214 Quartz: impossible to access
216 so stop that by preventing it from ever getting too narrow. 35
217 pixels is basically a rough guess at the tab width.
222 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
224 gint pos = pane->get_position ();
226 if (pos > max_width_of_lhs) {
227 pane->set_position (max_width_of_lhs);
232 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
234 /* time display buttons */
235 , minsec_label (_("Mins:Secs"))
236 , bbt_label (_("Bars:Beats"))
237 , timecode_label (_("Timecode"))
238 , samples_label (_("Samples"))
239 , tempo_label (_("Tempo"))
240 , meter_label (_("Meter"))
241 , mark_label (_("Location Markers"))
242 , range_mark_label (_("Range Markers"))
243 , transport_mark_label (_("Loop/Punch Ranges"))
244 , cd_mark_label (_("CD Markers"))
245 , videotl_label (_("Video Timeline"))
246 , edit_packer (4, 4, true)
248 /* the values here don't matter: layout widgets
249 reset them as needed.
252 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
253 , horizontal_adjustment (0.0, 0.0, 1e16)
254 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
256 , controls_layout (unused_adjustment, vertical_adjustment)
258 /* tool bar related */
260 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
262 , toolbar_selection_clock_table (2,3)
264 , automation_mode_button (_("mode"))
266 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
270 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
271 , meters_running(false)
272 , _pending_locate_request (false)
273 , _pending_initial_locate (false)
274 , _last_cut_copy_source_track (0)
276 , _region_selection_change_updates_region_list (true)
277 , _following_mixer_selection (false)
278 , _control_point_toggled_on_press (false)
279 , _stepping_axis_view (0)
283 /* we are a singleton */
285 PublicEditor::_instance = this;
289 selection = new Selection (this);
290 cut_buffer = new Selection (this);
292 clicked_regionview = 0;
293 clicked_axisview = 0;
294 clicked_routeview = 0;
295 clicked_control_point = 0;
296 last_update_frame = 0;
297 pre_press_cursor = 0;
298 _drags = new DragManager (this);
299 current_mixer_strip = 0;
302 snap_type_strings = I18N (_snap_type_strings);
303 snap_mode_strings = I18N (_snap_mode_strings);
304 zoom_focus_strings = I18N (_zoom_focus_strings);
305 edit_point_strings = I18N (_edit_point_strings);
306 #ifdef USE_RUBBERBAND
307 rb_opt_strings = I18N (_rb_opt_strings);
311 snap_threshold = 5.0;
312 bbt_beat_subdivision = 4;
313 _visible_canvas_width = 0;
314 _visible_canvas_height = 0;
315 last_autoscroll_x = 0;
316 last_autoscroll_y = 0;
317 autoscroll_active = false;
318 autoscroll_timeout_tag = -1;
323 current_interthread_info = 0;
324 _show_measures = true;
326 show_gain_after_trim = false;
328 have_pending_keyboard_selection = false;
329 _follow_playhead = true;
330 _stationary_playhead = false;
331 editor_ruler_menu = 0;
332 no_ruler_shown_update = false;
334 range_marker_menu = 0;
335 marker_menu_item = 0;
336 tempo_or_meter_marker_menu = 0;
337 transport_marker_menu = 0;
338 new_transport_marker_menu = 0;
339 editor_mixer_strip_width = Wide;
340 show_editor_mixer_when_tracks_arrive = false;
341 region_edit_menu_split_multichannel_item = 0;
342 region_edit_menu_split_item = 0;
345 current_stepping_trackview = 0;
347 entered_regionview = 0;
349 clear_entered_track = false;
352 button_release_can_deselect = true;
353 _dragging_playhead = false;
354 _dragging_edit_point = false;
355 select_new_marker = false;
357 layering_order_editor = 0;
358 no_save_visual = false;
360 within_track_canvas = false;
362 scrubbing_direction = 0;
366 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
367 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
368 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
369 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
370 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
372 zoom_focus = ZoomFocusLeft;
373 _edit_point = EditAtMouse;
374 _internal_editing = false;
375 current_canvas_cursor = 0;
377 samples_per_pixel = 2048; /* too early to use reset_zoom () */
379 _scroll_callbacks = 0;
381 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
383 bbt_label.set_name ("EditorRulerLabel");
384 bbt_label.set_size_request (-1, (int)timebar_height);
385 bbt_label.set_alignment (1.0, 0.5);
386 bbt_label.set_padding (5,0);
388 bbt_label.set_no_show_all();
389 minsec_label.set_name ("EditorRulerLabel");
390 minsec_label.set_size_request (-1, (int)timebar_height);
391 minsec_label.set_alignment (1.0, 0.5);
392 minsec_label.set_padding (5,0);
393 minsec_label.hide ();
394 minsec_label.set_no_show_all();
395 timecode_label.set_name ("EditorRulerLabel");
396 timecode_label.set_size_request (-1, (int)timebar_height);
397 timecode_label.set_alignment (1.0, 0.5);
398 timecode_label.set_padding (5,0);
399 timecode_label.hide ();
400 timecode_label.set_no_show_all();
401 samples_label.set_name ("EditorRulerLabel");
402 samples_label.set_size_request (-1, (int)timebar_height);
403 samples_label.set_alignment (1.0, 0.5);
404 samples_label.set_padding (5,0);
405 samples_label.hide ();
406 samples_label.set_no_show_all();
408 tempo_label.set_name ("EditorRulerLabel");
409 tempo_label.set_size_request (-1, (int)timebar_height);
410 tempo_label.set_alignment (1.0, 0.5);
411 tempo_label.set_padding (5,0);
413 tempo_label.set_no_show_all();
415 meter_label.set_name ("EditorRulerLabel");
416 meter_label.set_size_request (-1, (int)timebar_height);
417 meter_label.set_alignment (1.0, 0.5);
418 meter_label.set_padding (5,0);
420 meter_label.set_no_show_all();
422 mark_label.set_name ("EditorRulerLabel");
423 mark_label.set_size_request (-1, (int)timebar_height);
424 mark_label.set_alignment (1.0, 0.5);
425 mark_label.set_padding (5,0);
427 mark_label.set_no_show_all();
429 cd_mark_label.set_name ("EditorRulerLabel");
430 cd_mark_label.set_size_request (-1, (int)timebar_height);
431 cd_mark_label.set_alignment (1.0, 0.5);
432 cd_mark_label.set_padding (5,0);
433 cd_mark_label.hide();
434 cd_mark_label.set_no_show_all();
436 videotl_bar_height = 4;
437 videotl_label.set_name ("EditorRulerLabel");
438 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
439 videotl_label.set_alignment (1.0, 0.5);
440 videotl_label.set_padding (5,0);
441 videotl_label.hide();
442 videotl_label.set_no_show_all();
444 range_mark_label.set_name ("EditorRulerLabel");
445 range_mark_label.set_size_request (-1, (int)timebar_height);
446 range_mark_label.set_alignment (1.0, 0.5);
447 range_mark_label.set_padding (5,0);
448 range_mark_label.hide();
449 range_mark_label.set_no_show_all();
451 transport_mark_label.set_name ("EditorRulerLabel");
452 transport_mark_label.set_size_request (-1, (int)timebar_height);
453 transport_mark_label.set_alignment (1.0, 0.5);
454 transport_mark_label.set_padding (5,0);
455 transport_mark_label.hide();
456 transport_mark_label.set_no_show_all();
458 initialize_rulers ();
459 initialize_canvas ();
461 _summary = new EditorSummary (this);
463 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
464 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
466 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
468 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
469 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
471 edit_controls_vbox.set_spacing (0);
472 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
473 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
475 HBox* h = manage (new HBox);
476 _group_tabs = new EditorGroupTabs (this);
477 h->pack_start (*_group_tabs, PACK_SHRINK);
478 h->pack_start (edit_controls_vbox);
479 controls_layout.add (*h);
481 controls_layout.set_name ("EditControlsBase");
482 controls_layout.add_events (Gdk::SCROLL_MASK);
483 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
485 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
486 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
488 _cursors = new MouseCursors;
490 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
492 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
493 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
494 pad_line_1->set_outline_color (0xFF0000FF);
500 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
501 time_canvas_vbox.set_size_request (-1, -1);
503 ruler_label_event_box.add (ruler_label_vbox);
504 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
505 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
507 time_bars_event_box.add (time_bars_vbox);
508 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
509 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
511 time_canvas_event_box.add (time_canvas_vbox);
512 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
514 edit_packer.set_col_spacings (0);
515 edit_packer.set_row_spacings (0);
516 edit_packer.set_homogeneous (false);
517 edit_packer.set_border_width (0);
518 edit_packer.set_name ("EditorWindow");
520 /* labels for the rulers */
521 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
522 /* labels for the marker "tracks" (time bars) */
523 edit_packer.attach (time_bars_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
525 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
527 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
528 /* time bars canvas */
529 edit_packer.attach (*_time_bars_canvas_viewport, 2, 3, 1, 2, FILL, FILL, 0, 0);
531 edit_packer.attach (*_track_canvas_viewport, 2, 3, 2, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
533 bottom_hbox.set_border_width (2);
534 bottom_hbox.set_spacing (3);
536 _route_groups = new EditorRouteGroups (this);
537 _routes = new EditorRoutes (this);
538 _regions = new EditorRegions (this);
539 _snapshots = new EditorSnapshots (this);
540 _locations = new EditorLocations (this);
542 add_notebook_page (_("Regions"), _regions->widget ());
543 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
544 add_notebook_page (_("Snapshots"), _snapshots->widget ());
545 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
546 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
548 _the_notebook.set_show_tabs (true);
549 _the_notebook.set_scrollable (true);
550 _the_notebook.popup_disable ();
551 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
552 _the_notebook.show_all ();
554 _notebook_shrunk = false;
556 editor_summary_pane.pack1(edit_packer);
558 Button* summary_arrows_left_left = manage (new Button);
559 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
560 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
561 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
563 Button* summary_arrows_left_right = manage (new Button);
564 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
565 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
566 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
568 VBox* summary_arrows_left = manage (new VBox);
569 summary_arrows_left->pack_start (*summary_arrows_left_left);
570 summary_arrows_left->pack_start (*summary_arrows_left_right);
572 Button* summary_arrows_right_up = manage (new Button);
573 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
574 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
575 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
577 Button* summary_arrows_right_down = manage (new Button);
578 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
579 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
580 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
582 VBox* summary_arrows_right = manage (new VBox);
583 summary_arrows_right->pack_start (*summary_arrows_right_up);
584 summary_arrows_right->pack_start (*summary_arrows_right_down);
586 Frame* summary_frame = manage (new Frame);
587 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
589 summary_frame->add (*_summary);
590 summary_frame->show ();
592 _summary_hbox.pack_start (*summary_arrows_left, false, false);
593 _summary_hbox.pack_start (*summary_frame, true, true);
594 _summary_hbox.pack_start (*summary_arrows_right, false, false);
596 editor_summary_pane.pack2 (_summary_hbox);
598 edit_pane.pack1 (editor_summary_pane, true, true);
599 edit_pane.pack2 (_the_notebook, false, true);
601 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
603 /* XXX: editor_summary_pane might need similar to the edit_pane */
605 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
607 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
608 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
610 top_hbox.pack_start (toolbar_frame);
612 HBox *hbox = manage (new HBox);
613 hbox->pack_start (edit_pane, true, true);
615 global_vpacker.pack_start (top_hbox, false, false);
616 global_vpacker.pack_start (*hbox, true, true);
618 global_hpacker.pack_start (global_vpacker, true, true);
620 set_name ("EditorWindow");
621 add_accel_group (ActionManager::ui_manager->get_accel_group());
623 status_bar_hpacker.show ();
625 vpacker.pack_end (status_bar_hpacker, false, false);
626 vpacker.pack_end (global_hpacker, true, true);
628 /* register actions now so that set_state() can find them and set toggles/checks etc */
631 /* when we start using our own keybinding system for the editor, this
632 * will be uncommented
638 set_zoom_focus (zoom_focus);
639 _snap_type = SnapToBeat;
640 set_snap_to (_snap_type);
641 _snap_mode = SnapOff;
642 set_snap_mode (_snap_mode);
643 set_mouse_mode (MouseObject, true);
644 pre_internal_mouse_mode = MouseObject;
645 pre_internal_snap_type = _snap_type;
646 pre_internal_snap_mode = _snap_mode;
647 internal_snap_type = _snap_type;
648 internal_snap_mode = _snap_mode;
649 set_edit_point_preference (EditAtMouse, true);
651 _playlist_selector = new PlaylistSelector();
652 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
654 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
658 nudge_forward_button.set_name ("zoom button");
659 nudge_forward_button.add_elements (ArdourButton::FlatFace);
660 nudge_forward_button.set_image(::get_icon("nudge_right"));
662 nudge_backward_button.set_name ("zoom button");
663 nudge_backward_button.add_elements (ArdourButton::FlatFace);
664 nudge_backward_button.set_image(::get_icon("nudge_left"));
666 fade_context_menu.set_name ("ArdourContextMenu");
668 /* icons, titles, WM stuff */
670 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
671 Glib::RefPtr<Gdk::Pixbuf> icon;
673 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
674 window_icons.push_back (icon);
676 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
677 window_icons.push_back (icon);
679 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
680 window_icons.push_back (icon);
682 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
683 window_icons.push_back (icon);
685 if (!window_icons.empty()) {
686 // set_icon_list (window_icons);
687 set_default_icon_list (window_icons);
690 WindowTitle title(Glib::get_application_name());
691 title += _("Editor");
692 set_title (title.get_string());
693 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
696 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
698 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
699 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
701 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
703 /* allow external control surfaces/protocols to do various things */
705 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
706 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
707 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
708 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
709 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
710 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
711 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
712 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
713 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
714 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
715 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
716 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
717 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
718 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
720 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
721 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
722 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
723 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
724 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
726 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
728 /* problematic: has to return a value and thus cannot be x-thread */
730 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
732 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
734 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
736 _ignore_region_action = false;
737 _last_region_menu_was_main = false;
738 _popup_region_menu_item = 0;
740 _show_marker_lines = false;
741 _over_region_trim_target = false;
743 /* Button bindings */
745 button_bindings = new Bindings;
747 XMLNode* node = button_settings();
749 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
750 button_bindings->load (**i);
757 setup_fade_images ();
762 delete button_bindings;
764 delete _route_groups;
765 delete _time_bars_canvas_viewport;
766 delete _track_canvas_viewport;
771 Editor::button_settings () const
773 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
774 XMLNode* node = find_named_node (*settings, X_("Buttons"));
777 node = new XMLNode (X_("Buttons"));
784 Editor::add_toplevel_controls (Container& cont)
786 vpacker.pack_start (cont, false, false);
791 Editor::get_smart_mode () const
793 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
797 Editor::catch_vanishing_regionview (RegionView *rv)
799 /* note: the selection will take care of the vanishing
800 audioregionview by itself.
803 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
807 if (clicked_regionview == rv) {
808 clicked_regionview = 0;
811 if (entered_regionview == rv) {
812 set_entered_regionview (0);
815 if (!_all_region_actions_sensitized) {
816 sensitize_all_region_actions (true);
819 _over_region_trim_target = false;
823 Editor::set_entered_regionview (RegionView* rv)
825 if (rv == entered_regionview) {
829 if (entered_regionview) {
830 entered_regionview->exited ();
833 if ((entered_regionview = rv) != 0) {
834 entered_regionview->entered (internal_editing ());
837 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
838 /* This RegionView entry might have changed what region actions
839 are allowed, so sensitize them all in case a key is pressed.
841 sensitize_all_region_actions (true);
846 Editor::set_entered_track (TimeAxisView* tav)
849 entered_track->exited ();
852 if ((entered_track = tav) != 0) {
853 entered_track->entered ();
858 Editor::show_window ()
860 if (!is_visible ()) {
863 /* XXX: this is a bit unfortunate; it would probably
864 be nicer if we could just call show () above rather
865 than needing the show_all ()
868 /* re-hide stuff if necessary */
869 editor_list_button_toggled ();
870 parameter_changed ("show-summary");
871 parameter_changed ("show-group-tabs");
872 parameter_changed ("show-zoom-tools");
874 /* now reset all audio_time_axis heights, because widgets might need
880 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
881 tv = (static_cast<TimeAxisView*>(*i));
885 if (current_mixer_strip) {
886 current_mixer_strip->hide_things ();
887 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
895 Editor::instant_save ()
897 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
902 _session->add_instant_xml(get_state());
904 Config->add_instant_xml(get_state());
909 Editor::zoom_adjustment_changed ()
915 framecnt_t fpu = llrintf (zoom_range_clock->current_duration() / _visible_canvas_width);
916 bool clamped = clamp_samples_per_pixel (fpu);
919 zoom_range_clock->set ((framepos_t) floor (fpu * _visible_canvas_width));
926 Editor::control_vertical_zoom_in_all ()
928 tav_zoom_smooth (false, true);
932 Editor::control_vertical_zoom_out_all ()
934 tav_zoom_smooth (true, true);
938 Editor::control_vertical_zoom_in_selected ()
940 tav_zoom_smooth (false, false);
944 Editor::control_vertical_zoom_out_selected ()
946 tav_zoom_smooth (true, false);
950 Editor::control_view (uint32_t view)
952 goto_visual_state (view);
956 Editor::control_unselect ()
958 selection->clear_tracks ();
962 Editor::control_select (uint32_t rid, Selection::Operation op)
964 /* handles the (static) signal from the ControlProtocol class that
965 * requests setting the selected track to a given RID
972 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
978 TimeAxisView* tav = axis_view_from_route (r);
983 selection->add (tav);
985 case Selection::Toggle:
986 selection->toggle (tav);
988 case Selection::Extend:
991 selection->set (tav);
995 selection->clear_tracks ();
1000 Editor::control_step_tracks_up ()
1002 scroll_tracks_up_line ();
1006 Editor::control_step_tracks_down ()
1008 scroll_tracks_down_line ();
1012 Editor::control_scroll (float fraction)
1014 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1020 double step = fraction * current_page_samples();
1023 _control_scroll_target is an optional<T>
1025 it acts like a pointer to an framepos_t, with
1026 a operator conversion to boolean to check
1027 that it has a value could possibly use
1028 playhead_cursor->current_frame to store the
1029 value and a boolean in the class to know
1030 when it's out of date
1033 if (!_control_scroll_target) {
1034 _control_scroll_target = _session->transport_frame();
1035 _dragging_playhead = true;
1038 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1039 *_control_scroll_target = 0;
1040 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1041 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1043 *_control_scroll_target += (framepos_t) floor (step);
1046 /* move visuals, we'll catch up with it later */
1048 playhead_cursor->set_position (*_control_scroll_target);
1049 UpdateAllTransportClocks (*_control_scroll_target);
1051 if (*_control_scroll_target > (current_page_samples() / 2)) {
1052 /* try to center PH in window */
1053 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1059 Now we do a timeout to actually bring the session to the right place
1060 according to the playhead. This is to avoid reading disk buffers on every
1061 call to control_scroll, which is driven by ScrollTimeline and therefore
1062 probably by a control surface wheel which can generate lots of events.
1064 /* cancel the existing timeout */
1066 control_scroll_connection.disconnect ();
1068 /* add the next timeout */
1070 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1074 Editor::deferred_control_scroll (framepos_t /*target*/)
1076 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1077 // reset for next stream
1078 _control_scroll_target = boost::none;
1079 _dragging_playhead = false;
1084 Editor::access_action (std::string action_group, std::string action_item)
1090 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1093 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1101 Editor::on_realize ()
1103 Window::on_realize ();
1108 Editor::map_position_change (framepos_t frame)
1110 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1112 if (_session == 0) {
1116 if (_follow_playhead) {
1117 center_screen (frame);
1120 playhead_cursor->set_position (frame);
1124 Editor::center_screen (framepos_t frame)
1126 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1128 /* if we're off the page, then scroll.
1131 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1132 center_screen_internal (frame, page);
1137 Editor::center_screen_internal (framepos_t frame, float page)
1142 frame -= (framepos_t) page;
1147 reset_x_origin (frame);
1152 Editor::update_title ()
1154 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1157 bool dirty = _session->dirty();
1159 string session_name;
1161 if (_session->snap_name() != _session->name()) {
1162 session_name = _session->snap_name();
1164 session_name = _session->name();
1168 session_name = "*" + session_name;
1171 WindowTitle title(session_name);
1172 title += Glib::get_application_name();
1173 set_title (title.get_string());
1175 /* ::session_going_away() will have taken care of it */
1180 Editor::set_session (Session *t)
1182 SessionHandlePtr::set_session (t);
1188 zoom_range_clock->set_session (_session);
1189 _playlist_selector->set_session (_session);
1190 nudge_clock->set_session (_session);
1191 _summary->set_session (_session);
1192 _group_tabs->set_session (_session);
1193 _route_groups->set_session (_session);
1194 _regions->set_session (_session);
1195 _snapshots->set_session (_session);
1196 _routes->set_session (_session);
1197 _locations->set_session (_session);
1199 if (rhythm_ferret) {
1200 rhythm_ferret->set_session (_session);
1203 if (analysis_window) {
1204 analysis_window->set_session (_session);
1208 sfbrowser->set_session (_session);
1211 compute_fixed_ruler_scale ();
1213 /* Make sure we have auto loop and auto punch ranges */
1215 Location* loc = _session->locations()->auto_loop_location();
1217 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1219 if (loc->start() == loc->end()) {
1220 loc->set_end (loc->start() + 1);
1223 _session->locations()->add (loc, false);
1224 _session->set_auto_loop_location (loc);
1227 loc->set_name (_("Loop"));
1230 loc = _session->locations()->auto_punch_location();
1233 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1235 if (loc->start() == loc->end()) {
1236 loc->set_end (loc->start() + 1);
1239 _session->locations()->add (loc, false);
1240 _session->set_auto_punch_location (loc);
1243 loc->set_name (_("Punch"));
1246 refresh_location_display ();
1248 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1249 the selected Marker; this needs the LocationMarker list to be available.
1251 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1252 set_state (*node, Stateful::loading_state_version);
1254 /* catch up with the playhead */
1256 _session->request_locate (playhead_cursor->current_frame ());
1257 _pending_initial_locate = true;
1261 /* These signals can all be emitted by a non-GUI thread. Therefore the
1262 handlers for them must not attempt to directly interact with the GUI,
1263 but use PBD::Signal<T>::connect() which accepts an event loop
1264 ("context") where the handler will be asked to run.
1267 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1268 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1269 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1270 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1271 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1272 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1273 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1274 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1275 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1276 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1277 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1278 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1279 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1280 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1282 playhead_cursor->show ();
1284 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1285 Config->map_parameters (pc);
1286 _session->config.map_parameters (pc);
1288 restore_ruler_visibility ();
1289 //tempo_map_changed (PropertyChange (0));
1290 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1292 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1293 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1296 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1297 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1300 switch (_snap_type) {
1301 case SnapToRegionStart:
1302 case SnapToRegionEnd:
1303 case SnapToRegionSync:
1304 case SnapToRegionBoundary:
1305 build_region_boundary_cache ();
1312 /* register for undo history */
1313 _session->register_with_memento_command_factory(id(), this);
1315 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1317 start_updating_meters ();
1321 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1323 if (a->get_name() == "RegionMenu") {
1324 /* When the main menu's region menu is opened, we setup the actions so that they look right
1325 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1326 so we resensitize all region actions when the entered regionview or the region selection
1327 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1328 happens after the region context menu is opened. So we set a flag here, too.
1332 sensitize_the_right_region_actions ();
1333 _last_region_menu_was_main = true;
1338 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1340 using namespace Menu_Helpers;
1342 void (Editor::*emf)(FadeShape);
1343 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1346 images = &_xfade_in_images;
1347 emf = &Editor::set_fade_in_shape;
1349 images = &_xfade_out_images;
1350 emf = &Editor::set_fade_out_shape;
1355 _("Linear (for highly correlated material)"),
1356 *(*images)[FadeLinear],
1357 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1361 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1365 _("Constant power"),
1366 *(*images)[FadeConstantPower],
1367 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1370 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1375 *(*images)[FadeSymmetric],
1376 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1380 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1385 *(*images)[FadeSlow],
1386 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1389 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1394 *(*images)[FadeFast],
1395 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1398 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1401 /** Pop up a context menu for when the user clicks on a start crossfade */
1403 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1405 using namespace Menu_Helpers;
1407 MenuList& items (xfade_in_context_menu.items());
1409 if (items.empty()) {
1410 fill_xfade_menu (items, true);
1413 xfade_in_context_menu.popup (button, time);
1416 /** Pop up a context menu for when the user clicks on an end crossfade */
1418 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1420 using namespace Menu_Helpers;
1422 MenuList& items (xfade_out_context_menu.items());
1424 if (items.empty()) {
1425 fill_xfade_menu (items, false);
1428 xfade_out_context_menu.popup (button, time);
1432 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1434 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1436 using namespace Menu_Helpers;
1437 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1440 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1444 MenuList& items (fade_context_menu.items());
1447 switch (item_type) {
1449 case FadeInHandleItem:
1450 if (arv->audio_region()->fade_in_active()) {
1451 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1453 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1456 items.push_back (SeparatorElem());
1458 if (Profile->get_sae()) {
1460 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1461 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1468 *_fade_in_images[FadeLinear],
1469 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1473 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1478 *_fade_in_images[FadeSlow],
1479 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1482 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1487 *_fade_in_images[FadeFast],
1488 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1491 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1496 *_fade_in_images[FadeSymmetric],
1497 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1502 _("Constant power"),
1503 *_fade_in_images[FadeConstantPower],
1504 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1507 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1513 case FadeOutHandleItem:
1514 if (arv->audio_region()->fade_out_active()) {
1515 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1517 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1520 items.push_back (SeparatorElem());
1522 if (Profile->get_sae()) {
1523 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1524 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1530 *_fade_out_images[FadeLinear],
1531 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1535 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1540 *_fade_out_images[FadeSlow],
1541 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1544 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1549 *_fade_out_images[FadeFast],
1550 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1553 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1558 *_fade_out_images[FadeSymmetric],
1559 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1564 _("Constant power"),
1565 *_fade_out_images[FadeConstantPower],
1566 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1569 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1575 fatal << _("programming error: ")
1576 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1581 fade_context_menu.popup (button, time);
1585 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1587 using namespace Menu_Helpers;
1588 Menu* (Editor::*build_menu_function)();
1591 switch (item_type) {
1593 case RegionViewName:
1594 case RegionViewNameHighlight:
1595 case LeftFrameHandle:
1596 case RightFrameHandle:
1597 if (with_selection) {
1598 build_menu_function = &Editor::build_track_selection_context_menu;
1600 build_menu_function = &Editor::build_track_region_context_menu;
1605 if (with_selection) {
1606 build_menu_function = &Editor::build_track_selection_context_menu;
1608 build_menu_function = &Editor::build_track_context_menu;
1613 if (clicked_routeview->track()) {
1614 build_menu_function = &Editor::build_track_context_menu;
1616 build_menu_function = &Editor::build_track_bus_context_menu;
1621 /* probably shouldn't happen but if it does, we don't care */
1625 menu = (this->*build_menu_function)();
1626 menu->set_name ("ArdourContextMenu");
1628 /* now handle specific situations */
1630 switch (item_type) {
1632 case RegionViewName:
1633 case RegionViewNameHighlight:
1634 case LeftFrameHandle:
1635 case RightFrameHandle:
1636 if (!with_selection) {
1637 if (region_edit_menu_split_item) {
1638 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1639 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1641 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1644 if (region_edit_menu_split_multichannel_item) {
1645 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1646 region_edit_menu_split_multichannel_item->set_sensitive (true);
1648 region_edit_menu_split_multichannel_item->set_sensitive (false);
1661 /* probably shouldn't happen but if it does, we don't care */
1665 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1667 /* Bounce to disk */
1669 using namespace Menu_Helpers;
1670 MenuList& edit_items = menu->items();
1672 edit_items.push_back (SeparatorElem());
1674 switch (clicked_routeview->audio_track()->freeze_state()) {
1675 case AudioTrack::NoFreeze:
1676 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1679 case AudioTrack::Frozen:
1680 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1683 case AudioTrack::UnFrozen:
1684 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1690 if (item_type == StreamItem && clicked_routeview) {
1691 clicked_routeview->build_underlay_menu(menu);
1694 /* When the region menu is opened, we setup the actions so that they look right
1697 sensitize_the_right_region_actions ();
1698 _last_region_menu_was_main = false;
1700 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1701 menu->popup (button, time);
1705 Editor::build_track_context_menu ()
1707 using namespace Menu_Helpers;
1709 MenuList& edit_items = track_context_menu.items();
1712 add_dstream_context_items (edit_items);
1713 return &track_context_menu;
1717 Editor::build_track_bus_context_menu ()
1719 using namespace Menu_Helpers;
1721 MenuList& edit_items = track_context_menu.items();
1724 add_bus_context_items (edit_items);
1725 return &track_context_menu;
1729 Editor::build_track_region_context_menu ()
1731 using namespace Menu_Helpers;
1732 MenuList& edit_items = track_region_context_menu.items();
1735 /* we've just cleared the track region context menu, so the menu that these
1736 two items were on will have disappeared; stop them dangling.
1738 region_edit_menu_split_item = 0;
1739 region_edit_menu_split_multichannel_item = 0;
1741 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1744 boost::shared_ptr<Track> tr;
1745 boost::shared_ptr<Playlist> pl;
1747 if ((tr = rtv->track())) {
1748 add_region_context_items (edit_items, tr);
1752 add_dstream_context_items (edit_items);
1754 return &track_region_context_menu;
1758 Editor::analyze_region_selection ()
1760 if (analysis_window == 0) {
1761 analysis_window = new AnalysisWindow();
1764 analysis_window->set_session(_session);
1766 analysis_window->show_all();
1769 analysis_window->set_regionmode();
1770 analysis_window->analyze();
1772 analysis_window->present();
1776 Editor::analyze_range_selection()
1778 if (analysis_window == 0) {
1779 analysis_window = new AnalysisWindow();
1782 analysis_window->set_session(_session);
1784 analysis_window->show_all();
1787 analysis_window->set_rangemode();
1788 analysis_window->analyze();
1790 analysis_window->present();
1794 Editor::build_track_selection_context_menu ()
1796 using namespace Menu_Helpers;
1797 MenuList& edit_items = track_selection_context_menu.items();
1798 edit_items.clear ();
1800 add_selection_context_items (edit_items);
1801 // edit_items.push_back (SeparatorElem());
1802 // add_dstream_context_items (edit_items);
1804 return &track_selection_context_menu;
1808 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1810 using namespace Menu_Helpers;
1812 /* OK, stick the region submenu at the top of the list, and then add
1816 RegionSelection rs = get_regions_from_selection_and_entered ();
1818 string::size_type pos = 0;
1819 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1821 /* we have to hack up the region name because "_" has a special
1822 meaning for menu titles.
1825 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1826 menu_item_name.replace (pos, 1, "__");
1830 if (_popup_region_menu_item == 0) {
1831 _popup_region_menu_item = new MenuItem (menu_item_name);
1832 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1833 _popup_region_menu_item->show ();
1835 _popup_region_menu_item->set_label (menu_item_name);
1838 const framepos_t position = get_preferred_edit_position (false, true);
1840 edit_items.push_back (*_popup_region_menu_item);
1841 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1842 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1844 edit_items.push_back (SeparatorElem());
1847 /** Add context menu items relevant to selection ranges.
1848 * @param edit_items List to add the items to.
1851 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1853 using namespace Menu_Helpers;
1855 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1856 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1858 edit_items.push_back (SeparatorElem());
1859 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1861 edit_items.push_back (SeparatorElem());
1863 edit_items.push_back (
1865 _("Move Range Start to Previous Region Boundary"),
1866 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1870 edit_items.push_back (
1872 _("Move Range Start to Next Region Boundary"),
1873 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1877 edit_items.push_back (
1879 _("Move Range End to Previous Region Boundary"),
1880 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1884 edit_items.push_back (
1886 _("Move Range End to Next Region Boundary"),
1887 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1891 edit_items.push_back (SeparatorElem());
1892 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1893 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1895 edit_items.push_back (SeparatorElem());
1896 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1898 edit_items.push_back (SeparatorElem());
1899 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1900 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1902 edit_items.push_back (SeparatorElem());
1903 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1905 edit_items.push_back (SeparatorElem());
1906 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1907 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1908 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1910 edit_items.push_back (SeparatorElem());
1911 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1912 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1913 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1914 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1915 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1916 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1917 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1923 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1925 using namespace Menu_Helpers;
1929 Menu *play_menu = manage (new Menu);
1930 MenuList& play_items = play_menu->items();
1931 play_menu->set_name ("ArdourContextMenu");
1933 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1934 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1935 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1936 play_items.push_back (SeparatorElem());
1937 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1939 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1943 Menu *select_menu = manage (new Menu);
1944 MenuList& select_items = select_menu->items();
1945 select_menu->set_name ("ArdourContextMenu");
1947 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1948 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1949 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1950 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1951 select_items.push_back (SeparatorElem());
1952 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1953 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1954 select_items.push_back (SeparatorElem());
1955 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1956 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1957 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1958 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1959 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1960 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1961 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1963 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1967 Menu *cutnpaste_menu = manage (new Menu);
1968 MenuList& cutnpaste_items = cutnpaste_menu->items();
1969 cutnpaste_menu->set_name ("ArdourContextMenu");
1971 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1972 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1973 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1975 cutnpaste_items.push_back (SeparatorElem());
1977 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1978 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1980 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1982 /* Adding new material */
1984 edit_items.push_back (SeparatorElem());
1985 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1986 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1990 Menu *nudge_menu = manage (new Menu());
1991 MenuList& nudge_items = nudge_menu->items();
1992 nudge_menu->set_name ("ArdourContextMenu");
1994 edit_items.push_back (SeparatorElem());
1995 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1996 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1997 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1998 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2000 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2004 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2006 using namespace Menu_Helpers;
2010 Menu *play_menu = manage (new Menu);
2011 MenuList& play_items = play_menu->items();
2012 play_menu->set_name ("ArdourContextMenu");
2014 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2015 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2016 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2020 Menu *select_menu = manage (new Menu);
2021 MenuList& select_items = select_menu->items();
2022 select_menu->set_name ("ArdourContextMenu");
2024 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2025 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2026 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2027 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2028 select_items.push_back (SeparatorElem());
2029 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2030 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2031 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2032 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2034 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2038 Menu *cutnpaste_menu = manage (new Menu);
2039 MenuList& cutnpaste_items = cutnpaste_menu->items();
2040 cutnpaste_menu->set_name ("ArdourContextMenu");
2042 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2043 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2044 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2046 Menu *nudge_menu = manage (new Menu());
2047 MenuList& nudge_items = nudge_menu->items();
2048 nudge_menu->set_name ("ArdourContextMenu");
2050 edit_items.push_back (SeparatorElem());
2051 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2052 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2053 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2054 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2056 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2060 Editor::snap_type() const
2066 Editor::snap_mode() const
2072 Editor::set_snap_to (SnapType st)
2074 unsigned int snap_ind = (unsigned int)st;
2078 if (snap_ind > snap_type_strings.size() - 1) {
2080 _snap_type = (SnapType)snap_ind;
2083 string str = snap_type_strings[snap_ind];
2085 if (str != snap_type_selector.get_active_text()) {
2086 snap_type_selector.set_active_text (str);
2091 switch (_snap_type) {
2092 case SnapToBeatDiv128:
2093 case SnapToBeatDiv64:
2094 case SnapToBeatDiv32:
2095 case SnapToBeatDiv28:
2096 case SnapToBeatDiv24:
2097 case SnapToBeatDiv20:
2098 case SnapToBeatDiv16:
2099 case SnapToBeatDiv14:
2100 case SnapToBeatDiv12:
2101 case SnapToBeatDiv10:
2102 case SnapToBeatDiv8:
2103 case SnapToBeatDiv7:
2104 case SnapToBeatDiv6:
2105 case SnapToBeatDiv5:
2106 case SnapToBeatDiv4:
2107 case SnapToBeatDiv3:
2108 case SnapToBeatDiv2: {
2109 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2110 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2112 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2113 current_bbt_points_begin, current_bbt_points_end);
2114 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2115 current_bbt_points_begin, current_bbt_points_end);
2116 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2120 case SnapToRegionStart:
2121 case SnapToRegionEnd:
2122 case SnapToRegionSync:
2123 case SnapToRegionBoundary:
2124 build_region_boundary_cache ();
2132 SnapChanged (); /* EMIT SIGNAL */
2136 Editor::set_snap_mode (SnapMode mode)
2138 string str = snap_mode_strings[(int)mode];
2140 if (_internal_editing) {
2141 internal_snap_mode = mode;
2143 pre_internal_snap_mode = mode;
2148 if (str != snap_mode_selector.get_active_text ()) {
2149 snap_mode_selector.set_active_text (str);
2155 Editor::set_edit_point_preference (EditPoint ep, bool force)
2157 bool changed = (_edit_point != ep);
2160 string str = edit_point_strings[(int)ep];
2162 if (str != edit_point_selector.get_active_text ()) {
2163 edit_point_selector.set_active_text (str);
2166 set_canvas_cursor ();
2168 if (!force && !changed) {
2172 const char* action=NULL;
2174 switch (_edit_point) {
2175 case EditAtPlayhead:
2176 action = "edit-at-playhead";
2178 case EditAtSelectedMarker:
2179 action = "edit-at-marker";
2182 action = "edit-at-mouse";
2186 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2188 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2192 bool in_track_canvas;
2194 if (!mouse_frame (foo, in_track_canvas)) {
2195 in_track_canvas = false;
2198 reset_canvas_action_sensitivity (in_track_canvas);
2204 Editor::set_state (const XMLNode& node, int /*version*/)
2206 const XMLProperty* prop;
2213 g.base_width = default_width;
2214 g.base_height = default_height;
2218 if ((geometry = find_named_node (node, "geometry")) != 0) {
2222 if ((prop = geometry->property("x_size")) == 0) {
2223 prop = geometry->property ("x-size");
2226 g.base_width = atoi(prop->value());
2228 if ((prop = geometry->property("y_size")) == 0) {
2229 prop = geometry->property ("y-size");
2232 g.base_height = atoi(prop->value());
2235 if ((prop = geometry->property ("x_pos")) == 0) {
2236 prop = geometry->property ("x-pos");
2239 x = atoi (prop->value());
2242 if ((prop = geometry->property ("y_pos")) == 0) {
2243 prop = geometry->property ("y-pos");
2246 y = atoi (prop->value());
2250 set_default_size (g.base_width, g.base_height);
2253 if (_session && (prop = node.property ("playhead"))) {
2255 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2256 playhead_cursor->set_position (pos);
2258 playhead_cursor->set_position (0);
2261 if ((prop = node.property ("mixer-width"))) {
2262 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2265 if ((prop = node.property ("zoom-focus"))) {
2266 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2269 if ((prop = node.property ("zoom"))) {
2270 /* older versions of ardour used floating point samples_per_pixel */
2271 double f = PBD::atof (prop->value());
2272 reset_zoom (llrintf (f));
2274 reset_zoom (samples_per_pixel);
2277 if ((prop = node.property ("snap-to"))) {
2278 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2281 if ((prop = node.property ("snap-mode"))) {
2282 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2285 if ((prop = node.property ("internal-snap-to"))) {
2286 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2289 if ((prop = node.property ("internal-snap-mode"))) {
2290 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2293 if ((prop = node.property ("pre-internal-snap-to"))) {
2294 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2298 if ((prop = node.property ("pre-internal-snap-mode"))) {
2299 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2302 if ((prop = node.property ("mouse-mode"))) {
2303 MouseMode m = str2mousemode(prop->value());
2304 set_mouse_mode (m, true);
2306 set_mouse_mode (MouseObject, true);
2309 if ((prop = node.property ("left-frame")) != 0) {
2311 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2315 reset_x_origin (pos);
2319 if ((prop = node.property ("y-origin")) != 0) {
2320 reset_y_origin (atof (prop->value ()));
2323 if ((prop = node.property ("internal-edit"))) {
2324 bool yn = string_is_affirmative (prop->value());
2325 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2327 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2328 tact->set_active (!yn);
2329 tact->set_active (yn);
2333 if ((prop = node.property ("join-object-range"))) {
2334 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2335 bool yn = string_is_affirmative (prop->value());
2337 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2338 tact->set_active (!yn);
2339 tact->set_active (yn);
2341 set_mouse_mode(mouse_mode, true);
2344 if ((prop = node.property ("edit-point"))) {
2345 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2348 if ((prop = node.property ("show-measures"))) {
2349 bool yn = string_is_affirmative (prop->value());
2350 _show_measures = yn;
2351 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2353 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2354 /* do it twice to force the change */
2355 tact->set_active (!yn);
2356 tact->set_active (yn);
2360 if ((prop = node.property ("follow-playhead"))) {
2361 bool yn = string_is_affirmative (prop->value());
2362 set_follow_playhead (yn);
2363 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2365 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2366 if (tact->get_active() != yn) {
2367 tact->set_active (yn);
2372 if ((prop = node.property ("stationary-playhead"))) {
2373 bool yn = string_is_affirmative (prop->value());
2374 set_stationary_playhead (yn);
2375 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2377 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2378 if (tact->get_active() != yn) {
2379 tact->set_active (yn);
2384 if ((prop = node.property ("region-list-sort-type"))) {
2385 RegionListSortType st;
2386 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2389 if ((prop = node.property ("show-editor-mixer"))) {
2391 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2394 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2395 bool yn = string_is_affirmative (prop->value());
2397 /* do it twice to force the change */
2399 tact->set_active (!yn);
2400 tact->set_active (yn);
2403 if ((prop = node.property ("show-editor-list"))) {
2405 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2408 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2409 bool yn = string_is_affirmative (prop->value());
2411 /* do it twice to force the change */
2413 tact->set_active (!yn);
2414 tact->set_active (yn);
2417 if ((prop = node.property (X_("editor-list-page")))) {
2418 _the_notebook.set_current_page (atoi (prop->value ()));
2421 if ((prop = node.property (X_("show-marker-lines")))) {
2422 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2424 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2425 bool yn = string_is_affirmative (prop->value ());
2427 tact->set_active (!yn);
2428 tact->set_active (yn);
2431 XMLNodeList children = node.children ();
2432 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2433 selection->set_state (**i, Stateful::current_state_version);
2434 _regions->set_state (**i);
2437 if ((prop = node.property ("maximised"))) {
2438 bool yn = string_is_affirmative (prop->value());
2440 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2444 if ((prop = node.property ("nudge-clock-value"))) {
2446 sscanf (prop->value().c_str(), "%" PRId64, &f);
2447 nudge_clock->set (f);
2449 nudge_clock->set_mode (AudioClock::Timecode);
2450 nudge_clock->set (_session->frame_rate() * 5, true);
2457 Editor::get_state ()
2459 XMLNode* node = new XMLNode ("Editor");
2462 id().print (buf, sizeof (buf));
2463 node->add_property ("id", buf);
2465 if (is_realized()) {
2466 Glib::RefPtr<Gdk::Window> win = get_window();
2468 int x, y, width, height;
2469 win->get_root_origin(x, y);
2470 win->get_size(width, height);
2472 XMLNode* geometry = new XMLNode ("geometry");
2474 snprintf(buf, sizeof(buf), "%d", width);
2475 geometry->add_property("x-size", string(buf));
2476 snprintf(buf, sizeof(buf), "%d", height);
2477 geometry->add_property("y-size", string(buf));
2478 snprintf(buf, sizeof(buf), "%d", x);
2479 geometry->add_property("x-pos", string(buf));
2480 snprintf(buf, sizeof(buf), "%d", y);
2481 geometry->add_property("y-pos", string(buf));
2482 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2483 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2484 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2485 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2486 geometry->add_property("edit-vertical-pane-pos", string(buf));
2488 node->add_child_nocopy (*geometry);
2491 maybe_add_mixer_strip_width (*node);
2493 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2495 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2496 node->add_property ("zoom", buf);
2497 node->add_property ("snap-to", enum_2_string (_snap_type));
2498 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2499 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2500 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2501 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2502 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2503 node->add_property ("edit-point", enum_2_string (_edit_point));
2505 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2506 node->add_property ("playhead", buf);
2507 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2508 node->add_property ("left-frame", buf);
2509 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2510 node->add_property ("y-origin", buf);
2512 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2513 node->add_property ("maximised", _maximised ? "yes" : "no");
2514 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2515 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2516 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2517 node->add_property ("mouse-mode", enum2str(mouse_mode));
2518 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2519 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2521 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2523 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2524 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2527 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2529 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2530 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2533 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2534 node->add_property (X_("editor-list-page"), buf);
2536 if (button_bindings) {
2537 XMLNode* bb = new XMLNode (X_("Buttons"));
2538 button_bindings->save (*bb);
2539 node->add_child_nocopy (*bb);
2542 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2544 node->add_child_nocopy (selection->get_state ());
2545 node->add_child_nocopy (_regions->get_state ());
2547 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2548 node->add_property ("nudge-clock-value", buf);
2555 /** @param y y offset from the top of all trackviews.
2556 * @return pair: TimeAxisView that y is over, layer index.
2557 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2558 * in stacked or expanded region display mode, otherwise 0.
2560 std::pair<TimeAxisView *, double>
2561 Editor::trackview_by_y_position (double y)
2563 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2565 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2571 return std::make_pair ( (TimeAxisView *) 0, 0);
2574 /** Snap a position to the grid, if appropriate, taking into account current
2575 * grid settings and also the state of any snap modifier keys that may be pressed.
2576 * @param start Position to snap.
2577 * @param event Event to get current key modifier information from, or 0.
2580 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2582 if (!_session || !event) {
2586 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2587 if (_snap_mode == SnapOff) {
2588 snap_to_internal (start, direction, for_mark);
2591 if (_snap_mode != SnapOff) {
2592 snap_to_internal (start, direction, for_mark);
2598 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2600 if (!_session || _snap_mode == SnapOff) {
2604 snap_to_internal (start, direction, for_mark);
2608 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2610 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2611 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2613 switch (_snap_type) {
2614 case SnapToTimecodeFrame:
2615 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2616 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2618 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2622 case SnapToTimecodeSeconds:
2623 if (_session->config.get_timecode_offset_negative()) {
2624 start += _session->config.get_timecode_offset ();
2626 start -= _session->config.get_timecode_offset ();
2628 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2629 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2631 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2634 if (_session->config.get_timecode_offset_negative()) {
2635 start -= _session->config.get_timecode_offset ();
2637 start += _session->config.get_timecode_offset ();
2641 case SnapToTimecodeMinutes:
2642 if (_session->config.get_timecode_offset_negative()) {
2643 start += _session->config.get_timecode_offset ();
2645 start -= _session->config.get_timecode_offset ();
2647 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2648 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2650 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2652 if (_session->config.get_timecode_offset_negative()) {
2653 start -= _session->config.get_timecode_offset ();
2655 start += _session->config.get_timecode_offset ();
2659 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2665 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2667 const framepos_t one_second = _session->frame_rate();
2668 const framepos_t one_minute = _session->frame_rate() * 60;
2669 framepos_t presnap = start;
2673 switch (_snap_type) {
2674 case SnapToTimecodeFrame:
2675 case SnapToTimecodeSeconds:
2676 case SnapToTimecodeMinutes:
2677 return timecode_snap_to_internal (start, direction, for_mark);
2680 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2681 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2683 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2688 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2689 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2691 start = (framepos_t) floor ((double) start / one_second) * one_second;
2696 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2697 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2699 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2704 start = _session->tempo_map().round_to_bar (start, direction);
2708 start = _session->tempo_map().round_to_beat (start, direction);
2711 case SnapToBeatDiv128:
2712 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2714 case SnapToBeatDiv64:
2715 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2717 case SnapToBeatDiv32:
2718 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2720 case SnapToBeatDiv28:
2721 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2723 case SnapToBeatDiv24:
2724 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2726 case SnapToBeatDiv20:
2727 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2729 case SnapToBeatDiv16:
2730 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2732 case SnapToBeatDiv14:
2733 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2735 case SnapToBeatDiv12:
2736 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2738 case SnapToBeatDiv10:
2739 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2741 case SnapToBeatDiv8:
2742 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2744 case SnapToBeatDiv7:
2745 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2747 case SnapToBeatDiv6:
2748 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2750 case SnapToBeatDiv5:
2751 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2753 case SnapToBeatDiv4:
2754 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2756 case SnapToBeatDiv3:
2757 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2759 case SnapToBeatDiv2:
2760 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2768 _session->locations()->marks_either_side (start, before, after);
2770 if (before == max_framepos && after == max_framepos) {
2771 /* No marks to snap to, so just don't snap */
2773 } else if (before == max_framepos) {
2775 } else if (after == max_framepos) {
2777 } else if (before != max_framepos && after != max_framepos) {
2778 /* have before and after */
2779 if ((start - before) < (after - start)) {
2788 case SnapToRegionStart:
2789 case SnapToRegionEnd:
2790 case SnapToRegionSync:
2791 case SnapToRegionBoundary:
2792 if (!region_boundary_cache.empty()) {
2794 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2795 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2797 if (direction > 0) {
2798 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2800 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2803 if (next != region_boundary_cache.begin ()) {
2808 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2809 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2811 if (start > (p + n) / 2) {
2820 switch (_snap_mode) {
2826 if (presnap > start) {
2827 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2831 } else if (presnap < start) {
2832 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2838 /* handled at entry */
2846 Editor::setup_toolbar ()
2848 HBox* mode_box = manage(new HBox);
2849 mode_box->set_border_width (2);
2850 mode_box->set_spacing(4);
2852 HBox* mouse_mode_box = manage (new HBox);
2853 HBox* mouse_mode_hbox = manage (new HBox);
2854 VBox* mouse_mode_vbox = manage (new VBox);
2855 Alignment* mouse_mode_align = manage (new Alignment);
2857 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2858 // mouse_mode_size_group->add_widget (smart_mode_button);
2859 mouse_mode_size_group->add_widget (mouse_move_button);
2860 mouse_mode_size_group->add_widget (mouse_select_button);
2861 mouse_mode_size_group->add_widget (mouse_zoom_button);
2862 mouse_mode_size_group->add_widget (mouse_gain_button);
2863 mouse_mode_size_group->add_widget (mouse_timefx_button);
2864 mouse_mode_size_group->add_widget (mouse_audition_button);
2865 mouse_mode_size_group->add_widget (mouse_draw_button);
2866 mouse_mode_size_group->add_widget (internal_edit_button);
2868 /* make them just a bit bigger */
2869 mouse_move_button.set_size_request (-1, 30);
2871 mouse_mode_hbox->set_spacing (2);
2873 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2874 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2875 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2876 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2877 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2878 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2879 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2880 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2881 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2883 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2885 mouse_mode_align->add (*mouse_mode_vbox);
2886 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2888 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2890 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2891 if (!Profile->get_sae()) {
2892 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2894 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2896 edit_mode_selector.set_name ("EditModeSelector");
2897 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2898 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2900 mode_box->pack_start (edit_mode_selector, false, false);
2901 mode_box->pack_start (*mouse_mode_box, false, false);
2903 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2904 _mouse_mode_tearoff->set_name ("MouseModeBase");
2905 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2907 if (Profile->get_sae()) {
2908 _mouse_mode_tearoff->set_can_be_torn_off (false);
2911 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2912 &_mouse_mode_tearoff->tearoff_window()));
2913 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2914 &_mouse_mode_tearoff->tearoff_window(), 1));
2915 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2916 &_mouse_mode_tearoff->tearoff_window()));
2917 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2918 &_mouse_mode_tearoff->tearoff_window(), 1));
2922 _zoom_box.set_spacing (2);
2923 _zoom_box.set_border_width (2);
2927 zoom_in_button.set_name ("zoom button");
2928 zoom_in_button.add_elements ( ArdourButton::FlatFace );
2929 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2930 zoom_in_button.set_image(::get_icon ("zoom_in"));
2931 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2932 zoom_in_button.set_related_action (act);
2934 zoom_out_button.set_name ("zoom button");
2935 zoom_out_button.add_elements ( ArdourButton::FlatFace );
2936 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2937 zoom_out_button.set_image(::get_icon ("zoom_out"));
2938 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2939 zoom_out_button.set_related_action (act);
2941 zoom_out_full_button.set_name ("zoom button");
2942 zoom_out_full_button.add_elements ( ArdourButton::FlatFace );
2943 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2944 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2945 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2946 zoom_out_full_button.set_related_action (act);
2948 zoom_focus_selector.set_name ("ZoomFocusSelector");
2949 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2950 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2952 _zoom_box.pack_start (zoom_out_button, false, false);
2953 _zoom_box.pack_start (zoom_in_button, false, false);
2954 _zoom_box.pack_start (zoom_out_full_button, false, false);
2956 _zoom_box.pack_start (zoom_focus_selector, false, false);
2958 /* Track zoom buttons */
2959 tav_expand_button.set_name ("zoom button");
2960 tav_expand_button.add_elements ( ArdourButton::FlatFace );
2961 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2962 tav_expand_button.set_size_request (-1, 20);
2963 tav_expand_button.set_image(::get_icon ("tav_exp"));
2964 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2965 tav_expand_button.set_related_action (act);
2967 tav_shrink_button.set_name ("zoom button");
2968 tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2969 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2970 tav_shrink_button.set_size_request (-1, 20);
2971 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2972 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2973 tav_shrink_button.set_related_action (act);
2975 _zoom_box.pack_start (tav_shrink_button);
2976 _zoom_box.pack_start (tav_expand_button);
2978 _zoom_tearoff = manage (new TearOff (_zoom_box));
2980 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2981 &_zoom_tearoff->tearoff_window()));
2982 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2983 &_zoom_tearoff->tearoff_window(), 0));
2984 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2985 &_zoom_tearoff->tearoff_window()));
2986 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2987 &_zoom_tearoff->tearoff_window(), 0));
2989 snap_box.set_spacing (2);
2990 snap_box.set_border_width (2);
2992 snap_type_selector.set_name ("SnapTypeSelector");
2993 set_popdown_strings (snap_type_selector, snap_type_strings);
2994 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2996 snap_mode_selector.set_name ("SnapModeSelector");
2997 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2998 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
3000 edit_point_selector.set_name ("EditPointSelector");
3001 set_popdown_strings (edit_point_selector, edit_point_strings);
3002 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
3004 snap_box.pack_start (snap_mode_selector, false, false);
3005 snap_box.pack_start (snap_type_selector, false, false);
3006 snap_box.pack_start (edit_point_selector, false, false);
3010 HBox *nudge_box = manage (new HBox);
3011 nudge_box->set_spacing (2);
3012 nudge_box->set_border_width (2);
3014 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3015 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3017 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3018 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3020 nudge_box->pack_start (nudge_backward_button, false, false);
3021 nudge_box->pack_start (nudge_forward_button, false, false);
3022 nudge_box->pack_start (*nudge_clock, false, false);
3025 /* Pack everything in... */
3027 HBox* hbox = manage (new HBox);
3028 hbox->set_spacing(10);
3030 _tools_tearoff = manage (new TearOff (*hbox));
3031 _tools_tearoff->set_name ("MouseModeBase");
3032 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3034 if (Profile->get_sae()) {
3035 _tools_tearoff->set_can_be_torn_off (false);
3038 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3039 &_tools_tearoff->tearoff_window()));
3040 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3041 &_tools_tearoff->tearoff_window(), 0));
3042 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3043 &_tools_tearoff->tearoff_window()));
3044 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3045 &_tools_tearoff->tearoff_window(), 0));
3047 toolbar_hbox.set_spacing (10);
3048 toolbar_hbox.set_border_width (1);
3050 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3051 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3052 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3054 hbox->pack_start (snap_box, false, false);
3055 if (!Profile->get_small_screen()) {
3056 hbox->pack_start (*nudge_box, false, false);
3058 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3060 hbox->pack_start (panic_box, false, false);
3064 toolbar_base.set_name ("ToolBarBase");
3065 toolbar_base.add (toolbar_hbox);
3067 _toolbar_viewport.add (toolbar_base);
3068 /* stick to the required height but allow width to vary if there's not enough room */
3069 _toolbar_viewport.set_size_request (1, -1);
3071 toolbar_frame.set_shadow_type (SHADOW_OUT);
3072 toolbar_frame.set_name ("BaseFrame");
3073 toolbar_frame.add (_toolbar_viewport);
3077 Editor::setup_tooltips ()
3079 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3080 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3081 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3082 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3083 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3084 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3085 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3086 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3087 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3088 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3089 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3090 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3091 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3092 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3093 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3094 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3095 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3096 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3097 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3098 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3099 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3100 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3101 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3105 Editor::convert_drop_to_paths (
3106 vector<string>& paths,
3107 const RefPtr<Gdk::DragContext>& /*context*/,
3110 const SelectionData& data,
3114 if (_session == 0) {
3118 vector<string> uris = data.get_uris();
3122 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3123 are actually URI lists. So do it by hand.
3126 if (data.get_target() != "text/plain") {
3130 /* Parse the "uri-list" format that Nautilus provides,
3131 where each pathname is delimited by \r\n.
3133 THERE MAY BE NO NULL TERMINATING CHAR!!!
3136 string txt = data.get_text();
3140 p = (char *) malloc (txt.length() + 1);
3141 txt.copy (p, txt.length(), 0);
3142 p[txt.length()] = '\0';
3148 while (g_ascii_isspace (*p))
3152 while (*q && (*q != '\n') && (*q != '\r')) {
3159 while (q > p && g_ascii_isspace (*q))
3164 uris.push_back (string (p, q - p + 1));
3168 p = strchr (p, '\n');
3180 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3182 if ((*i).substr (0,7) == "file://") {
3184 string const p = PBD::url_decode (*i);
3186 // scan forward past three slashes
3188 string::size_type slashcnt = 0;
3189 string::size_type n = 0;
3190 string::const_iterator x = p.begin();
3192 while (slashcnt < 3 && x != p.end()) {
3195 } else if (slashcnt == 3) {
3202 if (slashcnt != 3 || x == p.end()) {
3203 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3207 paths.push_back (p.substr (n - 1));
3215 Editor::new_tempo_section ()
3221 Editor::map_transport_state ()
3223 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3225 if (_session && _session->transport_stopped()) {
3226 have_pending_keyboard_selection = false;
3229 update_loop_range_view (true);
3235 Editor::begin_reversible_command (string name)
3238 _session->begin_reversible_command (name);
3243 Editor::begin_reversible_command (GQuark q)
3246 _session->begin_reversible_command (q);
3251 Editor::commit_reversible_command ()
3254 _session->commit_reversible_command ();
3259 Editor::history_changed ()
3263 if (undo_action && _session) {
3264 if (_session->undo_depth() == 0) {
3265 label = S_("Command|Undo");
3267 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3269 undo_action->property_label() = label;
3272 if (redo_action && _session) {
3273 if (_session->redo_depth() == 0) {
3276 label = string_compose(_("Redo (%1)"), _session->next_redo());
3278 redo_action->property_label() = label;
3283 Editor::duplicate_range (bool with_dialog)
3287 RegionSelection rs = get_regions_from_selection_and_entered ();
3289 if ( selection->time.length() == 0 && rs.empty()) {
3295 ArdourDialog win (_("Duplicate"));
3296 Label label (_("Number of duplications:"));
3297 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3298 SpinButton spinner (adjustment, 0.0, 1);
3301 win.get_vbox()->set_spacing (12);
3302 win.get_vbox()->pack_start (hbox);
3303 hbox.set_border_width (6);
3304 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3306 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3307 place, visually. so do this by hand.
3310 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3311 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3312 spinner.grab_focus();
3318 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3319 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3320 win.set_default_response (RESPONSE_ACCEPT);
3322 spinner.grab_focus ();
3324 switch (win.run ()) {
3325 case RESPONSE_ACCEPT:
3331 times = adjustment.get_value();
3334 if ((current_mouse_mode() == Editing::MouseRange)) {
3335 if (selection->time.length()) {
3336 duplicate_selection (times);
3338 } else if (get_smart_mode()) {
3339 if (selection->time.length()) {
3340 duplicate_selection (times);
3342 duplicate_some_regions (rs, times);
3344 duplicate_some_regions (rs, times);
3349 Editor::set_edit_mode (EditMode m)
3351 Config->set_edit_mode (m);
3355 Editor::cycle_edit_mode ()
3357 switch (Config->get_edit_mode()) {
3359 if (Profile->get_sae()) {
3360 Config->set_edit_mode (Lock);
3362 Config->set_edit_mode (Splice);
3366 Config->set_edit_mode (Lock);
3369 Config->set_edit_mode (Slide);
3375 Editor::edit_mode_selection_done ()
3377 string s = edit_mode_selector.get_active_text ();
3380 Config->set_edit_mode (string_to_edit_mode (s));
3385 Editor::snap_type_selection_done ()
3387 string choice = snap_type_selector.get_active_text();
3388 SnapType snaptype = SnapToBeat;
3390 if (choice == _("Beats/2")) {
3391 snaptype = SnapToBeatDiv2;
3392 } else if (choice == _("Beats/3")) {
3393 snaptype = SnapToBeatDiv3;
3394 } else if (choice == _("Beats/4")) {
3395 snaptype = SnapToBeatDiv4;
3396 } else if (choice == _("Beats/5")) {
3397 snaptype = SnapToBeatDiv5;
3398 } else if (choice == _("Beats/6")) {
3399 snaptype = SnapToBeatDiv6;
3400 } else if (choice == _("Beats/7")) {
3401 snaptype = SnapToBeatDiv7;
3402 } else if (choice == _("Beats/8")) {
3403 snaptype = SnapToBeatDiv8;
3404 } else if (choice == _("Beats/10")) {
3405 snaptype = SnapToBeatDiv10;
3406 } else if (choice == _("Beats/12")) {
3407 snaptype = SnapToBeatDiv12;
3408 } else if (choice == _("Beats/14")) {
3409 snaptype = SnapToBeatDiv14;
3410 } else if (choice == _("Beats/16")) {
3411 snaptype = SnapToBeatDiv16;
3412 } else if (choice == _("Beats/20")) {
3413 snaptype = SnapToBeatDiv20;
3414 } else if (choice == _("Beats/24")) {
3415 snaptype = SnapToBeatDiv24;
3416 } else if (choice == _("Beats/28")) {
3417 snaptype = SnapToBeatDiv28;
3418 } else if (choice == _("Beats/32")) {
3419 snaptype = SnapToBeatDiv32;
3420 } else if (choice == _("Beats/64")) {
3421 snaptype = SnapToBeatDiv64;
3422 } else if (choice == _("Beats/128")) {
3423 snaptype = SnapToBeatDiv128;
3424 } else if (choice == _("Beats")) {
3425 snaptype = SnapToBeat;
3426 } else if (choice == _("Bars")) {
3427 snaptype = SnapToBar;
3428 } else if (choice == _("Marks")) {
3429 snaptype = SnapToMark;
3430 } else if (choice == _("Region starts")) {
3431 snaptype = SnapToRegionStart;
3432 } else if (choice == _("Region ends")) {
3433 snaptype = SnapToRegionEnd;
3434 } else if (choice == _("Region bounds")) {
3435 snaptype = SnapToRegionBoundary;
3436 } else if (choice == _("Region syncs")) {
3437 snaptype = SnapToRegionSync;
3438 } else if (choice == _("CD Frames")) {
3439 snaptype = SnapToCDFrame;
3440 } else if (choice == _("Timecode Frames")) {
3441 snaptype = SnapToTimecodeFrame;
3442 } else if (choice == _("Timecode Seconds")) {
3443 snaptype = SnapToTimecodeSeconds;
3444 } else if (choice == _("Timecode Minutes")) {
3445 snaptype = SnapToTimecodeMinutes;
3446 } else if (choice == _("Seconds")) {
3447 snaptype = SnapToSeconds;
3448 } else if (choice == _("Minutes")) {
3449 snaptype = SnapToMinutes;
3452 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3454 ract->set_active ();
3459 Editor::snap_mode_selection_done ()
3461 string choice = snap_mode_selector.get_active_text();
3462 SnapMode mode = SnapNormal;
3464 if (choice == _("No Grid")) {
3466 } else if (choice == _("Grid")) {
3468 } else if (choice == _("Magnetic")) {
3469 mode = SnapMagnetic;
3472 RefPtr<RadioAction> ract = snap_mode_action (mode);
3475 ract->set_active (true);
3480 Editor::cycle_edit_point (bool with_marker)
3482 switch (_edit_point) {
3484 set_edit_point_preference (EditAtPlayhead);
3486 case EditAtPlayhead:
3488 set_edit_point_preference (EditAtSelectedMarker);
3490 set_edit_point_preference (EditAtMouse);
3493 case EditAtSelectedMarker:
3494 set_edit_point_preference (EditAtMouse);
3500 Editor::edit_point_selection_done ()
3502 string choice = edit_point_selector.get_active_text();
3503 EditPoint ep = EditAtSelectedMarker;
3505 if (choice == _("Marker")) {
3506 set_edit_point_preference (EditAtSelectedMarker);
3507 } else if (choice == _("Playhead")) {
3508 set_edit_point_preference (EditAtPlayhead);
3510 set_edit_point_preference (EditAtMouse);
3513 RefPtr<RadioAction> ract = edit_point_action (ep);
3516 ract->set_active (true);
3521 Editor::zoom_focus_selection_done ()
3523 string choice = zoom_focus_selector.get_active_text();
3524 ZoomFocus focus_type = ZoomFocusLeft;
3526 if (choice == _("Left")) {
3527 focus_type = ZoomFocusLeft;
3528 } else if (choice == _("Right")) {
3529 focus_type = ZoomFocusRight;
3530 } else if (choice == _("Center")) {
3531 focus_type = ZoomFocusCenter;
3532 } else if (choice == _("Playhead")) {
3533 focus_type = ZoomFocusPlayhead;
3534 } else if (choice == _("Mouse")) {
3535 focus_type = ZoomFocusMouse;
3536 } else if (choice == _("Edit point")) {
3537 focus_type = ZoomFocusEdit;
3540 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3543 ract->set_active ();
3548 Editor::edit_controls_button_release (GdkEventButton* ev)
3550 if (Keyboard::is_context_menu_event (ev)) {
3551 ARDOUR_UI::instance()->add_route (this);
3552 } else if (ev->button == 1) {
3553 selection->clear_tracks ();
3560 Editor::mouse_select_button_release (GdkEventButton* ev)
3562 /* this handles just right-clicks */
3564 if (ev->button != 3) {
3572 Editor::set_zoom_focus (ZoomFocus f)
3574 string str = zoom_focus_strings[(int)f];
3576 if (str != zoom_focus_selector.get_active_text()) {
3577 zoom_focus_selector.set_active_text (str);
3580 if (zoom_focus != f) {
3587 Editor::cycle_zoom_focus ()
3589 switch (zoom_focus) {
3591 set_zoom_focus (ZoomFocusRight);
3593 case ZoomFocusRight:
3594 set_zoom_focus (ZoomFocusCenter);
3596 case ZoomFocusCenter:
3597 set_zoom_focus (ZoomFocusPlayhead);
3599 case ZoomFocusPlayhead:
3600 set_zoom_focus (ZoomFocusMouse);
3602 case ZoomFocusMouse:
3603 set_zoom_focus (ZoomFocusEdit);
3606 set_zoom_focus (ZoomFocusLeft);
3612 Editor::ensure_float (Window& win)
3614 win.set_transient_for (*this);
3618 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3620 /* recover or initialize pane positions. do this here rather than earlier because
3621 we don't want the positions to change the child allocations, which they seem to do.
3627 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3636 XMLNode* geometry = find_named_node (*node, "geometry");
3638 if (which == static_cast<Paned*> (&edit_pane)) {
3640 if (done & Horizontal) {
3644 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3645 _notebook_shrunk = string_is_affirmative (prop->value ());
3648 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3649 /* initial allocation is 90% to canvas, 10% to notebook */
3650 pos = (int) floor (alloc.get_width() * 0.90f);
3651 snprintf (buf, sizeof(buf), "%d", pos);
3653 pos = atoi (prop->value());
3656 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3657 edit_pane.set_position (pos);
3660 done = (Pane) (done | Horizontal);
3662 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3664 if (done & Vertical) {
3668 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3669 /* initial allocation is 90% to canvas, 10% to summary */
3670 pos = (int) floor (alloc.get_height() * 0.90f);
3671 snprintf (buf, sizeof(buf), "%d", pos);
3674 pos = atoi (prop->value());
3677 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3678 editor_summary_pane.set_position (pos);
3681 done = (Pane) (done | Vertical);
3686 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3688 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3689 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3690 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3691 top_hbox.remove (toolbar_frame);
3696 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3698 if (toolbar_frame.get_parent() == 0) {
3699 top_hbox.pack_end (toolbar_frame);
3704 Editor::set_show_measures (bool yn)
3706 if (_show_measures != yn) {
3709 if ((_show_measures = yn) == true) {
3711 tempo_lines->show();
3714 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3715 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3717 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3718 draw_measures (begin, end);
3726 Editor::toggle_follow_playhead ()
3728 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3730 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3731 set_follow_playhead (tact->get_active());
3735 /** @param yn true to follow playhead, otherwise false.
3736 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3739 Editor::set_follow_playhead (bool yn, bool catch_up)
3741 if (_follow_playhead != yn) {
3742 if ((_follow_playhead = yn) == true && catch_up) {
3744 reset_x_origin_to_follow_playhead ();
3751 Editor::toggle_stationary_playhead ()
3753 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3755 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3756 set_stationary_playhead (tact->get_active());
3761 Editor::set_stationary_playhead (bool yn)
3763 if (_stationary_playhead != yn) {
3764 if ((_stationary_playhead = yn) == true) {
3766 // FIXME need a 3.0 equivalent of this 2.X call
3767 // update_current_screen ();
3774 Editor::playlist_selector () const
3776 return *_playlist_selector;
3780 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3784 switch (_snap_type) {
3789 case SnapToBeatDiv128:
3792 case SnapToBeatDiv64:
3795 case SnapToBeatDiv32:
3798 case SnapToBeatDiv28:
3801 case SnapToBeatDiv24:
3804 case SnapToBeatDiv20:
3807 case SnapToBeatDiv16:
3810 case SnapToBeatDiv14:
3813 case SnapToBeatDiv12:
3816 case SnapToBeatDiv10:
3819 case SnapToBeatDiv8:
3822 case SnapToBeatDiv7:
3825 case SnapToBeatDiv6:
3828 case SnapToBeatDiv5:
3831 case SnapToBeatDiv4:
3834 case SnapToBeatDiv3:
3837 case SnapToBeatDiv2:
3843 return _session->tempo_map().meter_at (position).divisions_per_bar();
3848 case SnapToTimecodeFrame:
3849 case SnapToTimecodeSeconds:
3850 case SnapToTimecodeMinutes:
3853 case SnapToRegionStart:
3854 case SnapToRegionEnd:
3855 case SnapToRegionSync:
3856 case SnapToRegionBoundary:
3866 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3870 ret = nudge_clock->current_duration (pos);
3871 next = ret + 1; /* XXXX fix me */
3877 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3879 ArdourDialog dialog (_("Playlist Deletion"));
3880 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3881 "If it is kept, its audio files will not be cleaned.\n"
3882 "If it is deleted, audio files used by it alone will be cleaned."),
3885 dialog.set_position (WIN_POS_CENTER);
3886 dialog.get_vbox()->pack_start (label);
3890 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3891 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3892 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3894 switch (dialog.run ()) {
3895 case RESPONSE_ACCEPT:
3896 /* delete the playlist */
3900 case RESPONSE_REJECT:
3901 /* keep the playlist */
3913 Editor::audio_region_selection_covers (framepos_t where)
3915 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3916 if ((*a)->region()->covers (where)) {
3925 Editor::prepare_for_cleanup ()
3927 cut_buffer->clear_regions ();
3928 cut_buffer->clear_playlists ();
3930 selection->clear_regions ();
3931 selection->clear_playlists ();
3933 _regions->suspend_redisplay ();
3937 Editor::finish_cleanup ()
3939 _regions->resume_redisplay ();
3943 Editor::transport_loop_location()
3946 return _session->locations()->auto_loop_location();
3953 Editor::transport_punch_location()
3956 return _session->locations()->auto_punch_location();
3963 Editor::control_layout_scroll (GdkEventScroll* ev)
3965 if (Keyboard::some_magic_widget_has_focus()) {
3969 switch (ev->direction) {
3971 scroll_tracks_up_line ();
3975 case GDK_SCROLL_DOWN:
3976 scroll_tracks_down_line ();
3980 /* no left/right handling yet */
3988 Editor::session_state_saved (string)
3991 _snapshots->redisplay ();
3995 Editor::update_tearoff_visibility()
3997 bool visible = Config->get_keep_tearoffs();
3998 _mouse_mode_tearoff->set_visible (visible);
3999 _tools_tearoff->set_visible (visible);
4000 _zoom_tearoff->set_visible (visible);
4004 Editor::maximise_editing_space ()
4016 Editor::restore_editing_space ()
4028 * Make new playlists for a given track and also any others that belong
4029 * to the same active route group with the `select' property.
4034 Editor::new_playlists (TimeAxisView* v)
4036 begin_reversible_command (_("new playlists"));
4037 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4038 _session->playlists->get (playlists);
4039 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4040 commit_reversible_command ();
4044 * Use a copy of the current playlist for a given track and also any others that belong
4045 * to the same active route group with the `select' property.
4050 Editor::copy_playlists (TimeAxisView* v)
4052 begin_reversible_command (_("copy 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_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4056 commit_reversible_command ();
4059 /** Clear the current playlist for a given track and also any others that belong
4060 * to the same active route group with the `select' property.
4065 Editor::clear_playlists (TimeAxisView* v)
4067 begin_reversible_command (_("clear playlists"));
4068 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4069 _session->playlists->get (playlists);
4070 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4071 commit_reversible_command ();
4075 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4077 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4081 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4083 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4087 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4089 atv.clear_playlist ();
4093 Editor::on_key_press_event (GdkEventKey* ev)
4095 return key_press_focus_accelerator_handler (*this, ev);
4099 Editor::on_key_release_event (GdkEventKey* ev)
4101 return Gtk::Window::on_key_release_event (ev);
4102 // return key_press_focus_accelerator_handler (*this, ev);
4105 /** Queue up a change to the viewport x origin.
4106 * @param frame New x origin.
4109 Editor::reset_x_origin (framepos_t frame)
4111 pending_visual_change.add (VisualChange::TimeOrigin);
4112 pending_visual_change.time_origin = frame;
4113 ensure_visual_change_idle_handler ();
4117 Editor::reset_y_origin (double y)
4119 pending_visual_change.add (VisualChange::YOrigin);
4120 pending_visual_change.y_origin = y;
4121 ensure_visual_change_idle_handler ();
4125 Editor::reset_zoom (framecnt_t spp)
4127 clamp_samples_per_pixel (spp);
4129 if (spp == samples_per_pixel) {
4133 pending_visual_change.add (VisualChange::ZoomLevel);
4134 pending_visual_change.samples_per_pixel = spp;
4135 ensure_visual_change_idle_handler ();
4139 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4141 reset_x_origin (frame);
4144 if (!no_save_visual) {
4145 undo_visual_stack.push_back (current_visual_state(false));
4149 Editor::VisualState::VisualState (bool with_tracks)
4150 : gui_state (with_tracks ? new GUIObjectState : 0)
4154 Editor::VisualState::~VisualState ()
4159 Editor::VisualState*
4160 Editor::current_visual_state (bool with_tracks)
4162 VisualState* vs = new VisualState (with_tracks);
4163 vs->y_position = vertical_adjustment.get_value();
4164 vs->samples_per_pixel = samples_per_pixel;
4165 vs->leftmost_frame = leftmost_frame;
4166 vs->zoom_focus = zoom_focus;
4169 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4176 Editor::undo_visual_state ()
4178 if (undo_visual_stack.empty()) {
4182 VisualState* vs = undo_visual_stack.back();
4183 undo_visual_stack.pop_back();
4186 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4188 use_visual_state (*vs);
4192 Editor::redo_visual_state ()
4194 if (redo_visual_stack.empty()) {
4198 VisualState* vs = redo_visual_stack.back();
4199 redo_visual_stack.pop_back();
4201 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4203 use_visual_state (*vs);
4207 Editor::swap_visual_state ()
4209 if (undo_visual_stack.empty()) {
4210 redo_visual_state ();
4212 undo_visual_state ();
4217 Editor::use_visual_state (VisualState& vs)
4219 PBD::Unwinder<bool> nsv (no_save_visual, true);
4221 _routes->suspend_redisplay ();
4223 vertical_adjustment.set_value (vs.y_position);
4225 set_zoom_focus (vs.zoom_focus);
4226 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4229 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4231 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4232 (*i)->reset_visual_state ();
4236 _routes->update_visibility ();
4237 _routes->resume_redisplay ();
4240 /** This is the core function that controls the zoom level of the canvas. It is called
4241 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4242 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4245 Editor::set_samples_per_pixel (framecnt_t spp)
4247 clamp_samples_per_pixel (spp);
4248 samples_per_pixel = spp;
4251 tempo_lines->tempo_map_changed();
4254 /* convert fpu to frame count */
4256 framepos_t frames = samples_per_pixel * _visible_canvas_width;
4258 if (samples_per_pixel != zoom_range_clock->current_duration()) {
4259 zoom_range_clock->set (frames);
4262 bool const showing_time_selection = selection->time.length() > 0;
4264 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4265 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4266 (*i)->reshow_selection (selection->time);
4270 ZoomChanged (); /* EMIT_SIGNAL */
4272 ArdourCanvas::GtkCanvasViewport* c;
4274 c = get_time_bars_canvas();
4276 c->canvas()->zoomed ();
4278 c = get_track_canvas();
4280 c->canvas()->zoomed ();
4283 if (playhead_cursor) {
4284 playhead_cursor->set_position (playhead_cursor->current_frame ());
4287 refresh_location_display();
4288 _summary->set_overlays_dirty ();
4290 update_marker_labels ();
4296 Editor::queue_visual_videotimeline_update ()
4299 * pending_visual_change.add (VisualChange::VideoTimeline);
4300 * or maybe even more specific: which videotimeline-image
4301 * currently it calls update_video_timeline() to update
4302 * _all outdated_ images on the video-timeline.
4303 * see 'exposeimg()' in video_image_frame.cc
4305 ensure_visual_change_idle_handler ();
4309 Editor::ensure_visual_change_idle_handler ()
4311 if (pending_visual_change.idle_handler_id < 0) {
4312 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4313 pending_visual_change.being_handled = false;
4318 Editor::_idle_visual_changer (void* arg)
4320 return static_cast<Editor*>(arg)->idle_visual_changer ();
4324 Editor::idle_visual_changer ()
4326 /* set_horizontal_position() below (and maybe other calls) call
4327 gtk_main_iteration(), so it's possible that a signal will be handled
4328 half-way through this method. If this signal wants an
4329 idle_visual_changer we must schedule another one after this one, so
4330 mark the idle_handler_id as -1 here to allow that. Also make a note
4331 that we are doing the visual change, so that changes in response to
4332 super-rapid-screen-update can be dropped if we are still processing
4336 pending_visual_change.idle_handler_id = -1;
4337 pending_visual_change.being_handled = true;
4339 VisualChange::Type p = pending_visual_change.pending;
4340 pending_visual_change.pending = (VisualChange::Type) 0;
4342 double const last_time_origin = horizontal_position ();
4345 if (p & VisualChange::ZoomLevel) {
4346 set_samples_per_pixel (pending_visual_change.samples_per_pixel);
4348 compute_fixed_ruler_scale ();
4350 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4351 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4353 compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_samples(),
4354 current_bbt_points_begin, current_bbt_points_end);
4355 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_samples(),
4356 current_bbt_points_begin, current_bbt_points_end);
4357 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4359 update_video_timeline();
4362 if (p & VisualChange::TimeOrigin) {
4363 set_horizontal_position (pending_visual_change.time_origin / samples_per_pixel);
4366 if (p & VisualChange::YOrigin) {
4367 vertical_adjustment.set_value (pending_visual_change.y_origin);
4370 if (last_time_origin == horizontal_position ()) {
4371 /* changed signal not emitted */
4372 update_fixed_rulers ();
4373 redisplay_tempo (true);
4376 if (!(p & VisualChange::ZoomLevel)) {
4377 update_video_timeline();
4380 _summary->set_overlays_dirty ();
4382 pending_visual_change.being_handled = false;
4383 return 0; /* this is always a one-shot call */
4386 struct EditorOrderTimeAxisSorter {
4387 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4388 return a->order () < b->order ();
4393 Editor::sort_track_selection (TrackViewList& sel)
4395 EditorOrderTimeAxisSorter cmp;
4400 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4403 framepos_t where = 0;
4404 EditPoint ep = _edit_point;
4406 if (from_context_menu && (ep == EditAtMouse)) {
4407 return canvas_event_frame (&context_click_event, 0, 0);
4410 if (entered_marker) {
4411 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4412 return entered_marker->position();
4415 if (ignore_playhead && ep == EditAtPlayhead) {
4416 ep = EditAtSelectedMarker;
4420 case EditAtPlayhead:
4421 where = _session->audible_frame();
4422 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4425 case EditAtSelectedMarker:
4426 if (!selection->markers.empty()) {
4428 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4431 where = loc->start();
4435 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4443 if (!mouse_frame (where, ignored)) {
4444 /* XXX not right but what can we do ? */
4448 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4456 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4458 if (!_session) return;
4460 begin_reversible_command (cmd);
4464 if ((tll = transport_loop_location()) == 0) {
4465 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4466 XMLNode &before = _session->locations()->get_state();
4467 _session->locations()->add (loc, true);
4468 _session->set_auto_loop_location (loc);
4469 XMLNode &after = _session->locations()->get_state();
4470 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4472 XMLNode &before = tll->get_state();
4473 tll->set_hidden (false, this);
4474 tll->set (start, end);
4475 XMLNode &after = tll->get_state();
4476 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4479 commit_reversible_command ();
4483 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4485 if (!_session) return;
4487 begin_reversible_command (cmd);
4491 if ((tpl = transport_punch_location()) == 0) {
4492 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4493 XMLNode &before = _session->locations()->get_state();
4494 _session->locations()->add (loc, true);
4495 _session->set_auto_loop_location (loc);
4496 XMLNode &after = _session->locations()->get_state();
4497 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4500 XMLNode &before = tpl->get_state();
4501 tpl->set_hidden (false, this);
4502 tpl->set (start, end);
4503 XMLNode &after = tpl->get_state();
4504 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4507 commit_reversible_command ();
4510 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4511 * @param rs List to which found regions are added.
4512 * @param where Time to look at.
4513 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4516 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4518 const TrackViewList* tracks;
4521 tracks = &track_views;
4526 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4528 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4531 boost::shared_ptr<Track> tr;
4532 boost::shared_ptr<Playlist> pl;
4534 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4536 boost::shared_ptr<RegionList> regions = pl->regions_at (
4537 (framepos_t) floor ( (double) where * tr->speed()));
4539 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4540 RegionView* rv = rtv->view()->find_view (*i);
4551 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4553 const TrackViewList* tracks;
4556 tracks = &track_views;
4561 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4562 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4564 boost::shared_ptr<Track> tr;
4565 boost::shared_ptr<Playlist> pl;
4567 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4569 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4570 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4572 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4574 RegionView* rv = rtv->view()->find_view (*i);
4585 /** Get regions using the following method:
4587 * Make a region list using the selected regions, unless
4588 * the edit point is `mouse' and the mouse is over an unselected
4589 * region. In this case, use just that region.
4591 * If the edit point is not 'mouse', and there are no regions selected,
4592 * search the list of selected tracks and return regions that are under
4593 * the edit point on these tracks. If there are no selected tracks and
4594 * 'No Selection = All Tracks' is active, search all tracks,
4596 * The rationale here is that the mouse edit point is special in that
4597 * its position describes both a time and a track; the other edit
4598 * modes only describe a time. Hence if the edit point is `mouse' we
4599 * ignore selected tracks, as we assume the user means something by
4600 * pointing at a particular track. Also in this case we take note of
4601 * the region directly under the edit point, as there is always just one
4602 * (rather than possibly several with non-mouse edit points).
4606 Editor::get_regions_from_selection_and_edit_point ()
4608 RegionSelection regions;
4610 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4611 regions.add (entered_regionview);
4613 regions = selection->regions;
4617 if (regions.empty() && _edit_point != EditAtMouse) {
4618 TrackViewList tracks = selection->tracks;
4620 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4621 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4622 * is enabled, so consider all tracks
4624 tracks = track_views;
4627 if (!tracks.empty()) {
4628 /* no region selected or entered, but some selected tracks:
4629 * act on all regions on the selected tracks at the edit point
4631 framepos_t const where = get_preferred_edit_position ();
4632 get_regions_at(regions, where, tracks);
4638 /** Start with regions that are selected, or the entered regionview if none are selected.
4639 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4640 * of the regions that we started with.
4644 Editor::get_regions_from_selection_and_entered ()
4646 RegionSelection regions = selection->regions;
4648 if (regions.empty() && entered_regionview) {
4649 regions.add (entered_regionview);
4656 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4658 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4660 RouteTimeAxisView* tatv;
4662 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4664 boost::shared_ptr<Playlist> pl;
4665 vector<boost::shared_ptr<Region> > results;
4667 boost::shared_ptr<Track> tr;
4669 if ((tr = tatv->track()) == 0) {
4674 if ((pl = (tr->playlist())) != 0) {
4675 if (src_comparison) {
4676 pl->get_source_equivalent_regions (region, results);
4678 pl->get_region_list_equivalent_regions (region, results);
4682 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4683 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4684 regions.push_back (marv);
4693 Editor::show_rhythm_ferret ()
4695 if (rhythm_ferret == 0) {
4696 rhythm_ferret = new RhythmFerret(*this);
4699 rhythm_ferret->set_session (_session);
4700 rhythm_ferret->show ();
4701 rhythm_ferret->present ();
4705 Editor::first_idle ()
4707 MessageDialog* dialog = 0;
4709 if (track_views.size() > 1) {
4710 dialog = new MessageDialog (
4712 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4716 ARDOUR_UI::instance()->flush_pending ();
4719 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4723 // first idle adds route children (automation tracks), so we need to redisplay here
4724 _routes->redisplay ();
4731 Editor::_idle_resize (gpointer arg)
4733 return ((Editor*)arg)->idle_resize ();
4737 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4739 if (resize_idle_id < 0) {
4740 resize_idle_id = g_idle_add (_idle_resize, this);
4741 _pending_resize_amount = 0;
4744 /* make a note of the smallest resulting height, so that we can clamp the
4745 lower limit at TimeAxisView::hSmall */
4747 int32_t min_resulting = INT32_MAX;
4749 _pending_resize_amount += h;
4750 _pending_resize_view = view;
4752 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4754 if (selection->tracks.contains (_pending_resize_view)) {
4755 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4756 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4760 if (min_resulting < 0) {
4765 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4766 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4770 /** Handle pending resizing of tracks */
4772 Editor::idle_resize ()
4774 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4776 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4777 selection->tracks.contains (_pending_resize_view)) {
4779 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4780 if (*i != _pending_resize_view) {
4781 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4786 _pending_resize_amount = 0;
4787 _group_tabs->set_dirty ();
4788 resize_idle_id = -1;
4796 ENSURE_GUI_THREAD (*this, &Editor::located);
4799 playhead_cursor->set_position (_session->audible_frame ());
4800 if (_follow_playhead && !_pending_initial_locate) {
4801 reset_x_origin_to_follow_playhead ();
4805 _pending_locate_request = false;
4806 _pending_initial_locate = false;
4810 Editor::region_view_added (RegionView *)
4812 _summary->set_dirty ();
4816 Editor::region_view_removed ()
4818 _summary->set_dirty ();
4822 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4824 TrackViewList::const_iterator j = track_views.begin ();
4825 while (j != track_views.end()) {
4826 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4827 if (rtv && rtv->route() == r) {
4838 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4842 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4843 TimeAxisView* tv = axis_view_from_route (*i);
4853 Editor::add_routes (RouteList& routes)
4855 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4857 RouteTimeAxisView *rtv;
4858 list<RouteTimeAxisView*> new_views;
4860 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4861 boost::shared_ptr<Route> route = (*x);
4863 if (route->is_auditioner() || route->is_monitor()) {
4867 DataType dt = route->input()->default_type();
4869 if (dt == ARDOUR::DataType::AUDIO) {
4870 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4871 rtv->set_route (route);
4872 } else if (dt == ARDOUR::DataType::MIDI) {
4873 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4874 rtv->set_route (route);
4876 throw unknown_type();
4879 new_views.push_back (rtv);
4880 track_views.push_back (rtv);
4882 rtv->effective_gain_display ();
4884 if (internal_editing()) {
4885 rtv->enter_internal_edit_mode ();
4887 rtv->leave_internal_edit_mode ();
4890 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4891 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4894 if (new_views.size() > 0) {
4895 _routes->routes_added (new_views);
4896 _summary->routes_added (new_views);
4899 if (show_editor_mixer_when_tracks_arrive) {
4900 show_editor_mixer (true);
4903 editor_list_button.set_sensitive (true);
4907 Editor::timeaxisview_deleted (TimeAxisView *tv)
4909 if (_session && _session->deletion_in_progress()) {
4910 /* the situation is under control */
4914 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4916 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4918 _routes->route_removed (tv);
4920 if (tv == entered_track) {
4924 TimeAxisView::Children c = tv->get_child_list ();
4925 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4926 if (entered_track == i->get()) {
4931 /* remove it from the list of track views */
4933 TrackViewList::iterator i;
4935 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4936 i = track_views.erase (i);
4939 /* update whatever the current mixer strip is displaying, if revelant */
4941 boost::shared_ptr<Route> route;
4944 route = rtav->route ();
4947 if (current_mixer_strip && current_mixer_strip->route() == route) {
4949 TimeAxisView* next_tv;
4951 if (track_views.empty()) {
4953 } else if (i == track_views.end()) {
4954 next_tv = track_views.front();
4961 set_selected_mixer_strip (*next_tv);
4963 /* make the editor mixer strip go away setting the
4964 * button to inactive (which also unticks the menu option)
4967 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4973 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4975 if (apply_to_selection) {
4976 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4978 TrackSelection::iterator j = i;
4981 hide_track_in_display (*i, false);
4986 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4988 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4989 // this will hide the mixer strip
4990 set_selected_mixer_strip (*tv);
4993 _routes->hide_track_in_display (*tv);
4998 Editor::sync_track_view_list_and_routes ()
5000 track_views = TrackViewList (_routes->views ());
5002 _summary->set_dirty ();
5003 _group_tabs->set_dirty ();
5005 return false; // do not call again (until needed)
5009 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5011 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5016 /** Find a RouteTimeAxisView by the ID of its route */
5018 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5020 RouteTimeAxisView* v;
5022 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5023 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5024 if(v->route()->id() == id) {
5034 Editor::fit_route_group (RouteGroup *g)
5036 TrackViewList ts = axis_views_from_routes (g->route_list ());
5041 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5043 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5046 _session->cancel_audition ();
5050 if (_session->is_auditioning()) {
5051 _session->cancel_audition ();
5052 if (r == last_audition_region) {
5057 _session->audition_region (r);
5058 last_audition_region = r;
5063 Editor::hide_a_region (boost::shared_ptr<Region> r)
5065 r->set_hidden (true);
5069 Editor::show_a_region (boost::shared_ptr<Region> r)
5071 r->set_hidden (false);
5075 Editor::audition_region_from_region_list ()
5077 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5081 Editor::hide_region_from_region_list ()
5083 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5087 Editor::show_region_in_region_list ()
5089 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5093 Editor::step_edit_status_change (bool yn)
5096 start_step_editing ();
5098 stop_step_editing ();
5103 Editor::start_step_editing ()
5105 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5109 Editor::stop_step_editing ()
5111 step_edit_connection.disconnect ();
5115 Editor::check_step_edit ()
5117 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5118 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5120 mtv->check_step_edit ();
5124 return true; // do it again, till we stop
5128 Editor::scroll_press (Direction dir)
5130 ++_scroll_callbacks;
5132 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5133 /* delay the first auto-repeat */
5139 scroll_backward (1);
5147 scroll_tracks_up_line ();
5151 scroll_tracks_down_line ();
5155 /* do hacky auto-repeat */
5156 if (!_scroll_connection.connected ()) {
5158 _scroll_connection = Glib::signal_timeout().connect (
5159 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5162 _scroll_callbacks = 0;
5169 Editor::scroll_release ()
5171 _scroll_connection.disconnect ();
5174 /** Queue a change for the Editor viewport x origin to follow the playhead */
5176 Editor::reset_x_origin_to_follow_playhead ()
5178 framepos_t const frame = playhead_cursor->current_frame ();
5180 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5182 if (_session->transport_speed() < 0) {
5184 if (frame > (current_page_samples() / 2)) {
5185 center_screen (frame-(current_page_samples()/2));
5187 center_screen (current_page_samples()/2);
5194 if (frame < leftmost_frame) {
5196 if (_session->transport_rolling()) {
5197 /* rolling; end up with the playhead at the right of the page */
5198 l = frame - current_page_samples ();
5200 /* not rolling: end up with the playhead 1/4 of the way along the page */
5201 l = frame - current_page_samples() / 4;
5205 if (_session->transport_rolling()) {
5206 /* rolling: end up with the playhead on the left of the page */
5209 /* not rolling: end up with the playhead 3/4 of the way along the page */
5210 l = frame - 3 * current_page_samples() / 4;
5218 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5224 Editor::super_rapid_screen_update ()
5226 if (!_session || !_session->engine().running()) {
5230 /* METERING / MIXER STRIPS */
5232 /* update track meters, if required */
5233 if (is_mapped() && meters_running) {
5234 RouteTimeAxisView* rtv;
5235 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5236 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5237 rtv->fast_update ();
5242 /* and any current mixer strip */
5243 if (current_mixer_strip) {
5244 current_mixer_strip->fast_update ();
5247 /* PLAYHEAD AND VIEWPORT */
5249 framepos_t const frame = _session->audible_frame();
5251 /* There are a few reasons why we might not update the playhead / viewport stuff:
5253 * 1. we don't update things when there's a pending locate request, otherwise
5254 * when the editor requests a locate there is a chance that this method
5255 * will move the playhead before the locate request is processed, causing
5257 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5258 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5261 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5263 last_update_frame = frame;
5265 if (!_dragging_playhead) {
5266 playhead_cursor->set_position (frame);
5269 if (!_stationary_playhead) {
5271 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5272 /* We only do this if we aren't already
5273 handling a visual change (ie if
5274 pending_visual_change.being_handled is
5275 false) so that these requests don't stack
5276 up there are too many of them to handle in
5279 reset_x_origin_to_follow_playhead ();
5284 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5288 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5289 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5290 if (target <= 0.0) {
5293 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5294 target = (target * 0.15) + (current * 0.85);
5300 set_horizontal_position (current);
5309 Editor::session_going_away ()
5311 _have_idled = false;
5313 _session_connections.drop_connections ();
5315 super_rapid_screen_update_connection.disconnect ();
5317 selection->clear ();
5318 cut_buffer->clear ();
5320 clicked_regionview = 0;
5321 clicked_axisview = 0;
5322 clicked_routeview = 0;
5323 entered_regionview = 0;
5325 last_update_frame = 0;
5328 playhead_cursor->hide ();
5330 /* rip everything out of the list displays */
5334 _route_groups->clear ();
5336 /* do this first so that deleting a track doesn't reset cms to null
5337 and thus cause a leak.
5340 if (current_mixer_strip) {
5341 if (current_mixer_strip->get_parent() != 0) {
5342 global_hpacker.remove (*current_mixer_strip);
5344 delete current_mixer_strip;
5345 current_mixer_strip = 0;
5348 /* delete all trackviews */
5350 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5353 track_views.clear ();
5355 zoom_range_clock->set_session (0);
5356 nudge_clock->set_session (0);
5358 editor_list_button.set_active(false);
5359 editor_list_button.set_sensitive(false);
5361 /* clear tempo/meter rulers */
5362 remove_metric_marks ();
5364 clear_marker_display ();
5366 stop_step_editing ();
5368 /* get rid of any existing editor mixer strip */
5370 WindowTitle title(Glib::get_application_name());
5371 title += _("Editor");
5373 set_title (title.get_string());
5375 SessionHandlePtr::session_going_away ();
5380 Editor::show_editor_list (bool yn)
5383 _the_notebook.show ();
5385 _the_notebook.hide ();
5390 Editor::change_region_layering_order (bool from_context_menu)
5392 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5394 if (!clicked_routeview) {
5395 if (layering_order_editor) {
5396 layering_order_editor->hide ();
5401 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5407 boost::shared_ptr<Playlist> pl = track->playlist();
5413 if (layering_order_editor == 0) {
5414 layering_order_editor = new RegionLayeringOrderEditor (*this);
5417 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5418 layering_order_editor->maybe_present ();
5422 Editor::update_region_layering_order_editor ()
5424 if (layering_order_editor && layering_order_editor->is_visible ()) {
5425 change_region_layering_order (true);
5430 Editor::setup_fade_images ()
5432 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5433 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5434 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5435 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5436 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5438 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5439 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5440 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5441 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5442 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5444 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5445 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5446 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5447 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5448 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5450 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5451 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5452 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5453 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5454 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5458 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5460 Editor::action_menu_item (std::string const & name)
5462 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5465 return *manage (a->create_menu_item ());
5469 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5471 EventBox* b = manage (new EventBox);
5472 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5473 Label* l = manage (new Label (name));
5477 _the_notebook.append_page (widget, *b);
5481 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5483 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5484 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5487 if (ev->type == GDK_2BUTTON_PRESS) {
5489 /* double-click on a notebook tab shrinks or expands the notebook */
5491 if (_notebook_shrunk) {
5492 if (pre_notebook_shrink_pane_width) {
5493 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5495 _notebook_shrunk = false;
5497 pre_notebook_shrink_pane_width = edit_pane.get_position();
5499 /* this expands the LHS of the edit pane to cover the notebook
5500 PAGE but leaves the tabs visible.
5502 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5503 _notebook_shrunk = true;
5511 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5513 using namespace Menu_Helpers;
5515 MenuList& items = _control_point_context_menu.items ();
5518 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5519 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5520 if (!can_remove_control_point (item)) {
5521 items.back().set_sensitive (false);
5524 _control_point_context_menu.popup (event->button.button, event->button.time);
5528 Editor::zoom_vertical_modifier_released()
5530 _stepping_axis_view = 0;