Voicemeeter-remote-frontend/src/app/component/Bus.tsx
Maksym 81d889d66e modified: src/app/component/Bus.tsx
modified:   src/app/component/BusesList.tsx
	modified:   src/app/component/Strip.tsx
	modified:   src/app/page.tsx
2024-08-08 00:33:48 +02:00

260 lines
7.4 KiB
TypeScript

"use client";
import {
Button,
ButtonGroup,
Grid,
Input,
Slider,
Stack,
styled,
TextField,
Typography,
} from "@mui/material";
import React from "react";
import { StripBusOutput, StripBusOutputEvent } from "./StripBusOutput";
import { EventCounter } from "@/utils/EventCounter";
export interface BusProps {
values?: Partial<Omit<BusState, StateDefaultValueException>>;
width: number;
name: string;
onChange: (event: BusEvent) => any;
}
type StateDefaultValueException = "";
export interface BusState {
gain: number;
muted: boolean;
selected: boolean;
}
export type BusEvent = BusMuted | BusGainChanged | BusSelectToggle;
export interface BusGainChanged {
type: "StripGainChanged";
gain: number;
}
export interface BusMuted {
type: "StripMuted";
muted: boolean;
}
export interface BusSelectToggle {
type: "BusSelectToggle";
selected: boolean;
}
export class Bus extends React.Component<BusProps, BusState> {
private eventCounter = new EventCounter<"onSliderResetDefaults">();
private defaultValues: Omit<BusState, StateDefaultValueException> = {
gain: 0,
selected: false,
muted: false,
};
slider = styled(Slider)(({ theme }) => ({
"& .MuiSlider-valueLabel": {
top: 0,
fontFamily: '"Roboto","Helvetica","Arial",sans-serif',
fontWeight: 400,
fontSize: "0.75rem",
width:"4em",
letterSpacing: "0.03333em",
backgroundColor: "unset",
color: theme.palette.text.primary,
"&::before": {
display: "none",
},
"& *": {
background: "transparent",
color: theme.palette.mode === "dark" ? "#fff" : "#000",
},
},
}));
constructor(props: BusProps) {
super(props);
let { values: initialValues } = props;
const getValue = (name: keyof typeof this.defaultValues) => {
if (initialValues === undefined) return this.defaultValues[name];
return initialValues[name] !== undefined
? this.defaultValues[name]
: initialValues[name];
};
this.state = {
...(Object.fromEntries(
Object.entries(this.defaultValues).map(([name]) => [
name,
getValue(name as keyof typeof this.defaultValues) as any,
])
) as Omit<BusState, StateDefaultValueException>),
};
this.eventCounter.on({
callback: this.onResetDefaults.bind(this),
count: 2,
name: "onSliderResetDefaults",
});
}
onResetDefaults() {
this.setState({ gain: this.defaultValues.gain });
}
onKeyDown(event: React.KeyboardEvent) {
console.log(event);
if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
event.preventDefault();
}
}
onGainChange(event: Event | React.ChangeEvent<HTMLInputElement>) {
let changedGain = parseFloat((event.target as HTMLInputElement).value);
if (changedGain > 12) changedGain = 12;
else if (changedGain < -60) changedGain = -60;
this.setState({
gain: changedGain,
});
this.props.onChange({
type: "StripGainChanged",
gain: changedGain,
});
}
onStripWheel(event: React.WheelEvent) {
console.log(event);
}
onSliderClick(event: React.MouseEvent) {
this.stopPropagation(event);
this.eventCounter.emit("onSliderResetDefaults");
}
onMuteToggle(event: React.MouseEvent) {
this.stopPropagation(event);
this.setState(
(state) => ({ muted: !state.muted }),
() => {
this.props.onChange({ type: "StripMuted", muted: this.state.muted });
}
);
}
onSelectToggle(event: React.MouseEvent) {
this.stopPropagation(event);
this.setState(
(state) => ({ selected: !state.selected }),
() => {
this.props.onChange({
type: "BusSelectToggle",
selected: this.state.selected,
});
}
);
}
stopPropagation(event: Event | React.MouseEvent) {
if (event instanceof Event) event.stopImmediatePropagation();
else event.nativeEvent.stopImmediatePropagation();
}
render() {
return (
<>
<Stack
alignItems={"center"}
direction={"row"}
spacing={0}
sx={{ width: "inherit" }}
>
{this.props.width > 600 ? (
<TextField
// inputProps={{
// "aria-labelledby": "input-slider",
// itemType: "number",
// style:{padding: 0}
// }}
value={this.state.gain}
onWheel={(e) => this.onStripWheel(e)}
onClick={(e) => this.stopPropagation(e)}
onChange={(e) => this.onGainChange(e as unknown as Event)}
size="small"
label={this.props.name}
type="number"
variant="outlined"
sx={{ minWidth: "100px", maxWidth: "100px" }}
/>
) : (
<Typography variant="caption">{this.props.name}</Typography>
)}
{/* {this.props.width <= 600 && (
<Typography
position={"absolute"}
paddingInlineStart={"10rem"}
paddingBlockEnd={"2rem"}
fontSize={"0.6rem"}
width={"fit-content"}
variant="caption"
>
{this.state.gain}dB
</Typography>
)} */}
<this.slider
sx={{
// margin: "5px",
marginInline: "10px",
}}
valueLabelFormat={(e) => `${e} dB`}
// orientation="vertical"
color={
(this.state.gain > 0 && this.state.gain < 12 && "warning") ||
(this.state.gain >= 12 && "error") ||
(this.state.gain < 0 && "info") ||
"primary"
}
defaultValue={0.0}
step={0.1}
min={-60}
max={12}
value={this.state.gain}
valueLabelDisplay={this.props.width > 600 ? "off" : "on"}
onChange={(e) => this.onGainChange(e)}
onClick={(e) => this.onSliderClick(e)}
/>
<ButtonGroup>
<Button
onClick={(e) => this.onMuteToggle(e)}
variant={this.state.muted ? "contained" : "outlined"}
color={"error"}
>
Mute
</Button>
<Button
onClick={(e) => this.onSelectToggle(e)}
sx={{}}
variant={this.state.selected ? "contained" : "outlined"}
color={"warning"}
>
S
</Button>
</ButtonGroup>
</Stack>
{/* <Stack>
<ButtonGroup orientation="vertical">
{[
...Array(this.props.physicalBuses + this.props.virtualBuses),
].map((_v, i) => (
<StripBusOutput
key={`${i < this.props.physicalBuses ? "a" : "b"}${
i < this.props.physicalBuses
? i
: i - this.props.physicalBuses
}`}
id={
i < this.props.physicalBuses
? i
: i - this.props.physicalBuses
}
isVirtual={i < this.props.physicalBuses ? false : true}
onChange={(ev) => this.onBusChange(ev)}
default={{ enabled: this.state.buses[i] }}
/>
))}
</ButtonGroup>
</Stack> */}
</>
);
}
}