Add way to set spinner step without changing HTTP API

This commit is contained in:
Julian Stirling 2026-02-19 13:34:31 +00:00
parent cd14f470f6
commit e66fe5a35a
5 changed files with 50 additions and 11 deletions

View file

@ -173,13 +173,13 @@ class RectGridWorkflow(ScanWorkflow[SettingModelType], Generic[SettingModelType]
# Redefine _csm Thing Slot, as CSM is required for any RectGridWorkflow
_csm: CameraStageMapper = lt.thing_slot()
overlap: float = lt.setting(default=0.45, ge=0.1, le=0.7, multiple_of=0.05)
overlap: float = lt.setting(default=0.45, ge=0.1, le=0.7)
"""The fraction that adjacent images should overlap in x and y.
This must be between 0.1 and 0.7.
"""
autofocus_dz: int = lt.setting(default=1000, ge=400, le=3000, multiple_of=200)
autofocus_dz: int = lt.setting(default=1000, ge=400, le=3000)
"""The z distance to perform an autofocus in steps.
Must be greater than or equal to 400, and less than or equal to 3000.
@ -290,7 +290,7 @@ class HistoScanWorkflow(RectGridWorkflow[HistoScanSettingsModel]):
This uses the settings from the ``BackgroundDetectThing``.
"""
max_range: int = lt.setting(default=45000, multiple_of=1000)
max_range: int = lt.setting(default=45000)
"""The maximum distance in steps from the centre of the scan."""
# Stacking settings
@ -311,7 +311,7 @@ class HistoScanWorkflow(RectGridWorkflow[HistoScanSettingsModel]):
Defaults to 9 which balances reliability and speed.
"""
stack_dz: int = lt.setting(default=50, ge=20, le=400, multiple_of=10)
stack_dz: int = lt.setting(default=50, ge=20, le=400)
"""Distance in steps between images in a z-stack.
Suggested values:
@ -538,7 +538,9 @@ class HistoScanWorkflow(RectGridWorkflow[HistoScanSettingsModel]):
def settings_ui(self) -> list[PropertyControl]:
"""A list of PropertyControl objects to create the settings in the scan tab."""
return [
property_control_for(self, "overlap", label="Image Overlap (0.1-0.7)"),
property_control_for(
self, "overlap", label="Image Overlap (0.1-0.7)", step=0.05
),
property_control_for(
self, "stack_images_to_save", label="Images in Stack to Save"
),
@ -547,9 +549,13 @@ class HistoScanWorkflow(RectGridWorkflow[HistoScanSettingsModel]):
"stack_min_images_to_test",
label="Minimum number of images to test for focus",
),
property_control_for(self, "stack_dz", label="Stack dz (steps)"),
property_control_for(self, "autofocus_dz", label="Autofocus Range (steps)"),
property_control_for(self, "max_range", label="Maximum Distance (steps)"),
property_control_for(self, "stack_dz", label="Stack dz (steps)", step=5),
property_control_for(
self, "autofocus_dz", label="Autofocus Range (steps)", step=200
),
property_control_for(
self, "max_range", label="Maximum Distance (steps)", step=1000
),
property_control_for(
self, "skip_background", label="Detect and Skip Empty Fields "
),
@ -662,7 +668,9 @@ class RegularGridWorkflow(RectGridWorkflow[RegularGridSettingsModel]):
def settings_ui(self) -> list[PropertyControl]:
"""A list of PropertyControl objects to create the settings in the scan tab."""
return [
property_control_for(self, "overlap", label="Image Overlap (0.1-0.7)"),
property_control_for(
self, "overlap", label="Image Overlap (0.1-0.7)", step=0.05
),
property_control_for(self, "x_count", label="Number of columns"),
property_control_for(self, "y_count", label="Number of rows"),
property_control_for(self, "autofocus_dz", label="Autofocus Range (steps)"),

View file

@ -97,6 +97,16 @@ class PropertyControl(BaseModel):
when selected.
"""
step: Optional[int | float] = None
"""The step size for a numerical input.
If the property is not numeric this will be ignored.
If this is left as None, then the UI will try to use the ``multipleOf`` field in
the property dataSchema. If ``multipleOf`` is not set then the browser default is
used.
"""
def property_control_for(
thing: lt.Thing, property_name: str, **kwargs: Any

View file

@ -27,7 +27,7 @@
type="number"
:min="minimum"
:max="maximum"
:step="step"
:step="spinner_step"
@input="grabFocus"
@focusout="focusOut"
@keydown="keyDown"
@ -152,6 +152,11 @@ export default {
default: null,
required: false,
},
step: {
type: Number,
default: null,
required: false,
},
},
emits: ["requestUpdate", "sendValue", "animationShown"],
@ -253,8 +258,17 @@ export default {
if (this.dataType !== "number") return undefined;
return this.dataSchema.minimum;
},
step() {
/**
* The step size for numerical spinners.
*
* If not a number this is `undefined`. If `step` is set as a prop then it is used
* otherwise `multipleOf` from the property `dataSchema` is used. If `multipleOf`
* is not set in the `dataSchema` JS will return `undefined` and the browser will
* use its default value.
*/
spinner_step() {
if (this.dataType !== "number") return undefined;
if (this.step !== null) return this.step;
return this.dataSchema.multipleOf;
},
},

View file

@ -5,6 +5,7 @@
:label="label"
:animate="animate"
:options="options"
:step="step"
@request-update="readProperty"
@send-value="writeProperty"
@animation-shown="resetAnimate"
@ -50,6 +51,11 @@ export default {
default: null,
required: false,
},
step: {
type: Number,
default: null,
required: false,
},
},
data() {

View file

@ -7,6 +7,7 @@
:read-back="propertyData.read_back"
:read-back-delay="propertyData.read_back_delay"
:options="propertyData.options"
:step="propertyData.step"
/>
</template>