Programmatic Panel Design

Ooh fancy, how did you do this?

:slight_smile: A combination of a really bad bash script (below), some hand editing in Sublime Text to make the data a quoted value CSV and then pasted into discourse, which is clever enough to spot CSV formatted data and convert it into a markdown table.

Bad code warning!

#!/usr/bin/env bash

for i in *.svg
do
	cat "$i" | xpath '//svg/@sodipodi:docname[1]'
	cat "$i" | xpath '//svg/@width[1]'
	cat "$i" | xpath '//svg/@height[1]'
	echo ""
done

Very messy, quick hack. I’ll make a better version and stick on GitHub when I’ve got time later this week, if there’s a desire for that.

3 Likes

Thanks for that. Wow! I had no idea there were SO many components. Not what I expected. I thought there would only be 4 components:

  • input
  • output
  • param
  • light

Plus custom components that have their own ‘model’. I guess I need to look into how the model for all the components works now.

I just export an svg from svg.js - and then convert the paths from there.

the source lives in res-src and the converted paths live in res. I’m able to generate all of my text, lines, and polygons as normal svg, and “simply” convert to paths. sure, it would be a lot easier if nanovg fully supported svg, but at least there are possible solutions that can be both semantic and converted to something rack can understand.

1 Like

I find

//geometry edit
#define HP 3
#define LANES 1
#define RUNGS 6

//ok
#define HP_UNIT 5.08
#define WIDTH (HP*HP_UNIT)
#define X_SPLIT (WIDTH / 2.f / LANES)

#define HEIGHT 128.5
#define Y_MARGIN 0.05f
#define R_HEIGHT (HEIGHT*(1-2*Y_MARGIN))
#define Y_SPLIT (R_HEIGHT / 2.f / RUNGS)

//placement macro
#define loc(x,y) mm2px(Vec(X_SPLIT*(1+2*(x-1)), (HEIGHT*Y_MARGIN)+Y_SPLIT*(1+2*(y-1))))

struct TWidget : ModuleWidget {
	TWidget(T* module) {
		setModule(module);
		setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/T.svg")));

		addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
		addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
		addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
		addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));

		addParam(createParamCentered<RoundBlackKnob>(loc(1, 1), module, T::NOTE));
		addParam(createParamCentered<RoundBlackKnob>(loc(1, 2), module, T::FINE));

		addInput(createInputCentered<PJ301MPort>(loc(1, 3), module, T::IN));
		addInput(createInputCentered<PJ301MPort>(loc(1, 4), module, T::TRIG));

		addOutput(createOutputCentered<PJ301MPort>(loc(1, 5), module, T::HI));
		addOutput(createOutputCentered<PJ301MPort>(loc(1, 6), module, T::OUT));
	}
};

Useful to place grid controls.

2 Likes

Hello Ken,

Do you have an “utility” to convert SVG file to its equivalent C/C++ code (compatible against nvg library used in VCV Rack 2)?

Thanks in advance.

Interesting question. A web search led me to: svg2nvg No idea if it handles Inkscape → VCV correctly with its quirks and limitations, but it might be worth looking into.

1 Like

Thanks Ken, but finally I’m using another approach (using circle, and filled pie inside the circle).

Ho Dominique,

No, I did not not use any utilities to convert SVG to NVG.

1 Like

Ok Ken, thanks for this precision (I don’t have checked in your Meander if you’re using or not SVGs for note symbols, I’m too busy because I’ll try to implement code for triggers or gates on outputs).

I use the Steinberg Media Technologies SIL Open Font license Bravura font for all music symbols in Meander. Bravura.otf

1 Like

By the way, thanks to @Squinky for making me aware of the Bravura open music font last year.

1 Like

Thanks!

1 Like