@@ -157,7 +157,8 @@ struct CircularShadow : TransparentWidget { | |||
}; | |||
struct Light : TransparentWidget { | |||
NVGcolor color; | |||
NVGcolor bgColor = nvgRGBf(0, 0, 0); | |||
NVGcolor color = nvgRGBf(1, 1, 1); | |||
void draw(NVGcontext *vg); | |||
}; | |||
@@ -321,6 +322,7 @@ struct PluginManagerWidget : Widget { | |||
struct RackScene : Scene { | |||
Toolbar *toolbar; | |||
ScrollWidget *scrollWidget; | |||
ZoomWidget *zoomWidget; | |||
RackScene(); | |||
void step(); | |||
@@ -402,7 +402,7 @@ struct ColorValueLight : ValueLight { | |||
void setValue(float v) { | |||
v = sqrtBipolar(v); | |||
color = baseColor; | |||
color.a = clampf(v, 0.0, 1.0); | |||
color.a = clampf(v * baseColor.a, 0.0, 1.0); | |||
} | |||
}; | |||
@@ -430,7 +430,7 @@ struct PolarityLight : ValueLight { | |||
void setValue(float v) { | |||
v = sqrtBipolar(v); | |||
color = (v >= 0.0) ? posColor : negColor; | |||
color.a = clampf(fabsf(v), 0.0, 1.0); | |||
color.a = clampf(fabsf(v) * color.a, 0.0, 1.0); | |||
} | |||
}; | |||
@@ -548,6 +548,15 @@ struct BefacoPush : SVGSwitch, MomentarySwitch { | |||
} | |||
}; | |||
struct PB61303 : SVGSwitch, MomentarySwitch { | |||
PB61303() { | |||
addFrame(SVG::load(assetGlobal("res/ComponentLibrary/PB61303_0.svg"))); | |||
addFrame(SVG::load(assetGlobal("res/ComponentLibrary/PB61303_1.svg"))); | |||
sw->wrap(); | |||
box.size = sw->box.size; | |||
} | |||
}; | |||
//////////////////// | |||
// Misc | |||
@@ -160,7 +160,7 @@ | |||
x2="87.030029" | |||
y2="73.994049" | |||
gradientUnits="userSpaceOnUse" | |||
gradientTransform="rotate(-90,83.154938,73.994048)" /> | |||
gradientTransform="matrix(0,-0.93432349,0.93432349,0,14.020561,151.68766)" /> | |||
</defs> | |||
<sodipodi:namedview | |||
id="base" | |||
@@ -169,12 +169,12 @@ | |||
borderopacity="1.0" | |||
inkscape:pageopacity="0.0" | |||
inkscape:pageshadow="2" | |||
inkscape:zoom="7.9195959" | |||
inkscape:cx="22.964109" | |||
inkscape:cy="8.9651844" | |||
inkscape:zoom="22.4" | |||
inkscape:cx="22.801127" | |||
inkscape:cy="13.743925" | |||
inkscape:document-units="mm" | |||
inkscape:current-layer="layer1" | |||
showgrid="false" | |||
inkscape:current-layer="g19440" | |||
showgrid="true" | |||
fit-margin-top="0" | |||
fit-margin-left="0" | |||
fit-margin-right="0" | |||
@@ -186,7 +186,12 @@ | |||
inkscape:window-maximized="0" | |||
inkscape:snap-page="true" | |||
inkscape:snap-bbox="true" | |||
inkscape:bbox-nodes="true" /> | |||
inkscape:bbox-nodes="true" | |||
inkscape:object-nodes="false"> | |||
<inkscape:grid | |||
type="xygrid" | |||
id="grid20375" /> | |||
</sodipodi:namedview> | |||
<metadata | |||
id="metadata18402"> | |||
<rdf:RDF> | |||
@@ -195,7 +200,7 @@ | |||
<dc:format>image/svg+xml</dc:format> | |||
<dc:type | |||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |||
<dc:title /> | |||
<dc:title></dc:title> | |||
</cc:Work> | |||
</rdf:RDF> | |||
</metadata> | |||
@@ -217,12 +222,12 @@ | |||
inkscape:connector-curvature="0" | |||
id="path17974" | |||
style="fill:#6b6969;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.45976272" | |||
d="m 87.654936,73.994048 c 0,2.484967 -2.014361,4.49968 -4.500033,4.49968 -2.485672,0 -4.500033,-2.014713 -4.500033,-4.49968 0,-2.484967 2.014361,-4.49968 4.500033,-4.49968 2.485672,0 4.500033,2.014713 4.500033,4.49968" /> | |||
d="m 87.465003,73.994048 c 0,2.380367 -1.929341,4.310275 -4.3101,4.310275 -2.380759,0 -4.310099,-1.929908 -4.310099,-4.310275 0,-2.380367 1.92934,-4.310275 4.310099,-4.310275 2.380759,0 4.3101,1.929908 4.3101,4.310275" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
id="path18024" | |||
style="fill:url(#linearGradient19435);fill-opacity:1;stroke:none;stroke-width:0.45976272" | |||
d="m 79.280028,73.994224 c 0,2.140303 1.735314,3.874911 3.87491,3.874911 2.139597,0 3.874911,-1.734608 3.874911,-3.874911 0,-2.140656 -1.735314,-3.875264 -3.874911,-3.875264 -2.139596,0 -3.87491,1.734608 -3.87491,3.875264 m 0.176389,0 c 0,-2.039761 1.659114,-3.698875 3.698521,-3.698875 2.039408,0 3.698522,1.659114 3.698522,3.698875 0,2.039408 -1.659114,3.698522 -3.698522,3.698522 -2.039407,0 -3.698521,-1.659114 -3.698521,-3.698522" /> | |||
d="m 79.534519,73.994213 c 0,1.999735 1.621344,3.62042 3.620419,3.62042 1.999076,0 3.620421,-1.620685 3.620421,-3.62042 0,-2.000066 -1.621345,-3.620751 -3.620421,-3.620751 -1.999075,0 -3.620419,1.620685 -3.620419,3.620751 m 0.164804,0 c 0,-1.905797 1.550149,-3.455946 3.455615,-3.455946 1.905467,0 3.455616,1.550149 3.455616,3.455946 0,1.905466 -1.550149,3.455615 -3.455616,3.455615 -1.905466,0 -3.455615,-1.550149 -3.455615,-3.455615" /> | |||
</g> | |||
</g> | |||
</svg> |
@@ -160,7 +160,7 @@ | |||
x2="87.030029" | |||
y2="73.994049" | |||
gradientUnits="userSpaceOnUse" | |||
gradientTransform="rotate(-90,83.154938,73.994048)" /> | |||
gradientTransform="matrix(0,-0.93432349,0.93432349,0,14.020561,151.68766)" /> | |||
</defs> | |||
<sodipodi:namedview | |||
id="base" | |||
@@ -169,12 +169,12 @@ | |||
borderopacity="1.0" | |||
inkscape:pageopacity="0.0" | |||
inkscape:pageshadow="2" | |||
inkscape:zoom="7.9195959" | |||
inkscape:cx="22.964109" | |||
inkscape:cy="8.9651844" | |||
inkscape:zoom="22.4" | |||
inkscape:cx="22.801127" | |||
inkscape:cy="13.743925" | |||
inkscape:document-units="mm" | |||
inkscape:current-layer="layer1" | |||
showgrid="false" | |||
showgrid="true" | |||
fit-margin-top="0" | |||
fit-margin-left="0" | |||
fit-margin-right="0" | |||
@@ -186,7 +186,12 @@ | |||
inkscape:window-maximized="0" | |||
inkscape:snap-page="true" | |||
inkscape:snap-bbox="true" | |||
inkscape:bbox-nodes="true" /> | |||
inkscape:bbox-nodes="true" | |||
inkscape:object-nodes="false"> | |||
<inkscape:grid | |||
type="xygrid" | |||
id="grid20375" /> | |||
</sodipodi:namedview> | |||
<metadata | |||
id="metadata18402"> | |||
<rdf:RDF> | |||
@@ -217,12 +222,12 @@ | |||
inkscape:connector-curvature="0" | |||
id="path17974" | |||
style="fill:#6b6969;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.45976272" | |||
d="m 87.654936,73.994048 c 0,2.484967 -2.014361,4.49968 -4.500033,4.49968 -2.485672,0 -4.500033,-2.014713 -4.500033,-4.49968 0,-2.484967 2.014361,-4.49968 4.500033,-4.49968 2.485672,0 4.500033,2.014713 4.500033,4.49968" /> | |||
d="m 87.465003,73.994048 c 0,2.380367 -1.929341,4.310275 -4.3101,4.310275 -2.380759,0 -4.310099,-1.929908 -4.310099,-4.310275 0,-2.380367 1.92934,-4.310275 4.310099,-4.310275 2.380759,0 4.3101,1.929908 4.3101,4.310275" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
id="path18024" | |||
style="fill:url(#linearGradient19435);fill-opacity:1;stroke:none;stroke-width:0.45976272" | |||
d="m 79.280028,73.994224 c 0,2.140303 1.735314,3.874911 3.87491,3.874911 2.139597,0 3.874911,-1.734608 3.874911,-3.874911 0,-2.140656 -1.735314,-3.875264 -3.874911,-3.875264 -2.139596,0 -3.87491,1.734608 -3.87491,3.875264 m 0.176389,0 c 0,-2.039761 1.659114,-3.698875 3.698521,-3.698875 2.039408,0 3.698522,1.659114 3.698522,3.698875 0,2.039408 -1.659114,3.698522 -3.698522,3.698522 -2.039407,0 -3.698521,-1.659114 -3.698521,-3.698522" /> | |||
d="m 79.534519,73.994213 c 0,1.999735 1.621344,3.62042 3.620419,3.62042 1.999076,0 3.620421,-1.620685 3.620421,-3.62042 0,-2.000066 -1.621345,-3.620751 -3.620421,-3.620751 -1.999075,0 -3.620419,1.620685 -3.620419,3.620751 m 0.164804,0 c 0,-1.905797 1.550149,-3.455946 3.455615,-3.455946 1.905467,0 3.455616,1.550149 3.455616,3.455946 0,1.905466 -1.550149,3.455615 -3.455616,3.455615 -1.905466,0 -3.455615,-1.550149 -3.455615,-3.455615" /> | |||
</g> | |||
</g> | |||
</svg> |
@@ -5,8 +5,7 @@ namespace rack { | |||
void Light::draw(NVGcontext *vg) { | |||
NVGcolor bgColor = nvgRGBf(0.0, 0.0, 0.0); | |||
float radius = roundf(box.size.x / 2.0); | |||
float radius = box.size.x / 2.0; | |||
float oradius = radius + 30.0; | |||
// Solid | |||
@@ -17,7 +16,9 @@ void Light::draw(NVGcontext *vg) { | |||
// Border | |||
nvgStrokeWidth(vg, 1.0); | |||
nvgStrokeColor(vg, nvgTransRGBAf(bgColor, 0.5)); | |||
NVGcolor borderColor = bgColor; | |||
borderColor.a *= 0.5; | |||
nvgStrokeColor(vg, borderColor); | |||
nvgStroke(vg); | |||
// Inner glow | |||
@@ -8,7 +8,7 @@ | |||
namespace rack { | |||
static std::string versionMessage = ""; | |||
static std::string newVersion = ""; | |||
static void checkVersion() { | |||
json_t *resJ = requestJson(METHOD_GET, gApiHost + "/version", NULL); | |||
@@ -18,7 +18,7 @@ static void checkVersion() { | |||
if (versionJ) { | |||
const char *version = json_string_value(versionJ); | |||
if (version && version != gApplicationVersion) { | |||
versionMessage = stringf("Rack %s is available.\n\nYou have Rack %s.\n\nWould you like to download the new version on the website?", version, gApplicationVersion.c_str()); | |||
newVersion = version; | |||
} | |||
} | |||
json_decref(resJ); | |||
@@ -29,14 +29,14 @@ static void checkVersion() { | |||
RackScene::RackScene() { | |||
scrollWidget = new ScrollWidget(); | |||
{ | |||
// ZoomWidget *zoomWidget = new ZoomWidget(); | |||
// zoomWidget->zoom = 0.8; | |||
// scrollWidget->container->addChild(zoomWidget); | |||
assert(!gRackWidget); | |||
gRackWidget = new RackWidget(); | |||
scrollWidget->container->addChild(gRackWidget); | |||
// zoomWidget->addChild(gRackWidget); | |||
zoomWidget = new ZoomWidget(); | |||
zoomWidget->zoom = 1.0; | |||
{ | |||
assert(!gRackWidget); | |||
gRackWidget = new RackWidget(); | |||
zoomWidget->addChild(gRackWidget); | |||
} | |||
scrollWidget->container->addChild(zoomWidget); | |||
} | |||
addChild(scrollWidget); | |||
@@ -52,19 +52,29 @@ RackScene::RackScene() { | |||
} | |||
void RackScene::step() { | |||
// Resize owned descendants | |||
toolbar->box.size.x = box.size.x; | |||
scrollWidget->box.size = box.size.minus(scrollWidget->box.pos); | |||
// Resize to be a bit larger than the ScrollWidget viewport | |||
gRackWidget->box.size = scrollWidget->box.size | |||
.minus(scrollWidget->container->box.pos) | |||
.plus(Vec(500, 500)) | |||
.div(zoomWidget->zoom); | |||
Scene::step(); | |||
zoomWidget->box.size = gRackWidget->box.size.mult(zoomWidget->zoom); | |||
// Version popup message | |||
if (!versionMessage.empty()) { | |||
if (!newVersion.empty()) { | |||
std::string versionMessage = stringf("Rack %s is available.\n\nYou have Rack %s.\n\nWould you like to download the new version on the website?", newVersion, gApplicationVersion.c_str()); | |||
if (osdialog_message(OSDIALOG_INFO, OSDIALOG_YES_NO, versionMessage.c_str())) { | |||
std::thread t(openBrowser, "https://vcvrack.com/"); | |||
t.detach(); | |||
guiClose(); | |||
} | |||
versionMessage = ""; | |||
newVersion = ""; | |||
} | |||
} | |||
@@ -304,12 +304,10 @@ void RackWidget::repositionModule(ModuleWidget *m) { | |||
void RackWidget::step() { | |||
rails->step(); | |||
// Resize to be a bit larger than the ScrollWidget viewport | |||
assert(parent); | |||
assert(parent->parent); | |||
// Expand size to fit modules | |||
Vec moduleSize = moduleContainer->getChildrenBoundingBox().getBottomRight(); | |||
Vec viewportSize = parent->parent->box.size.minus(parent->box.pos); | |||
box.size = moduleSize.max(viewportSize).plus(Vec(500, 500)); | |||
// We assume that the size is reset by a parent before calling step(). Otherwise it will grow unbounded. | |||
box.size = box.size.max(moduleSize); | |||
// Reposition modules | |||
for (Widget *child : moduleContainer->children) { | |||
@@ -26,7 +26,7 @@ void SVGSwitch::onChange() { | |||
if (0 <= index && index < (int)frames.size()) | |||
sw->svg = frames[index]; | |||
dirty = true; | |||
ParamWidget::onChange(); | |||
Switch::onChange(); | |||
} | |||
@@ -172,7 +172,7 @@ void WireWidget::drawPlugs(NVGcontext *vg) { | |||
Vec outputPos = getOutputPos(); | |||
Vec inputPos = getInputPos(); | |||
drawPlug(vg, outputPos, color); | |||
drawPlug(vg, getInputPos(), color); | |||
drawPlug(vg, inputPos, color); | |||
// Draw plug light | |||
/* | |||
@@ -1,4 +1,5 @@ | |||
#include <map> | |||
#include <queue> | |||
#include "gui.hpp" | |||
#include "app.hpp" | |||
@@ -87,6 +88,28 @@ void mouseButtonCallback(GLFWwindow *window, int button, int action, int mods) { | |||
} | |||
} | |||
struct MouseButtonArguments { | |||
GLFWwindow *window; | |||
int button; | |||
int action; | |||
int mods; | |||
}; | |||
static std::queue<MouseButtonArguments> mouseButtonQueue; | |||
void mouseButtonStickyPop() { | |||
if (!mouseButtonQueue.empty()) { | |||
MouseButtonArguments args = mouseButtonQueue.front(); | |||
mouseButtonQueue.pop(); | |||
mouseButtonCallback(args.window, args.button, args.action, args.mods); | |||
} | |||
} | |||
void mouseButtonStickyCallback(GLFWwindow *window, int button, int action, int mods) { | |||
// Defer multiple clicks per frame to future frames | |||
MouseButtonArguments args = {window, button, action, mods}; | |||
mouseButtonQueue.push(args); | |||
} | |||
void cursorPosCallback(GLFWwindow* window, double xpos, double ypos) { | |||
Vec mousePos = Vec(xpos, ypos).round(); | |||
Vec mouseRel = mousePos.minus(gMousePos); | |||
@@ -238,7 +261,7 @@ void guiInit() { | |||
glfwSwapInterval(1); | |||
glfwSetWindowSizeCallback(gWindow, windowSizeCallback); | |||
glfwSetMouseButtonCallback(gWindow, mouseButtonCallback); | |||
glfwSetMouseButtonCallback(gWindow, mouseButtonStickyCallback); | |||
// glfwSetCursorPosCallback(gWindow, cursorPosCallback); | |||
glfwSetCursorEnterCallback(gWindow, cursorEnterCallback); | |||
glfwSetScrollCallback(gWindow, scrollCallback); | |||
@@ -293,6 +316,7 @@ void guiRun() { | |||
glfwGetCursorPos(gWindow, &xpos, &ypos); | |||
cursorPosCallback(gWindow, xpos, ypos); | |||
} | |||
mouseButtonStickyPop(); | |||
// Set window title | |||
std::string title = gApplicationName + " " + gApplicationVersion; | |||
@@ -15,6 +15,31 @@ static NVGcolor getNVGColor(uint32_t color) { | |||
(color >> 24) & 0xff); | |||
} | |||
static NVGpaint getPaint(NVGcontext *vg, NSVGpaint *p) { | |||
assert(p->type == NSVG_PAINT_LINEAR_GRADIENT || p->type == NSVG_PAINT_RADIAL_GRADIENT); | |||
NSVGgradient *g = p->gradient; | |||
assert(g->nstops >= 1); | |||
NVGcolor icol = getNVGColor(g->stops[0].color); | |||
NVGcolor ocol = getNVGColor(g->stops[g->nstops - 1].color); | |||
float inverse[6]; | |||
nvgTransformInverse(inverse, g->xform); | |||
DEBUG_ONLY(printf(" inverse: %f %f %f %f %f %f\n", inverse[0], inverse[1], inverse[2], inverse[3], inverse[4], inverse[5]);) | |||
Vec s, e; | |||
DEBUG_ONLY(printf(" sx: %f sy: %f ex: %f ey: %f\n", s.x, s.y, e.x, e.y);) | |||
// Is it always the case that the gradient should be transformed from (0, 0) to (0, 1)? | |||
nvgTransformPoint(&s.x, &s.y, inverse, 0, 0); | |||
nvgTransformPoint(&e.x, &e.y, inverse, 0, 1); | |||
DEBUG_ONLY(printf(" sx: %f sy: %f ex: %f ey: %f\n", s.x, s.y, e.x, e.y);) | |||
NVGpaint paint; | |||
if (p->type == NSVG_PAINT_LINEAR_GRADIENT) | |||
paint = nvgLinearGradient(vg, s.x, s.y, e.x, e.y, icol, ocol); | |||
else | |||
paint = nvgRadialGradient(vg, s.x, s.y, 0.0, 160, icol, ocol); | |||
return paint; | |||
} | |||
/** Returns the parameterized value of the line p2--p3 where it intersects with p0--p1 */ | |||
static float getLineCrossing(Vec p0, Vec p1, Vec p2, Vec p3) { | |||
Vec b = p2.minus(p0); | |||
@@ -121,30 +146,15 @@ static void drawSVG(NVGcontext *vg, NSVGimage *svg) { | |||
nvgFillColor(vg, color); | |||
DEBUG_ONLY(printf(" fill color (%g, %g, %g, %g)\n", color.r, color.g, color.b, color.a);) | |||
} break; | |||
case NSVG_PAINT_LINEAR_GRADIENT: { | |||
NSVGgradient *g = shape->fill.gradient; | |||
(void)g; | |||
DEBUG_ONLY(printf(" linear gradient: %f\t%f\n", g->fx, g->fy);) | |||
} break; | |||
case NSVG_PAINT_LINEAR_GRADIENT: | |||
case NSVG_PAINT_RADIAL_GRADIENT: { | |||
NSVGgradient *g = shape->fill.gradient; | |||
DEBUG_ONLY(printf(" radial gradient: %f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\n", g->fx, g->fy, g->xform[0], g->xform[1], g->xform[2], g->xform[3], g->xform[4], g->xform[5]);) | |||
(void)g; | |||
DEBUG_ONLY(printf(" gradient: type: %s xform: %f %f %f %f %f %f spread: %d fx: %f fy: %f nstops: %d\n", (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT ? "linear" : "radial"), g->xform[0], g->xform[1], g->xform[2], g->xform[3], g->xform[4], g->xform[5], g->spread, g->fx, g->fy, g->nstops);) | |||
for (int i = 0; i < g->nstops; i++) { | |||
DEBUG_ONLY(printf(" stop: #%08x\t%f\n", g->stops[i].color, g->stops[i].offset);) | |||
} | |||
assert(g->nstops >= 1); | |||
NVGcolor color0 = getNVGColor(g->stops[0].color); | |||
NVGcolor color1 = getNVGColor(g->stops[g->nstops - 1].color); | |||
float inverse[6]; | |||
// Rect shapeBox = Rect::fromMinMax(Vec(shape->bounds[0], shape->bounds[1]), Vec(shape->bounds[2], shape->bounds[3])); | |||
nvgTransformInverse(inverse, g->xform); | |||
Vec c; | |||
nvgTransformPoint(&c.x, &c.y, inverse, 5, 5); | |||
printf("%f %f\n", c.x, c.y); | |||
NVGpaint paint = nvgRadialGradient(vg, c.x, c.y, 0.0, 160, color0, color1); | |||
nvgFillPaint(vg, paint); | |||
nvgFillPaint(vg, getPaint(vg, &shape->fill)); | |||
} break; | |||
} | |||
nvgFill(vg); | |||
@@ -171,6 +181,9 @@ static void drawSVG(NVGcontext *vg, NSVGimage *svg) { | |||
} | |||
nvgRestore(vg); | |||
// if (std::string(shape->id) == "rect19347") | |||
// exit(0); | |||
} | |||
DEBUG_ONLY(printf("\n");) | |||
@@ -8,13 +8,13 @@ namespace rack { | |||
void ScrollBar::draw(NVGcontext *vg) { | |||
ScrollWidget *scrollWidget = dynamic_cast<ScrollWidget*>(parent); | |||
assert(scrollWidget); | |||
Vec containerCorner = scrollWidget->container->getChildrenBoundingBox().getBottomRight(); | |||
Vec viewportCorner = scrollWidget->container->getChildrenBoundingBox().getBottomRight(); | |||
float containerSize = (orientation == HORIZONTAL) ? containerCorner.x : containerCorner.y; | |||
float boxSize = (orientation == HORIZONTAL) ? box.size.x : box.size.y; | |||
float offset = (orientation == HORIZONTAL) ? scrollWidget->offset.x : scrollWidget->offset.y; | |||
offset = offset / (containerSize - boxSize); | |||
float size = boxSize / containerSize; | |||
float viewportSize = (orientation == HORIZONTAL) ? viewportCorner.x : viewportCorner.y; | |||
float containerSize = (orientation == HORIZONTAL) ? scrollWidget->box.size.x : scrollWidget->box.size.y; | |||
float viewportOffset = (orientation == HORIZONTAL) ? scrollWidget->offset.x : scrollWidget->offset.y; | |||
float offset = viewportOffset / (viewportSize - containerSize); | |||
float size = containerSize / viewportSize; | |||
size = clampf(size, 0.0, 1.0); | |||
bndScrollBar(vg, 0.0, 0.0, box.size.x, box.size.y, state, offset, size); | |||
} | |||