Discussion about the Interface Designer
-
Hi everybody,
I'd like to get a little feedback about how (and if) you use the interface designer (which is the list of properties that change the script widgets and generates these JSON code snippets). I've been thinking about a more robust implementation, which might have an impact on existing workflows, but in the other hand vastly improve the general workflow (as far as I can think of).
The proposed change
The idea is to remove the code snippets that the interface designer creates:
// [JSON MyKnob] Content.setPropertiesFromJSON("MyKnob", { "max": 20000, "mode": "Time", "stepSize": 1, "middlePosition": 1000, "suffix": " ms" }); // [/JSON MyKnob] // [JSON MyOtherKnob] Content.setPropertiesFromJSON("MyOtherKnob", { "max": 19000, "mode": "Time", "stepSize": 1, "middlePosition": 800, "suffix": " ms" }); // [/JSON MyKnob]
and instead create a internal JSON object for all widgets, which will be updated directly from the property list:
{ "MyKnob": { "max": 20000, "mode": "Time", "stepSize": 1, "middlePosition": 1000, "suffix": " ms" }, "MyOtherKnob": { "max": 20000, "mode": "Time", "stepSize": 1, "middlePosition": 1000, "suffix": " ms" } }
This JSON object will be persistent across script compilation and when a Script widget is created, it will fetch its properties from this list.
There are a lot of advantages using this method, which I will sketch below:
Way more robust
Currently I am going totally bogus on Regex using this expression:
"(const)?\\s*(global|var|reg)?\\s*" + id.toString() + "\\s*=\\s*.*;[\\n\\r]";
in order to find the correct place to insert the JSON, which sometimes fails if the UI widget is defined in an external file. With the new method, it has exactly one place to look (and internally it doesn't have to parse any text but operate on the object directly), so it's faster and safer.
Cleaner code
Your script will not be scattered with all these
// [JSON myWidget]
code snippets. Instead it will be all saved into one big JSON file which will be separately saved in your script folder.Support for custom templates
Let's say you have 20 sliders which all share the same filmstrip image, but differ in their range (which was the case in literally every project I've worked on so far). The current solution is not ideal for this, because you'll end up writing a lot of
widget.set("min", 0.2);
functions after you've set the common properties using either a common JSON object or a UI Factory method. With the new method, you can simple duplicate the slider, change the range in the properties editor and don't care about how and which properties are updated behind the scenes.Backward compatible
It's crucial for a change like this that it doesn't affect backward compatibility. The methods
widget.setPropertiesFromObject();` widget.set("property", value);
will stay functional, however I advise to not use the first function anymore unless you have a very good reason to do so as in general it will become deprecated with the new approach (but for dynamic stuff it might still be useful).
However, before I proceed with this step and implement it, I'd like to open a discussion about general use cases and issues that the new method might create. So my (slightly suggestive) questions are:
- Are you using it at all, or do you do all your interface design with pure coding.
- If not, why? And how do you set your widget's properties then? Do you eg. pass around an object and use the
Content.setPropertiesFromObject()
method? - If you're using it, do you bother about the auto generated code or do you consider it as noise in your script?
- If you're using it, how do you handle the problem that you have a set of widgets which have some shared properties (eg. the filmstrip skin), but differ in other properties?
- Are you using the UI Factory method paradigm when applicable (that is the
const var myWidget = createMyWidget("myWidget", x, y, additionalParameters);
Please feel free to only answer the questions you like :)
BTW: the "Connect to module" wizard will also be removed soon, as there are
processorId
andparameterId
properties, which do the exact same thing but more robust. -
I don't use it much, except to position object and play around with their size, once I get the values I want I add them into my code and delete any JSON noise ;)
If it's for modules I plan to reuse in other projects or share with others I mainly use raw HISE script (sometimes incorporating a factory function) to create my GUI. If I'm doing this I use a lot of
control.set()
commands to set up properties. It's a little verbose but I like to keep things compatible and simple if I intend to share them with others.If I'm creating something that's a little more complicate then I will use factory functions that take an x and y parameter and an object with all the other properties I wish to use. I haven't actually used the
setPropertiesFromObject()
function, but I'll try it out.I use code more than the UI designer because I find it quicker and it's what I'm used to.
-
Ah, OK, for smaller script interfaces which are supposed to be reusable (eg. a legato script or whatever), your approach is indeed better. However for big interface scripts, it quickly gets out of hand (I am currently working on an interface with hundreds of controls) which made me think about a clearer way.
-
Hello,
the idea is good and I feel that it will be easier after meeting. That being said, I am currently working on several projects and it really should that when I open an old project with the new version, I do not go to rewrite the whole code ... but from what I understood it is what is going to be (googles translations are not always the best).
-
This is the problem for me:
"a internal JSON object for all widgets"-- if this means that this JSON (which defines the UI) is now ONLY accessible via property lists then this is BAD BAD BAD.
I use a stand-alone code-generator for UI layout etc. that I then import into Kontakt (in the currently working product). I planned to port this across to write the JSON/UI part of products in HISE but if there's nowhere to import this "internal JSON" then this would be a big problem for me...
-
From what Christoph said I'm guessing the "JSON object" will be accessible as a separate file in the project folder so you should still have access to it for use with your UI generator
-
Hi Lindon,
long time no see :)
The internal JSON list will indeed be accessible only via the UI elements. However when you save them / load them it will be stored directly in the XML element (I've played around and this is much more versatile as it allows sharing of modules without having to rely on another JSON file like David suggested).
This is an example script with one Knob that has it's
max
property set to 40:<Processor Type="ScriptProcessor" ID="Interface" Bypassed="0" Script="Content.makeFrontInterface(600, 500); const var Knob = Content.addKnob("Knob", 37, 20); // [JSON Knob] Content.setPropertiesFromJSON("Knob", { "max": 40 }); // [/JSON Knob]function onNoteOn() { 	 } function onNoteOff() { 	 } function onController() { 	 } function onTimer() { 	 } function onControl(number, value) { 	 } "> <EditorStates BodyShown="1" Visible="1" Solo="0" contentShown="1" onInitOpen="1" Folded="1"/> <ChildProcessors/> <Content> <Control type="ScriptSlider" id="Knob" value="0"/> </Content> </Processor>
As you can see, it stored the JSON data in the script with some weird white space replacements that are terrible to the human eyes :)
Now it looks like this:
<Processor Type="ScriptProcessor" ID="Interface" Bypassed="0" Script="Content.makeFrontInterface(600, 500); const var Knob = Content.addKnob("Knob", 31, 19); function onNoteOn() { 	 } function onNoteOff() { 	 } function onController() { 	 } function onTimer() { 	 } function onControl(number, value) { 	 } "> <EditorStates BodyShown="1" Visible="1" Solo="0" contentShown="1" onInitOpen="1" Folded="1"/> <ChildProcessors/> <Content> <Control type="ScriptSlider" id="Knob" value="0"/> </Content> <ContentProperties> <Knob type="ScriptSlider" max="40"/> </ContentProperties> </Processor>
Now there's just another child element called
ContentProperties
which contains all non-default values. No more weird JSON comments / autogenerated boilerplate stuff in the script.Basically, this adds another data layer before the script code. If you don't need it, it won't change anything for you (you can still set the properties using Javascript). The problem was that the UI widgets (the property list, the dragger, etc) had no own data model so they kept interfering with the script which was a theoretically nice idea, but very error prone.
I will also add some functions that update / change the "global" UI data object using a JSON from Javascript. I'll also think about some handy migrating tools in case you want to switch your UI to the new scheme. In fact, I think this scheme will be even better for important any kind of autogenerated data.
The only breaking change so far is that if your interface was creating only by using the autogenerated JSON data from the property list, it will become some sort of "read-only", which means that it still loads the correct properties, but the property lists (and the UI dragger) will not change the JSON code anymore, because their property changes get overwritten by the already existing JSON data.
-
Hi,
I've been diving in headfirst and absolutely loving HISE! I was wondering, is there a way, perhaps a setting, to go back to code snippets being added to the script editor when creating components in the interface designer?My brain is so used to seeing the variable declaration for elements in my oninit, and it might help my transition coming from Kontakt. If not, I totally understand, I just figured I would ask since that legacy functionality also appears in some of the tutorials.
-
@musictranscriber No. :p
But you can declare all of your components in code if you want instead of using the interface designer. I do this for all of my scripts except my main interface script.
For example to create a knob you write
const var aKnob = Content.createKnob("aKnob", 0, 0);
I wrote some helper functions for this ages ago, I no longer use them but you might find them useful.If you want to see the underlying JSON code for any of the controls on your interface, select the control in the widget list and press
J
. -
Thank you. Yeah, I learned a lot from your youtube interface designer tutorial.
To that end, perhaps you could clarify for me why my interface in the interface designer shows wonderfully, but in the Container>Midi Processor>Script Processor, the interface doesn't show at all?!
-
@musictranscriber Front interface doesn't show in HISE's main view, not sure why exactly but that's how it's been for a long time. You can add a script content view to the left hand panel to view your interface (this is what I do). It has the added bonus that you can scroll up and down the tree and try out different things with your interface in view all the time.