@@ -22,6 +22,7 @@ struct ScrollWidget : widget::OpaqueWidget { | |||
bool hideScrollbars = false; | |||
ScrollWidget(); | |||
~ScrollWidget(); | |||
void scrollTo(math::Rect r); | |||
/** Returns the bound of allowed `offset` values in pixels. */ | |||
math::Rect getContainerOffsetBound(); | |||
@@ -29,8 +30,11 @@ struct ScrollWidget : widget::OpaqueWidget { | |||
math::Vec getHandleOffset(); | |||
/** Returns the handle size relative to the scrollbar. [0, 1]. */ | |||
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 step() override; | |||
void onHover(const HoverEvent& e) override; | |||
void onButton(const ButtonEvent& e) override; | |||
void onDragStart(const DragStartEvent& e) override; | |||
void onDragMove(const DragMoveEvent& e) override; | |||
@@ -1,6 +1,7 @@ | |||
#include <app/Knob.hpp> | |||
#include <context.hpp> | |||
#include <app/Scene.hpp> | |||
#include <app/RackScrollWidget.hpp> | |||
#include <random.hpp> | |||
#include <history.hpp> | |||
#include <settings.hpp> | |||
@@ -226,38 +227,43 @@ void Knob::onDragLeave(const DragLeaveEvent& e) { | |||
void Knob::onHoverScroll(const HoverScrollEvent& 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) { | |||
ScrollWidget::onHoverScroll(e); | |||
if (e.isConsumed()) | |||
return; | |||
if ((APP->window->getMods() & RACK_MOD_MASK) == RACK_MOD_CTRL) { | |||
// Increase zoom | |||
float zoomDelta = e.scrollDelta.y / 50 / 4; | |||
@@ -132,6 +128,10 @@ void RackScrollWidget::onHoverScroll(const HoverScrollEvent& e) { | |||
internal->zoomPos = e.pos; | |||
e.consume(this); | |||
} | |||
if (e.isConsumed()) | |||
return; | |||
ScrollWidget::onHoverScroll(e); | |||
} | |||
@@ -6,10 +6,14 @@ namespace rack { | |||
namespace ui { | |||
// Internal not currently used | |||
struct ScrollWidget::Internal { | |||
bool scrolling = false; | |||
}; | |||
ScrollWidget::ScrollWidget() { | |||
internal = new Internal; | |||
container = new widget::Widget; | |||
addChild(container); | |||
@@ -25,6 +29,11 @@ ScrollWidget::ScrollWidget() { | |||
} | |||
ScrollWidget::~ScrollWidget() { | |||
delete internal; | |||
} | |||
void ScrollWidget::scrollTo(math::Rect r) { | |||
math::Rect bound = math::Rect::fromMinMax(r.getBottomRight().minus(box.size), r.pos); | |||
offset = offset.clampSafe(bound); | |||
@@ -49,6 +58,11 @@ math::Vec ScrollWidget::getHandleSize() { | |||
} | |||
bool ScrollWidget::isScrolling() { | |||
return internal->scrolling; | |||
} | |||
void ScrollWidget::draw(const DrawArgs& args) { | |||
nvgScissor(args.vg, RECT_ARGS(args.clipBox)); | |||
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) { | |||
math::Rect offsetBound = getContainerOffsetBound(); | |||
// Check if scrollable | |||
@@ -144,6 +167,7 @@ void ScrollWidget::onHoverScroll(const HoverScrollEvent& e) { | |||
offset = offset.minus(scrollDelta); | |||
e.consume(this); | |||
internal->scrolling = true; | |||
} | |||