66 lines
2.3 KiB
TypeScript
66 lines
2.3 KiB
TypeScript
import { h } from 'preact';
|
|
import { useState, useEffect } from 'preact/hooks';
|
|
import { getSignalStore } from '../lib/stores';
|
|
import type { Widget, SignalValue } from '../lib/types';
|
|
|
|
const DEFAULT_VALUE: SignalValue = { value: null, quality: 'unknown', ts: null };
|
|
|
|
function getBit(val: number, bit: number): boolean {
|
|
return (val & (1 << bit)) !== 0;
|
|
}
|
|
|
|
interface Props { widget: Widget; onContextMenu?: (e: MouseEvent) => void; }
|
|
|
|
export default function MultiLed({ widget, onContextMenu }: Props) {
|
|
const sigRef = widget.signals[0];
|
|
const [sv, setSv] = useState<SignalValue>(DEFAULT_VALUE);
|
|
|
|
useEffect(() => {
|
|
if (!sigRef) return;
|
|
const unsub = getSignalStore(sigRef).subscribe(setSv);
|
|
return unsub;
|
|
}, [sigRef?.ds, sigRef?.name]);
|
|
|
|
const bits = parseInt(widget.options['bits'] ?? '8', 10);
|
|
const labelsRaw = widget.options['labels'] ?? '';
|
|
const colorsTrueRaw = widget.options['colorsTrue'] ?? '';
|
|
const colorsFalseRaw = widget.options['colorsFalse'] ?? '';
|
|
|
|
const labelArr = labelsRaw ? labelsRaw.split(',') : [];
|
|
const colorsTrueArr = colorsTrueRaw ? colorsTrueRaw.split(',') : [];
|
|
const colorsFalseArr = colorsFalseRaw ? colorsFalseRaw.split(',') : [];
|
|
|
|
const quality = sv.quality;
|
|
const isUncertain = quality === 'uncertain' || quality === 'unknown';
|
|
|
|
const rawV = sv.value;
|
|
const intValue = rawV === null || rawV === undefined ? 0
|
|
: typeof rawV === 'number' ? Math.floor(rawV) : parseInt(String(rawV), 10);
|
|
|
|
const bitStates = Array.from({ length: bits }, (_, i) => getBit(intValue, i));
|
|
|
|
return (
|
|
<div
|
|
class="multiled-widget"
|
|
style={`left:${widget.x}px;top:${widget.y}px;width:${widget.w}px;height:${widget.h}px;`}
|
|
onContextMenu={onContextMenu}
|
|
>
|
|
{bitStates.map((on, i) => {
|
|
const trueColor = colorsTrueArr[i] ?? '#22c55e';
|
|
const falseColor = colorsFalseArr[i] ?? '#ef4444';
|
|
const color = on ? trueColor : falseColor;
|
|
const bitLabel = labelArr[i] ?? String(i);
|
|
return (
|
|
<div key={i} class="bit-item">
|
|
<div
|
|
class={`led-circle${isUncertain ? ' blink' : ''}`}
|
|
style={`background:${color};box-shadow:0 0 6px ${color}88;`}
|
|
/>
|
|
<div class="bit-label">{bitLabel}</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
);
|
|
}
|