diff options
Diffstat (limited to 'src/client/views/nodes/PhysicsBox/PhysicsSimulationInputField.tsx')
-rw-r--r-- | src/client/views/nodes/PhysicsBox/PhysicsSimulationInputField.tsx | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationInputField.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationInputField.tsx new file mode 100644 index 000000000..91b0ad84c --- /dev/null +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationInputField.tsx @@ -0,0 +1,184 @@ +import { useState, useEffect } from "react"; +import { TextField, InputAdornment } from "@mui/material"; + +import TaskAltIcon from "@mui/icons-material/TaskAlt"; +import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline"; +export interface IInputProps { + label?: JSX.Element; + lowerBound: number; + changeValue: (val: number) => any; + step: number; + unit: string; + upperBound: number; + value: number | string | Array<number | string>; + correctValue?: number; + showIcon?: boolean; + effect?: (val: number) => any; + radianEquivalent?: boolean; + small?: boolean; + mode?: string; + update?: boolean; + labelWidth?: string; +} + +export const InputField = (props: IInputProps) => { + const { + changeValue, + correctValue, + effect, + label, + lowerBound, + mode, + radianEquivalent, + showIcon, + small, + step, + unit, + upperBound, + value, + update, + labelWidth, + } = props; + let epsilon: number = 0.01; + + let width = small ? "6em" : "7em"; + let margin = small ? "0px" : "10px"; + + const [tempValue, setTempValue] = useState<any>( + mode != "Freeform" && !showIcon ? 0 : value + ); + + const [tempRadianValue, setTempRadianValue] = useState( + mode != "Freeform" && !showIcon ? 0 : (Number(value) * Math.PI) / 180 + ); + + useEffect(() => { + if (mode == "Freeform") { + if (Math.abs(tempValue - Number(value)) > 1) { + setTempValue(Number(value)); + } + } + }, [value]); + + const externalUpdate = () => { + changeValue(Number(value)); + setTempValue(Number(value)); + setTempRadianValue((Number(value) * Math.PI) / 180); + }; + + useEffect(() => { + externalUpdate(); + }, [update]); + + const onChange = (event: React.ChangeEvent<HTMLInputElement>) => { + let value = event.target.value == "" ? 0 : Number(event.target.value); + if (value > upperBound) { + value = upperBound; + } else if (value < lowerBound) { + value = lowerBound; + } + changeValue(value); + setTempValue(event.target.value == "" ? event.target.value : value); + setTempRadianValue((value * Math.PI) / 180); + if (effect) { + effect(value); + } + }; + + const onChangeRadianValue = (event: React.ChangeEvent<HTMLInputElement>) => { + let value = event.target.value === "" ? 0 : Number(event.target.value); + if (value > 2 * Math.PI) { + value = 2 * Math.PI; + } else if (value < 0) { + value = 0; + } + changeValue((value * 180) / Math.PI); + setTempValue((value * 180) / Math.PI); + setTempRadianValue(value); + if (effect) { + effect((value * 180) / Math.PI); + } + }; + + return ( + <div + style={{ + display: "flex", + lineHeight: "1.5", + textAlign: "right", + alignItems: "center", + }} + > + {label && ( + <div + style={{ + marginTop: "0.3em", + marginBottom: "-0.5em", + width: labelWidth ?? "2em", + }} + > + {label} + </div> + )} + <TextField + type="number" + variant="standard" + value={tempValue} + onChange={onChange} + sx={{ + height: "1em", + width: { width }, + marginLeft: { margin }, + zIndex: "modal", + }} + inputProps={{ + step: step, + min: lowerBound, + max: upperBound, + type: "number", + }} + InputProps={{ + startAdornment: ( + <InputAdornment position="start"> + {Math.abs(Number(value) - (correctValue ?? 0)) < epsilon && + showIcon && <TaskAltIcon color={"success"} />} + {Math.abs(Number(value) - (correctValue ?? 0)) >= epsilon && + showIcon && <ErrorOutlineIcon color={"error"} />} + </InputAdornment> + ), + endAdornment: <InputAdornment position="end">{unit}</InputAdornment>, + }} + /> + {radianEquivalent && ( + <div + style={{ marginTop: "0.3em", marginBottom: "-0.5em", width: "1em" }} + > + <p>≈</p> + </div> + )} + {radianEquivalent && ( + <TextField + type="number" + variant="standard" + value={tempRadianValue} + onChange={onChangeRadianValue} + sx={{ + height: "1em", + width: { width }, + marginLeft: { margin }, + zIndex: "modal", + }} + inputProps={{ + step: Math.PI / 8, + min: 0, + max: 2 * Math.PI, + type: "number", + }} + InputProps={{ + endAdornment: <InputAdornment position="end">rad</InputAdornment>, + }} + /> + )} + </div> + ); +}; |