import React, { ReactNode, SyntheticEvent } from 'react'; import Grid from '@material-ui/core/Grid'; import { createStyles, withStyles, WithStyles, Theme } from '@material-ui/core/styles'; import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel'; import { UiPlugin, PluginType } from './Lv2Plugin'; import ButtonBase from '@material-ui/core/ButtonBase'; import Button from '@material-ui/core/Button'; import MenuItem from '@material-ui/core/MenuItem'; import Typography from '@material-ui/core/Typography'; import PluginInfoDialog from './PluginInfoDialog' import PluginIcon from './PluginIcon' import Dialog from '@material-ui/core/Dialog'; import DialogActions from '@material-ui/core/DialogActions'; import DialogContent from '@material-ui/core/DialogContent'; import DialogTitle from '@material-ui/core/DialogTitle'; import SelectHoverBackground from './SelectHoverBackground'; import ArrowBackIcon from '@material-ui/icons/ArrowBack'; import IconButton from '@material-ui/core/IconButton'; import Select from '@material-ui/core/Select'; import PluginClass from './PluginClass' import ClearIcon from '@material-ui/icons/Clear'; import ResizeResponsiveComponent from './ResizeResponsiveComponent'; import { TransitionProps } from '@material-ui/core/transitions/transition'; import Slide from '@material-ui/core/Slide'; export type CloseEventHandler = () => void; export type OkEventHandler = (pluginUri: string) => void; const NARROW_DISPLAY_THRESHOLD = 600; const FILTER_STORAGE_KEY = "com.twoplay.piddle.load_dlg.filter"; const pluginGridStyles = (theme: Theme) => createStyles({ frame: { position: "relative", width: "100%", height: "100%" }, top: { top: "0px", right: "0px", left: "0px", bottom: "64px", position: "relative", flexGrow: 1, overflowX: "hidden", overflowY: "visible" }, bottom: { position: "relative", bottom: "0px", height: "64px", width: "100%", display: "flex", flexDirection: "row", flexWrap: "nowrap", justifyContent: "space-between", paddingLeft: "24px", paddingRight: "48px", background: theme.palette.background.paper, }, paper: { position: "relative", overflow: "hidden", height: "56px", width: "100%", background: theme.palette.background.paper }, buttonBase: { width: "100%", height: "100%'" }, content: { marginTop: "8px", marginBottom: "8px", marginLeft: "12px", marginRight: "12px", width: "100%", overflow: "hidden", textAlign: "left", display: "flex", flexDirection: "row", justifyContent: "flex-start", height: 48, alignItems: "start", flexWrap: "nowrap" }, content2: { display: "flex", flexDirection: "column", flex: "1 1 auto", width: "100%", paddingLeft: 16, whiteSpace: "nowrap" }, table: { borderCollapse: "collapse", }, icon: { width: "24px", height: "24px", margin: "0px", opacity: "0.6" }, iconBorder: { flex: "0 0 auto" }, label: { width: "100%" }, label2: { marginTop: 8, color: theme.palette.text.secondary }, control: { padding: theme.spacing(1), }, tdText: { padding: "0px" } }) ; interface PluginGridProps extends WithStyles { onOk: OkEventHandler; onCancel: CloseEventHandler; uri?: string; minimumItemWidth?: number; theme: Theme; open: boolean }; type PluginGridState = { selected_uri?: string, hover_uri?: string, filterType: PluginType, client_width: number, client_height: number, minimumItemWidth: number, } const Transition = React.forwardRef(function Transition( props: TransitionProps & { children?: React.ReactElement }, ref: React.Ref, ) { return ; }); export const LoadPluginDialog = withStyles(pluginGridStyles, { withTheme: true })( class extends ResizeResponsiveComponent { model: PiPedalModel; constructor(props: PluginGridProps) { super(props); this.model = PiPedalModelFactory.getInstance(); let filterType_ = PluginType.Plugin; // i.e. "Any". let persistedFilter = window.localStorage.getItem(FILTER_STORAGE_KEY); if (persistedFilter) { filterType_ = persistedFilter as PluginType; } this.state = { selected_uri: this.props.uri, hover_uri: "", filterType: filterType_, client_width: window.innerWidth, client_height: window.innerHeight, minimumItemWidth: props.minimumItemWidth ? props.minimumItemWidth : 220 }; this.updateWindowSize = this.updateWindowSize.bind(this); this.handleCancel = this.handleCancel.bind(this); this.handleOk = this.handleOk.bind(this); } updateWindowSize() { this.setState({ client_width: window.innerWidth, client_height: window.innerHeight }); } componentDidMount() { super.componentDidMount(); this.updateWindowSize(); window.addEventListener('resize', this.updateWindowSize); } componentWillUnmount() { super.componentWillUnmount(); window.removeEventListener('resize', this.updateWindowSize); } onWindowSizeChanged(width: number, height: number): void { super.onWindowSizeChanged(width, height); } onFilterChange(e: any) { let value = e.target.value as PluginType; window.localStorage.setItem(FILTER_STORAGE_KEY, value as string); this.setState({ filterType: value }); } onClearFilter(): void { let value = PluginType.Plugin; window.localStorage.setItem(FILTER_STORAGE_KEY, value as string); this.setState({ filterType: value }); } selectItem(item: number): void { let uri: string = ""; let plugins = this.model.ui_plugins.get(); if (item >= 0 && item < plugins.length) { uri = plugins[item].uri; } if (uri !== this.state.selected_uri) { this.setState({ selected_uri: uri }); } }; handleCancel(e: SyntheticEvent): void { e.preventDefault(); this.cancel(); } handleOk(e: SyntheticEvent): void { e.preventDefault(); if (this.state.selected_uri) { this.props.onOk(this.state.selected_uri); } } onDoubleClick(e: SyntheticEvent, uri: string): void { this.props.onOk(uri); } cancel(): void { this.props.onCancel(); } fireSelected(item?: UiPlugin) { if (item) { this.setState({ selected_uri: item.uri }); } } setHoverUri(uri: string) { this.setState({ hover_uri: uri }); } onClick(e: SyntheticEvent, uri: string): void { this.setState({ selected_uri: uri }); } handleMouseEnter(e: SyntheticEvent, uri: string): void { this.setHoverUri(uri); } handleMouseLeave(e: SyntheticEvent, uri: string): void { this.setHoverUri(""); } onInfoClicked(): void { // let selectedUri = this.state.selected_uri; } stereo_indicator(uiPlugin?: UiPlugin): string { if (!uiPlugin) return ""; if (uiPlugin.audio_inputs === 2 || uiPlugin.audio_outputs === 2) { return " (Stereo)"; } return ""; } info_string(uiPlugin?: UiPlugin): string { if (uiPlugin === undefined) return ""; let result = uiPlugin.name; if (uiPlugin.author_name !== "") { result += ", " + uiPlugin.author_name; } result += this.stereo_indicator(uiPlugin); return result; } createFilterChildren(result: ReactNode[], classNode: PluginClass, level: number): void { for (let i = 0; i < classNode.children.length; ++i) { let child = classNode.children[i]; let name = "\u00A0".repeat(level * 3 + 1) + child.display_name; result.push(({name})); if (child.children.length !== 0) { this.createFilterChildren(result, child, level + 1); } } } createFilterOptions(): ReactNode[] { let classes = this.model.plugin_classes.get(); let result: ReactNode[] = []; result.push(( All)); this.createFilterChildren(result, classes, 1); return result; } filterPlugins(plugins: UiPlugin[]): ReactNode[] { let result: ReactNode[] = []; let filterType = this.state.filterType; let classes = this.props.classes; let rootClass = this.model.plugin_classes.get(); for (let i = 0; i < plugins.length; ++i) { let value = plugins[i]; if (filterType === PluginType.Plugin || rootClass.is_type_of(filterType, value.plugin_type)) { result.push( ( { this.onDoubleClick(e, value.uri) }} onClick={(e) => { this.onClick(e, value.uri) }} onMouseEnter={(e) => { this.handleMouseEnter(e, value.uri) }} onMouseLeave={(e) => { this.handleMouseLeave(e, value.uri) }} >
{value.name} {value.plugin_display_type} {this.stereo_indicator(value)}
) ); } } return result; } render() { const { classes } = this.props; let model = this.model; let plugins = model.ui_plugins.get(); let selectedPlugin: UiPlugin | undefined = undefined; if (this.state.selected_uri) { let t = this.model.getUiPlugin(this.state.selected_uri); if (t) selectedPlugin = t; } return (
{ this.cancel(); }} style={{ flex: "0 0 auto" }} > {this.state.client_width > 520 ? "Select Plugin" : ""}
{ this.onClearFilter(); }}>
{ this.filterPlugins(plugins) } {(this.state.client_width >= NARROW_DISPLAY_THRESHOLD) ? (
{this.info_string(selectedPlugin)}
) : (
{this.info_string(selectedPlugin)}
)}
); } } ); export default LoadPluginDialog;