| @@ -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" | ||||