Skip to content

Commit 17c13ef

Browse files
Add scale to ScaledSlider
1 parent 39df110 commit 17c13ef

File tree

2 files changed

+110
-58
lines changed

2 files changed

+110
-58
lines changed

src/ui/widgets/SlideControl/slideControl.test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ test("slideControl", () => {
1010
connected={true}
1111
readonly={false}
1212
pvName="pv"
13-
max={10}
14-
min={0}
13+
maximum={10}
14+
minimum={0}
1515
></SlideControlComponent>
1616
);
1717

1818
// The label on the progress bar.
19-
expect(screen.getByText("5")).toBeInTheDocument();
19+
expect(screen.getByText("4")).toBeInTheDocument();
2020
// The slider element.
2121
const slider = container.querySelector("input");
2222
expect(slider?.value).toEqual("5");

src/ui/widgets/SlideControl/slideControl.tsx

Lines changed: 107 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ import {
1616
import { registerWidget } from "../register";
1717
import { DType } from "../../../types/dtypes";
1818
import { Slider, useTheme } from "@mui/material";
19+
import { WIDGET_DEFAULT_SIZES } from "../EmbeddedDisplay/bobParser";
1920

2021
export const SliderControlProps = {
21-
min: FloatPropOpt,
22-
max: FloatPropOpt,
22+
minimum: FloatPropOpt,
23+
maximum: FloatPropOpt,
2324
limitsFromPv: BoolPropOpt,
2425
logScale: BoolPropOpt,
2526
horizontal: BoolPropOpt,
@@ -40,7 +41,10 @@ export const SliderControlProps = {
4041
showHigh: BoolPropOpt,
4142
showLow: BoolPropOpt,
4243
showLolo: BoolPropOpt,
43-
increment: FloatPropOpt
44+
increment: FloatPropOpt,
45+
majorTickStepHint: IntPropOpt,
46+
width: FloatPropOpt,
47+
height: FloatPropOpt
4448
};
4549

4650
export const SlideControlComponent = (
@@ -49,7 +53,6 @@ export const SlideControlComponent = (
4953
const theme = useTheme();
5054
const {
5155
pvName,
52-
connected,
5356
value = null,
5457
enabled = true,
5558
horizontal = true,
@@ -65,16 +68,58 @@ export const SlideControlComponent = (
6568
showHigh = true,
6669
showLow = true,
6770
showLolo = true,
68-
increment = 1
71+
increment = 1,
72+
majorTickStepHint = 40,
73+
width = WIDGET_DEFAULT_SIZES["scaledslider"][0],
74+
height = WIDGET_DEFAULT_SIZES["scaledslider"][1]
6975
} = props;
70-
let { min = 0, max = 100 } = props;
76+
let { minimum = 0, maximum = 100 } = props;
7177

72-
const disabled = !connected || value === null ? true : !enabled;
7378
const font = props.font?.css() ?? theme.typography;
7479

7580
if (limitsFromPv && value?.display.controlRange) {
76-
min = value.display.controlRange?.min;
77-
max = value.display.controlRange?.max;
81+
minimum = value.display.controlRange?.min;
82+
maximum = value.display.controlRange?.max;
83+
}
84+
85+
const range = maximum - minimum;
86+
let marks = [];
87+
let decimalPlaces = 0;
88+
let tickInterval;
89+
90+
// Calculate number of ticks to show
91+
let numOfTicks = Math.round(
92+
(horizontal ? width : height) / majorTickStepHint
93+
);
94+
if (numOfTicks > 15) numOfTicks = 15; // Phoebus roughly has a maximum of 15 ticks
95+
// Check if the number of ticks makes equal markers, iterate until we find good value
96+
// If range is less than one, we will never have round numbers
97+
if (range > 1) {
98+
let tickRemainder = range % numOfTicks;
99+
while (tickRemainder !== 0) {
100+
numOfTicks--;
101+
tickRemainder = range % numOfTicks;
102+
}
103+
tickInterval = range / numOfTicks;
104+
} else {
105+
// Can't use remainder so round to 1 less decimal place than parent
106+
decimalPlaces = (range / 10).toString().split(".")[1].length;
107+
tickInterval = Number((range / numOfTicks).toFixed(decimalPlaces));
108+
}
109+
110+
// Create marks
111+
for (let i = minimum; i <= maximum; ) {
112+
marks.push({
113+
value: i,
114+
label: i.toFixed(decimalPlaces)
115+
});
116+
i = i + tickInterval;
117+
if (i > maximum) {
118+
marks.push({
119+
value: maximum,
120+
label: maximum.toFixed(decimalPlaces)
121+
});
122+
}
78123
}
79124

80125
const [inputValue, setInputValue] = useState<number>(
@@ -88,68 +133,70 @@ export const SlideControlComponent = (
88133
}, [value]);
89134

90135
function onMouseUp(value: number): void {
91-
try {
92-
writePv(pvName, new DType({ doubleValue: value }));
93-
} catch (error) {
94-
log.warn(`Unexpected value ${value} set to slider.`);
136+
if (pvName !== undefined) {
137+
try {
138+
writePv(pvName, new DType({ doubleValue: value }));
139+
} catch (error) {
140+
log.warn(`Unexpected value ${value} set to slider.`);
141+
}
95142
}
96143
}
97144

98-
const marks = showScale
99-
? [
100-
...(showHihi
101-
? [
102-
{
103-
value: levelHihi,
104-
label: levelHihi.toString()
105-
}
106-
]
107-
: []),
108-
...(showHigh
109-
? [
110-
{
111-
value: levelHigh,
112-
label: levelHigh.toString()
113-
}
114-
]
115-
: []),
116-
...(showLow
117-
? [
118-
{
119-
value: levelLow,
120-
label: levelLow.toString()
121-
}
122-
]
123-
: []),
124-
...(showLolo
125-
? [
126-
{
127-
value: levelLolo,
128-
label: levelLolo.toString()
129-
}
130-
]
131-
: [])
132-
]
133-
: [];
145+
// Add HIGH, HIHI, LOW and LOLO markers
146+
marks = marks.concat([
147+
...(showHihi
148+
? [
149+
{
150+
value: levelHihi,
151+
label: "\nHIHI"
152+
}
153+
]
154+
: []),
155+
...(showHigh
156+
? [
157+
{
158+
value: levelHigh,
159+
label: "\nHIGH"
160+
}
161+
]
162+
: []),
163+
...(showLow
164+
? [
165+
{
166+
value: levelLow,
167+
label: "\nLOW"
168+
}
169+
]
170+
: []),
171+
...(showLolo
172+
? [
173+
{
174+
value: levelLolo,
175+
label: "\nLOLO"
176+
}
177+
]
178+
: [])
179+
]);
134180

135181
return (
136182
<Slider
137183
value={inputValue}
138-
disabled={disabled}
184+
disabled={!enabled}
139185
orientation={horizontal ? "horizontal" : "vertical"}
140186
onChange={(_, newValue) => setInputValue(newValue as number)}
141187
onChangeCommitted={(_, newValue) => onMouseUp(newValue as number)}
142188
valueLabelDisplay="auto"
143-
min={min}
144-
max={max}
145-
marks={marks}
189+
min={minimum}
190+
max={maximum}
191+
marks={showScale ? marks : false}
146192
step={increment}
147193
sx={{
148194
color: foregroundColor.toString(),
149195
"& .MuiSlider-thumb": {
150196
height: 16,
151197
width: 16,
152-
backgroundColor: foregroundColor.toString(),
198+
backgroundColor: "white",
199+
border: "2px solid currentColor",
153200
"&:focus, &:hover, &.Mui-active, &.Mui-focusVisible": {
154201
boxShadow: "inherit"
155202
}
@@ -162,7 +209,12 @@ export const SlideControlComponent = (
162209
},
163210
"& .MuiSlider-markLabel": {
164211
fontFamily: font,
165-
color: foregroundColor.toString()
212+
color: foregroundColor.toString(),
213+
whiteSpace: "pre"
214+
},
215+
"&.Mui-disabled": {
216+
cursor: "not-allowed",
217+
pointerEvents: "all !important"
166218
}
167219
}}
168220
/>

0 commit comments

Comments
 (0)