I wanted more control over not only updates, but also a spinner that would continually inc/dec the value if you hold down the button, so I rolled my own:
Here’s the view JSON for anyone interested in trying it:
{
"custom": {
"running": true
},
"events": {
"system": {
"onShutdown": {
"config": {
"script": "\tself.custom.running \u003d False"
},
"scope": "G",
"type": "script"
}
}
},
"params": {
"buttonStyle": {
"classes": ""
},
"buttonWidth": 0.2,
"deferUpdates": false,
"enabled": true,
"focus": false,
"increment": 1,
"isFloat": false,
"maximum": null,
"minimum": 0,
"pressDelay": 0.2,
"pressDelayAccelerate": 0.015,
"pressDelayMinimum": 0.03,
"pressInitialDelay": 0.33,
"rejectUpdatesWhileFocused": true,
"style": {
"borderBottomLeftRadius": 5,
"borderBottomRightRadius": 5,
"borderColor": "#000000",
"borderStyle": "solid",
"borderTopLeftRadius": 5,
"borderTopRightRadius": 5,
"borderWidth": 1,
"classes": "",
"overflow": "hidden"
},
"textFieldStyle": {
"borderStyle": "none",
"classes": "",
"fontFamily": "monospace",
"fontSize": "200%",
"paddingRight": "25%",
"textAlign": "right"
},
"value": 0
},
"propConfig": {
"custom.running": {
"persistent": true
},
"params.buttonStyle": {
"paramDirection": "input",
"persistent": true
},
"params.buttonWidth": {
"paramDirection": "input",
"persistent": true
},
"params.deferUpdates": {
"paramDirection": "input",
"persistent": true
},
"params.enabled": {
"paramDirection": "input",
"persistent": true
},
"params.focus": {
"onChange": {
"enabled": null,
"script": "\tif currentValue.value and self.custom.running:\n\t\tself.getChild(\"root\").getChild(\"TextField\").focus()\n\t\tself.params.focus \u003d False"
},
"paramDirection": "inout",
"persistent": true
},
"params.increment": {
"paramDirection": "input",
"persistent": true
},
"params.isFloat": {
"paramDirection": "input",
"persistent": true
},
"params.maximum": {
"paramDirection": "input",
"persistent": true
},
"params.minimum": {
"paramDirection": "input",
"persistent": true
},
"params.pressDelay": {
"paramDirection": "input",
"persistent": true
},
"params.pressDelayAccelerate": {
"paramDirection": "input",
"persistent": true
},
"params.pressDelayMinimum": {
"paramDirection": "input",
"persistent": true
},
"params.pressInitialDelay": {
"paramDirection": "input",
"persistent": true
},
"params.rejectUpdatesWhileFocused": {
"paramDirection": "input",
"persistent": true
},
"params.style": {
"paramDirection": "input",
"persistent": true
},
"params.textFieldStyle": {
"paramDirection": "inout",
"persistent": true
},
"params.value": {
"binding": {
"config": {
"bidirectional": true,
"path": "/root/TextField.props.text"
},
"type": "property"
},
"paramDirection": "inout",
"persistent": true
}
},
"props": {
"defaultSize": {
"height": 38,
"width": 120
}
},
"root": {
"children": [
{
"meta": {
"name": "TextField"
},
"position": {
"height": 1,
"width": 1
},
"propConfig": {
"props.deferUpdates": {
"binding": {
"config": {
"path": "view.params.deferUpdates"
},
"type": "property"
}
},
"props.enabled": {
"binding": {
"config": {
"path": "view.params.enabled"
},
"type": "property"
}
},
"props.rejectUpdatesWhileFocused": {
"binding": {
"config": {
"path": "view.params.rejectUpdatesWhileFocused"
},
"type": "property"
}
},
"props.style": {
"binding": {
"config": {
"path": "view.params.textFieldStyle"
},
"type": "property"
}
},
"props.text": {
"onChange": {
"enabled": null,
"script": "\tif currentValue.value is not None and currentValue.value !\u003d \u0027\u0027:\n\t\tif self.view.params.isFloat:\n\t\t\tif not Strings.isNumeric(currentValue.value) and Strings.isNumeric(previousValue.value):\n\t\t\t\tself.props.text \u003d previousValue.value\n\t\telse:\n\t\t\tif not Strings.isInteger(currentValue.value) and Strings.isInteger(previousValue.value):\n\t\t\t\tself.props.text \u003d previousValue.value\n\t\tself.parent.increment(0)"
}
}
},
"props": {
"spellcheck": false,
"text": 0
},
"type": "ia.input.text-field"
},
{
"custom": {
"mouseIsDown": false
},
"events": {
"component": {
"onActionPerformed": {
"config": {
"script": "\tself.custom.mouseIsDown \u003d False\n\tself.parent.increment(self.view.params.increment)"
},
"scope": "G",
"type": "script"
}
},
"dom": {
"onMouseDown": {
"config": {
"script": "\tself.custom.mouseIsDown \u003d True"
},
"scope": "G",
"type": "script"
},
"onMouseLeave": {
"config": {
"script": "\tself.custom.mouseIsDown \u003d False"
},
"scope": "G",
"type": "script"
},
"onMouseUp": {
"config": {
"script": "\tself.custom.mouseIsDown \u003d False"
},
"scope": "G",
"type": "script"
}
}
},
"meta": {
"name": "Up"
},
"position": {
"height": 0.5
},
"propConfig": {
"custom.mouseIsDown": {
"onChange": {
"enabled": null,
"script": "\timport time\n\t\n\tdef inc(delay\u003dself.view.params.pressDelay):\n\t\tif self.custom.mouseIsDown:\n\t\t\tself.parent.increment(self.view.params.increment)\n\t\t\ttime.sleep(delay)\n\t\t\tinc(max(delay - self.view.params.pressDelayAccelerate, self.view.params.pressDelayMinimum))\n\t\t\t\n\tdef asynch():\n\t\ttime.sleep(self.view.params.pressInitialDelay)\n\t\tinc()\n\t\t\n\tif currentValue.value:\n\t\tsystem.util.invokeAsynchronous(asynch)"
}
},
"position.width": {
"binding": {
"config": {
"path": "view.params.buttonWidth"
},
"type": "property"
}
},
"position.x": {
"binding": {
"config": {
"expression": "1.001 - {view.params.buttonWidth}"
},
"type": "expr"
}
},
"props.style": {
"binding": {
"config": {
"path": "view.params.buttonStyle"
},
"type": "property"
}
}
},
"props": {
"image": {
"height": "100%",
"icon": {
"path": "material/keyboard_arrow_up"
},
"width": "100%"
},
"primary": false,
"text": ""
},
"type": "ia.input.button"
},
{
"custom": {
"mouseIsDown": false
},
"events": {
"component": {
"onActionPerformed": {
"config": {
"script": "\tself.custom.mouseIsDown \u003d False\n\tself.parent.increment(-self.view.params.increment)"
},
"scope": "G",
"type": "script"
}
},
"dom": {
"onMouseDown": {
"config": {
"script": "\tself.custom.mouseIsDown \u003d True"
},
"scope": "G",
"type": "script"
},
"onMouseLeave": {
"config": {
"script": "\tself.custom.mouseIsDown \u003d False"
},
"scope": "G",
"type": "script"
},
"onMouseUp": {
"config": {
"script": "\tself.custom.mouseIsDown \u003d False"
},
"scope": "G",
"type": "script"
}
}
},
"meta": {
"name": "Down"
},
"position": {
"height": 0.5,
"y": 0.5
},
"propConfig": {
"custom.mouseIsDown": {
"onChange": {
"enabled": null,
"script": "\timport time\n\t\t\t\n\tdef inc(delay\u003dself.view.params.pressDelay):\n\t\tif self.custom.mouseIsDown:\n\t\t\tself.parent.increment(-self.view.params.increment)\n\t\t\ttime.sleep(delay)\n\t\t\tinc(max(delay - self.view.params.pressDelayAccelerate, self.view.params.pressDelayMinimum))\n\t\t\t\n\tdef asynch():\n\t\ttime.sleep(self.view.params.pressInitialDelay)\n\t\tinc()\n\t\t\n\tif currentValue.value:\n\t\tsystem.util.invokeAsynchronous(asynch)"
}
},
"position.width": {
"binding": {
"config": {
"path": "view.params.buttonWidth"
},
"type": "property"
}
},
"position.x": {
"binding": {
"config": {
"expression": "1.001 - {view.params.buttonWidth}"
},
"type": "expr"
}
},
"props.style": {
"binding": {
"config": {
"path": "view.params.buttonStyle"
},
"type": "property"
}
}
},
"props": {
"image": {
"height": "100%",
"icon": {
"path": "material/keyboard_arrow_down"
},
"width": "100%"
},
"primary": false,
"text": ""
},
"type": "ia.input.button"
}
],
"meta": {
"name": "root"
},
"propConfig": {
"props.style": {
"binding": {
"config": {
"path": "view.params.style"
},
"type": "property"
}
}
},
"props": {
"mode": "percent"
},
"scripts": {
"customMethods": [
{
"name": "increment",
"params": [
"amt"
],
"script": "\tif self.getChild(\"TextField\").props.text is None or self.getChild(\"TextField\").props.text \u003d\u003d \u0027\u0027:\n\t\tct \u003d 0\n\telif self.view.params.isFloat:\n\t\tct \u003d float(self.getChild(\"TextField\").props.text)\n\telse:\n\t\tct \u003d int(self.getChild(\"TextField\").props.text)\n\tct +\u003d amt\n\tif self.view.params.minimum is not None and ct \u003c self.view.params.minimum:\n\t\tct \u003d self.view.params.minimum\n\telif self.view.params.maximum is not None and ct \u003e self.view.params.maximum:\n\t\tct \u003d self.view.params.maximum\n\tif self.view.params.isFloat:\n\t\tself.getChild(\"TextField\").props.text \u003d float(ct)\n\telse:\n\t\tself.getChild(\"TextField\").props.text \u003d int(ct)"
}
],
"extensionFunctions": null,
"messageHandlers": []
},
"type": "ia.container.coord"
}
}