Is there anyway to programmatically lay out a panel instead of creating an SVG? I’d really like to skip the Inkscape step when I’m prototyping and would be more than happy to just code up the panel. For me, the panel design is really the last step I care about.
I’ve looked at the code generated and I think I can just work with that. Sorry for asking obvious questions.
Sure, you can subclass
Widget, make a
draw() method with calls to nanovg functions, put it in a
FramebufferWidget, and add it as a child of your
ModuleWidget. You’ll need to manually set sizes for each step.
In my opinion you would be much better off mocking up at least a basic sketch before starting something, you then have an idea of what you want to accomplish. At the very least make one blank panel and use this as a template for other modules, with enough room for components. You can just add things where needed. But doing so is a lot harder because you then have to design the panel and go back over the code to see what should be where. There would be a lot of back and forth with Inkscape and code when designing the panel at the end. Having the design first makes things a lot clearer for me anyway.
I tend to think of incremental functionality. Add an output, play with it, what do I need to add/change. I don’t have the experiential knowledge now that I’ll have after playing with it, so it’s really hard for me to anticipate what to design, if that makes sense?
But then I also haven’t experienced any pain that may come from trying to layout everything after I’ve finished the functionality.
That might be lower level than what I was after. I’m just wanting to fill in the parts that
helper.py fills in for me from the SVG. At this point I’m just manually adding
addOutput() calls, etc.
Yeah, just make a basic solid color panel and add components programmatically until your parameter list is stable. Then spend time designing a panel SVG and have it generate component positions.
In my (still very limited) experience, doing most of the widget placement with code, then giving your layout a final graphic design pass after the fact is a perfectly viable way to go about things, at least for me. I’m no longer using the the python script for my new plugins.
My Meander module panel is now 99.9% procedurally generated. I started out with an Inkscape SVG file and slowly migrated everything to nanovg calls in my module. Since I was porting an existing application, I had a fairly complete idea of the controls and UI for the panel. Fairly quickly it became too cumbersome to use helper.py to generate C++ code from the SVG fle. So, I began doing all parameters, inputs, outputs and lights manually in my module. There is a symmetry in which there is a conservation of effort whichever way you go. I had to add a lot of code to do almost all of the panel text via nanovg since the SVG route “bakes” text into a “path” which is a graphic representation that can be rendered once when the panel is created or at most as a framebuffer once per frame, I’m a bit unclear on that. Using nanovg, all of the text has to be rendered during each frame at run time.
Meander is more of a sequencer than a sound generator/modifier and as such, I was able to get away with a lot of nanovg drawing per frame, which DSP sample modifiers might not be able to get away with.
We all have our own styles of doing development. But, I’m a lot like you if I am starting a new software project. I consider my programming methodology scultping. I start with the absolute minimal functionality so that I can quickly have a functioning program or plugin. Then I incrementally increase the functionality and complexity in a strange here and there approach. It works for me, but surely not for everyone.
There may be a way to avoid rendering all nanovg stuff each frame by using frame buffers, but I have not explored that.
the time budget for drawing and the time budget for DSP processing come from different pools, so whether or not a module draws too slowly had nothing do to with how much processing it might do.
The obvious thing that happens if your drawing is crazy slow is that the UI or rack gets slow and jerky, just like you would expect.
Remember that there is one UI thread for the entire rack app, so ideally every module can draw one after the other and maintains 60 fps.
The unexpected thing is that doing too much drawing also heats up laptops, especially mac ones, and the CPU clock gets lowered to compensate (thermal throttling).
That’s why it’s always good to measure your drawing time. The standard way to make it faster is using the FramebufferWidget to cache unchanging pieces of the UI.
So the next question is what are the dimension of all the GUI components? Is this documented somewhere?
I work the same way and draw everything apart from controls at run time. The GUI components are whatever size you choose to make them. Have a look at: https://github.com/ContemporaryInsanity/RacketScience Specifically RS.hpp & RSWidgetDraw.cpp, still a work in progress.
I meant the base components, (inputs, outputs, etc) not custom components. (Hope I’m using the right terminology…)
Load them into inkscape, inspect the dimensions there.
For any widget, including param, input, output and light, you can use the box data member, which is a rack::math::Rect type, from which you can get the position and size. You can also then modify that position to be what you want.
Unfortunately changing the size does not seem to work, which is odd, considering the widgets are based on SVG images…
I know I’ve not done many modules but I spent a long time sketching the panels on paper, just trying to think through the interface. Just a personal thing, but I found it helped.
This is a major help for me also. Even if the sketch looks like a 4 year old’s drawing it is still a representation that you do not have to remember as it is already on paper! Doing this also helps with getting a better GUI on the first go in Inkscape, you’ve already done the bad layout on paper.
to go slightly off topic: Just as a note to everyone the co-ordinates in Inskape v0.x are reversed for Y so in rack you would do (380px - inskapeYpx), or the mm (128.693mm - inskapeYmm). But this will not be the case in Inkscape v1.x which is fairly close to release. There is a beta available that is not fully featured but easier to get co-ordinates from. https://inkscape.org/release/inkscape-1.0beta2/
to go bring it back on topic: if you are to use nanovg to draw and you have labels etc the Y positions will still have to take Inkscape 0, 0 into account in either versions so positions for each box will be
Y + labelHeight
Just did a quick XPath scan through the SVG files from res/ComponentLibrary in a clone of the main Rack repository to get the dimensions.
Not all are in millimetres. Some are points. Where there’s no suffix they are in pixels.