From 784d2ecce416d79e266da2d2e0de8bd2f59caac5 Mon Sep 17 00:00:00 2001 From: Ben Loftis Date: Tue, 5 Sep 2023 11:36:17 -0500 Subject: [PATCH] Add the tool for Grid, and accompanying buttons and event-handling --- gtk2_ardour/editing_syms.h | 1 + gtk2_ardour/editor.cc | 18 +++++ gtk2_ardour/editor.h | 6 ++ gtk2_ardour/editor_actions.cc | 5 ++ gtk2_ardour/editor_mouse.cc | 121 ++++++++++++++++++++-------------- gtk2_ardour/enums.cc | 1 + 6 files changed, 103 insertions(+), 49 deletions(-) diff --git a/gtk2_ardour/editing_syms.h b/gtk2_ardour/editing_syms.h index 9e3ea41212..8159c18c8f 100644 --- a/gtk2_ardour/editing_syms.h +++ b/gtk2_ardour/editing_syms.h @@ -66,6 +66,7 @@ MOUSEMODE(MouseObject) MOUSEMODE(MouseRange) MOUSEMODE(MouseCut) MOUSEMODE(MouseTimeFX) +MOUSEMODE(MouseGrid) MOUSEMODE(MouseAudition) MOUSEMODE(MouseDraw) MOUSEMODE(MouseContent) diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 8c74ada03c..f536c510e8 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -924,6 +924,7 @@ Editor::~Editor() delete _snapshots; delete _sections; delete _locations; + delete _canvas_grid_zone; delete _properties_box; delete selection; delete cut_buffer; @@ -3259,6 +3260,7 @@ Editor::setup_toolbar () mouse_mode_size_group->add_widget (mouse_cut_button); mouse_mode_size_group->add_widget (mouse_select_button); mouse_mode_size_group->add_widget (mouse_timefx_button); + mouse_mode_size_group->add_widget (mouse_grid_button); if (!Profile->get_mixbus()) { mouse_mode_size_group->add_widget (mouse_audition_button); } @@ -3277,6 +3279,8 @@ Editor::setup_toolbar () mouse_mode_size_group->add_widget (visible_tracks_selector); } + mouse_mode_size_group->add_widget (stretch_midi_cb); + mouse_mode_size_group->add_widget (grid_type_selector); mouse_mode_size_group->add_widget (draw_length_selector); mouse_mode_size_group->add_widget (draw_velocity_selector); @@ -3304,6 +3308,7 @@ Editor::setup_toolbar () } mouse_mode_hbox->pack_start (mouse_timefx_button, false, false); + mouse_mode_hbox->pack_start (mouse_grid_button, false, false); mouse_mode_hbox->pack_start (mouse_draw_button, false, false); mouse_mode_hbox->pack_start (mouse_content_button, false, false); @@ -3393,6 +3398,8 @@ Editor::setup_toolbar () snap_box.set_spacing (2); snap_box.set_border_width (2); + stretch_midi_cb.set_name ("mouse mode button"); + grid_type_selector.set_name ("mouse mode button"); draw_length_selector.set_name ("mouse mode button"); draw_velocity_selector.set_name ("mouse mode button"); @@ -3424,6 +3431,13 @@ Editor::setup_toolbar () nudge_box->pack_start (nudge_forward_button, false, false); nudge_box->pack_start (*nudge_clock, false, false); + stretch_midi_cb.set_label(_("Stretch MIDI")); + + /* Grid - these tools are only visible when in Grid mode */ + grid_box.set_spacing (2); + grid_box.set_border_width (2); + grid_box.pack_start (stretch_midi_cb, false, false, 4); + /* Draw - these MIDI tools are only visible when in Draw mode */ draw_box.set_spacing (2); draw_box.set_border_width (2); @@ -3462,6 +3476,8 @@ Editor::setup_toolbar () toolbar_hbox.pack_start (snap_box, false, false); toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3); toolbar_hbox.pack_start (*nudge_box, false, false); + toolbar_hbox.pack_start (_grid_box_spacer, false, false, 3); + toolbar_hbox.pack_start (grid_box, false, false); toolbar_hbox.pack_start (_draw_box_spacer, false, false, 3); toolbar_hbox.pack_start (draw_box, false, false); toolbar_hbox.pack_end (_zoom_box, false, false, 2); @@ -3621,6 +3637,7 @@ Editor::setup_tooltips () set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)")); set_tooltip (mouse_cut_button, _("Cut Mode (split regions)")); set_tooltip (mouse_select_button, _("Range Mode (select time ranges)")); + set_tooltip (mouse_grid_button, _("Grid Mode (edit tempo-map, drag/drop music-time grid)")); set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)")); set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)")); set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)")); @@ -3636,6 +3653,7 @@ Editor::setup_tooltips () set_tooltip (tav_expand_button, _("Expand Tracks")); set_tooltip (tav_shrink_button, _("Shrink Tracks")); set_tooltip (visible_tracks_selector, _("Number of visible tracks")); + set_tooltip (stretch_midi_cb, _("Enable to move MIDI events when stretching the Grid")); set_tooltip (draw_length_selector, _("Note Length to Draw (AUTO uses the current Grid setting)")); set_tooltip (draw_velocity_selector, _("Note Velocity to Draw (AUTO uses the nearest note's velocity)")); set_tooltip (draw_channel_selector, _("Note Channel to Draw (AUTO uses the nearest note's channel)")); diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 5185687c48..682a0cb179 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -1966,6 +1966,7 @@ private: ArdourWidgets::ArdourButton mouse_draw_button; ArdourWidgets::ArdourButton mouse_move_button; ArdourWidgets::ArdourButton mouse_timefx_button; + ArdourWidgets::ArdourButton mouse_grid_button; ArdourWidgets::ArdourButton mouse_content_button; ArdourWidgets::ArdourButton mouse_audition_button; ArdourWidgets::ArdourButton mouse_cut_button; @@ -2005,12 +2006,16 @@ private: ArdourWidgets::ArdourDropdown draw_channel_selector; void build_draw_midi_menus (); + Gtk::CheckButton stretch_midi_cb; + ArdourWidgets::ArdourButton snap_mode_button; bool snap_mode_button_clicked (GdkEventButton*); Gtk::HBox snap_box; + Gtk::HBox grid_box; Gtk::HBox draw_box; + ArdourWidgets::ArdourVSpacer _grid_box_spacer; ArdourWidgets::ArdourVSpacer _draw_box_spacer; Gtk::HBox ebox_hpacker; @@ -2550,6 +2555,7 @@ private: void remove_gap_marker_callback (Temporal::timepos_t at, Temporal::timecnt_t distance); + Editing::GridType determine_mapping_grid_snap (Temporal::timepos_t t); void choose_mapping_drag (ArdourCanvas::Item*, GdkEvent*); Editing::TempoEditBehavior _tempo_edit_behavior; diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc index b0ed1fb352..764dea0053 100644 --- a/gtk2_ardour/editor_actions.cc +++ b/gtk2_ardour/editor_actions.cc @@ -597,6 +597,11 @@ Editor::register_actions () mouse_timefx_button.set_icon (ArdourWidgets::ArdourIcon::ToolStretch); mouse_timefx_button.set_name ("mouse mode button"); + act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-grid", _("Grid Tool"), sigc::bind (sigc::mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGrid)); + mouse_grid_button.set_related_action (act); + mouse_grid_button.set_icon (ArdourWidgets::ArdourIcon::ToolGrid); + mouse_grid_button.set_name ("mouse mode button"); + act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-content", _("Internal Edit (Content Tool)"), sigc::bind (sigc::mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseContent)); mouse_content_button.set_related_action (act); mouse_content_button.set_icon (ArdourWidgets::ArdourIcon::ToolContent); diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index 4e157e2e45..1f2fcf6a2e 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -270,6 +270,8 @@ Editor::get_mouse_mode_action(MouseMode m) const return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-draw")); case MouseTimeFX: return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-timefx")); + case MouseGrid: + return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-grid")); case MouseContent: return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-content")); case MouseAudition: @@ -376,6 +378,15 @@ Editor::mouse_mode_toggled (MouseMode m) _draw_box_spacer.hide(); } + if (mouse_mode == MouseGrid) { + grid_box.show(); + _grid_box_spacer.show(); + _canvas_grid_zone->set_ignore_events (false); // woohoo + } else { + grid_box.hide(); + _grid_box_spacer.hide(); + _canvas_grid_zone->set_ignore_events (true); // important !!! + } if (internal_editing()) { @@ -478,6 +489,7 @@ Editor::update_time_selection_display () selection->clear_tracks (); break; + case MouseGrid: default: /*Clear everything */ selection->clear_objects(); @@ -1237,6 +1249,12 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT return true; break; + case MouseGrid: + /* MouseGrid clicks are handled by _canvas_grid_zone */ + assert (0); + abort(); /*NOTREACHED*/ + break; + case MouseDraw: switch (item_type) { case GainLineItem: @@ -1917,6 +1935,12 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT } break; + case MouseGrid: + /* MouseGrid clicks are handled by _canvas_grid_zone */ + assert (0); + abort(); /*NOTREACHED*/ + break; + case MouseAudition: if (scrubbing_direction == 0) { /* no drag, just a click */ @@ -2321,6 +2345,27 @@ Editor::scrub (samplepos_t sample, double current_x) last_scrub_x = current_x; } +GridType +Editor::determine_mapping_grid_snap(timepos_t t) +{ + timepos_t snapped = _snap_to_bbt (t, RoundNearest, SnapToGrid_Unscaled, GridTypeBeat); + timepos_t snapped_to_bar = _snap_to_bbt (t, RoundNearest, SnapToGrid_Unscaled, GridTypeBar); + const double unsnapped_pos = time_to_pixel_unrounded (t); + const double snapped_pos = time_to_pixel_unrounded (snapped); + + double ruler_line_granularity = UIConfiguration::instance().get_ruler_granularity () * UIConfiguration::instance().get_ui_scale(); // in pixels + + if (std::abs (snapped_pos - unsnapped_pos) < ruler_line_granularity) { + if (snapped == snapped_to_bar) { + return GridTypeBar; + } else { + return GridTypeBeat; + } + } else { + return GridTypeNone; + } +} + bool Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, bool from_autoscroll) { @@ -2377,44 +2422,22 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, bool from_aut timepos_t t (where); bool move_snapped_cursor = true; - - if (item == mapping_bar) { - - /* Snap to the nearest beat, and figure out how - * many pixels from the pointer cursor that is. - */ - - Editor::EnterContext* ctx = get_enter_context (MappingBarItem); - - if (ctx) { - timepos_t snapped = _snap_to_bbt (t, RoundNearest, SnapToGrid_Unscaled, GridTypeBeat); - timepos_t snapped_to_bar = _snap_to_bbt (t, RoundNearest, SnapToGrid_Unscaled, GridTypeBar); - const double unsnapped_pos = time_to_pixel_unrounded (t); - const double snapped_pos = time_to_pixel_unrounded (snapped); - - if (std::abs (snapped_pos - unsnapped_pos) < 10 * UIConfiguration::instance().get_ui_scale()) { - - /* Close to a beat, so snap the mapping - * cursor *and* the snapped cursor to - * the beat. - */ - - if (snapped == snapped_to_bar) { - ctx->cursor_ctx->change (cursors()->time_fx); - } else { - /* snapped to a beat, not a bar .... we'll implement a TWIST here */ - ctx->cursor_ctx->change (cursors()->expand_left_right); - } - } else { - ctx->cursor_ctx->change (cursors()->grabber); - } - } - } - if (move_snapped_cursor) { snap_to_with_modifier (t, event); set_snapped_cursor_position (t); } + + /* if tempo-mapping, set a cursor to indicate whether we are close to a bar line, beat line, or neither */ + if (mouse_mode == MouseGrid && item == _canvas_grid_zone) { + GridType gt = determine_mapping_grid_snap (t); + if (gt == GridTypeBar) { + set_canvas_cursor (cursors()->time_fx); + } else if (gt == GridTypeBeat) { + set_canvas_cursor (cursors()->expand_left_right); + } else { + set_canvas_cursor (cursors()->grabber); + } + } } if (!peaks_visible) { @@ -2996,29 +3019,29 @@ Editor::choose_mapping_drag (ArdourCanvas::Item* item, GdkEvent* event) { /* In a departure from convention, this event is not handled by a widget * 'on' the ruler-bar, like a tempo marker, but is instead handled by the - * mapping-bar widget itself. The intent is for the user to feel that they + * whole canvas. The intent is for the user to feel that they * are manipulating the 'beat and bar grid' which may or may not have tempo * markers already assigned at the point under the mouse. */ - if (item != mapping_bar) { - return; - } - - if (_cursor_stack.empty()) { + bool ignored; + samplepos_t where; + + if (!mouse_sample (where, ignored)) { return; } + /* if tempo-mapping, set a cursor to indicate whether we are close to a bar line, beat line, or neither */ bool ramped = false; - if (_cursor_stack.back() == cursors()->time_fx) { - /* We are on a BAR line ... the user can drag the line exactly where it's needed */ - ramped = false; - } else if (_cursor_stack.back() == cursors()->expand_left_right) { - /* We are on a BEAT line ... we will nudge the beat line via ramping, without moving any tempo markers */ - ramped = true; - } else { - /* Not close enough to a beat line to start any mapping drag */ - return; + if (mouse_mode == MouseGrid && item ==_canvas_grid_zone) { + GridType gt = determine_mapping_grid_snap (timepos_t (where)); + if (gt == GridTypeBar) { + ramped = false; + } else if (gt == GridTypeBeat) { + ramped = true; + } else { + return; // neither a bar nor a beat; don't start a drag + } } /* The reversible command starts here, must be ended/aborted in drag */ diff --git a/gtk2_ardour/enums.cc b/gtk2_ardour/enums.cc index 1149bade3e..644d17d765 100644 --- a/gtk2_ardour/enums.cc +++ b/gtk2_ardour/enums.cc @@ -192,6 +192,7 @@ setup_gtk_ardour_enums () REGISTER_ENUM(MouseRange); REGISTER_ENUM(MouseDraw); REGISTER_ENUM(MouseTimeFX); + REGISTER_ENUM(MouseGrid); REGISTER_ENUM(MouseAudition); REGISTER_ENUM(MouseCut); REGISTER_ENUM(MouseContent);