Browse Source

Use larger canvas for RackScrollWidget.

tags/v1.0.0
Andrew Belt 5 years ago
parent
commit
7e2d4a6bf9
10 changed files with 96 additions and 105 deletions
  1. +2
    -3
      helper.py
  2. +1
    -0
      include/app/RackScrollWidget.hpp
  3. +1
    -0
      include/app/common.hpp
  4. +37
    -36
      include/math.hpp
  5. +0
    -9
      src/app/RackRail.cpp
  6. +28
    -17
      src/app/RackScrollWidget.cpp
  7. +8
    -16
      src/app/RackWidget.cpp
  8. +7
    -7
      src/engine/Engine.cpp
  9. +2
    -2
      src/patch.cpp
  10. +10
    -15
      src/ui/ScrollWidget.cpp

+ 2
- 3
helper.py View File

@@ -7,9 +7,8 @@ import json
import xml.etree.ElementTree import xml.etree.ElementTree




if sys.version_info < (3, 6):
print("Python 3.6 or higher required")
exit(1)
# Version check
f"Python 3.6 is required"




class UserException(Exception): class UserException(Exception):


+ 1
- 0
include/app/RackScrollWidget.hpp View File

@@ -20,6 +20,7 @@ struct RackScrollWidget : ui::ScrollWidget {
void draw(const DrawArgs &args) override; void draw(const DrawArgs &args) override;
void onHover(const widget::HoverEvent &e) override; void onHover(const widget::HoverEvent &e) override;
void onHoverScroll(const widget::HoverScrollEvent &e) override; void onHoverScroll(const widget::HoverScrollEvent &e) override;
void reset();
}; };






+ 1
- 0
include/app/common.hpp View File

@@ -43,6 +43,7 @@ inline math::Vec mm2px(math::Vec mm) {
static const float RACK_GRID_WIDTH = 15; static const float RACK_GRID_WIDTH = 15;
static const float RACK_GRID_HEIGHT = 380; static const float RACK_GRID_HEIGHT = 380;
static const math::Vec RACK_GRID_SIZE = math::Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT); static const math::Vec RACK_GRID_SIZE = math::Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT);
static const math::Vec RACK_OFFSET = RACK_GRID_SIZE.mult(math::Vec(2000, 100));




} // namespace app } // namespace app


+ 37
- 36
include/math.hpp View File

@@ -15,25 +15,25 @@ namespace math {
// basic integer functions // basic integer functions
//////////////////// ////////////////////


/** Returns true if x is odd */
/** Returns true if x is odd. */
inline bool isEven(int x) { inline bool isEven(int x) {
return x % 2 == 0; return x % 2 == 0;
} }


/** Returns true if x is odd */
/** Returns true if x is odd. */
inline bool isOdd(int x) { inline bool isOdd(int x) {
return x % 2 != 0; return x % 2 != 0;
} }


/** Limits `x` between `a` and `b`
Assumes a <= b
/** Limits `x` between `a` and `b`.
If b < a, returns a.
*/ */
inline int clamp(int x, int a, int b) { inline int clamp(int x, int a, int b) {
return std::min(std::max(x, a), b);
return std::max(std::min(x, b), a);
} }


/** Limits `x` between `a` and `b`
If a > b, switches the two values
/** Limits `x` between `a` and `b`.
If b < a, switches the two values.
*/ */
inline int clampSafe(int x, int a, int b) { inline int clampSafe(int x, int a, int b) {
return clamp(x, std::min(a, b), std::max(a, b)); return clamp(x, std::min(a, b), std::max(a, b));
@@ -72,8 +72,7 @@ inline void eucDivMod(int a, int b, int *div, int *mod) {
} }
} }


/** Returns floor(log_2(n)), or 0 if n == 1.
*/
/** Returns floor(log_2(n)), or 0 if n == 1. */
inline int log2(int n) { inline int log2(int n) {
int i = 0; int i = 0;
while (n >>= 1) { while (n >>= 1) {
@@ -82,7 +81,7 @@ inline int log2(int n) {
return i; return i;
} }


/** Returns whether `n` is a power of 2 */
/** Returns whether `n` is a power of 2. */
inline bool isPow2(int n) { inline bool isPow2(int n) {
return n > 0 && (n & (n - 1)) == 0; return n > 0 && (n & (n - 1)) == 0;
} }
@@ -91,22 +90,22 @@ inline bool isPow2(int n) {
// basic float functions // basic float functions
//////////////////// ////////////////////


/** Limits `x` between `a` and `b`
Assumes a <= b
/** Limits `x` between `a` and `b`.
If b < a, returns a.
*/ */
inline float clamp(float x, float a, float b) { inline float clamp(float x, float a, float b) {
return std::fmin(std::fmax(x, a), b);
return std::fmax(std::fmin(x, b), a);
} }


/** Limits `x` between `a` and `b`
If a > b, switches the two values
/** Limits `x` between `a` and `b`.
If b < a, switches the two values.
*/ */
inline float clampSafe(float x, float a, float b) { inline float clampSafe(float x, float a, float b) {
return clamp(x, std::fmin(a, b), std::fmax(a, b)); return clamp(x, std::fmin(a, b), std::fmax(a, b));
} }


/** Returns 1 for positive numbers, -1 for negative numbers, and 0 for zero
See https://en.wikipedia.org/wiki/Sign_function
/** Returns 1 for positive numbers, -1 for negative numbers, and 0 for zero.
See https://en.wikipedia.org/wiki/Sign_function.
*/ */
inline float sgn(float x) { inline float sgn(float x) {
return x > 0.f ? 1.f : x < 0.f ? -1.f : 0.f; return x > 0.f ? 1.f : x < 0.f ? -1.f : 0.f;
@@ -118,18 +117,19 @@ inline float normalizeZero(float x) {
} }


/** Euclidean modulus. Always returns 0 <= mod < b. /** Euclidean modulus. Always returns 0 <= mod < b.
See https://en.wikipedia.org/wiki/Euclidean_division
See https://en.wikipedia.org/wiki/Euclidean_division.
*/ */
inline float eucMod(float a, float base) { inline float eucMod(float a, float base) {
float mod = std::fmod(a, base); float mod = std::fmod(a, base);
return (mod >= 0.f) ? mod : mod + base; return (mod >= 0.f) ? mod : mod + base;
} }


/** Returns whether a is within epsilon distance from b. */
inline bool isNear(float a, float b, float epsilon = 1e-6f) { inline bool isNear(float a, float b, float epsilon = 1e-6f) {
return std::fabs(a - b) <= epsilon; return std::fabs(a - b) <= epsilon;
} }


/** If the magnitude of x if less than epsilon, return 0 */
/** If the magnitude of x if less than epsilon, return 0. */
inline float chop(float x, float epsilon = 1e-6f) { inline float chop(float x, float epsilon = 1e-6f) {
return isNear(x, 0.f, epsilon) ? 0.f : x; return isNear(x, 0.f, epsilon) ? 0.f : x;
} }
@@ -142,7 +142,7 @@ inline float crossfade(float a, float b, float p) {
return a + (b - a) * p; return a + (b - a) * p;
} }


/** Linearly interpolate an array `p` with index `x`
/** Linearly interpolates an array `p` with index `x`.
Assumes that the array at `p` is of length at least floor(x)+1. Assumes that the array at `p` is of length at least floor(x)+1.
*/ */
inline float interpolateLinear(const float *p, float x) { inline float interpolateLinear(const float *p, float x) {
@@ -151,8 +151,8 @@ inline float interpolateLinear(const float *p, float x) {
return crossfade(p[xi], p[xi+1], xf); return crossfade(p[xi], p[xi+1], xf);
} }


/** Complex multiply c = a * b
Arguments may be the same pointers
/** Complex multiplies c = a * b.
Arguments may be the same pointers.
i.e. cmultf(&ar, &ai, ar, ai, br, bi) i.e. cmultf(&ar, &ai, ar, ai, br, bi)
*/ */
inline void complexMult(float *cr, float *ci, float ar, float ai, float br, float bi) { inline void complexMult(float *cr, float *ci, float ar, float ai, float br, float bi) {
@@ -173,7 +173,7 @@ struct Vec {
Vec() {} Vec() {}
Vec(float x, float y) : x(x), y(y) {} Vec(float x, float y) : x(x), y(y) {}


/** Negates the vector
/** Negates the vector.
Equivalent to a reflection across the y=-x line. Equivalent to a reflection across the y=-x line.
*/ */
Vec neg() const { Vec neg() const {
@@ -206,13 +206,13 @@ struct Vec {
float square() const { float square() const {
return x * x + y * y; return x * x + y * y;
} }
/** Rotates counterclockwise in radians */
/** Rotates counterclockwise in radians. */
Vec rotate(float angle) { Vec rotate(float angle) {
float sin = std::sin(angle); float sin = std::sin(angle);
float cos = std::cos(angle); float cos = std::cos(angle);
return Vec(x * cos - y * sin, x * sin + y * cos); return Vec(x * cos - y * sin, x * sin + y * cos);
} }
/** Swaps the coordinates
/** Swaps the coordinates.
Equivalent to a reflection across the y=x line. Equivalent to a reflection across the y=x line.
*/ */
Vec flip() const { Vec flip() const {
@@ -256,22 +256,23 @@ struct Rect {


Rect() {} Rect() {}
Rect(Vec pos, Vec size) : pos(pos), size(size) {} Rect(Vec pos, Vec size) : pos(pos), size(size) {}
/** Constructs a Rect from the upper-left position `a` and lower-right pos `b` */
Rect(float posX, float posY, float sizeX, float sizeY) : pos(math::Vec(posX, posY)), size(math::Vec(sizeX, sizeY)) {}
/** Constructs a Rect from the upper-left position `a` and lower-right pos `b`. */
static Rect fromMinMax(Vec a, Vec b) { static Rect fromMinMax(Vec a, Vec b) {
return Rect(a, b.minus(a)); return Rect(a, b.minus(a));
} }


/** Returns whether this Rect contains an entire point, 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 isContaining(Vec v) const { bool isContaining(Vec v) const {
return pos.x <= v.x && v.x < pos.x + size.x return pos.x <= v.x && v.x < pos.x + size.x
&& pos.y <= v.y && v.y < pos.y + size.y; && pos.y <= v.y && v.y < pos.y + size.y;
} }
/** Returns whether this Rect contains an entire Rect */
/** Returns whether this Rect contains an entire Rect. */
bool isContaining(Rect r) const { bool isContaining(Rect r) const {
return pos.x <= r.pos.x && r.pos.x + r.size.x <= pos.x + size.x 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; && pos.y <= r.pos.y && r.pos.y + r.size.y <= pos.y + size.y;
} }
/** Returns whether this Rect overlaps with another Rect */
/** Returns whether this Rect overlaps with another Rect. */
bool isIntersecting(Rect r) const { bool isIntersecting(Rect r) const {
return (pos.x + size.x > r.pos.x && r.pos.x + r.size.x > pos.x) return (pos.x + size.x > r.pos.x && r.pos.x + r.size.x > pos.x)
&& (pos.y + size.y > r.pos.y && r.pos.y + r.size.y > pos.y); && (pos.y + size.y > r.pos.y && r.pos.y + r.size.y > pos.y);
@@ -300,7 +301,7 @@ struct Rect {
Vec getBottomRight() const { Vec getBottomRight() const {
return pos.plus(size); return pos.plus(size);
} }
/** Clamps the edges of the rectangle to fit within a bound */
/** Clamps the edges of the rectangle to fit within a bound. */
Rect clamp(Rect bound) const { Rect clamp(Rect bound) const {
Rect r; Rect r;
r.pos.x = math::clampSafe(pos.x, bound.pos.x, bound.pos.x + bound.size.x); r.pos.x = math::clampSafe(pos.x, bound.pos.x, bound.pos.x + bound.size.x);
@@ -309,7 +310,7 @@ struct Rect {
r.size.y = math::clamp(pos.y + size.y, bound.pos.y, bound.pos.y + bound.size.y) - r.pos.y; r.size.y = math::clamp(pos.y + size.y, bound.pos.y, bound.pos.y + bound.size.y) - r.pos.y;
return r; return r;
} }
/** Nudges the position to fix inside a bounding box */
/** Nudges the position to fix inside a bounding box. */
Rect nudge(Rect bound) const { Rect nudge(Rect bound) const {
Rect r; Rect r;
r.size = size; r.size = size;
@@ -317,7 +318,7 @@ struct Rect {
r.pos.y = math::clampSafe(pos.y, bound.pos.y, bound.pos.y + bound.size.y - size.y); r.pos.y = math::clampSafe(pos.y, bound.pos.y, bound.pos.y + bound.size.y - size.y);
return r; return r;
} }
/** Expands this Rect to contain `b` */
/** Expands this Rect to contain `b`. */
Rect expand(Rect b) const { Rect expand(Rect b) const {
Rect r; Rect r;
r.pos.x = std::fmin(pos.x, b.pos.x); r.pos.x = std::fmin(pos.x, b.pos.x);
@@ -326,7 +327,7 @@ struct Rect {
r.size.y = std::fmax(pos.y + size.y, b.pos.y + b.size.y) - r.pos.y; r.size.y = std::fmax(pos.y + size.y, b.pos.y + b.size.y) - r.pos.y;
return r; return r;
} }
/** Returns the intersection of `this` and `b` */
/** Returns the intersection of `this` and `b`. */
Rect intersect(Rect b) const { Rect intersect(Rect b) const {
Rect r; Rect r;
r.pos.x = std::fmax(pos.x, b.pos.x); r.pos.x = std::fmax(pos.x, b.pos.x);
@@ -335,11 +336,11 @@ struct Rect {
r.size.y = std::fmin(pos.y + size.y, b.pos.y + b.size.y) - r.pos.y; r.size.y = std::fmin(pos.y + size.y, b.pos.y + b.size.y) - r.pos.y;
return r; return r;
} }
/** Returns a Rect with its position set to zero */
/** Returns a Rect with its position set to zero. */
Rect zeroPos() const { Rect zeroPos() const {
return Rect(Vec(), size); return Rect(Vec(), size);
} }
/** Expands each corner
/** Expands each corner.
Use a negative delta to shrink. Use a negative delta to shrink.
*/ */
Rect grow(Vec delta) const { Rect grow(Vec delta) const {
@@ -371,7 +372,7 @@ inline Vec Vec::clampSafe(Rect bound) const {
/** Expands a Vec and Rect into a comma-separated list. /** Expands a Vec and Rect into a comma-separated list.
Useful for print debugging. Useful for print debugging.


printf("%f %f %f %f", RECT_ARGS(r));
printf("(%f %f) (%f %f %f %f)", VEC_ARGS(v), RECT_ARGS(r));


Or passing the values to a C function. Or passing the values to a C function.




+ 0
- 9
src/app/RackRail.cpp View File

@@ -47,15 +47,6 @@ void RackRail::draw(const DrawArgs &args) {
nvgLineTo(args.vg, box.size.x, railY + RACK_GRID_HEIGHT - 0.5); nvgLineTo(args.vg, box.size.x, railY + RACK_GRID_HEIGHT - 0.5);
nvgStroke(args.vg); nvgStroke(args.vg);
} }


// Useful for screenshots
if (0) {
nvgBeginPath(args.vg);
nvgRect(args.vg, 0.0, 0.0, box.size.x, box.size.y);
nvgFillColor(args.vg, nvgRGBf(1.0, 1.0, 1.0));
nvgFill(args.vg);
}
} }






+ 28
- 17
src/app/RackScrollWidget.cpp View File

@@ -14,11 +14,14 @@ RackScrollWidget::RackScrollWidget() {
container->addChild(zoomWidget); container->addChild(zoomWidget);


rackWidget = new RackWidget; rackWidget = new RackWidget;
rackWidget->box.size = RACK_OFFSET.mult(2);
zoomWidget->addChild(rackWidget); zoomWidget->addChild(rackWidget);

reset();
} }


void RackScrollWidget::step() { void RackScrollWidget::step() {
float zoom = std::round(settings.zoom * 100) / 100;
float zoom = std::round(settings.zoom / 0.01) * 0.01;
if (zoom != zoomWidget->zoom) { if (zoom != zoomWidget->zoom) {
// Set offset based on zoomPos // Set offset based on zoomPos
offset = offset.plus(zoomPos).div(zoomWidget->zoom).mult(zoom).minus(zoomPos); offset = offset.plus(zoomPos).div(zoomWidget->zoom).mult(zoom).minus(zoomPos);
@@ -28,14 +31,20 @@ void RackScrollWidget::step() {


zoomPos = box.size.div(2); zoomPos = box.size.div(2);


// Resize RackWidget to be a bit larger than the viewport
rackWidget->box.size = box.size
.minus(container->box.pos)
.plus(math::Vec(500, 500))
.div(zoomWidget->zoom);

// Resize ZoomWidget
zoomWidget->box.size = rackWidget->box.size.mult(zoomWidget->zoom);
// Set zoomWidget box to module bounding box
math::Rect moduleBox = rackWidget->moduleContainer->getChildrenBoundingBox();
if (!moduleBox.size.isFinite())
moduleBox = math::Rect(RACK_OFFSET, math::Vec(0, 0));
zoomWidget->box.pos = moduleBox.pos.mult(zoomWidget->zoom);
zoomWidget->box.size = moduleBox.size.mult(zoomWidget->zoom);
// Expand to viewport
math::Rect viewportBox = box;
viewportBox.pos = viewportBox.pos.plus(offset);
zoomWidget->box = zoomWidget->box.expand(viewportBox);
// Grow a few pixels
zoomWidget->box = zoomWidget->box.grow(math::Vec(100, 100));
// Reposition rackWidget
rackWidget->box.pos = zoomWidget->box.pos.div(zoomWidget->zoom).neg();


// Scroll rack if dragging cable near the edge of the screen // Scroll rack if dragging cable near the edge of the screen
math::Vec pos = APP->window->mousePos; math::Vec pos = APP->window->mousePos;
@@ -58,6 +67,7 @@ void RackScrollWidget::step() {




void RackScrollWidget::draw(const DrawArgs &args) { void RackScrollWidget::draw(const DrawArgs &args) {
// DEBUG("%f %f %f %f", RECT_ARGS(args.clipBox));
ScrollWidget::draw(args); ScrollWidget::draw(args);
} }


@@ -72,18 +82,14 @@ void RackScrollWidget::onHover(const widget::HoverEvent &e) {
else if ((APP->window->getMods() & WINDOW_MOD_MASK) == GLFW_MOD_SHIFT) else if ((APP->window->getMods() & WINDOW_MOD_MASK) == GLFW_MOD_SHIFT)
arrowSpeed /= 4.0; arrowSpeed /= 4.0;


if (glfwGetKey(APP->window->win, GLFW_KEY_LEFT) == GLFW_PRESS) {
if (glfwGetKey(APP->window->win, GLFW_KEY_LEFT) == GLFW_PRESS)
offset.x -= arrowSpeed; offset.x -= arrowSpeed;
}
if (glfwGetKey(APP->window->win, GLFW_KEY_RIGHT) == GLFW_PRESS) {
if (glfwGetKey(APP->window->win, GLFW_KEY_RIGHT) == GLFW_PRESS)
offset.x += arrowSpeed; offset.x += arrowSpeed;
}
if (glfwGetKey(APP->window->win, GLFW_KEY_UP) == GLFW_PRESS) {
if (glfwGetKey(APP->window->win, GLFW_KEY_UP) == GLFW_PRESS)
offset.y -= arrowSpeed; offset.y -= arrowSpeed;
}
if (glfwGetKey(APP->window->win, GLFW_KEY_DOWN) == GLFW_PRESS) {
if (glfwGetKey(APP->window->win, GLFW_KEY_DOWN) == GLFW_PRESS)
offset.y += arrowSpeed; offset.y += arrowSpeed;
}
} }


ScrollWidget::onHover(e); ScrollWidget::onHover(e);
@@ -105,6 +111,11 @@ void RackScrollWidget::onHoverScroll(const widget::HoverScrollEvent &e) {
ScrollWidget::onHoverScroll(e); ScrollWidget::onHoverScroll(e);
} }


void RackScrollWidget::reset() {
offset = RACK_OFFSET.mult(zoomWidget->zoom);
offset = offset.minus(math::Vec(20, 20));
}



} // namespace app } // namespace app
} // namespace rack } // namespace rack

+ 8
- 16
src/app/RackWidget.cpp View File

@@ -97,13 +97,7 @@ RackWidget::~RackWidget() {
} }


void RackWidget::step() { void RackWidget::step() {
// Expand size to fit modules
math::Vec moduleSize = moduleContainer->getChildrenBoundingBox().getBottomRight();
// We assume that the size is reset by a parent before calling step(). Otherwise it will grow unbounded.
box.size = box.size.max(moduleSize);

// Adjust size and position of rails // Adjust size and position of rails
widget::Widget *rail = rails->children.front();
math::Rect bound = getViewport(math::Rect(math::Vec(), box.size)); math::Rect bound = getViewport(math::Rect(math::Vec(), box.size));
if (!rails->box.isContaining(bound)) { if (!rails->box.isContaining(bound)) {
math::Vec cellMargin = math::Vec(20, 1); math::Vec cellMargin = math::Vec(20, 1);
@@ -111,14 +105,15 @@ void RackWidget::step() {
rails->box.size = bound.size.plus(cellMargin.mult(RACK_GRID_SIZE).mult(2)); rails->box.size = bound.size.plus(cellMargin.mult(RACK_GRID_SIZE).mult(2));
rails->dirty = true; rails->dirty = true;


RackRail *rail = rails->getFirstDescendantOfType<RackRail>();
rail->box.size = rails->box.size; rail->box.size = rails->box.size;
} }


Widget::step();
OpaqueWidget::step();
} }


void RackWidget::draw(const DrawArgs &args) { void RackWidget::draw(const DrawArgs &args) {
Widget::draw(args);
OpaqueWidget::draw(args);
} }


void RackWidget::onHover(const widget::HoverEvent &e) { void RackWidget::onHover(const widget::HoverEvent &e) {
@@ -157,7 +152,6 @@ void RackWidget::onButton(const widget::ButtonEvent &e) {
} }


void RackWidget::onZoom(const widget::ZoomEvent &e) { void RackWidget::onZoom(const widget::ZoomEvent &e) {
rails->box.size = math::Vec();
OpaqueWidget::onZoom(e); OpaqueWidget::onZoom(e);
} }


@@ -189,7 +183,8 @@ json_t *RackWidget::toJson() {
// id // id
json_object_set_new(moduleJ, "id", json_integer(moduleWidget->module->id)); json_object_set_new(moduleJ, "id", json_integer(moduleWidget->module->id));
// pos // pos
math::Vec pos = moduleWidget->box.pos.div(RACK_GRID_SIZE).round();
math::Vec pos = moduleWidget->box.pos.minus(RACK_OFFSET);
pos = pos.div(RACK_GRID_SIZE).round();
json_t *posJ = json_pack("[i, i]", (int) pos.x, (int) pos.y); json_t *posJ = json_pack("[i, i]", (int) pos.x, (int) pos.y);
json_object_set_new(moduleJ, "pos", posJ); json_object_set_new(moduleJ, "pos", posJ);
} }
@@ -252,6 +247,7 @@ void RackWidget::fromJson(json_t *rootJ) {
else { else {
moduleWidget->box.pos = pos.mult(RACK_GRID_SIZE); moduleWidget->box.pos = pos.mult(RACK_GRID_SIZE);
} }
moduleWidget->box.pos = moduleWidget->box.pos.plus(RACK_OFFSET);


addModule(moduleWidget); addModule(moduleWidget);
} }
@@ -387,10 +383,6 @@ void RackWidget::removeModule(ModuleWidget *m) {
} }


bool RackWidget::requestModuleBox(ModuleWidget *m, math::Rect requestedBox) { bool RackWidget::requestModuleBox(ModuleWidget *m, math::Rect requestedBox) {
// Check bounds
if (requestedBox.pos.x < 0 || requestedBox.pos.y < 0)
return false;

// Check intersection with other modules // Check intersection with other modules
for (widget::Widget *m2 : moduleContainer->children) { for (widget::Widget *m2 : moduleContainer->children) {
// Don't intersect with self // Don't intersect with self
@@ -412,8 +404,8 @@ bool RackWidget::requestModuleBoxNearest(ModuleWidget *m, math::Rect requestedBo
int x0 = std::round(requestedBox.pos.x / RACK_GRID_WIDTH); int x0 = std::round(requestedBox.pos.x / RACK_GRID_WIDTH);
int y0 = std::round(requestedBox.pos.y / RACK_GRID_HEIGHT); int y0 = std::round(requestedBox.pos.y / RACK_GRID_HEIGHT);
std::vector<math::Vec> positions; std::vector<math::Vec> positions;
for (int y = std::max(0, y0 - 8); y < y0 + 8; y++) {
for (int x = std::max(0, x0 - 400); x < x0 + 400; x++) {
for (int y = y0 - 4; y < y0 + 4; y++) {
for (int x = x0 - 200; x < x0 + 200; x++) {
positions.push_back(math::Vec(x * RACK_GRID_WIDTH, y * RACK_GRID_HEIGHT)); positions.push_back(math::Vec(x * RACK_GRID_WIDTH, y * RACK_GRID_HEIGHT));
} }
} }


+ 7
- 7
src/engine/Engine.cpp View File

@@ -473,14 +473,14 @@ void Engine::removeModule(Module *module) {
paramHandle->module = NULL; paramHandle->module = NULL;
} }
// Update adjacent modules // Update adjacent modules
for (Module *module : internal->modules) {
if (module->leftModule == module) {
module->leftModuleId = -1;
module->leftModule = NULL;
for (Module *m : internal->modules) {
if (m->leftModule == module) {
m->leftModuleId = -1;
m->leftModule = NULL;
} }
if (module->rightModule == module) {
module->rightModuleId = -1;
module->rightModule = NULL;
if (m->rightModule == module) {
m->rightModuleId = -1;
m->rightModule = NULL;
} }
} }
// Check that the module actually exists // Check that the module actually exists


+ 2
- 2
src/patch.cpp View File

@@ -60,7 +60,7 @@ void PatchManager::init(std::string path) {
void PatchManager::reset() { void PatchManager::reset() {
APP->history->clear(); APP->history->clear();
APP->scene->rack->clear(); APP->scene->rack->clear();
APP->scene->rackScroll->offset = math::Vec(0, 0);
APP->scene->rackScroll->reset();
// Fails silently if file does not exist // Fails silently if file does not exist
load(asset::user("template.vcv")); load(asset::user("template.vcv"));
legacy = 0; legacy = 0;
@@ -169,7 +169,7 @@ bool PatchManager::load(std::string path) {


APP->history->clear(); APP->history->clear();
APP->scene->rack->clear(); APP->scene->rack->clear();
APP->scene->rackScroll->offset = math::Vec(0, 0);
APP->scene->rackScroll->reset();
fromJson(rootJ); fromJson(rootJ);
return true; return true;
} }


+ 10
- 15
src/ui/ScrollWidget.cpp View File

@@ -37,22 +37,17 @@ void ScrollWidget::step() {
Widget::step(); Widget::step();


// Clamp scroll offset // Clamp scroll offset
math::Vec containerCorner = container->getChildrenBoundingBox().getBottomRight();
math::Rect containerBox = math::Rect(math::Vec(0, 0), containerCorner.minus(box.size));
offset = offset.clamp(containerBox);
// Lock offset to top/left if no scrollbar will display
if (containerBox.size.x < 0.0)
offset.x = 0.0;
if (containerBox.size.y < 0.0)
offset.y = 0.0;

// Update the container's positions from the offset
math::Rect containerBox = container->getChildrenBoundingBox();
math::Rect offsetBounds = containerBox;
offsetBounds.size = offsetBounds.size.minus(box.size);
offset = offset.clamp(offsetBounds);

// Update the container's position from the offset
container->box.pos = offset.neg().round(); container->box.pos = offset.neg().round();


// Update scrollbar offsets and sizes // Update scrollbar offsets and sizes
math::Vec viewportSize = container->getChildrenBoundingBox().getBottomRight();
math::Vec scrollbarOffset = offset.div(viewportSize.minus(box.size));
math::Vec scrollbarSize = box.size.div(viewportSize);
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); horizontalScrollBar->visible = (0.0 < scrollbarSize.x && scrollbarSize.x < 1.0);
verticalScrollBar->visible = (0.0 < scrollbarSize.y && scrollbarSize.y < 1.0); verticalScrollBar->visible = (0.0 < scrollbarSize.y && scrollbarSize.y < 1.0);
@@ -61,8 +56,8 @@ void ScrollWidget::step() {
horizontalScrollBar->size = scrollbarSize.x; horizontalScrollBar->size = scrollbarSize.x;
verticalScrollBar->size = scrollbarSize.y; verticalScrollBar->size = scrollbarSize.y;


// Resize scroll bars
math::Vec inner = math::Vec(box.size.x - verticalScrollBar->box.size.x, box.size.y - horizontalScrollBar->box.size.y);
// 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; horizontalScrollBar->box.pos.y = inner.y;
verticalScrollBar->box.pos.x = inner.x; verticalScrollBar->box.pos.x = inner.x;
horizontalScrollBar->box.size.x = verticalScrollBar->visible ? inner.x : box.size.x; horizontalScrollBar->box.size.x = verticalScrollBar->visible ? inner.x : box.size.x;


Loading…
Cancel
Save