Browse Source

Implement LEDSlider using new template class structure.

tags/v2.0.0
Andrew Belt 3 years ago
parent
commit
65666c23ac
6 changed files with 125 additions and 76 deletions
  1. +1
    -0
      include/app/LightWidget.hpp
  2. +2
    -0
      include/app/SvgSlider.hpp
  3. +77
    -54
      include/componentlibrary.hpp
  4. +18
    -13
      src/app/LightWidget.cpp
  5. +6
    -2
      src/app/ModuleLightWidget.cpp
  6. +21
    -7
      src/app/SvgSlider.cpp

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

@@ -13,6 +13,7 @@ struct LightWidget : widget::TransparentWidget {
NVGcolor borderColor = nvgRGBA(0, 0, 0, 0);

void draw(const DrawArgs& args) override;
virtual void drawBackground(const DrawArgs& args);
virtual void drawLight(const DrawArgs& args);
virtual void drawHalo(const DrawArgs& args);
};


+ 2
- 0
include/app/SvgSlider.hpp View File

@@ -23,6 +23,8 @@ struct SvgSlider : app::SliderKnob {
void setBackgroundSvg(std::shared_ptr<Svg> svg);
void setHandleSvg(std::shared_ptr<Svg> svg);
void onChange(const ChangeEvent& e) override;
void setHandlePos(math::Vec minHandlePos, math::Vec maxHandlePos);
void setHandlePosCentered(math::Vec minHandlePosCentered, math::Vec maxHandlePosCentered);

DEPRECATED void setBackgroundSVG(std::shared_ptr<Svg> svg) {
setBackgroundSvg(svg);


+ 77
- 54
include/componentlibrary.hpp View File

@@ -53,7 +53,7 @@ Many of these classes use CRTP (https://en.wikipedia.org/wiki/Curiously_recurrin

To use a red light with its default base class for example, use `RedLight` or `TRedLight<>`. (They are synonymous.)

Use the `Base` template argument if you want a different base class.
Use the `TBase` template argument if you want a different base class.
E.g. `RectangleLight<RedLight>`

Although this paradigm might seem confusing at first, it ends up being extremely simple in your plugin code and perfect for "decorating" your classes with appearance traits and behavioral properties.
@@ -62,8 +62,8 @@ For example, need a slider with a green LED? Just use
createLightParamCentered<LEDLightSlider<GreenLight>>(...)
*/

template <typename Base = app::ModuleLightWidget>
struct TSvgLight : Base {
template <typename TBase = app::ModuleLightWidget>
struct TSvgLight : TBase {
widget::FramebufferWidget* fb;
widget::SvgWidget* sw;

@@ -83,8 +83,8 @@ struct TSvgLight : Base {
};
typedef TSvgLight<> SvgLight;

template <typename Base = app::ModuleLightWidget>
struct TGrayModuleLightWidget : Base {
template <typename TBase = app::ModuleLightWidget>
struct TGrayModuleLightWidget : TBase {
TGrayModuleLightWidget() {
this->bgColor = nvgRGBA(0x33, 0x33, 0x33, 0xff);
this->borderColor = nvgRGBA(0, 0, 0, 53);
@@ -92,40 +92,40 @@ struct TGrayModuleLightWidget : Base {
};
typedef TGrayModuleLightWidget<> GrayModuleLightWidget;

template <typename Base = GrayModuleLightWidget>
struct TRedLight : Base {
template <typename TBase = GrayModuleLightWidget>
struct TRedLight : TBase {
TRedLight() {
this->addBaseColor(SCHEME_RED);
}
};
typedef TRedLight<> RedLight;

template <typename Base = GrayModuleLightWidget>
struct TGreenLight : Base {
template <typename TBase = GrayModuleLightWidget>
struct TGreenLight : TBase {
TGreenLight() {
this->addBaseColor(SCHEME_GREEN);
}
};
typedef TGreenLight<> GreenLight;

template <typename Base = GrayModuleLightWidget>
struct TYellowLight : Base {
template <typename TBase = GrayModuleLightWidget>
struct TYellowLight : TBase {
TYellowLight() {
this->addBaseColor(SCHEME_YELLOW);
}
};
typedef TYellowLight<> YellowLight;

template <typename Base = GrayModuleLightWidget>
struct TBlueLight : Base {
template <typename TBase = GrayModuleLightWidget>
struct TBlueLight : TBase {
TBlueLight() {
this->addBaseColor(SCHEME_BLUE);
}
};
typedef TBlueLight<> BlueLight;

template <typename Base = GrayModuleLightWidget>
struct TWhiteLight : Base {
template <typename TBase = GrayModuleLightWidget>
struct TWhiteLight : TBase {
TWhiteLight() {
this->addBaseColor(SCHEME_WHITE);
}
@@ -133,8 +133,8 @@ struct TWhiteLight : Base {
typedef TWhiteLight<> WhiteLight;

/** Reads two adjacent lightIds, so `lightId` and `lightId + 1` must be defined */
template <typename Base = GrayModuleLightWidget>
struct TGreenRedLight : Base {
template <typename TBase = GrayModuleLightWidget>
struct TGreenRedLight : TBase {
TGreenRedLight() {
this->addBaseColor(SCHEME_GREEN);
this->addBaseColor(SCHEME_RED);
@@ -142,8 +142,8 @@ struct TGreenRedLight : Base {
};
typedef TGreenRedLight<> GreenRedLight;

template <typename Base = GrayModuleLightWidget>
struct TRedGreenBlueLight : Base {
template <typename TBase = GrayModuleLightWidget>
struct TRedGreenBlueLight : TBase {
TRedGreenBlueLight() {
this->addBaseColor(SCHEME_RED);
this->addBaseColor(SCHEME_GREEN);
@@ -153,40 +153,42 @@ struct TRedGreenBlueLight : Base {
typedef TRedGreenBlueLight<> RedGreenBlueLight;

/** Based on the size of 5mm LEDs */
template <typename Base>
struct LargeLight : TSvgLight<Base> {
template <typename TBase>
struct LargeLight : TSvgLight<TBase> {
LargeLight() {
this->setSvg(Svg::load(asset::system("res/ComponentLibrary/LargeLight.svg")));
}
};

/** Based on the size of 3mm LEDs */
template <typename Base>
struct MediumLight : TSvgLight<Base> {
template <typename TBase>
struct MediumLight : TSvgLight<TBase> {
MediumLight() {
this->setSvg(Svg::load(asset::system("res/ComponentLibrary/MediumLight.svg")));
}
};

/** Based on the size of 2mm LEDs */
template <typename Base>
struct SmallLight : TSvgLight<Base> {
template <typename TBase>
struct SmallLight : TSvgLight<TBase> {
SmallLight() {
this->setSvg(Svg::load(asset::system("res/ComponentLibrary/SmallLight.svg")));
}
};

/** Based on the size of 1mm LEDs */
template <typename Base>
struct TinyLight : TSvgLight<Base> {
template <typename TBase>
struct TinyLight : TSvgLight<TBase> {
TinyLight() {
this->setSvg(Svg::load(asset::system("res/ComponentLibrary/TinyLight.svg")));
}
};

template <typename Base>
struct RectangleLight : Base {
void drawLight(const widget::Widget::DrawArgs& args) override {
template <typename TBase>
struct RectangleLight : TBase {
void drawBackground(const widget::Widget::DrawArgs& args) override {
// Derived from LightWidget::drawBackground()

nvgBeginPath(args.vg);
nvgRect(args.vg, 0, 0, this->box.size.x, this->box.size.y);

@@ -196,12 +198,6 @@ struct RectangleLight : Base {
nvgFill(args.vg);
}

// Foreground
if (this->color.a > 0.0) {
nvgFillColor(args.vg, this->color);
nvgFill(args.vg);
}

// Border
if (this->borderColor.a > 0.0) {
nvgStrokeWidth(args.vg, 0.5);
@@ -209,11 +205,24 @@ struct RectangleLight : Base {
nvgStroke(args.vg);
}
}

void drawLight(const widget::Widget::DrawArgs& args) override {
// Derived from LightWidget::drawLight()

// Foreground
if (this->color.a > 0.0) {
nvgBeginPath(args.vg);
nvgRect(args.vg, 0, 0, this->box.size.x, this->box.size.y);

nvgFillColor(args.vg, this->color);
nvgFill(args.vg);
}
}
};

/** A light for displaying on top of PB61303. Must add a color by subclassing or templating. */
template <typename Base>
struct LEDBezelLight : Base {
template <typename TBase>
struct LEDBezelLight : TBase {
LEDBezelLight() {
this->borderColor = color::BLACK_TRANSPARENT;
this->bgColor = color::BLACK_TRANSPARENT;
@@ -224,8 +233,8 @@ struct LEDBezelLight : Base {
/** A light to displayed over PB61303. Must add a color by subclassing or templating.
Don't add this as a child of the PB61303 itself. Instead, just place it over it as a sibling in the scene graph, offset by mm2px(math::Vec(0.5, 0.5)).
*/
template <typename Base>
struct PB61303Light : Base {
template <typename TBase>
struct PB61303Light : TBase {
PB61303Light() {
this->bgColor = color::BLACK_TRANSPARENT;
this->box.size = mm2px(math::Vec(9.0, 9.0));
@@ -633,43 +642,52 @@ struct BefacoSlidePot : app::SvgSlider {

struct LEDSlider : app::SvgSlider {
LEDSlider() {
maxHandlePos = mm2px(math::Vec(0.738, 0.738).plus(math::Vec(2, 0)));
minHandlePos = mm2px(math::Vec(0.738, 22.078).plus(math::Vec(2, 0)));
// TODO Fix positions
setHandlePos(
mm2px(math::Vec(0.738, 22.078).plus(math::Vec(2, 0))),
mm2px(math::Vec(0.738, 0.738).plus(math::Vec(2, 0)))
);
setBackgroundSvg(Svg::load(asset::system("res/ComponentLibrary/LEDSlider.svg")));
setHandleSvg(Svg::load(asset::system("res/ComponentLibrary/LEDSliderHandle.svg")));
}
};

/** API is unstable for LEDSlider. Will add a LightWidget later. */
// TODO Modernize
struct LEDSliderGreen : LEDSlider {
LEDSliderGreen() {
setHandleSvg(Svg::load(asset::system("res/ComponentLibrary/LEDSliderGreenHandle.svg")));
}
};

// TODO Modernize
struct LEDSliderRed : LEDSlider {
LEDSliderRed() {
setHandleSvg(Svg::load(asset::system("res/ComponentLibrary/LEDSliderRedHandle.svg")));
}
};

// TODO Modernize
struct LEDSliderYellow : LEDSlider {
LEDSliderYellow() {
setHandleSvg(Svg::load(asset::system("res/ComponentLibrary/LEDSliderYellowHandle.svg")));
}
};

// TODO Modernize
struct LEDSliderBlue : LEDSlider {
LEDSliderBlue() {
setHandleSvg(Svg::load(asset::system("res/ComponentLibrary/LEDSliderBlueHandle.svg")));
}
};

// TODO Modernize
struct LEDSliderWhite : LEDSlider {
LEDSliderWhite() {
setHandleSvg(Svg::load(asset::system("res/ComponentLibrary/LEDSliderWhiteHandle.svg")));
}
};

// TODO Modernize
struct LEDSliderHorizontal : app::SvgSlider {
LEDSliderHorizontal() {
horizontal = true;
@@ -679,32 +697,37 @@ struct LEDSliderHorizontal : app::SvgSlider {
}
};

template <typename Base, typename TLightBase = RedLight>
struct LightSlider : Base {
template <typename TBase, typename TLightBase = RedLight>
struct LightSlider : TBase {
app::ModuleLightWidget* light;

LightSlider() {
light = new RectangleLight<TLightBase>;
light = new TLightBase;
this->addChild(light);
}

void step() override {
Base::step();
TBase::step();
// Move center of light to center of handle
light->box.pos = this->handle->box.pos
.plus(this->handle->box.size.div(2))
.minus(light->box.size.div(2));
.plus(this->handle->box.size.div(2))
.minus(light->box.size.div(2));
}
};

template <typename TLightBase = RedLight>
struct LEDLightSlider : LightSlider<LEDSlider, TLightBase> {
LEDLightSlider() {
this->setHandleSvg(Svg::load(asset::system("res/ComponentLibrary/LEDSliderHandle.svg")));
this->light->box.size = mm2px(math::Vec(1.524, 3.276));
template <typename TBase>
struct LEDSliderLight : RectangleLight<TSvgLight<TBase>> {
LEDSliderLight() {
this->setSvg(Svg::load(asset::system("res/ComponentLibrary/LEDSliderLight.svg")));
}
};

template <typename TLightBase = RedLight>
struct LEDLightSlider : LightSlider<LEDSlider, LEDSliderLight<TLightBase>> {
LEDLightSlider() {}
};

// TODO Modernize
template <typename TLightBase = RedLight>
struct LEDLightSliderHorizontal : LightSlider<LEDSliderHorizontal, TLightBase> {
LEDLightSliderHorizontal() {


+ 18
- 13
src/app/LightWidget.cpp View File

@@ -8,6 +8,22 @@ namespace app {


void LightWidget::draw(const DrawArgs& args) {
drawBackground(args);

// Child widgets
Widget::draw(args);

// Dynamic light and halo
// Override tint from rack brightness adjustment
nvgGlobalAlpha(args.vg, 1.0);
// Use the formula `lightColor * (1 - dest) + dest` for blending
nvgGlobalCompositeBlendFunc(args.vg, NVG_ONE_MINUS_DST_COLOR, NVG_ONE);
drawLight(args);
drawHalo(args);
}


void LightWidget::drawBackground(const DrawArgs& args) {
float radius = std::min(box.size.x, box.size.y) / 2.0;
nvgBeginPath(args.vg);
nvgCircle(args.vg, radius, radius, radius);
@@ -24,21 +40,9 @@ void LightWidget::draw(const DrawArgs& args) {
nvgStrokeColor(args.vg, borderColor);
nvgStroke(args.vg);
}

// Child widgets
// TODO Upload new graphics instead of use this hack.
// nvgGlobalAlpha(args.vg, 0.5);
TransparentWidget::draw(args);

// Dynamic light and halo
// Override tint from rack brightness adjustment
nvgGlobalAlpha(args.vg, 1.0);
// Use the formula `lightColor * (1 - dest) + dest` for blending
nvgGlobalCompositeBlendFunc(args.vg, NVG_ONE_MINUS_DST_COLOR, NVG_ONE);
drawLight(args);
drawHalo(args);
}


void LightWidget::drawLight(const DrawArgs& args) {
// Foreground
if (color.a > 0.0) {
@@ -51,6 +55,7 @@ void LightWidget::drawLight(const DrawArgs& args) {
}
}


void LightWidget::drawHalo(const DrawArgs& args) {
// Don't draw halo if rendering in a framebuffer, e.g. screenshots or Module Browser
if (args.fb)


+ 6
- 2
src/app/ModuleLightWidget.cpp View File

@@ -54,6 +54,8 @@ ModuleLightWidget::~ModuleLightWidget() {
engine::Light* ModuleLightWidget::getLight(int colorId) {
if (!module)
return NULL;
if (firstLightId < 0)
return NULL;
return &module->lights[firstLightId + colorId];
}

@@ -61,6 +63,8 @@ engine::Light* ModuleLightWidget::getLight(int colorId) {
engine::LightInfo* ModuleLightWidget::getLightInfo() {
if (!module)
return NULL;
if (firstLightId < 0)
return NULL;
return module->lightInfos[firstLightId];
}

@@ -92,8 +96,8 @@ void ModuleLightWidget::destroyTooltip() {
void ModuleLightWidget::step() {
std::vector<float> brightnesses(baseColors.size());

if (module) {
assert(module->lights.size() >= firstLightId + baseColors.size());
if (module && firstLightId >= 0) {
assert((int) module->lights.size() >= firstLightId + (int) baseColors.size());

for (size_t i = 0; i < baseColors.size(); i++) {
float b = module->lights[firstLightId + i].getBrightness();


+ 21
- 7
src/app/SvgSlider.cpp View File

@@ -18,31 +18,45 @@ SvgSlider::SvgSlider() {
speed = 2.0;
}


void SvgSlider::setBackgroundSvg(std::shared_ptr<Svg> svg) {
background->setSvg(svg);
fb->box.size = background->box.size;
box.size = background->box.size;
fb->box.size = background->box.size;
fb->setDirty();
}


void SvgSlider::setHandleSvg(std::shared_ptr<Svg> svg) {
handle->setSvg(svg);
handle->box.pos = maxHandlePos;
fb->dirty = true;
handle->box.pos = minHandlePos;
fb->setDirty();
}


void SvgSlider::onChange(const ChangeEvent& e) {
engine::ParamQuantity* pq = getParamQuantity();
if (pq) {
// Interpolate handle position
float v = math::rescale(pq->getSmoothValue(), pq->getMinValue(), pq->getMaxValue(), 0.f, 1.f);
handle->box.pos = math::Vec(
math::rescale(v, 0.f, 1.f, minHandlePos.x, maxHandlePos.x),
math::rescale(v, 0.f, 1.f, minHandlePos.y, maxHandlePos.y));
fb->dirty = true;
handle->box.pos = minHandlePos.crossfade(maxHandlePos, v);
fb->setDirty();
}
ParamWidget::onChange(e);
}


void SvgSlider::setHandlePos(math::Vec minHandlePos, math::Vec maxHandlePos) {
this->minHandlePos = minHandlePos;
this->maxHandlePos = maxHandlePos;
}


void SvgSlider::setHandlePosCentered(math::Vec minHandlePosCentered, math::Vec maxHandlePosCentered) {
this->minHandlePos = minHandlePosCentered.minus(handle->box.size.div(2));
this->maxHandlePos = maxHandlePosCentered.minus(handle->box.size.div(2));
}


} // namespace app
} // namespace rack

Loading…
Cancel
Save