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
	cat "$i" | xpath '//svg/@sodipodi:docname[1]'
	cat "$i" | xpath '//svg/@width[1]'
	cat "$i" | xpath '//svg/@height[1]'
	echo ""

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.


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

#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) {
		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.