@@ -39,6 +39,7 @@ struct PortWidget : widget::OpaqueWidget { | |||||
void onDragDrop(const DragDropEvent& e) override; | void onDragDrop(const DragDropEvent& e) override; | ||||
void onDragEnter(const DragEnterEvent& e) override; | void onDragEnter(const DragEnterEvent& e) override; | ||||
void onDragLeave(const DragLeaveEvent& e) override; | void onDragLeave(const DragLeaveEvent& e) override; | ||||
void onContextDestroy(const ContextDestroyEvent& e) override; | |||||
}; | }; | ||||
@@ -0,0 +1,213 @@ | |||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||||
<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> | |||||
<svg | |||||
version="1.0" | |||||
id="svg15246" | |||||
x="0px" | |||||
y="0px" | |||||
width="15.8003px" | |||||
height="15.8003px" | |||||
viewBox="0 0 15.8003 15.8003" | |||||
enable-background="new 0 0 15.8003 15.8003" | |||||
xml:space="preserve" | |||||
sodipodi:docname="PlugPort.svg" | |||||
inkscape:version="1.1 (c4e8f9ed74, 2021-05-24)" | |||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||||
xmlns="http://www.w3.org/2000/svg" | |||||
xmlns:svg="http://www.w3.org/2000/svg"><defs | |||||
id="defs157" /> | |||||
<linearGradient | |||||
id="SVGID_2_" | |||||
gradientUnits="userSpaceOnUse" | |||||
x1="355.22113" | |||||
y1="-3759.56128" | |||||
x2="377.73505" | |||||
y2="-3759.56128" | |||||
gradientTransform="matrix(0 1 -1 0 -4696.65137 578.8092)"> | |||||
<stop | |||||
offset="0.00559" | |||||
style="stop-color:#FFFFFF" | |||||
id="stop11" /> | |||||
<stop | |||||
offset="1" | |||||
style="stop-color:#454545" | |||||
id="stop13" /> | |||||
</linearGradient> | |||||
<linearGradient | |||||
id="SVGID_3_" | |||||
gradientUnits="userSpaceOnUse" | |||||
x1="-8019.91748" | |||||
y1="2332.14722" | |||||
x2="-8002.08936" | |||||
y2="2332.14722" | |||||
gradientTransform="matrix(0 -1 1 0 -3269.23706 -7065.71631)"> | |||||
<stop | |||||
offset="0.00559" | |||||
style="stop-color:#FFFFFF" | |||||
id="stop20" /> | |||||
<stop | |||||
offset="1" | |||||
style="stop-color:#454545" | |||||
id="stop22" /> | |||||
</linearGradient> | |||||
<linearGradient | |||||
id="SVGID_4_" | |||||
gradientUnits="userSpaceOnUse" | |||||
x1="-6757.92383" | |||||
y1="3834.65601" | |||||
x2="-6757.92383" | |||||
y2="3849.91846" | |||||
gradientTransform="matrix(-1 0 0 1 -7695.01367 -2897)"> | |||||
<stop | |||||
offset="0" | |||||
style="stop-color:#FFFEFE" | |||||
id="stop31" /> | |||||
<stop | |||||
offset="1" | |||||
style="stop-color:#5E5E5E" | |||||
id="stop33" /> | |||||
</linearGradient> | |||||
<linearGradient | |||||
id="SVGID_5_" | |||||
gradientUnits="userSpaceOnUse" | |||||
x1="-6757.92383" | |||||
y1="3848.08325" | |||||
x2="-6757.92383" | |||||
y2="3836.49146" | |||||
gradientTransform="matrix(-1 0 0 1 -7695.01367 -2897)"> | |||||
<stop | |||||
offset="0" | |||||
style="stop-color:#FFFEFE" | |||||
id="stop40" /> | |||||
<stop | |||||
offset="1" | |||||
style="stop-color:#383636" | |||||
id="stop42" /> | |||||
</linearGradient> | |||||
<sodipodi:namedview | |||||
bordercolor="#666666" | |||||
borderopacity="1.0" | |||||
fit-margin-bottom="0" | |||||
fit-margin-left="0" | |||||
fit-margin-right="0" | |||||
fit-margin-top="0" | |||||
id="base" | |||||
inkscape:current-layer="svg15246" | |||||
inkscape:cx="9.7740969" | |||||
inkscape:cy="20.981046" | |||||
inkscape:document-units="mm" | |||||
inkscape:pageopacity="0.0" | |||||
inkscape:pageshadow="2" | |||||
inkscape:snap-bbox="true" | |||||
inkscape:snap-bbox-midpoints="true" | |||||
inkscape:snap-nodes="false" | |||||
inkscape:snap-others="false" | |||||
inkscape:window-height="882" | |||||
inkscape:window-maximized="0" | |||||
inkscape:window-width="1600" | |||||
inkscape:window-x="0" | |||||
inkscape:window-y="18" | |||||
inkscape:zoom="9.7707237" | |||||
pagecolor="#ffffff" | |||||
showgrid="false" | |||||
units="px" | |||||
inkscape:pagecheckerboard="0"> | |||||
</sodipodi:namedview> | |||||
<linearGradient | |||||
id="SVGID_11_" | |||||
gradientUnits="userSpaceOnUse" | |||||
x1="-8066.65869" | |||||
y1="2299.03101" | |||||
x2="-8048.83008" | |||||
y2="2299.03101" | |||||
gradientTransform="matrix(0 -1 1 0 -3269.23706 -7065.71631)"> | |||||
<stop | |||||
offset="0" | |||||
style="stop-color:#8C8B8B" | |||||
id="stop93" /> | |||||
<stop | |||||
offset="1" | |||||
style="stop-color:#454545" | |||||
id="stop95" /> | |||||
</linearGradient> | |||||
<linearGradient | |||||
id="SVGID_16_" | |||||
gradientUnits="userSpaceOnUse" | |||||
x1="-2831.54297" | |||||
y1="3096.30811" | |||||
x2="-2831.54297" | |||||
y2="3080.50781" | |||||
gradientTransform="matrix(1 0 0 1 2839.44287 -3080.50781)"> | |||||
<stop | |||||
offset="0" | |||||
style="stop-color:#FFFEFE" | |||||
id="stop138" /> | |||||
<stop | |||||
offset="1" | |||||
style="stop-color:#0A0A0A" | |||||
id="stop140" /> | |||||
</linearGradient> | |||||
<circle | |||||
opacity="0.32" | |||||
fill="url(#SVGID_16_)" | |||||
cx="7.90013" | |||||
cy="7.90013" | |||||
r="7.90013" | |||||
id="circle143" /> | |||||
<circle | |||||
fill="#E0E0E0" | |||||
cx="7.90013" | |||||
cy="7.90013" | |||||
r="6.46479" | |||||
id="circle145" /> | |||||
<linearGradient | |||||
id="SVGID_17_" | |||||
gradientUnits="userSpaceOnUse" | |||||
x1="-2802.25293" | |||||
y1="3043.80615" | |||||
x2="-2813.42529" | |||||
y2="3043.80615" | |||||
gradientTransform="matrix(-3.491481e-15 1 -1 -3.491481e-15 3051.7063 2815.73926)"> | |||||
<stop | |||||
offset="0" | |||||
style="stop-color:#FFFEFE" | |||||
id="stop147" /> | |||||
<stop | |||||
offset="1" | |||||
style="stop-color:#706C6C" | |||||
id="stop149" /> | |||||
</linearGradient> | |||||
<circle | |||||
fill="url(#SVGID_17_)" | |||||
cx="7.90013" | |||||
cy="7.90013" | |||||
r="5.58624" | |||||
id="circle152" /> | |||||
<circle | |||||
cx="7.90013" | |||||
cy="7.90013" | |||||
r="4.82294" | |||||
id="circle154" /> | |||||
</svg> |
@@ -4,6 +4,7 @@ | |||||
#include <window.hpp> | #include <window.hpp> | ||||
#include <context.hpp> | #include <context.hpp> | ||||
#include <patch.hpp> | #include <patch.hpp> | ||||
#include <asset.hpp> | |||||
#include <settings.hpp> | #include <settings.hpp> | ||||
#include <engine/Engine.hpp> | #include <engine/Engine.hpp> | ||||
#include <engine/Port.hpp> | #include <engine/Port.hpp> | ||||
@@ -13,12 +14,20 @@ namespace rack { | |||||
namespace app { | namespace app { | ||||
struct CableWidget::Internal { | |||||
std::shared_ptr<Svg> plugPortSvg; | |||||
}; | |||||
CableWidget::CableWidget() { | CableWidget::CableWidget() { | ||||
internal = new Internal; | |||||
color = color::BLACK_TRANSPARENT; | color = color::BLACK_TRANSPARENT; | ||||
internal->plugPortSvg = Svg::load(asset::system("res/ComponentLibrary/PlugPort.svg")); | |||||
} | } | ||||
CableWidget::~CableWidget() { | CableWidget::~CableWidget() { | ||||
setCable(NULL); | setCable(NULL); | ||||
delete internal; | |||||
} | } | ||||
void CableWidget::setNextCableColor() { | void CableWidget::setNextCableColor() { | ||||
@@ -115,36 +124,43 @@ void CableWidget::fromJson(json_t* rootJ) { | |||||
} | } | ||||
} | } | ||||
static void drawPlug(NVGcontext* vg, math::Vec pos, NVGcolor color) { | |||||
static void CableWidget_drawPlug(CableWidget* that, const widget::Widget::DrawArgs& args, math::Vec pos, NVGcolor color, bool top) { | |||||
if (!top) | |||||
return; | |||||
NVGcolor colorOutline = nvgLerpRGBA(color, nvgRGBf(0.0, 0.0, 0.0), 0.5); | NVGcolor colorOutline = nvgLerpRGBA(color, nvgRGBf(0.0, 0.0, 0.0), 0.5); | ||||
nvgSave(args.vg); | |||||
nvgTranslate(args.vg, pos.x, pos.y); | |||||
// Plug solid | // Plug solid | ||||
nvgBeginPath(vg); | |||||
nvgCircle(vg, pos.x, pos.y, 9); | |||||
nvgFillColor(vg, color); | |||||
nvgFill(vg); | |||||
nvgBeginPath(args.vg); | |||||
nvgCircle(args.vg, 0.0, 0.0, 9); | |||||
nvgFillColor(args.vg, color); | |||||
nvgFill(args.vg); | |||||
// Border | // Border | ||||
nvgStrokeWidth(vg, 1.0); | |||||
nvgStrokeColor(vg, colorOutline); | |||||
nvgStroke(vg); | |||||
// Hole | |||||
nvgBeginPath(vg); | |||||
nvgCircle(vg, pos.x, pos.y, 5); | |||||
nvgFillColor(vg, nvgRGBf(0.0, 0.0, 0.0)); | |||||
nvgFill(vg); | |||||
nvgStrokeWidth(args.vg, 1.0); | |||||
nvgStrokeColor(args.vg, colorOutline); | |||||
nvgStroke(args.vg); | |||||
// Port | |||||
std::shared_ptr<Svg> plugPortSvg = that->internal->plugPortSvg; | |||||
math::Vec plugPortSize = plugPortSvg->getSize(); | |||||
nvgTranslate(args.vg, VEC_ARGS(plugPortSize.div(2).neg())); | |||||
plugPortSvg->draw(args.vg); | |||||
nvgRestore(args.vg); | |||||
} | } | ||||
static void drawCable(NVGcontext* vg, math::Vec pos1, math::Vec pos2, NVGcolor color, float thickness, float tension, float opacity) { | |||||
static void CableWidget_drawCable(CableWidget* that, const widget::Widget::DrawArgs& args, math::Vec pos1, math::Vec pos2, NVGcolor color, float thickness, float tension, float opacity) { | |||||
NVGcolor colorShadow = nvgRGBAf(0, 0, 0, 0.10); | NVGcolor colorShadow = nvgRGBAf(0, 0, 0, 0.10); | ||||
NVGcolor colorOutline = nvgLerpRGBA(color, nvgRGBf(0.0, 0.0, 0.0), 0.5); | NVGcolor colorOutline = nvgLerpRGBA(color, nvgRGBf(0.0, 0.0, 0.0), 0.5); | ||||
// Cable | // Cable | ||||
if (opacity > 0.0) { | if (opacity > 0.0) { | ||||
nvgSave(vg); | |||||
nvgSave(args.vg); | |||||
// This power scaling looks more linear than actual linear scaling | // This power scaling looks more linear than actual linear scaling | ||||
nvgGlobalAlpha(vg, std::pow(opacity, 1.5)); | |||||
nvgGlobalAlpha(args.vg, std::pow(opacity, 1.5)); | |||||
float dist = pos1.minus(pos2).norm(); | float dist = pos1.minus(pos2).norm(); | ||||
math::Vec slump; | math::Vec slump; | ||||
@@ -155,31 +171,31 @@ static void drawCable(NVGcontext* vg, math::Vec pos1, math::Vec pos2, NVGcolor c | |||||
pos1 = pos1.plus(pos3.minus(pos1).normalize().mult(9)); | pos1 = pos1.plus(pos3.minus(pos1).normalize().mult(9)); | ||||
pos2 = pos2.plus(pos3.minus(pos2).normalize().mult(9)); | pos2 = pos2.plus(pos3.minus(pos2).normalize().mult(9)); | ||||
nvgLineJoin(vg, NVG_ROUND); | |||||
nvgLineJoin(args.vg, NVG_ROUND); | |||||
// Shadow | // Shadow | ||||
math::Vec pos4 = pos3.plus(slump.mult(0.08)); | math::Vec pos4 = pos3.plus(slump.mult(0.08)); | ||||
nvgBeginPath(vg); | |||||
nvgMoveTo(vg, pos1.x, pos1.y); | |||||
nvgQuadTo(vg, pos4.x, pos4.y, pos2.x, pos2.y); | |||||
nvgStrokeColor(vg, colorShadow); | |||||
nvgStrokeWidth(vg, thickness); | |||||
nvgStroke(vg); | |||||
nvgBeginPath(args.vg); | |||||
nvgMoveTo(args.vg, pos1.x, pos1.y); | |||||
nvgQuadTo(args.vg, pos4.x, pos4.y, pos2.x, pos2.y); | |||||
nvgStrokeColor(args.vg, colorShadow); | |||||
nvgStrokeWidth(args.vg, thickness); | |||||
nvgStroke(args.vg); | |||||
// Cable outline | // Cable outline | ||||
nvgBeginPath(vg); | |||||
nvgMoveTo(vg, pos1.x, pos1.y); | |||||
nvgQuadTo(vg, pos3.x, pos3.y, pos2.x, pos2.y); | |||||
nvgStrokeColor(vg, colorOutline); | |||||
nvgStrokeWidth(vg, thickness); | |||||
nvgStroke(vg); | |||||
nvgBeginPath(args.vg); | |||||
nvgMoveTo(args.vg, pos1.x, pos1.y); | |||||
nvgQuadTo(args.vg, pos3.x, pos3.y, pos2.x, pos2.y); | |||||
nvgStrokeColor(args.vg, colorOutline); | |||||
nvgStrokeWidth(args.vg, thickness); | |||||
nvgStroke(args.vg); | |||||
// Cable solid | // Cable solid | ||||
nvgStrokeColor(vg, color); | |||||
nvgStrokeWidth(vg, thickness - 2); | |||||
nvgStroke(vg); | |||||
nvgStrokeColor(args.vg, color); | |||||
nvgStrokeWidth(args.vg, thickness - 2); | |||||
nvgStroke(args.vg); | |||||
nvgRestore(vg); | |||||
nvgRestore(args.vg); | |||||
} | } | ||||
} | } | ||||
@@ -212,33 +228,36 @@ void CableWidget::draw(const DrawArgs& args) { | |||||
math::Vec outputPos = getOutputPos(); | math::Vec outputPos = getOutputPos(); | ||||
math::Vec inputPos = getInputPos(); | math::Vec inputPos = getInputPos(); | ||||
drawCable(args.vg, outputPos, inputPos, color, thickness, tension, opacity); | |||||
CableWidget_drawCable(this, args, outputPos, inputPos, color, thickness, tension, opacity); | |||||
} | } | ||||
void CableWidget::drawPlugs(const DrawArgs& args) { | void CableWidget::drawPlugs(const DrawArgs& args) { | ||||
// Draw output plug | |||||
math::Vec outputPos = getOutputPos(); | math::Vec outputPos = getOutputPos(); | ||||
math::Vec inputPos = getInputPos(); | |||||
// Draw plug if the cable is on top, or if the cable is incomplete | |||||
if (!isComplete() || APP->scene->rack->getTopCable(outputPort) == this) { | |||||
drawPlug(args.vg, outputPos, color); | |||||
if (isComplete()) { | |||||
// Draw plug light | |||||
nvgSave(args.vg); | |||||
nvgTranslate(args.vg, outputPos.x - 4, outputPos.y - 4); | |||||
outputPort->getPlugLight()->draw(args); | |||||
nvgRestore(args.vg); | |||||
} | |||||
bool outputTop = !isComplete() || APP->scene->rack->getTopCable(outputPort) == this; | |||||
CableWidget_drawPlug(this, args, outputPos, color, outputTop); | |||||
if (outputTop && isComplete()) { | |||||
// Draw output plug light | |||||
nvgSave(args.vg); | |||||
LightWidget* plugLight = outputPort->getPlugLight(); | |||||
math::Vec plugPos = outputPos.minus(plugLight->getSize().div(2)); | |||||
nvgTranslate(args.vg, VEC_ARGS(plugPos)); | |||||
plugLight->draw(args); | |||||
nvgRestore(args.vg); | |||||
} | } | ||||
if (!isComplete() || APP->scene->rack->getTopCable(inputPort) == this) { | |||||
drawPlug(args.vg, inputPos, color); | |||||
if (isComplete()) { | |||||
nvgSave(args.vg); | |||||
nvgTranslate(args.vg, inputPos.x - 4, inputPos.y - 4); | |||||
inputPort->getPlugLight()->draw(args); | |||||
nvgRestore(args.vg); | |||||
} | |||||
// Draw input plug | |||||
math::Vec inputPos = getInputPos(); | |||||
bool inputTop = !isComplete() || APP->scene->rack->getTopCable(inputPort) == this; | |||||
CableWidget_drawPlug(this, args, inputPos, color, inputTop); | |||||
if (inputTop && isComplete()) { | |||||
// Draw input plug light | |||||
nvgSave(args.vg); | |||||
LightWidget* plugLight = inputPort->getPlugLight(); | |||||
math::Vec plugPos = inputPos.minus(plugLight->getSize().div(2)); | |||||
nvgTranslate(args.vg, VEC_ARGS(plugPos)); | |||||
plugLight->draw(args); | |||||
nvgRestore(args.vg); | |||||
} | } | ||||
} | } | ||||
@@ -63,36 +63,33 @@ struct PortTooltip : ui::Tooltip { | |||||
}; | }; | ||||
struct PlugLight : MultiLightWidget { | |||||
PlugLight() { | |||||
addBaseColor(componentlibrary::SCHEME_GREEN); | |||||
addBaseColor(componentlibrary::SCHEME_RED); | |||||
addBaseColor(componentlibrary::SCHEME_BLUE); | |||||
box.size = math::Vec(8, 8); | |||||
bgColor = componentlibrary::SCHEME_BLACK_TRANSPARENT; | |||||
} | |||||
}; | |||||
struct PortWidget::Internal { | struct PortWidget::Internal { | ||||
ui::Tooltip* tooltip = NULL; | ui::Tooltip* tooltip = NULL; | ||||
PlugLight* plugLight; | |||||
app::MultiLightWidget* plugLight; | |||||
}; | }; | ||||
PortWidget::PortWidget() { | PortWidget::PortWidget() { | ||||
internal = new Internal; | internal = new Internal; | ||||
using namespace componentlibrary; | |||||
struct PlugLight : TRedGreenBlueLight<TGrayModuleLightWidget<MediumLight<app::MultiLightWidget>>> { | |||||
PlugLight() { | |||||
// fb->bypassed = true; | |||||
fb->oversample = 1.0; | |||||
} | |||||
}; | |||||
internal->plugLight = new PlugLight; | internal->plugLight = new PlugLight; | ||||
} | } | ||||
PortWidget::~PortWidget() { | PortWidget::~PortWidget() { | ||||
// The port shouldn't have any cables when destroyed, but just to make sure. | |||||
if (module) | |||||
APP->scene->rack->clearCablesOnPort(this); | |||||
// HACK: In case onDragDrop() is called but not onLeave() afterwards... | // HACK: In case onDragDrop() is called but not onLeave() afterwards... | ||||
destroyTooltip(); | destroyTooltip(); | ||||
// plugLight is not a child but owned by the PortWidget, so we need to delete it here | // plugLight is not a child but owned by the PortWidget, so we need to delete it here | ||||
delete internal->plugLight; | delete internal->plugLight; | ||||
// The port shouldn't have any cables when destroyed, but just to make sure. | |||||
if (module) | |||||
APP->scene->rack->clearCablesOnPort(this); | |||||
delete internal; | delete internal; | ||||
} | } | ||||
@@ -151,6 +148,7 @@ void PortWidget::step() { | |||||
values[i] = module->inputs[portId].plugLights[i].getBrightness(); | values[i] = module->inputs[portId].plugLights[i].getBrightness(); | ||||
} | } | ||||
internal->plugLight->setBrightnesses(values); | internal->plugLight->setBrightnesses(values); | ||||
internal->plugLight->step(); | |||||
Widget::step(); | Widget::step(); | ||||
} | } | ||||
@@ -336,6 +334,11 @@ void PortWidget::onDragLeave(const DragLeaveEvent& e) { | |||||
} | } | ||||
} | } | ||||
void PortWidget::onContextDestroy(const ContextDestroyEvent& e) { | |||||
internal->plugLight->onContextDestroy(e); | |||||
Widget::onContextDestroy(e); | |||||
} | |||||
} // namespace app | } // namespace app | ||||
} // namespace rack | } // namespace rack |
@@ -60,7 +60,11 @@ struct CableContainer : widget::TransparentWidget { | |||||
for (widget::Widget* w : children) { | for (widget::Widget* w : children) { | ||||
CableWidget* cw = dynamic_cast<CableWidget*>(w); | CableWidget* cw = dynamic_cast<CableWidget*>(w); | ||||
assert(cw); | assert(cw); | ||||
cw->drawPlugs(args); | |||||
DrawArgs childArgs = args; | |||||
// TODO Make clip box equal actual viewport | |||||
childArgs.clipBox = math::Rect::inf(); | |||||
cw->drawPlugs(childArgs); | |||||
} | } | ||||
Widget::draw(args); | Widget::draw(args); | ||||
@@ -433,6 +437,7 @@ void RackWidget::removeModule(ModuleWidget* m) { | |||||
bool RackWidget::requestModulePos(ModuleWidget* mw, math::Vec pos) { | bool RackWidget::requestModulePos(ModuleWidget* mw, math::Vec pos) { | ||||
// Check intersection with other modules | // Check intersection with other modules | ||||
math::Rect mwBox = math::Rect(pos, mw->box.size); | math::Rect mwBox = math::Rect(pos, mw->box.size); | ||||
mwBox.size.x -= 0.01; | |||||
for (widget::Widget* w2 : moduleContainer->children) { | for (widget::Widget* w2 : moduleContainer->children) { | ||||
// Don't intersect with self | // Don't intersect with self | ||||
if (mw == w2) | if (mw == w2) | ||||
@@ -441,7 +446,9 @@ bool RackWidget::requestModulePos(ModuleWidget* mw, math::Vec pos) { | |||||
if (!w2->visible) | if (!w2->visible) | ||||
continue; | continue; | ||||
// Check intersection | // Check intersection | ||||
if (mwBox.intersects(w2->box)) | |||||
math::Rect w2Box = w2->box; | |||||
w2Box.size.x -= 0.01; | |||||
if (mwBox.intersects(w2Box)) | |||||
return false; | return false; | ||||
} | } | ||||
@@ -315,16 +315,12 @@ static void Port_step(Port* that, float deltaTime) { | |||||
} | } | ||||
else if (that->channels == 1) { | else if (that->channels == 1) { | ||||
float v = that->getVoltage() / 10.f; | float v = that->getVoltage() / 10.f; | ||||
that->plugLights[0].setSmoothBrightness(v, deltaTime); | |||||
that->plugLights[1].setSmoothBrightness(-v, deltaTime); | |||||
that->plugLights[0].setSmoothBrightness(-v, deltaTime); | |||||
that->plugLights[1].setSmoothBrightness(v, deltaTime); | |||||
that->plugLights[2].setBrightness(0.f); | that->plugLights[2].setBrightness(0.f); | ||||
} | } | ||||
else { | else { | ||||
float v2 = 0.f; | |||||
for (int c = 0; c < that->channels; c++) { | |||||
v2 += std::pow(that->getVoltage(c), 2); | |||||
} | |||||
float v = std::sqrt(v2) / 10.f; | |||||
float v = that->getVoltageRMS() / 10.f; | |||||
that->plugLights[0].setBrightness(0.f); | that->plugLights[0].setBrightness(0.f); | ||||
that->plugLights[1].setBrightness(0.f); | that->plugLights[1].setBrightness(0.f); | ||||
that->plugLights[2].setSmoothBrightness(v, deltaTime); | that->plugLights[2].setSmoothBrightness(v, deltaTime); | ||||
@@ -105,6 +105,7 @@ void FramebufferWidget::step() { | |||||
// Create a framebuffer | // Create a framebuffer | ||||
if (internal->fbSize.isFinite() && !internal->fbSize.isZero()) { | if (internal->fbSize.isFinite() && !internal->fbSize.isZero()) { | ||||
internal->fb = nvgluCreateFramebuffer(vg, internal->fbSize.x, internal->fbSize.y, 0); | internal->fb = nvgluCreateFramebuffer(vg, internal->fbSize.x, internal->fbSize.y, 0); | ||||
// DEBUG("Created framebuffer of size (%f, %f)", VEC_ARGS(internal->fbSize)); | |||||
} | } | ||||
} | } | ||||
if (!internal->fb) { | if (!internal->fb) { | ||||
@@ -268,15 +268,16 @@ void Widget::draw(const DrawArgs& args) { | |||||
if (!args.clipBox.intersects(child->box)) | if (!args.clipBox.intersects(child->box)) | ||||
continue; | continue; | ||||
DrawArgs childCtx = args; | |||||
DrawArgs childArgs = args; | |||||
// Intersect child clip box with self | // Intersect child clip box with self | ||||
childCtx.clipBox = childCtx.clipBox.intersect(child->box); | |||||
childCtx.clipBox.pos = childCtx.clipBox.pos.minus(child->box.pos); | |||||
childArgs.clipBox = childArgs.clipBox.intersect(child->box); | |||||
// Offset clip box by child pos | |||||
childArgs.clipBox.pos = childArgs.clipBox.pos.minus(child->box.pos); | |||||
nvgSave(args.vg); | nvgSave(args.vg); | ||||
nvgTranslate(args.vg, child->box.pos.x, child->box.pos.y); | nvgTranslate(args.vg, child->box.pos.x, child->box.pos.y); | ||||
child->draw(childCtx); | |||||
child->draw(childArgs); | |||||
#pragma GCC diagnostic push | #pragma GCC diagnostic push | ||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" | ||||