How to draw a line depending on a slider value

For a module I’m working on I want to be able to draw a line (of a given width) of a certain length which depends on the value of a slider. If the slider value changes, the line should change as well. So this needs to be drawn and redrawn in some way.I’ve implemented the slider and know how to use its value, but have no clue how to dynamically (re)draw a line. Can anybody explain to me how this could be done?

Maybe something like this?

struct MyWidget : Widget {
	ParamQuantity* pq = NULL;

	void draw(const DrawArgs& args) override {
		float value = pq ? pq->getValue() : 0.f;

		nvgMoveTo(args.vg, 0.f, 0.f);
		nvgLineTo(args.vg, value * 100.f, 0.f);
		nvgStrokeColor(args.vg, nvgRGB(0xff, 0x00, 0x00));
		nvgStrokeWidth(args.vg, 2.f);
		nvgStroke(args.vg);

		MyWidget::draw(args);
	}
};

Thx! I’ll give this a try.

The draw method is automatically called by a timer at the display update rate, so you don’t have to do anything particular to achieve that.

I changed the code a bit by adding the module pointer:

struct MyWidget {
    Vocode_O_Matic_XL *module;
    ParamQuantity* pq = NULL;

    void draw(const DrawArgs& args) override {
        //float value = pq ? pq->getValue() : 0.f;
        float value = pq ? pq->getValue() : 1.f;

        nvgMoveTo(args.vg, 0.f, 0.f);
        nvgLineTo(args.vg, value * 100.f, 0.f);
        nvgStrokeColor(args.vg, nvgRGB(0xff, 0x00, 0x00));
        nvgStrokeWidth(args.vg, 2.f);
        nvgStroke(args.vg);

        MyWidget::draw(args);
    }
};

I’m not sure this it the right way to use the code:

    // Draw line that shows the bandwidth in semitones.
    MyWidget *carr_bw_line = new MyWidget();
    carr_bw_line->module = module;
    if (module) {
        carr_bw_line->pq = module->paramQuantities[Vocode_O_Matic_XL::CARR_BW_PARAM];
    }
    addChild(carr_bw_line);
    DrawArgs carr_line_args;
    carr_bw_line.draw(carr_line_args);

This leads to the following errors:

src/Vocode_O_Matic_XL.hpp:754:18: error: unknown type name 'DrawArgs'; did you mean
      'ButtonCenter::DrawArgs'?
        void draw(const DrawArgs& args) override {
                        ^~~~~~~~
                        ButtonCenter::DrawArgs
../../include/widget/Widget.hpp:89:9: note: 'ButtonCenter::DrawArgs' declared here
        struct DrawArgs {
               ^
In file included from src/Vocode_O_Matic_XL.cpp:4:
src/Vocode_O_Matic_XL.hpp:754:34: error: only virtual member functions can be marked 'override'
        void draw(const DrawArgs& args) override {
                                        ^~~~~~~~~
src/Vocode_O_Matic_XL.cpp:647:14: error: cannot initialize a parameter of type 'rack::widget::Widget *'
      with an lvalue of type 'MyWidget *'
    addChild(carr_bw_line);
             ^~~~~~~~~~~~
../../include/widget/Widget.hpp:77:24: note: passing argument to parameter 'child' here
        void addChild(Widget* child);
                              ^
src/Vocode_O_Matic_XL.cpp:649:17: error: member reference type 'MyWidget *' is a pointer; did you mean to
      use '->'?
    carr_bw_line.draw(carr_line_args);
    ~~~~~~~~~~~~^
                ->
4 errors generated.

Does this not knowing DrawArgs mean I’m missing an include file ?

It’s hard to know what’s wrong without seeing the rest of the code, but it looks like you might have included Widget.hpp within a class or namespace declaration:

class ButtonCenter {
...
#include "Widget.hpp"

or:

namespace ButtonCenter {
...
#include "Widget.hpp"
  1. You don’t call draw(). Rack’s renderer does that.
  2. What’s the point of having a module member variable if you don’t need it, i.e. are only using the ParamQuantity pointer?

Ad 1 and 2: I’m not sure why I call draw / added the module member. Since I do not know the inside of vcv-rack I’m often guessing what all the classes etc are about.

But why is DrawArgs giving errors here?

I have a class like that but I’m not including Widget.hpp in it:

struct ButtonCenter: SvgSwitch
{
    ButtonCenter()
    {
        momentary = true;
        // The first svg is the one shown when the button is not pressed.
        addFrame(APP->window->loadSvg(asset::plugin(thePlugin, "res/tresamigos/BtnCenter_1.svg")));
        // The second svg is the one shown when the button is pressed and held down.
        addFrame(APP->window->loadSvg(asset::plugin(thePlugin, "res/tresamigos/BtnCenter_2.svg")));
        sw->wrap();
    }
};

Andrew’s code wasn’t a complete, self-contained example to copy verbatim.

The struct MyWidget piece was to indicate that the rest of it lives inside a Widget-derived class, possibly your ModuleWidget in the simplest case. The draw function is something that either you already have, or can add to your existing Widget-derived class.

1 Like

Ah, that makes things a bit more clear. My experience in C++ is limited … therefore I didn’t see the greater picture here. Thx.