Table of Contents

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:

{“type”:”label”, “text”:”Fade Speed:”, “bounds”:[4, 4, 75, 16]}
{"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"]
	]
},
{“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"}
   ]
}
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 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: Plugin API: info.json Defining Unit Types NEXT: Plugin API: Talking To XTension