Helper.py and custom widgets

I’m new to VCV Rack plugin development, so I have been using helper.py to help me create my first module. I’m curious as to whether helper.py is intended to be a production tool or just a getting started tool. It is very tedious to re-edit the .cpp file after every use of helper.py that must rerwrite the .cpp file due to SVG components changes. Be that as it is, it seems to me that the support for custom widgets is incomplete, as compared to params, etc. Is this so? In the .cpp file, any widgets components result in code such as:
// mm2px(Vec(2.811, 59.342))
addChild(createWidget(mm2px(Vec(63.307, 18.225))));

I.E., none of the widget component info in the SVG file such as ID and Label are retained in the .cpp file . Is this correct, or am I misinterpreting this (or doing something wrong)? I can look at the coordinates and determine which SVG component this widget is for, but how do I identify the widget object in code where I flesh out the widget functionality?

Thanks

Hello. :slight_smile:

I work around that by:

  1. Using helper.py to create a “fake” .cpp file from the “real” .svg file.
  2. Manually copy across the changes to the “real” .cpp file from the “fake” one.
  3. Remove the details for the “fake” module from the plugin.json file, and delete the “fake” .cpp file.

For example…

Rack-SDK/helper.py createmodule MyFakeModule res/MyRealModule.svg src/MyFakeModule.cpp

As for custom components.

I put an example module repo on GitHub which contains a file called res/Thing.svg which contains a components layer with the “placeholder circles” for a param, input, output, light and custom widget. The resulting src/Thing.cpp file, created by the helper.py script, is also in the repo.

You’ll see in the src/Thing.cpp file that the labels for the placeholder circles from the res/Thing.svg file are kept for the param, input, output and light, using the format NAME_TYPE, e.g. the placeholder circle in the Inkscape file named a_param is named A_PARAM_PARAM.

However, for the custom widget all you get in the src/Thing.cpp file is…

addChild(createWidgetCentered<Widget>(mm2px(Vec(5.08, 277.125))));

No name, just the position of the placeholder circle from the res/Thing.svg file.

Which is OK, when you think about it. The custom widget is up to you to write and the helper script (correct me if I’m wrong, folks!) can’t really predict all the different widgets people might want to write and have a bunch of boilerplate code to hand just in case. I realise that sounds awkward. Don’t mean it to. :slight_smile:

I found that looking at other developers’ module source code helps to understand how to get custom widgets working.

Also (apologies if you know these already):

  • Make sure that you have created circles in Inkscape for the placeholders, not ellipses. Press F5 to get circles.
  • Check that you’ve set the fill colours correctly for each component type, as listed in the Panel Guide.
  • Put the placeholder circles on an Inkspace layer of their own named components, and hide the layer when you save the .svg file or the placeholder circles will show on the module in Rack.
  • Remember to press ENTER when you change the name of an object’s label in Inkscape. Just typing the new name and clicking away doesn’t save it.

Thanks,
Alan.

1 Like

Thanks Alan. My work process is very similar to yours. I have all of the components layer in the SVG file working correctly. But, I’m wondering if it is an oversight that the

addChild(createWidgetCentered<Widget>(mm2px(Vec(5.08, 277.125))));

created by helper.py does not include the component Label from the SVG file. AddChild() will take the label argument and helper.py should read this info when it parses the SVG file. I could modify helper.py to add the label for widgets, but I’m reluctant to mess with helper.py too much. I have experimented with modifying helper.py to add more types of components via different circle and square fill color coding. That works but would be hard to maintain as new versions of helper.py come out.

I’m biting off a lot with my first plugin and module. I’m trying to turn my Meander application into a plugin. Meander is a massive algorithmic composition engine and an expert system for music theory. I wrote it for Windows(Dos) from '88-'95 and have updated it for newer Windows versions and also ported it two years ago in Javascript for Max/MSP. Currently I have it set up as a 32HP panel, but that is not going to be large enough. Meander does algorithmic chordal harmonic progressions in any key or scale and composes compatible melody and bass parts and melody arpeggiation. It also does percussion rhythm but I probably will not port that to the plugin. It is called “Meander” because I use exponentiallly smoothed random values to drive pleasing variations, thus the melody meanders in a musically pleasing manner. The user interface is quite complex, thus a tough project for my first plugin.

Thanks again for sharing your workflow.
Ken

4 Likes

Meander sounds amazing. Can’t wait! :smiley:

1 Like

Looking forward to it, sounds amazing!

Edit to add: let me know if you need a tester!

Upon closer examination, I see that the helper.py widget issue is that CreateWidget() does not accept a name argument. helper.py does parse the widget label. Also, helper.py by default names each widget component “widget” at the module level. Perhaps at least including the label in the widget coordinates comment line comment might be appropriate. I can work around this though as I understand what it is doing.

1 Like