| @@ -62,10 +62,10 @@ inline float eucmodf(float a, float base) { | |||
| } | |||
| /** Limits a value between a minimum and maximum | |||
| If min < max, returns max | |||
| If min > max, the limits are switched | |||
| */ | |||
| inline float clampf(float x, float min, float max) { | |||
| return fmaxf(fminf(x, max), min); | |||
| return fmaxf(fminf(x, fmaxf(min, max)), fminf(min, max)); | |||
| } | |||
| /** If the magnitude of x if less than eps, return 0 */ | |||
| @@ -199,11 +199,16 @@ struct Rect { | |||
| return Rect(min, max.minus(min)); | |||
| } | |||
| /** Returns whether this Rect contains another Rect, inclusive on the top/left, non-inclusive on the bottom/right */ | |||
| /** Returns whether this Rect contains an entire point, inclusive on the top/left, non-inclusive on the bottom/right */ | |||
| bool contains(Vec v) { | |||
| return pos.x <= v.x && v.x < pos.x + size.x | |||
| && pos.y <= v.y && v.y < pos.y + size.y; | |||
| } | |||
| /** Returns whether this Rect contains an entire Rect */ | |||
| bool contains(Rect r) { | |||
| return pos.x <= r.pos.x && r.pos.x + r.size.x <= pos.x + size.x | |||
| && pos.y <= r.pos.y && r.pos.y + r.size.y <= pos.y + size.y; | |||
| } | |||
| /** Returns whether this Rect overlaps with another Rect */ | |||
| bool intersects(Rect r) { | |||
| return (pos.x + size.x > r.pos.x && r.pos.x + r.size.x > pos.x) | |||
| @@ -145,7 +145,7 @@ struct TransparentWidget : virtual Widget { | |||
| Widget *onScroll(Vec pos, Vec scrollRel) {return NULL;} | |||
| }; | |||
| /** Widget that itself responds to mouse events */ | |||
| /** Widget that automatically responds to all mouse events but gives a chance for children to respond instead */ | |||
| struct OpaqueWidget : virtual Widget { | |||
| Widget *onMouseDown(Vec pos, int button) { | |||
| Widget *w = Widget::onMouseDown(pos, button); | |||
| @@ -165,6 +165,13 @@ struct OpaqueWidget : virtual Widget { | |||
| onMouseMoveOpaque(mouseRel); | |||
| return this; | |||
| } | |||
| Widget *onScroll(Vec pos, Vec scrollRel) { | |||
| Widget *w = Widget::onScroll(pos, scrollRel); | |||
| if (w) return w; | |||
| if (onScrollOpaque(scrollRel)) | |||
| return this; | |||
| return NULL; | |||
| } | |||
| /** "High level" events called by the above lower level events. | |||
| Use these if you don't care about the clicked position. | |||
| @@ -172,6 +179,7 @@ struct OpaqueWidget : virtual Widget { | |||
| virtual void onMouseDownOpaque(int button) {} | |||
| virtual void onMouseUpOpaque(int button) {} | |||
| virtual void onMouseMoveOpaque(Vec mouseRel) {} | |||
| virtual bool onScrollOpaque(Vec scrollRel) {return false;} | |||
| }; | |||
| struct SpriteWidget : virtual Widget { | |||
| @@ -249,9 +257,6 @@ struct Label : Widget { | |||
| // Deletes itself from parent when clicked | |||
| struct MenuOverlay : OpaqueWidget { | |||
| void step(); | |||
| Widget *onScroll(Vec pos, Vec scrollRel) { | |||
| return this; | |||
| } | |||
| void onDragDrop(Widget *origin); | |||
| }; | |||
| @@ -262,6 +267,7 @@ struct Menu : OpaqueWidget { | |||
| // Resizes menu and calls addChild() | |||
| void pushChild(Widget *child); | |||
| void draw(NVGcontext *vg); | |||
| bool onScrollOpaque(Vec scrollRel); | |||
| }; | |||
| struct MenuEntry : OpaqueWidget { | |||
| @@ -340,8 +346,8 @@ struct ScrollBar : OpaqueWidget { | |||
| ScrollBar() { | |||
| box.size = Vec(BND_SCROLLBAR_WIDTH, BND_SCROLLBAR_HEIGHT); | |||
| } | |||
| void step(); | |||
| void draw(NVGcontext *vg); | |||
| void move(float delta); | |||
| void onDragStart(); | |||
| void onDragMove(Vec mouseRel); | |||
| void onDragEnd(); | |||
| @@ -356,7 +362,7 @@ struct ScrollWidget : OpaqueWidget { | |||
| ScrollWidget(); | |||
| void step(); | |||
| void draw(NVGcontext *vg); | |||
| Widget *onScroll(Vec pos, Vec scrollRel); | |||
| bool onScrollOpaque(Vec scrollRel); | |||
| }; | |||
| struct TextField : OpaqueWidget { | |||
| @@ -151,7 +151,7 @@ void cursorEnterCallback(GLFWwindow* window, int entered) { | |||
| void scrollCallback(GLFWwindow *window, double x, double y) { | |||
| Vec scrollRel = Vec(x, y); | |||
| // onScroll | |||
| gScene->onScroll(gMousePos, scrollRel.mult(-95)); | |||
| gScene->onScroll(gMousePos, scrollRel.mult(-38.0)); | |||
| } | |||
| void charCallback(GLFWwindow *window, unsigned int codepoint) { | |||
| @@ -29,4 +29,13 @@ void Menu::draw(NVGcontext *vg) { | |||
| } | |||
| bool Menu::onScrollOpaque(Vec scrollRel) { | |||
| if (!parent) | |||
| return true; | |||
| if (!parent->box.contains(box)) | |||
| box.pos = box.pos.plus(scrollRel.neg()); | |||
| return true; | |||
| } | |||
| } // namespace rack | |||
| @@ -8,6 +8,7 @@ void MenuOverlay::step() { | |||
| for (Widget *child : children) { | |||
| child->box = child->box.clamp(Rect(Vec(0, 0), box.size)); | |||
| } | |||
| Widget::step(); | |||
| } | |||
| @@ -4,6 +4,13 @@ | |||
| namespace rack { | |||
| void ScrollBar::step() { | |||
| float boxSize = (orientation == VERTICAL ? box.size.y : box.size.x); | |||
| float maxOffset = containerSize - boxSize; | |||
| containerOffset = clampf(containerOffset, 0.0, maxOffset); | |||
| Widget::step(); | |||
| } | |||
| void ScrollBar::draw(NVGcontext *vg) { | |||
| float boxSize = (orientation == VERTICAL ? box.size.y : box.size.x); | |||
| float maxOffset = containerSize - boxSize; | |||
| @@ -13,21 +20,13 @@ void ScrollBar::draw(NVGcontext *vg) { | |||
| bndScrollBar(vg, 0.0, 0.0, box.size.x, box.size.y, state, offset, size); | |||
| } | |||
| void ScrollBar::move(float delta) { | |||
| float boxSize = (orientation == VERTICAL ? box.size.y : box.size.x); | |||
| float maxOffset = containerSize - boxSize; | |||
| containerOffset += delta; | |||
| containerOffset = clampf(containerOffset, 0.0, maxOffset); | |||
| } | |||
| void ScrollBar::onDragStart() { | |||
| state = BND_ACTIVE; | |||
| guiCursorLock(); | |||
| } | |||
| void ScrollBar::onDragMove(Vec mouseRel) { | |||
| float delta = (orientation == VERTICAL ? mouseRel.y : mouseRel.x); | |||
| move(delta); | |||
| containerOffset += (orientation == VERTICAL ? mouseRel.y : mouseRel.x); | |||
| } | |||
| void ScrollBar::onDragEnd() { | |||
| @@ -40,13 +40,10 @@ void ScrollWidget::draw(NVGcontext *vg) { | |||
| Widget::draw(vg); | |||
| } | |||
| Widget *ScrollWidget::onScroll(Vec pos, Vec scrollRel) { | |||
| Widget *w = Widget::onScroll(pos, scrollRel); | |||
| if (w) return w; | |||
| hScrollBar->move(scrollRel.x); | |||
| vScrollBar->move(scrollRel.y); | |||
| return this; | |||
| bool ScrollWidget::onScrollOpaque(Vec scrollRel) { | |||
| hScrollBar->containerOffset += scrollRel.x; | |||
| vScrollBar->containerOffset += scrollRel.y; | |||
| return true; | |||
| } | |||