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); NVGcolor borderColor = nvgRGBA(0, 0, 0, 0);


void draw(const DrawArgs& args) override; void draw(const DrawArgs& args) override;
virtual void drawBackground(const DrawArgs& args);
virtual void drawLight(const DrawArgs& args); virtual void drawLight(const DrawArgs& args);
virtual void drawHalo(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 setBackgroundSvg(std::shared_ptr<Svg> svg);
void setHandleSvg(std::shared_ptr<Svg> svg); void setHandleSvg(std::shared_ptr<Svg> svg);
void onChange(const ChangeEvent& e) override; 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) { DEPRECATED void setBackgroundSVG(std::shared_ptr<Svg> svg) {
setBackgroundSvg(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.) 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>` 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. 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>>(...) createLightParamCentered<LEDLightSlider<GreenLight>>(...)
*/ */


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


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


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


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


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


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


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


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


/** Reads two adjacent lightIds, so `lightId` and `lightId + 1` must be defined */ /** 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() { TGreenRedLight() {
this->addBaseColor(SCHEME_GREEN); this->addBaseColor(SCHEME_GREEN);
this->addBaseColor(SCHEME_RED); this->addBaseColor(SCHEME_RED);
@@ -142,8 +142,8 @@ struct TGreenRedLight : Base {
}; };
typedef TGreenRedLight<> GreenRedLight; typedef TGreenRedLight<> GreenRedLight;


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


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


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


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


/** Based on the size of 1mm LEDs */ /** Based on the size of 1mm LEDs */
template <typename Base>
struct TinyLight : TSvgLight<Base> {
template <typename TBase>
struct TinyLight : TSvgLight<TBase> {
TinyLight() { TinyLight() {
this->setSvg(Svg::load(asset::system("res/ComponentLibrary/TinyLight.svg"))); 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); nvgBeginPath(args.vg);
nvgRect(args.vg, 0, 0, this->box.size.x, this->box.size.y); nvgRect(args.vg, 0, 0, this->box.size.x, this->box.size.y);


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


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

// Border // Border
if (this->borderColor.a > 0.0) { if (this->borderColor.a > 0.0) {
nvgStrokeWidth(args.vg, 0.5); nvgStrokeWidth(args.vg, 0.5);
@@ -209,11 +205,24 @@ struct RectangleLight : Base {
nvgStroke(args.vg); 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. */ /** 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() { LEDBezelLight() {
this->borderColor = color::BLACK_TRANSPARENT; this->borderColor = color::BLACK_TRANSPARENT;
this->bgColor = 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. /** 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)). 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() { PB61303Light() {
this->bgColor = color::BLACK_TRANSPARENT; this->bgColor = color::BLACK_TRANSPARENT;
this->box.size = mm2px(math::Vec(9.0, 9.0)); this->box.size = mm2px(math::Vec(9.0, 9.0));
@@ -633,43 +642,52 @@ struct BefacoSlidePot : app::SvgSlider {


struct LEDSlider : app::SvgSlider { struct LEDSlider : app::SvgSlider {
LEDSlider() { 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"))); 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 { struct LEDSliderGreen : LEDSlider {
LEDSliderGreen() { LEDSliderGreen() {
setHandleSvg(Svg::load(asset::system("res/ComponentLibrary/LEDSliderGreenHandle.svg"))); setHandleSvg(Svg::load(asset::system("res/ComponentLibrary/LEDSliderGreenHandle.svg")));
} }
}; };


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


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


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


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


// TODO Modernize
struct LEDSliderHorizontal : app::SvgSlider { struct LEDSliderHorizontal : app::SvgSlider {
LEDSliderHorizontal() { LEDSliderHorizontal() {
horizontal = true; 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; app::ModuleLightWidget* light;


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


void step() override { void step() override {
Base::step();
TBase::step();
// Move center of light to center of handle // Move center of light to center of handle
light->box.pos = this->handle->box.pos 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> template <typename TLightBase = RedLight>
struct LEDLightSliderHorizontal : LightSlider<LEDSliderHorizontal, TLightBase> { struct LEDLightSliderHorizontal : LightSlider<LEDSliderHorizontal, TLightBase> {
LEDLightSliderHorizontal() { LEDLightSliderHorizontal() {


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

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




void LightWidget::draw(const DrawArgs& args) { 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; float radius = std::min(box.size.x, box.size.y) / 2.0;
nvgBeginPath(args.vg); nvgBeginPath(args.vg);
nvgCircle(args.vg, radius, radius, radius); nvgCircle(args.vg, radius, radius, radius);
@@ -24,21 +40,9 @@ void LightWidget::draw(const DrawArgs& args) {
nvgStrokeColor(args.vg, borderColor); nvgStrokeColor(args.vg, borderColor);
nvgStroke(args.vg); 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) { void LightWidget::drawLight(const DrawArgs& args) {
// Foreground // Foreground
if (color.a > 0.0) { if (color.a > 0.0) {
@@ -51,6 +55,7 @@ void LightWidget::drawLight(const DrawArgs& args) {
} }
} }



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


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

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


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


@@ -92,8 +96,8 @@ void ModuleLightWidget::destroyTooltip() {
void ModuleLightWidget::step() { void ModuleLightWidget::step() {
std::vector<float> brightnesses(baseColors.size()); 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++) { for (size_t i = 0; i < baseColors.size(); i++) {
float b = module->lights[firstLightId + i].getBrightness(); float b = module->lights[firstLightId + i].getBrightness();


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

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



void SvgSlider::setBackgroundSvg(std::shared_ptr<Svg> svg) { void SvgSlider::setBackgroundSvg(std::shared_ptr<Svg> svg) {
background->setSvg(svg); background->setSvg(svg);
fb->box.size = background->box.size;
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) { void SvgSlider::setHandleSvg(std::shared_ptr<Svg> svg) {
handle->setSvg(svg); handle->setSvg(svg);
handle->box.pos = maxHandlePos;
fb->dirty = true;
handle->box.pos = minHandlePos;
fb->setDirty();
} }



void SvgSlider::onChange(const ChangeEvent& e) { void SvgSlider::onChange(const ChangeEvent& e) {
engine::ParamQuantity* pq = getParamQuantity(); engine::ParamQuantity* pq = getParamQuantity();
if (pq) { if (pq) {
// Interpolate handle position // Interpolate handle position
float v = math::rescale(pq->getSmoothValue(), pq->getMinValue(), pq->getMaxValue(), 0.f, 1.f); 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); 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 app
} // namespace rack } // namespace rack

Loading…
Cancel
Save