// Copyright (c) 2022 Robin 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 React, { ReactNode } from 'react'; import { Theme } from '@mui/material/styles'; import { WithStyles } from '@mui/styles'; import createStyles from '@mui/styles/createStyles'; import withStyles from '@mui/styles/withStyles'; import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel'; import ResizeResponsiveComponent from './ResizeResponsiveComponent'; import { UiControl } from './Lv2Plugin'; import Dialog from '@mui/material/Dialog'; import Input from '@mui/material/Input'; import { nullCast } from './Utility'; import Typography from '@mui/material/Typography'; const styles = (theme: Theme) => createStyles({ frame: { display: "block", position: "relative", flexDirection: "row", flexWrap: "nowrap", paddingTop: "8px", paddingBottom: "0px", height: "100%", overflowX: "auto", overflowY: "auto" }, }); interface FullScreenIMEProps extends WithStyles { theme: Theme; uiControl?: UiControl; caption: string; value: number; onChange: (key: string, value: number) => void; onClose: () => void; initialHeight: number; } type FullScreenIMEState = { error: boolean; }; const FullScreenIME = withStyles(styles, { withTheme: true })( class extends ResizeResponsiveComponent { model: PiPedalModel; inputRef: React.RefObject; constructor(props: FullScreenIMEProps) { super(props); this.model = PiPedalModelFactory.getInstance(); this.inputRef = React.createRef(); this.state = { error: false } this.onValueChanged = this.onValueChanged.bind(this); this.handleClose = this.handleClose.bind(this); this.onInputChange = this.onInputChange.bind(this); this.onInputKeyPress = this.onInputKeyPress.bind(this); this.onInputLostFocus = this.onInputLostFocus.bind(this); } onValueChanged(key: string, value: number): void { this.props.onChange(key, value); } onWindowSizeChanged(width: number, height: number): void { if (this.props.uiControl) { // detecting a keyboard IME is painfully difficult. // we do it by comparing the current window height against the window height // when the IME was requested. // a width change indicates a screen flip. Cancel the fullscreen ime in that case // because we can't determine the initial window heigth anymore. if (this.currentWidth === undefined) { this.currentWidth = window.innerWidth; } if (this.currentWidth !== window.innerWidth) { this.validateInput(true); } // eslint-disable-next-line no-restricted-globals if (window.innerHeight >= this.props.initialHeight) { this.validateInput(true); } } } handleClose(e: {}, reason: string): void { this.props.onClose(); } onInputLostFocus() { this.validateInput(true); } inputChanged: boolean = false; onInputChange() { this.inputChanged = true; this.validateInput(false); } currentValue: number = 0; validateInput(commitValue: boolean) { if (!this.inputRef.current) return; let text = this.inputRef.current.value; let valid = false; let result: number = this.currentValue; try { if (text.length === 0) { valid = false; } else { let v = Number(text); if (isNaN(v)) { valid = false; } else { valid = true; result = v; } } } catch (error) { valid = false; } if (commitValue) { this.setState({ error: false }); if (!valid) { result = this.currentValue; // reset the value! } // clamp and quantize. let uiControl = nullCast(this.uiControl); // quantize value. result = uiControl.clampValue(result); this.props.onChange(this.props.uiControl!.symbol, result); } } onInputKeyPress(e: any): void { if (e.charCode === 13) { if (this.inputChanged) { this.inputChanged = false; this.validateInput(true); } else { this.props.onClose(); } } } uiControl?: UiControl; currentWidth?: number; render(): ReactNode { //let classes = this.props.classes; let control = this.props.uiControl; if (!control) { this.currentWidth = undefined; return (
); } this.currentWidth = window.innerWidth; this.uiControl = control; let value = this.props.value; return ( this.handleClose(e, r)} >
{this.props.caption}
); } } ); export default FullScreenIME;