Files
op-pedal/vite/src/pipedal/MidiChannelBindingDialog.tsx
T
2025-06-22 16:12:03 -04:00

203 lines
8.6 KiB
TypeScript

/* eslint-disable @typescript-eslint/no-unused-vars */
// Copyright (c) 2024 Robin E. R. Davies
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import { useState } from 'react';
import Button from '@mui/material/Button';
import DialogTitle from '@mui/material/DialogTitle';
import DialogActions from '@mui/material/DialogActions';
import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
import FormControlLabel from '@mui/material/FormControlLabel';
import ChannelBindingHelpDialog from './ChannelBindingsHelpDialog';
import IconButtonEx from './IconButtonEx';
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
import Checkbox from '@mui/material/Checkbox';
import { AlsaMidiDeviceInfo } from './AlsaMidiDeviceInfo';
import DialogEx from './DialogEx';
import MidiChannelBinding, { MidiDeviceSelection } from './MidiChannelBinding';
import DialogContent from '@mui/material/DialogContent';
import Typography from '@mui/material/Typography';
import Select, { SelectChangeEvent } from '@mui/material/Select';
import MenuItem from '@mui/material/MenuItem';
export interface MidiChannelBindingDialogProps {
open: boolean;
midiChannelBinding: MidiChannelBinding;
onClose: () => void;
onChanged: (midiChannelBinding: MidiChannelBinding) => void;
midiDevices: AlsaMidiDeviceInfo[];
}
function MidiChannelBindingDialog(props: MidiChannelBindingDialogProps) {
const { onClose, midiChannelBinding, open } = props;
const [currentChannel, setCurrentChannel] = useState(midiChannelBinding.channel);
const [allowProgramChanges, setAllowProgramChanges] = useState(midiChannelBinding.acceptCommonMessages);
const [helpDialog, setHelpDialog] = useState(false);
const model: PiPedalModel = PiPedalModelFactory.getInstance();
const handleClose = (): void => {
onClose();
};
const handleOk = (): void => {
onClose();
};
const generateDeviceSelect = () => {
let result: React.ReactElement[] = [
(<MenuItem key={0} value={0}>Any</MenuItem>),
(<MenuItem key={1} value={1}>None</MenuItem>)
];
let i = 2;
for (let midiDevice of model.jackConfiguration.get().inputMidiDevices) {
result.push((<MenuItem key={i} value={i}>{midiDevice.description}</MenuItem>));
++i;
}
return result;
};
const getDefaultDeviceSelect = (): number => {
if (midiChannelBinding.deviceSelection === MidiDeviceSelection.DeviceAny as number) {
return 0;
}
if (midiChannelBinding.deviceSelection === MidiDeviceSelection.DeviceNone as number) {
return 1;
}
if (midiChannelBinding.midiDevices.length === 0) {
return 0;
}
let selectedDevice = midiChannelBinding.midiDevices[0];
let ix = 2;
for (let midiDevice of model.jackConfiguration.get().inputMidiDevices) {
if (midiDevice.name === selectedDevice) {
return ix;
}
++ix;
}
return 0; // any.
}
const [currentDeviceSelect, setCurrentDeviceSelect] = useState(getDefaultDeviceSelect())
const handleDeviceSelecChange = (event: SelectChangeEvent) => {
setCurrentDeviceSelect(parseInt(event.target.value));
};
const handleChannelChange = (event: SelectChangeEvent) => {
setCurrentChannel(parseInt(event.target.value));
};
return (
<DialogEx tag="midiChannelBinding" onClose={handleClose} aria-labelledby="select-channels-title" open={open}
onEnterKey={()=>{}} fullWidth maxWidth="xs"
>
<DialogTitle id="simple-dialog-title">MIDI Channel Filters</DialogTitle>
<DialogContent>
<div style={{
display: "grid", alignItems: "center", columnGap: 24, rowGap: 24,
gridTemplateColumns: "1fr"
}}>
<div >
<Typography display="block" variant="caption">MIDI Devices</Typography>
<Select variant='standard' value={currentDeviceSelect.toString()} fullWidth
onChange={handleDeviceSelecChange} >
{
generateDeviceSelect()
}
</Select>
</div>
<div>
<Typography display="block" variant="caption">Channels</Typography>
<Select variant='standard' label="Channels" value={currentChannel.toString()} fullWidth
onChange={handleChannelChange}>
<MenuItem value={-1}>Omni</MenuItem>
<MenuItem value={0}>Channel 1</MenuItem>
<MenuItem value={1}>Channel 2</MenuItem>
<MenuItem value={2}>Channel 3</MenuItem>
<MenuItem value={3}>Channel 4</MenuItem>
<MenuItem value={4}>Channel 5</MenuItem>
<MenuItem value={5}>Channel 6</MenuItem>
<MenuItem value={6}>Channel 7</MenuItem>
<MenuItem value={7}>Channel 8</MenuItem>
<MenuItem value={8}>Channel 9</MenuItem>
<MenuItem value={9}>Channel 10</MenuItem>
<MenuItem value={10}>Channel 11</MenuItem>
<MenuItem value={11}>Channel 12</MenuItem>
<MenuItem value={12}>Channel 13</MenuItem>
<MenuItem value={13}>Channel 14</MenuItem>
<MenuItem value={14}>Channel 15</MenuItem>
<MenuItem value={15}>Channel 16</MenuItem>
</Select>
</div>
<div style={{ display: "flex", flexFlow: "row nowrap", justifyContent: "center" }}>
<FormControlLabel control={
<Checkbox checked={allowProgramChanges}
onChange={(event) => {
setAllowProgramChanges(event.target.checked);
}}
/>
} label="Allow Program Changes"
/>
{false&&( // wait until the implementation stabilizes before exposing the help dialog.
<IconButtonEx
tooltip="Help"
aria-label="help"
onClick={() => { setHelpDialog(true); }}
size="large">
<InfoOutlinedIcon color='inherit'
style={{
fill: "var(--mui-palette.text.primary)",
opacity: 0.6
}}
/>
</IconButtonEx>
)}
</div>
</div>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} variant="dialogSecondary" >
Cancel
</Button>
<Button onClick={handleOk} variant="dialogPrimary" >
OK
</Button>
</DialogActions>
<ChannelBindingHelpDialog open={helpDialog} onClose={()=>setHelpDialog(false)}
/>
</DialogEx>
);
}
export default MidiChannelBindingDialog;