Browse Source

Add get and set methods to Vec1. Add helper methods to Widget. Refactor ScrollWidget and ScrollBar.

tags/v2.0.0
Andrew Belt 4 years ago
parent
commit
7908dd8b9f
7 changed files with 138 additions and 66 deletions
  1. +12
    -0
      include/math.hpp
  2. +6
    -8
      include/ui/ScrollBar.hpp
  3. +5
    -0
      include/ui/ScrollWidget.hpp
  4. +10
    -12
      include/widget/Widget.hpp
  5. +39
    -16
      src/ui/ScrollBar.cpp
  6. +21
    -17
      src/ui/ScrollWidget.cpp
  7. +45
    -13
      src/widget/Widget.cpp

+ 12
- 0
include/math.hpp View File

@@ -184,6 +184,18 @@ struct Vec {
Vec() {}
Vec(float x, float y) : x(x), y(y) {}

float get(int index) const {
return (index == 0) ? x : y;
}
float& get(int index) {
return (index == 0) ? x : y;
}
void set(int index, float value) {
if (index == 0)
x = value;
else
y = value;
}
/** Negates the vector.
Equivalent to a reflection across the `y = -x` line.
*/


+ 6
- 8
include/ui/ScrollBar.hpp View File

@@ -9,19 +9,17 @@ namespace ui {

/** Parent must be a ScrollWidget */
struct ScrollBar : widget::OpaqueWidget {
enum Orientation {
VERTICAL,
HORIZONTAL
};
Orientation orientation;
float offset = 0.0;
float size = 0.0;
struct Internal;
Internal* internal;

bool vertical = false;

ScrollBar();
~ScrollBar();
void draw(const DrawArgs& args) override;
void onDragStart(const event::DragStart& e) override;
void onDragMove(const event::DragMove& e) override;
void onDragEnd(const event::DragEnd& e) override;
void onDragMove(const event::DragMove& e) override;
};




+ 5
- 0
include/ui/ScrollWidget.hpp View File

@@ -10,10 +10,15 @@ namespace ui {

/** Handles a container with ScrollBar */
struct ScrollWidget : widget::OpaqueWidget {
struct Internal;
Internal* internal;

widget::Widget* container;
ScrollBar* horizontalScrollBar;
ScrollBar* verticalScrollBar;

math::Vec offset;
math::Rect containerBox;

ScrollWidget();
void scrollTo(math::Rect r);


+ 10
- 12
include/widget/Widget.hpp View File

@@ -33,23 +33,21 @@ struct Widget {

virtual ~Widget();

math::Rect getBox();
void setBox(math::Rect box);
math::Rect getBox() {
return box;
}
math::Vec getPosition();
void setPosition(math::Vec pos);
math::Vec getPosition() {
return box.pos;
}
math::Vec getSize();
void setSize(math::Vec size);
math::Vec getSize() {
return box.size;
bool isVisible();
void setVisible(bool visible);
void show() {
setVisible(true);
}
void show();
void hide();
bool isVisible() {
return visible;
void hide() {
setVisible(false);
}

void requestDelete();

virtual math::Rect getChildrenBoundingBox();


+ 39
- 16
src/ui/ScrollBar.cpp View File

@@ -8,40 +8,63 @@ namespace rack {
namespace ui {


// Internal not currently used


ScrollBar::ScrollBar() {
box.size = math::Vec(BND_SCROLLBAR_WIDTH, BND_SCROLLBAR_HEIGHT);
}


ScrollBar::~ScrollBar() {
}


void ScrollBar::draw(const DrawArgs& args) {
ScrollWidget* sw = dynamic_cast<ScrollWidget*>(parent);
assert(sw);

BNDwidgetState state = BND_DEFAULT;
if (APP->event->hoveredWidget == this)
if (APP->event->getHoveredWidget() == this)
state = BND_HOVER;
if (APP->event->draggedWidget == this)
if (APP->event->getDraggedWidget() == this)
state = BND_ACTIVE;

bndScrollBar(args.vg, 0.0, 0.0, box.size.x, box.size.y, state, offset, size);
float offsetBound = sw->containerBox.size.get(vertical) - sw->box.size.get(vertical);
// The handle position relative to the scrollbar. [0, 1]
float scrollBarOffset = (sw->offset.get(vertical) - sw->containerBox.pos.get(vertical)) / offsetBound;
// The handle size relative to the scrollbar. [0, 1]
float scrollBarSize = sw->box.size.get(vertical) / sw->containerBox.size.get(vertical);
bndScrollBar(args.vg, 0.0, 0.0, box.size.x, box.size.y, state, scrollBarOffset, scrollBarSize);
}


void ScrollBar::onDragStart(const event::DragStart& e) {
if (e.button != GLFW_MOUSE_BUTTON_LEFT)
return;
if (e.button == GLFW_MOUSE_BUTTON_LEFT) {
APP->window->cursorLock();
}
}


APP->window->cursorLock();
void ScrollBar::onDragEnd(const event::DragEnd& e) {
if (e.button == GLFW_MOUSE_BUTTON_LEFT) {
APP->window->cursorUnlock();
}
}


void ScrollBar::onDragMove(const event::DragMove& e) {
const float sensitivity = 1.f;
ScrollWidget* sw = dynamic_cast<ScrollWidget*>(parent);
assert(sw);

ScrollWidget* scrollWidget = dynamic_cast<ScrollWidget*>(parent);
assert(scrollWidget);
if (orientation == HORIZONTAL)
scrollWidget->offset.x += sensitivity * e.mouseDelta.x;
else
scrollWidget->offset.y += sensitivity * e.mouseDelta.y;
}
// TODO
// float offsetBound = sw->containerBox.size.get(vertical) - sw->box.size.get(vertical);
// float scrollBarSize = sw->box.size.get(vertical) / sw->containerBox.size.get(vertical);

void ScrollBar::onDragEnd(const event::DragEnd& e) {
APP->window->cursorUnlock();
const float sensitivity = 1.f;
float offsetDelta = e.mouseDelta.get(vertical);
offsetDelta *= sensitivity;
sw->offset.get(vertical) += offsetDelta;
}




+ 21
- 17
src/ui/ScrollWidget.cpp View File

@@ -6,37 +6,43 @@ namespace rack {
namespace ui {


// Internal not currently used


ScrollWidget::ScrollWidget() {
container = new widget::Widget;
addChild(container);

horizontalScrollBar = new ScrollBar;
horizontalScrollBar->orientation = ScrollBar::HORIZONTAL;
horizontalScrollBar->visible = false;
horizontalScrollBar->vertical = false;
horizontalScrollBar->hide();
addChild(horizontalScrollBar);

verticalScrollBar = new ScrollBar;
verticalScrollBar->orientation = ScrollBar::VERTICAL;
verticalScrollBar->visible = false;
verticalScrollBar->vertical = true;
verticalScrollBar->hide();
addChild(verticalScrollBar);
}


void ScrollWidget::scrollTo(math::Rect r) {
math::Rect bound = math::Rect::fromMinMax(r.getBottomRight().minus(box.size), r.pos);
offset = offset.clampSafe(bound);
}


void ScrollWidget::draw(const DrawArgs& args) {
nvgScissor(args.vg, RECT_ARGS(args.clipBox));
Widget::draw(args);
nvgResetScissor(args.vg);
}


void ScrollWidget::step() {
Widget::step();

// Clamp scroll offset
math::Rect containerBox = container->getChildrenBoundingBox();
containerBox = container->getChildrenBoundingBox();
math::Rect offsetBounds = containerBox;
offsetBounds.size = offsetBounds.size.minus(box.size);
offset = offset.clamp(offsetBounds);
@@ -44,25 +50,19 @@ void ScrollWidget::step() {
// Update the container's position from the offset
container->box.pos = offset.neg().round();

// Update scrollbar offsets and sizes
math::Vec scrollbarOffset = offset.minus(containerBox.pos).div(offsetBounds.size);
math::Vec scrollbarSize = box.size.div(containerBox.size);

horizontalScrollBar->visible = (0.0 < scrollbarSize.x && scrollbarSize.x < 1.0);
verticalScrollBar->visible = (0.0 < scrollbarSize.y && scrollbarSize.y < 1.0);
horizontalScrollBar->offset = scrollbarOffset.x;
verticalScrollBar->offset = scrollbarOffset.y;
horizontalScrollBar->size = scrollbarSize.x;
verticalScrollBar->size = scrollbarSize.y;
// Make scrollbars visible only if there is a positive range to scroll.
horizontalScrollBar->setVisible(offsetBounds.size.x > 0.f);
verticalScrollBar->setVisible(offsetBounds.size.y > 0.f);

// Reposition and resize scroll bars
math::Vec inner = box.size.minus(math::Vec(verticalScrollBar->box.size.x, horizontalScrollBar->box.size.y));
horizontalScrollBar->box.pos.y = inner.y;
verticalScrollBar->box.pos.x = inner.x;
horizontalScrollBar->box.size.x = verticalScrollBar->visible ? inner.x : box.size.x;
verticalScrollBar->box.size.y = horizontalScrollBar->visible ? inner.y : box.size.y;
horizontalScrollBar->box.size.x = verticalScrollBar->isVisible() ? inner.x : box.size.x;
verticalScrollBar->box.size.y = horizontalScrollBar->isVisible() ? inner.y : box.size.y;
}


void ScrollWidget::onButton(const event::Button& e) {
OpaqueWidget::onButton(e);
if (e.isConsumed())
@@ -77,12 +77,14 @@ void ScrollWidget::onButton(const event::Button& e) {
}
}


void ScrollWidget::onDragStart(const event::DragStart& e) {
if (e.button == GLFW_MOUSE_BUTTON_LEFT || e.button == GLFW_MOUSE_BUTTON_MIDDLE) {
e.consume(this);
}
}


void ScrollWidget::onDragMove(const event::DragMove& e) {
// Scroll only if the scrollbars are visible
if (!(horizontalScrollBar->visible || verticalScrollBar->visible))
@@ -91,6 +93,7 @@ void ScrollWidget::onDragMove(const event::DragMove& e) {
offset = offset.minus(e.mouseDelta);
}


void ScrollWidget::onHoverScroll(const event::HoverScroll& e) {
OpaqueWidget::onHoverScroll(e);
if (e.isConsumed())
@@ -112,6 +115,7 @@ void ScrollWidget::onHoverScroll(const event::HoverScroll& e) {
e.consume(this);
}


void ScrollWidget::onHoverKey(const event::HoverKey& e) {
OpaqueWidget::onHoverKey(e);
if (e.isConsumed())


+ 45
- 13
src/widget/Widget.cpp View File

@@ -14,11 +14,23 @@ Widget::~Widget() {
clearChildren();
}


math::Rect Widget::getBox() {
return box;
}


void Widget::setBox(math::Rect box) {
setPosition(box.pos);
setSize(box.size);
}


math::Vec Widget::getPosition() {
return box.pos;
}


void Widget::setPosition(math::Vec pos) {
if (pos.isEqual(box.pos))
return;
@@ -28,6 +40,12 @@ void Widget::setPosition(math::Vec pos) {
onReposition(eReposition);
}


math::Vec Widget::getSize() {
return box.size;
}


void Widget::setSize(math::Vec size) {
if (size.isEqual(box.size))
return;
@@ -37,28 +55,34 @@ void Widget::setSize(math::Vec size) {
onResize(eResize);
}

void Widget::show() {
if (visible)
return;
visible = true;
// Trigger Show event
event::Show eShow;
onShow(eShow);

bool Widget::isVisible() {
return visible;
}

void Widget::hide() {
if (!visible)

void Widget::setVisible(bool visible) {
if (visible == this->visible)
return;
visible = false;
// Trigger Hide event
event::Hide eHide;
onHide(eHide);
this->visible = visible;
if (visible) {
// Trigger Show event
event::Show eShow;
onShow(eShow);
}
else {
// Trigger Hide event
event::Hide eHide;
onHide(eHide);
}
}


void Widget::requestDelete() {
requestedDelete = true;
}


math::Rect Widget::getChildrenBoundingBox() {
math::Vec min = math::Vec(INFINITY, INFINITY);
math::Vec max = math::Vec(-INFINITY, -INFINITY);
@@ -71,6 +95,7 @@ math::Rect Widget::getChildrenBoundingBox() {
return math::Rect::fromMinMax(min, max);
}


math::Vec Widget::getRelativeOffset(math::Vec v, Widget* relative) {
if (this == relative) {
return v;
@@ -82,6 +107,7 @@ math::Vec Widget::getRelativeOffset(math::Vec v, Widget* relative) {
return v;
}


math::Rect Widget::getViewport(math::Rect r) {
math::Rect bound;
if (parent) {
@@ -94,6 +120,7 @@ math::Rect Widget::getViewport(math::Rect r) {
return r.clamp(bound);
}


void Widget::addChild(Widget* child) {
assert(child);
assert(!child->parent);
@@ -104,6 +131,7 @@ void Widget::addChild(Widget* child) {
child->onAdd(eAdd);
}


void Widget::addChildBottom(Widget* child) {
assert(child);
assert(!child->parent);
@@ -114,6 +142,7 @@ void Widget::addChildBottom(Widget* child) {
child->onAdd(eAdd);
}


void Widget::removeChild(Widget* child) {
assert(child);
// Make sure `this` is the child's parent
@@ -131,6 +160,7 @@ void Widget::removeChild(Widget* child) {
child->parent = NULL;
}


void Widget::clearChildren() {
for (Widget* child : children) {
// Trigger Remove event
@@ -143,6 +173,7 @@ void Widget::clearChildren() {
children.clear();
}


void Widget::step() {
for (auto it = children.begin(); it != children.end();) {
Widget* child = *it;
@@ -163,6 +194,7 @@ void Widget::step() {
}
}


void Widget::draw(const DrawArgs& args) {
// Iterate children
for (Widget* child : children) {


Loading…
Cancel
Save