[noob] light with svg

hello,
I’m looking for an example on how to create custom widget : I want to be able to create something similar to a light, but using a custom svn image.
I.E : to be able to draw or not an image on top of the module.
what is the most simple way?

(I found answer for custom switch, but I don’t need the user interaction part)

Thanks

2 Likes

Take a look at the SvgButton source code for reference: https://github.com/VCVRack/Rack/blob/v1/include/app/SvgButton.hpp
https://github.com/VCVRack/Rack/blob/v1/src/app/SvgButton.cpp

Maybe there is an easier way, but what I would do is make a new custom widget inheriting from TransparentWidget which basically copies SvgButton without the click functionality. I think this is what the widget should look like, but WARNING: I didn’t actually run this code so there are probably errors.

struct ChCustomWidget : TransparentWidget {
	ChModule *module;
	widget::FramebufferWidget *fb;
	widget::SvgWidget *sw;

	ChCustomWidget() {
		addFrame(APP->window->loadSvg(asset::plugin(chPluginInstance,"res/svg1.svg"));
		addFrame(APP->window->loadSvg(asset::plugin(chPluginInstance,"res/svg2.svg"));
	}

	void addFrame(std::shared_ptr<Svg> svg) {
		frames.push_back(svg);
		// If this is our first frame, automatically set SVG and size
		if (!sw->svg) {
			sw->setSvg(svg);
			box.size = sw->box.size;
			fb->box.size = sw->box.size;
		}
	};

	void draw(const DrawArgs &args) override {
		if (module) {
			sw->setSvg(frames[module->svgIndex]);
			fb->dirty = true;
		}
		else {

		}
	}

}

Your Module (of type ChModule in my example) must have a member svgIndex which tells the widget which svg to show. Instantiate the ChCustomWidget in your ModuleWidget constructor like this:

ChCustomWidget *chWidget = new ChCustomWidget();
			chWidget->module = module;
			chWidget->box.pos = Vec(20, 20);
			addChild(chWidget);

I adapted @computerscare 's code and got it working. One big difference is that I pass in a pointer to a boolean instead of a pointer to the entire module. I’m hoping that this will make the code more reusable between different modules.

Here’s what I came up with:

struct StepLightWidget : SvgWidget
{

  bool *state_bool_ptr = NULL;
  std::vector<std::shared_ptr<window::Svg>> frames;

  StepLightWidget(bool *state)
  {
    addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/groovebox/groove_box_led.svg")));
    addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/groovebox/groove_box_led_lit.svg")));

    this->state_bool_ptr = state;
  }

  void addFrame(std::shared_ptr<Svg> svg)
  {
    this->frames.push_back(svg);

    // If this is our first frame, automatically set SVG and size
    if (!this->svg)
    {
      this->setSvg(svg);
      box.size = svg->getSize();
    }
  };

  void step() override
  {
    SvgWidget::step();

    if (state_bool_ptr != NULL)
    {
      this->setSvg(frames[(*state_bool_ptr) ? 1 : 0]);
    }
    else
    {
      this->setSvg(frames[0]);
    }
  }
};

And here’s how I add it to the ModuleWidget constructor:

StepLightWidget *step_light_widget = new StepLightWidget((module) ? &module->light_status_boolean : &dummy_boolean);
step_light_widget->box.pos = Vec(20.0, 20.0);  // Adjust this to place it where you want it
addChild(step_light_widget);

// Where dummy_boolean is defined in the module widget as bool dummy_boolean = false;

Hope this helps!

I don’t quite get it doesn’t SvgWidget do exactly what OP wanted?

I agree, and my example extends SvgWidget instead of TransparentWidget. Is my code overly verbose? I’m all ears if it can be streamlined! :ear: :+1:

I was responding to @computerscare . I didn’t look at your code, but I’m sure it’s fine.

1 Like

Very possible

1 Like