=====Plugin API: Dynamic Interfaces=====
As shown on the first page of the plugins documentation there are 4 places you can insert plugin defined user interfaces into XTension. On the edit Interface sheet window, the Edit Unit dialog and both the small and advanced HUD unit control displays.\\
\\
The state and contents or selections of each control is saved and restored for the user. This data is also available to your script through the configuration python dictionaries that are passed to the script. Additionally to just saving their settings, controls can call directly to plugin methods if the interface is running so that you can have changes or control actions executed immediately in response to user actions.\\
\\
These interfaces are defined by yet more JSON data in the info.json file.\\
\\
==editControls==
“editControls”:[
{control specific info...},
{control specific info...}
]
The “editControls” key can be included in 2 places. If included in the root level of the info.json file those controls will be embedded into the Edit Interface sheet window. If embedded into a “deviceTypes” record then those controls will be rendered in the Edit Unit dialog.\\
\\
Controls embedded into the Edit Interface sheet window can be of any reasonable height as the window resizes automatically. The width should be limited to 584px.\\
\\
Controls embedded into the Edit Unit window do not yet resize the window. The “Device Options” portion of the Edit Unit dialog is limited to 547px in width and 176px in height. If your unit has “allowColor” turned on then a portion of that space will be used for the edit color preset display. If you need more space I can implement an auto resize of the window please let me know if I need to move that up the priority list.\\
==smallControls==
OPTIONAL: (json list of dictionaries) any controls defined in the “deviceType” entry under this key will be rendered on the small HUD unit control window. The height is calculated automatically but the width should be limited to 200px.
==controls==
OPTIONAL: (json list of dictionaries) any controls defined in the “deviceType” entry under this key will be rendered on the Advanced HUD unit control window. The height is calculated automatically but the width should be limited to 272px.
===Control Specific Keys===
==key==
REQUIRED: (string) a short unique tag used to save and restore the data and let you access this value from the plugin script.
==bounds==
REQUIRED: (json list of 4 elements) the top, left width and height of the control you are creating.
"bounds":[5, 40, 120, 32]
==requiresInterface==
OPTIONAL: (boolean) if included and true the control will be disabled if the interface isn't actually running when it's being displayed. Controls using the "action" parameter can't call back into the script if the interface is not enabled so they will be disabled. This is useful for making changes live or having control buttons act immediately. If you’re simply saving configuration information then it need not be limited to just when the interface is open. Once the interface is enabled all this data will be available to you by walking your configuration dictionaries and units which are sent to the script upon launch and whenever the database is saved or edited.
==areYouSure==
OPTIONAL: (string) if present the text will be popped up as an Are You Sure window prompt prior to sending the command to the script. Currently implemented for the Button and segmentedControl control types.
==type==
REQUIRED: (string) the type of control you wish to create. Supported control types:
* **label** A simple interface label. Supports keys of: "align", "fontSize", "text", “help”
{“type”:”label”, “text”:”Fade Speed:”, “bounds”:[4, 4, 75, 16]}
* **textField** a text entry field. Supports keys of: “key”(required), “align”, “fontSize”, “text”, “cueText”, “help"
* **button** Generic button with “text” as the title. requires the “action” parameter to send the current data in the interface to the named parameter in the script. Supports: “key”(required), “fontSize”, “text”, “action”, “help”, “requiresInterface”, “areYouSure"
* **popup** popup menu. Uses the Options array to setup it’s interface. Supports: “key”(required), “fontSize”, “options”, “help”, “action”, “requiresInterface”
{"type":"popup",
"bounds":[388, 20, 81, 20],
"key":"pwm3",
"fontSize":"11",
"help":"The PWM frequency of the dimmer, see docs for important considerations when using ballasted lamps.",
"options":[
["32khz (fastest)", "0"],
["3.9khz", "1"],
["488hz", "3", True],
["122hz", "5"],
["30.5hz", "6"]
]
},
* **checkbox** a checkbox control. Supports: “key”(required), “fontSize”, “help”, “action”, “text”, “value”, “requiresInterface"
* **image** a control based on a supplied image file. supported: “key”(required), "help", "action", “fileName”(required), "requiresInterface" display an image from your plugin folder in the interface. If the image is clicked on and an "action" parameter is specified that script method will be called with a dictionary of the state of the current interface with all the user entered values. In addition an "x" and "y" value will be added giving you the location of the mouse click. Like all action handlers a key named "action" will be added which will hold the key of this control.
* **segmented** a segmented button control. Supports: “key”(required), “help”, “requiresInterface”, “selType”(required) can be either “single” or “none” use none for a row of button like behavior.
* “options”(required) a list of embedded dictionaries with the following options.
* **text**(required) the text to display in that element
* **key**(required) a unique string to identify which element was clicked or selected
* **help**(optional) each segment may have it’s own help text.
* **width**(required) the width of this individual element.
* **action**(optional) if sel type is set to “none” then this call call the selected segments action handler as if you had clicked a button. You can set the same handler for each segment as the key of the clicked segment will be in the dictionary passed to the script.
* **areYouSure**(optional) if selType is set to “none” then you can also ask are you sure before calling the plugin method.
* **selected**(boolean) if the selType is “single” and this is included and true then this will be the default selected item. If the user has already selected a different item then that selection will be restored.
{“type":"segmented",
"key":"seg",
"bounds":[331, 300, 138, 20],
"requiresInterface":True,
"selType":"none",
"options":[
{"text":"segment one", "key":"segOne", "width":75, "action":"segClick"},
{"text":"segment two", "key":"segTwo", "width":75, "action":"segClick"}
]
}
* **slider** a slider control. Supported: “key”(required), “help”, “requiresInterface”, “min”(required) an integer value that is the minimum value of the slider. “max”(required) an integer value which is the maximum value of the slider. “action”(optional) if included the script will get called with the new value when the slider is changed by the user. The value is always saved to the database and will be available to the script from the configurationChanged event when starting up or saved by the user. If you wish to make immediate changes in response to the user changes then you should implement the event. The the value cannot be handled without the script running then set the requiresInterface parameter and the slider will be disabled unless the interface is running. If the Bounds values are wider than they are tall then the control will be a horizontal slider, if taller than it is wide then it will be a vertical slider.
==align==
OPTIONAL(string) defaults to “left” valid values are: “left”, “center”, “right”
==fontSize==
OPTIONAL(integer) defaults to system default. NOTE that segmented controls cannot change their font size.
==text==
(string) if needed this will be the display text or edit field text. In the case of an edit field this will be filled in from the info.json file only if there is no saved data for that key already saved by the used. Otherwise the data previously entered by the user will be restored.
==cueText==
(string) if the textField is empty this will be displayed ghosted in the control to show the format or type of data that is needed.
==help==
(string) the help text that will be displayed if the user hovers their mouse over the control.
==action==
(string) the name of a handler in your script that will be called with the interface data if the user makes a change to this interface element.
==options==
(JSON list) for a popup menu this is the list of options to choose from. Each item should also be a list with 2 or 3 elements in it. The first element is the text you wish to display to the user. The second is the key that will be used to present the selected option to your script and to restore the selection when the interface is opened again after saving. If a third item is a boolean true then that entry will be the default selected if no user selection has yet been stored.
"options":[
["do it carefully", "careful"],
["do it fast", "fast"],
["do it faster!", "faster", True],
["just rush through it", "rush"]
]
If the control is a segmented control then the option array is different, instead of a list of lists it's a list of dictionaries that list out some of the options for each segment:
"options":[
{"text":"segment one", "key":"segOne", "width":75, "action":"segSelected", "selected":True},
{"text":"segment two", "key":"segTwo", "width":75, "action":"segSelected"}
]
==value==
(BOOLEAN) defaults to false. if included for checkbox the boolean value will be used as the default if there is no user state already saved.
==fileName==
(STRING) required for the "image" control, the name of the image you would like to load and display in the "image" control. It must be inside of your plugin folder. The name should include the file extension, but not any path information or folder reference. Only images at the root level of your plugin folder may be loaded.
===Putting it all together===
It can be very tedious to create an interface like this with the Bounds having to be tweaked and setup to get it to look right. I recommend downloading the demo version of the [[http://xojo.com|Xojo]] Ide and creating a window of the appropriate size. You can then manually transfer the bounds from the IDE to the bounds values in the JSON file much easier than trying to guess and eyeball them. You will also end up with control spacing that follows the Apple User Interface Guidelines and will look more normal and part of the overall UI of the app that way.
\\
\\
PREVIOUS: [[plugins:03_units|]] NEXT: [[plugins:05_commandsAndEvents|]]