|
@@ -15,6 +15,7 @@ namespace app { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct CableWidget::Internal { |
|
|
struct CableWidget::Internal { |
|
|
|
|
|
std::shared_ptr<Svg> plugSvg; |
|
|
std::shared_ptr<Svg> plugPortSvg; |
|
|
std::shared_ptr<Svg> plugPortSvg; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
@@ -22,6 +23,7 @@ struct CableWidget::Internal { |
|
|
CableWidget::CableWidget() { |
|
|
CableWidget::CableWidget() { |
|
|
internal = new Internal; |
|
|
internal = new Internal; |
|
|
color = color::BLACK_TRANSPARENT; |
|
|
color = color::BLACK_TRANSPARENT; |
|
|
|
|
|
internal->plugSvg = Svg::load(asset::system("res/ComponentLibrary/Plug.svg")); |
|
|
internal->plugPortSvg = Svg::load(asset::system("res/ComponentLibrary/PlugPort.svg")); |
|
|
internal->plugPortSvg = Svg::load(asset::system("res/ComponentLibrary/PlugPort.svg")); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@@ -124,91 +126,96 @@ void CableWidget::fromJson(json_t* rootJ) { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void CableWidget_drawPlug(CableWidget* that, const widget::Widget::DrawArgs& args, math::Vec pos, NVGcolor color, bool top) { |
|
|
|
|
|
|
|
|
static math::Vec getCableSlump(math::Vec pos1, math::Vec pos2) { |
|
|
|
|
|
float dist = pos1.minus(pos2).norm(); |
|
|
|
|
|
math::Vec avg = pos1.plus(pos2).div(2); |
|
|
|
|
|
// Lower average point as distance increases |
|
|
|
|
|
avg.y += (1.0 - settings::cableTension) * (150.0 + 1.0 * dist); |
|
|
|
|
|
return avg; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void CableWidget_drawPlug(CableWidget* that, const widget::Widget::DrawArgs& args, math::Vec pos, math::Vec slump, NVGcolor color, bool top) { |
|
|
if (!top) |
|
|
if (!top) |
|
|
return; |
|
|
return; |
|
|
|
|
|
|
|
|
NVGcolor colorOutline = nvgLerpRGBA(color, nvgRGBf(0.0, 0.0, 0.0), 0.5); |
|
|
|
|
|
nvgSave(args.vg); |
|
|
nvgSave(args.vg); |
|
|
nvgTranslate(args.vg, pos.x, pos.y); |
|
|
nvgTranslate(args.vg, pos.x, pos.y); |
|
|
|
|
|
|
|
|
// Plug solid |
|
|
|
|
|
nvgBeginPath(args.vg); |
|
|
|
|
|
nvgCircle(args.vg, 0.0, 0.0, 9); |
|
|
|
|
|
nvgFillColor(args.vg, color); |
|
|
|
|
|
nvgFill(args.vg); |
|
|
|
|
|
|
|
|
|
|
|
// Border |
|
|
|
|
|
nvgStrokeWidth(args.vg, 1.0); |
|
|
|
|
|
nvgStrokeColor(args.vg, colorOutline); |
|
|
|
|
|
nvgStroke(args.vg); |
|
|
|
|
|
|
|
|
// Plug |
|
|
|
|
|
nvgSave(args.vg); |
|
|
|
|
|
nvgTint(args.vg, color); |
|
|
|
|
|
std::shared_ptr<Svg> plugSvg = that->internal->plugSvg; |
|
|
|
|
|
math::Vec plugSize = plugSvg->getSize(); |
|
|
|
|
|
float angle = slump.minus(pos).arg() - 0.5f * M_PI; |
|
|
|
|
|
nvgRotate(args.vg, angle); |
|
|
|
|
|
nvgTranslate(args.vg, VEC_ARGS(plugSize.div(2).neg())); |
|
|
|
|
|
plugSvg->draw(args.vg); |
|
|
|
|
|
nvgRestore(args.vg); |
|
|
|
|
|
|
|
|
// Port |
|
|
// Port |
|
|
|
|
|
nvgSave(args.vg); |
|
|
std::shared_ptr<Svg> plugPortSvg = that->internal->plugPortSvg; |
|
|
std::shared_ptr<Svg> plugPortSvg = that->internal->plugPortSvg; |
|
|
math::Vec plugPortSize = plugPortSvg->getSize(); |
|
|
math::Vec plugPortSize = plugPortSvg->getSize(); |
|
|
nvgTranslate(args.vg, VEC_ARGS(plugPortSize.div(2).neg())); |
|
|
nvgTranslate(args.vg, VEC_ARGS(plugPortSize.div(2).neg())); |
|
|
plugPortSvg->draw(args.vg); |
|
|
plugPortSvg->draw(args.vg); |
|
|
|
|
|
nvgRestore(args.vg); |
|
|
|
|
|
|
|
|
nvgRestore(args.vg); |
|
|
nvgRestore(args.vg); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
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 colorOutline = nvgLerpRGBA(color, nvgRGBf(0.0, 0.0, 0.0), 0.5); |
|
|
|
|
|
|
|
|
static void CableWidget_drawCable(CableWidget* that, const widget::Widget::DrawArgs& args, math::Vec pos1, math::Vec pos2, NVGcolor color, bool thick, float opacity) { |
|
|
|
|
|
if (opacity <= 0.0) |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
// Cable |
|
|
|
|
|
if (opacity > 0.0) { |
|
|
|
|
|
nvgSave(args.vg); |
|
|
|
|
|
// This power scaling looks more linear than actual linear scaling |
|
|
|
|
|
nvgAlpha(args.vg, std::pow(opacity, 1.5)); |
|
|
|
|
|
|
|
|
|
|
|
float dist = pos1.minus(pos2).norm(); |
|
|
|
|
|
math::Vec slump; |
|
|
|
|
|
slump.y = (1.0 - tension) * (150.0 + 1.0 * dist); |
|
|
|
|
|
math::Vec pos3 = pos1.plus(pos2).div(2).plus(slump); |
|
|
|
|
|
|
|
|
|
|
|
// Adjust pos1 and pos2 to not draw over the plug |
|
|
|
|
|
pos1 = pos1.plus(pos3.minus(pos1).normalize().mult(9)); |
|
|
|
|
|
pos2 = pos2.plus(pos3.minus(pos2).normalize().mult(9)); |
|
|
|
|
|
|
|
|
|
|
|
nvgLineJoin(args.vg, NVG_ROUND); |
|
|
|
|
|
|
|
|
|
|
|
// Shadow |
|
|
|
|
|
math::Vec pos4 = pos3.plus(slump.mult(0.08)); |
|
|
|
|
|
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 |
|
|
|
|
|
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 |
|
|
|
|
|
nvgStrokeColor(args.vg, color); |
|
|
|
|
|
nvgStrokeWidth(args.vg, thickness - 2); |
|
|
|
|
|
nvgStroke(args.vg); |
|
|
|
|
|
|
|
|
float thickness = thick ? 10.0 : 6.0; |
|
|
|
|
|
|
|
|
nvgRestore(args.vg); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// The endpoints are off-center |
|
|
|
|
|
math::Vec slump = getCableSlump(pos1, pos2); |
|
|
|
|
|
pos1 = pos1.plus(slump.minus(pos1).normalize().mult(13.0)); |
|
|
|
|
|
pos2 = pos2.plus(slump.minus(pos2).normalize().mult(13.0)); |
|
|
|
|
|
|
|
|
|
|
|
nvgSave(args.vg); |
|
|
|
|
|
nvgAlpha(args.vg, std::pow(opacity, 1.5)); |
|
|
|
|
|
|
|
|
|
|
|
nvgLineCap(args.vg, NVG_ROUND); |
|
|
|
|
|
// Avoids glitches when cable is bent |
|
|
|
|
|
nvgLineJoin(args.vg, NVG_ROUND); |
|
|
|
|
|
|
|
|
|
|
|
// Shadow |
|
|
|
|
|
math::Vec shadowSlump = slump.plus(math::Vec(0, 30)); |
|
|
|
|
|
nvgBeginPath(args.vg); |
|
|
|
|
|
nvgMoveTo(args.vg, VEC_ARGS(pos1)); |
|
|
|
|
|
nvgQuadTo(args.vg, VEC_ARGS(shadowSlump), VEC_ARGS(pos2)); |
|
|
|
|
|
NVGcolor shadowColor = nvgRGBAf(0, 0, 0, 0.10); |
|
|
|
|
|
nvgStrokeColor(args.vg, shadowColor); |
|
|
|
|
|
nvgStrokeWidth(args.vg, thickness - 1.0); |
|
|
|
|
|
nvgStroke(args.vg); |
|
|
|
|
|
|
|
|
|
|
|
// Cable solid |
|
|
|
|
|
nvgBeginPath(args.vg); |
|
|
|
|
|
nvgMoveTo(args.vg, VEC_ARGS(pos1)); |
|
|
|
|
|
nvgQuadTo(args.vg, VEC_ARGS(slump), VEC_ARGS(pos2)); |
|
|
|
|
|
// nvgStrokePaint(args.vg, nvgLinearGradient(args.vg, VEC_ARGS(pos1), VEC_ARGS(pos2), color::mult(color, 0.5), color)); |
|
|
|
|
|
nvgStrokeColor(args.vg, color::mult(color, 0.75)); |
|
|
|
|
|
nvgStrokeWidth(args.vg, thickness); |
|
|
|
|
|
nvgStroke(args.vg); |
|
|
|
|
|
|
|
|
|
|
|
nvgStrokeColor(args.vg, color); |
|
|
|
|
|
nvgStrokeWidth(args.vg, thickness - 1.0); |
|
|
|
|
|
nvgStroke(args.vg); |
|
|
|
|
|
|
|
|
|
|
|
nvgRestore(args.vg); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void CableWidget::draw(const DrawArgs& args) { |
|
|
void CableWidget::draw(const DrawArgs& args) { |
|
|
float opacity = settings::cableOpacity; |
|
|
float opacity = settings::cableOpacity; |
|
|
float tension = settings::cableTension; |
|
|
|
|
|
float thickness = 5; |
|
|
|
|
|
|
|
|
bool thick = false; |
|
|
|
|
|
|
|
|
if (isComplete()) { |
|
|
if (isComplete()) { |
|
|
engine::Output* output = &cable->outputModule->outputs[cable->outputId]; |
|
|
engine::Output* output = &cable->outputModule->outputs[cable->outputId]; |
|
|
// Increase thickness if output port is polyphonic |
|
|
// Increase thickness if output port is polyphonic |
|
|
if (output->channels > 1) { |
|
|
if (output->channels > 1) { |
|
|
thickness = 9; |
|
|
|
|
|
|
|
|
thick = true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Draw opaque if mouse is hovering over a connected port |
|
|
// Draw opaque if mouse is hovering over a connected port |
|
@@ -228,14 +235,17 @@ void CableWidget::draw(const DrawArgs& args) { |
|
|
|
|
|
|
|
|
math::Vec outputPos = getOutputPos(); |
|
|
math::Vec outputPos = getOutputPos(); |
|
|
math::Vec inputPos = getInputPos(); |
|
|
math::Vec inputPos = getInputPos(); |
|
|
CableWidget_drawCable(this, args, outputPos, inputPos, color, thickness, tension, opacity); |
|
|
|
|
|
|
|
|
CableWidget_drawCable(this, args, outputPos, inputPos, color, thick, 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(); |
|
|
|
|
|
math::Vec slump = getCableSlump(outputPos, inputPos); |
|
|
|
|
|
|
|
|
|
|
|
// Draw output plug |
|
|
bool outputTop = !isComplete() || APP->scene->rack->getTopCable(outputPort) == this; |
|
|
bool outputTop = !isComplete() || APP->scene->rack->getTopCable(outputPort) == this; |
|
|
CableWidget_drawPlug(this, args, outputPos, color, outputTop); |
|
|
|
|
|
|
|
|
CableWidget_drawPlug(this, args, outputPos, slump, color, outputTop); |
|
|
if (outputTop && isComplete()) { |
|
|
if (outputTop && isComplete()) { |
|
|
// Draw output plug light |
|
|
// Draw output plug light |
|
|
nvgSave(args.vg); |
|
|
nvgSave(args.vg); |
|
@@ -247,9 +257,8 @@ void CableWidget::drawPlugs(const DrawArgs& args) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Draw input plug |
|
|
// Draw input plug |
|
|
math::Vec inputPos = getInputPos(); |
|
|
|
|
|
bool inputTop = !isComplete() || APP->scene->rack->getTopCable(inputPort) == this; |
|
|
bool inputTop = !isComplete() || APP->scene->rack->getTopCable(inputPort) == this; |
|
|
CableWidget_drawPlug(this, args, inputPos, color, inputTop); |
|
|
|
|
|
|
|
|
CableWidget_drawPlug(this, args, inputPos, slump, color, inputTop); |
|
|
if (inputTop && isComplete()) { |
|
|
if (inputTop && isComplete()) { |
|
|
// Draw input plug light |
|
|
// Draw input plug light |
|
|
nvgSave(args.vg); |
|
|
nvgSave(args.vg); |
|
|