Discussion about the Interface Designer


  • administrators

    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:

    1. Are you using it at all, or do you do all your interface design with pure coding.
    2. 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?
    3. If you're using it, do you bother about the auto generated code or do you consider it as noise in your script?
    4. 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?
    5. 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 and parameterId 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.


  • administrators

    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


  • administrators

    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);&#10;const var Knob = Content.addKnob(&quot;Knob&quot;, 37, 20);&#10;// [JSON Knob]&#10;Content.setPropertiesFromJSON(&quot;Knob&quot;, {&#13;&#10;  &quot;max&quot;: 40&#13;&#10;});&#10;// [/JSON Knob]function onNoteOn()&#10;{&#10;&#9;&#10;}&#10;function onNoteOff()&#10;{&#10;&#9;&#10;}&#10;function onController()&#10;{&#10;&#9;&#10;}&#10;function onTimer()&#10;{&#10;&#9;&#10;}&#10;function onControl(number, value)&#10;{&#10;&#9;&#10;}&#10;">
      <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);&#10;const var Knob = Content.addKnob(&quot;Knob&quot;, 31, 19);&#10;function onNoteOn()&#10;{&#10;&#9;&#10;}&#10;function onNoteOff()&#10;{&#10;&#9;&#10;}&#10;function onController()&#10;{&#10;&#9;&#10;}&#10;function onTimer()&#10;{&#10;&#9;&#10;}&#10;function onControl(number, value)&#10;{&#10;&#9;&#10;}&#10;">
      <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.


Log in to reply
 

2
Online

315
Users

914
Topics

5.9k
Posts

Looks like your connection to Forum was lost, please wait while we try to reconnect.