// 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, { TouchEvent, PointerEvent, ReactNode, Component, SyntheticEvent } from 'react';
import { css } from '@emotion/react';
import Button from '@mui/material/Button';
import { Theme } from '@mui/material/styles';
import WithStyles, { withTheme } from './WithStyles';
import { createStyles } from './WithStyles';
import ControlTooltip from './ControlTooltip';
import { withStyles } from "tss-react/mui";
import { UiControl, ScalePoint } from './Lv2Plugin';
import Typography from '@mui/material/Typography';
import Input from '@mui/material/Input';
import Select from '@mui/material/Select';
import Switch from '@mui/material/Switch';
import Utility from './Utility';
import MenuItem from '@mui/material/MenuItem';
import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
import DialIcon from './svg/fx_dial.svg?react';
import { isDarkMode } from './DarkMode';
import PlayArrowIcon from '@mui/icons-material/PlayArrow';
import StopIcon from '@mui/icons-material/Stop';
import FiberManualRecordIcon from '@mui/icons-material/FiberManualRecord';
import GraphicEqCtl, { UpdateGraphicEqPath } from './GraphicEqCtl';
const MIN_ANGLE = -135;
const MAX_ANGLE = 135;
const FONT_SIZE = "0.8em";
function isMobileDevice() {
return (navigator.maxTouchPoints && navigator.maxTouchPoints > 1);
}
enum ButtonStyle { None, Trigger, Momentary, MomentaryOnByDefault }
const SELECTED_OPACITY = 0.8;
const DEFAULT_OPACITY = 0.6;
const RANGE_SCALE = 120; // 120 pixels to move from 0 to 1.
const FINE_RANGE_SCALE = RANGE_SCALE * 10; // 1200 pixels to move from 0 to 1.
const ULTRA_FINE_RANGE_SCALE = RANGE_SCALE * 50; // 12000 pixels to move from 0 to 1.
export const StandardItemSize = { width: 80, height: 140 }
function preventNextClickAfterDrag() {
// the broswer fires a click event when the pointer goes up
// on ANY element under the mouse. Prevent this click event
// (and any other click event) from happening for 100ms
// after the drag stops.
let clickHandler = (e: MouseEvent) => {
e.preventDefault();
e.stopPropagation();
};
document.addEventListener('click', clickHandler, true);
window.setTimeout(() => {
document.removeEventListener('click', clickHandler, true);
}, 100);
}
function androidEmoji(text: string) {
// android chrome doesn't support these characters properly.
if (text === "⏹") {
return ();
}
if (text === "⏺") {
return ()
}
if (text === "⏵") {
return ();
}
return text;
}
export const pluginControlStyles = (theme: Theme) => createStyles({
frame: css({
position: "relative",
margin: "12px"
}),
switchTrack: css({
height: '100%',
width: '100%',
borderRadius: 14 / 2,
zIndex: -1,
transition: theme.transitions.create(['opacity', 'background-color'], {
duration: theme.transitions.duration.shortest
}),
backgroundColor: theme.palette.primary.main,
opacity: theme.palette.mode === 'light' ? 0.38 : 0.3
}),
controlFrame: css({
display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "space-between", height: 116
}),
titleSection: css({
flex: "0 0 auto", alignSelf: "stretch", marginBottom: 8, marginLeft: 0, marginRight: 0
}),
displayValue: css({
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 4,
textAlign: "center",
background: "transparent",
color: theme.palette.text.secondary,
// zIndex: -1,
}),
midSection: css({
flex: "1 1 1", display: "flex", flexFlow: "column nowrap", alignContent: "center", justifyContent: "center"
}),
editSection: css({
flex: "0 0 0", display: "flex", flexFlow: "column nowrap", justifyContent: "center", position: "relative", width: 60, height: 28, minHeight: 28
})
});
export interface PluginControlProps extends WithStyles {
uiControl?: UiControl;
instanceId: number;
value: number;
onPreviewChange?: (value: number) => void;
onChange: (value: number) => void;
theme: Theme;
requestIMEEdit: (uiControl: UiControl, value: number) => void;
}
export type PluginControlState = {
error: boolean;
editFocused: boolean;
previewValue?: string;
};
export interface CustomPluginControlProps extends WithStyles {
title: string;
isSelect?: boolean;
isButton?: boolean;
item_width?: number;
mainControl: React.ReactNode;
editControl?: React.ReactNode;
};
export interface CustomPluginControlState {
};
const CustomPluginControl =
withStyles(
class extends Component {
constructor(props: CustomPluginControlProps) {
super(props);
}
render() {
let classes = withStyles.getClasses(this.props);
return (