| @@ -22,6 +22,7 @@ struct ScrollWidget : widget::OpaqueWidget { | |||||
| bool hideScrollbars = false; | bool hideScrollbars = false; | ||||
| ScrollWidget(); | ScrollWidget(); | ||||
| ~ScrollWidget(); | |||||
| void scrollTo(math::Rect r); | void scrollTo(math::Rect r); | ||||
| /** Returns the bound of allowed `offset` values in pixels. */ | /** Returns the bound of allowed `offset` values in pixels. */ | ||||
| math::Rect getContainerOffsetBound(); | math::Rect getContainerOffsetBound(); | ||||
| @@ -29,8 +30,11 @@ struct ScrollWidget : widget::OpaqueWidget { | |||||
| math::Vec getHandleOffset(); | math::Vec getHandleOffset(); | ||||
| /** Returns the handle size relative to the scrollbar. [0, 1]. */ | /** Returns the handle size relative to the scrollbar. [0, 1]. */ | ||||
| math::Vec getHandleSize(); | math::Vec getHandleSize(); | ||||
| /** The user is considered scrolling with the wheel until the mouse is moved. */ | |||||
| bool isScrolling(); | |||||
| void draw(const DrawArgs& args) override; | void draw(const DrawArgs& args) override; | ||||
| void step() override; | void step() override; | ||||
| void onHover(const HoverEvent& e) override; | |||||
| void onButton(const ButtonEvent& e) override; | void onButton(const ButtonEvent& e) override; | ||||
| void onDragStart(const DragStartEvent& e) override; | void onDragStart(const DragStartEvent& e) override; | ||||
| void onDragMove(const DragMoveEvent& e) override; | void onDragMove(const DragMoveEvent& e) override; | ||||
| @@ -1,6 +1,7 @@ | |||||
| #include <app/Knob.hpp> | #include <app/Knob.hpp> | ||||
| #include <context.hpp> | #include <context.hpp> | ||||
| #include <app/Scene.hpp> | #include <app/Scene.hpp> | ||||
| #include <app/RackScrollWidget.hpp> | |||||
| #include <random.hpp> | #include <random.hpp> | ||||
| #include <history.hpp> | #include <history.hpp> | ||||
| #include <settings.hpp> | #include <settings.hpp> | ||||
| @@ -226,38 +227,43 @@ void Knob::onDragLeave(const DragLeaveEvent& e) { | |||||
| void Knob::onHoverScroll(const HoverScrollEvent& e) { | void Knob::onHoverScroll(const HoverScrollEvent& e) { | ||||
| ParamWidget::onHoverScroll(e); | ParamWidget::onHoverScroll(e); | ||||
| if (settings::knobScroll) { | |||||
| engine::ParamQuantity* pq = getParamQuantity(); | |||||
| if (pq) { | |||||
| float value = pq->getSmoothValue(); | |||||
| if (!settings::knobScroll) | |||||
| return; | |||||
| float rangeRatio; | |||||
| if (pq->isBounded()) { | |||||
| rangeRatio = pq->getRange(); | |||||
| } | |||||
| else { | |||||
| rangeRatio = 1.f; | |||||
| } | |||||
| if (APP->scene->rackScroll->isScrolling()) | |||||
| return; | |||||
| float delta = e.scrollDelta.y; | |||||
| delta *= settings::knobScrollSensitivity; | |||||
| delta *= getModSpeed(); | |||||
| delta *= rangeRatio; | |||||
| engine::ParamQuantity* pq = getParamQuantity(); | |||||
| if (!pq) | |||||
| return; | |||||
| // Handle value snapping | |||||
| if (pq->snapEnabled) { | |||||
| // Replace delta with an accumulated delta since the last integer knob. | |||||
| internal->snapDelta += delta; | |||||
| delta = std::trunc(internal->snapDelta); | |||||
| internal->snapDelta -= delta; | |||||
| } | |||||
| float value = pq->getSmoothValue(); | |||||
| value += delta; | |||||
| pq->setSmoothValue(value); | |||||
| float rangeRatio; | |||||
| if (pq->isBounded()) { | |||||
| rangeRatio = pq->getRange(); | |||||
| } | |||||
| else { | |||||
| rangeRatio = 1.f; | |||||
| } | |||||
| e.consume(this); | |||||
| } | |||||
| float delta = e.scrollDelta.y; | |||||
| delta *= settings::knobScrollSensitivity; | |||||
| delta *= getModSpeed(); | |||||
| delta *= rangeRatio; | |||||
| // Handle value snapping | |||||
| if (pq->snapEnabled) { | |||||
| // Replace delta with an accumulated delta since the last integer knob. | |||||
| internal->snapDelta += delta; | |||||
| delta = std::trunc(internal->snapDelta); | |||||
| internal->snapDelta -= delta; | |||||
| } | } | ||||
| value += delta; | |||||
| pq->setSmoothValue(value); | |||||
| e.consume(this); | |||||
| } | } | ||||
| @@ -114,10 +114,6 @@ void RackScrollWidget::onHoverKey(const HoverKeyEvent& e) { | |||||
| void RackScrollWidget::onHoverScroll(const HoverScrollEvent& e) { | void RackScrollWidget::onHoverScroll(const HoverScrollEvent& e) { | ||||
| ScrollWidget::onHoverScroll(e); | |||||
| if (e.isConsumed()) | |||||
| return; | |||||
| if ((APP->window->getMods() & RACK_MOD_MASK) == RACK_MOD_CTRL) { | if ((APP->window->getMods() & RACK_MOD_MASK) == RACK_MOD_CTRL) { | ||||
| // Increase zoom | // Increase zoom | ||||
| float zoomDelta = e.scrollDelta.y / 50 / 4; | float zoomDelta = e.scrollDelta.y / 50 / 4; | ||||
| @@ -132,6 +128,10 @@ void RackScrollWidget::onHoverScroll(const HoverScrollEvent& e) { | |||||
| internal->zoomPos = e.pos; | internal->zoomPos = e.pos; | ||||
| e.consume(this); | e.consume(this); | ||||
| } | } | ||||
| if (e.isConsumed()) | |||||
| return; | |||||
| ScrollWidget::onHoverScroll(e); | |||||
| } | } | ||||
| @@ -6,10 +6,14 @@ namespace rack { | |||||
| namespace ui { | namespace ui { | ||||
| // Internal not currently used | |||||
| struct ScrollWidget::Internal { | |||||
| bool scrolling = false; | |||||
| }; | |||||
| ScrollWidget::ScrollWidget() { | ScrollWidget::ScrollWidget() { | ||||
| internal = new Internal; | |||||
| container = new widget::Widget; | container = new widget::Widget; | ||||
| addChild(container); | addChild(container); | ||||
| @@ -25,6 +29,11 @@ ScrollWidget::ScrollWidget() { | |||||
| } | } | ||||
| ScrollWidget::~ScrollWidget() { | |||||
| delete internal; | |||||
| } | |||||
| void ScrollWidget::scrollTo(math::Rect r) { | void ScrollWidget::scrollTo(math::Rect r) { | ||||
| math::Rect bound = math::Rect::fromMinMax(r.getBottomRight().minus(box.size), r.pos); | math::Rect bound = math::Rect::fromMinMax(r.getBottomRight().minus(box.size), r.pos); | ||||
| offset = offset.clampSafe(bound); | offset = offset.clampSafe(bound); | ||||
| @@ -49,6 +58,11 @@ math::Vec ScrollWidget::getHandleSize() { | |||||
| } | } | ||||
| bool ScrollWidget::isScrolling() { | |||||
| return internal->scrolling; | |||||
| } | |||||
| void ScrollWidget::draw(const DrawArgs& args) { | void ScrollWidget::draw(const DrawArgs& args) { | ||||
| nvgScissor(args.vg, RECT_ARGS(args.clipBox)); | nvgScissor(args.vg, RECT_ARGS(args.clipBox)); | ||||
| Widget::draw(args); | Widget::draw(args); | ||||
| @@ -88,6 +102,15 @@ void ScrollWidget::step() { | |||||
| } | } | ||||
| void ScrollWidget::onHover(const HoverEvent& e) { | |||||
| OpaqueWidget::onHover(e); | |||||
| if (!e.mouseDelta.isZero()) { | |||||
| internal->scrolling = false; | |||||
| } | |||||
| } | |||||
| void ScrollWidget::onButton(const ButtonEvent& e) { | void ScrollWidget::onButton(const ButtonEvent& e) { | ||||
| math::Rect offsetBound = getContainerOffsetBound(); | math::Rect offsetBound = getContainerOffsetBound(); | ||||
| // Check if scrollable | // Check if scrollable | ||||
| @@ -144,6 +167,7 @@ void ScrollWidget::onHoverScroll(const HoverScrollEvent& e) { | |||||
| offset = offset.minus(scrollDelta); | offset = offset.minus(scrollDelta); | ||||
| e.consume(this); | e.consume(this); | ||||
| internal->scrolling = true; | |||||
| } | } | ||||