v1.1.20 Release

This commit is contained in:
Robin Davies
2023-04-20 15:27:18 -04:00
parent e2b62da073
commit 37426d9047
117 changed files with 2147 additions and 711 deletions
+189 -159
View File
@@ -21,176 +21,206 @@ add_custom_command(
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/react
DEPENDS
src/AlsaMidiDeviceInfo.tsx
src/SearchControl.tsx
src/SplitControlView.tsx
src/WifiConfigSettings.tsx
src/FullScreenIME.tsx
src/OkCancelDialog.tsx
src/PluginControl.tsx
src/reportWebVitals.ts
src/JackHostStatus.tsx
src/PluginPresetsDialog.tsx
src/ToobSpectrumAnalyzerView.tsx
src/MidiBindingsDialog.tsx
src/MidiBinding.tsx
src/TemporaryDrawer.tsx
src/ToobFrequencyResponseView.tsx
src/index.css
src/setupTests.ts
src/SearchFilter.tsx
src/PluginOutputControl.tsx
src/BankDialog.tsx
src/VuMeter.tsx
src/StringBuilder.tsx
src/FilePropertyDialog.tsx
src/GxTunerControl.tsx
src/App.tsx
src/GxTunerView.tsx
src/Rect.tsx
src/ToobSpectrumResponseView.tsx
src/DialogEx.tsx
src/GovernorSettings.tsx
src/FilePropertyControl.tsx
src/JackServerSettingsDialog.tsx
src/ZoomedUiControl.tsx
src/Pedal.tsx
src/FullScreenIME.tsx
src/PluginPreset.tsx
src/SystemMidiBindingsDialog.tsx
src/AppThemed.tsx
src/MainPage.tsx
src/PiPedalModel.tsx
src/AppThemed.css
src/PedalboardView.tsx
src/ControlViewFactory.tsx
src/PiPedalSocket.tsx
src/PluginClass.tsx
src/SplitControlView.tsx
src/logo.svg
src/ToobToneStackView.tsx
src/Banks.tsx
src/ToobPowerStage2View.tsx
src/ListSelectDialog.tsx
src/ToobWaveShapeView.tsx
src/PluginInfoDialog.tsx
src/SearchFilter.tsx
src/SearchControl.tsx
src/JackServerSettings.tsx
src/WifiChannel.tsx
src/WifiConfigDialog.tsx
src/App.test.tsx
src/PluginPresetSelector.tsx
src/Pedal.tsx
src/ToobMLView.tsx
src/SettingsDialog.tsx
src/ObservableProperty.tsx
src/PresetDialog.tsx
src/AndroidHost.tsx
src/SelectHoverBackground.tsx
src/WifiDirectConfigDialog.tsx
src/WifiDirectConfigSettings.tsx
src/PiPedalSocket.tsx
src/ToobFrequencyResponseView.tsx
src/ControlViewFactory.tsx
src/Utility.tsx
src/ToobToneStackView.tsx
src/SelectHoverBackground.tsx
src/MidiBindingsDialog.tsx
src/TemporaryDrawer.tsx
src/GxTunerView.tsx
src/ToobInputStageView.tsx
src/DraggableGrid.tsx
src/JackStatusView.tsx
src/PluginControl.tsx
src/XxxSnippet.tsx
src/PluginPreset.tsx
src/Jack.tsx
src/AlsaDeviceInfo.tsx
src/MidiBinding.tsx
src/PiPedalError.tsx
src/IControlViewFactory.tsx
src/Lv2Plugin.tsx
src/Pedalboard.tsx
src/AndroidHost.tsx
src/PedalboardView.tsx
src/PresetDialog.tsx
src/AppThemed.tsx
src/ZoomedDial.tsx
src/RenameDialog.tsx
src/SplitUiControls.tsx
src/GovernorSettings.tsx
src/AboutDialog.tsx
src/ToobSpectrumResponseView.tsx
src/PluginControlView.tsx
src/NoChangePassword.tsx
src/ToobSpectrumAnalyzerView.tsx
src/MidiBindingView.tsx
src/GxTunerControl.tsx
src/Banks.tsx
src/PluginPresetsDialog.tsx
src/BankDialog.tsx
src/UploadPresetDialog.tsx
src/ToobPowerStage2View.tsx
src/index.tsx
src/Units.tsx
src/VuMeter.tsx
src/App.test.tsx
src/DialogEx.tsx
src/StringBuilder.tsx
src/SelectChannelsDialog.tsx
src/WifiConfigSettings.tsx
src/Draggable.tsx
src/ZoomedUiControl.tsx
src/logo.svg
src/Rect.tsx
src/PluginClass.tsx
src/reportWebVitals.ts
src/PluginIcon.tsx
src/App.tsx
src/ResizeResponsiveComponent.tsx
src/SvgPathBuilder.tsx
src/JsonAtom.tsx
src/SplitUiControls.tsx
src/SelectChannelsDialog.tsx
src/ToobMLView.tsx
src/IControlViewFactory.tsx
src/AppThemed.css
src/ZoomedDial.tsx
src/Units.tsx
src/UploadPresetDialog.tsx
src/NumericInput.tsx
src/JackServerSettings.tsx
src/ListSelectDialog.tsx
src/react-app-env.d.ts
src/JackServerSettingsDialog.tsx
src/ObservableProperty.tsx
src/Pedalboard.tsx
src/SelectMidiChannelsDialog.tsx
src/WifiChannel.tsx
src/LoadPluginDialog.tsx
src/WifiConfigDialog.tsx
src/PluginInfoDialog.tsx
src/ToobWaveShapeView.tsx
src/ToobCabSimView.tsx
src/AlsaMidiDeviceInfo.tsx
src/ResizeResponsiveComponent.tsx
src/RenameDialog.tsx
src/SystemMidiBindingView.tsx
src/OldDeleteIcon.tsx
src/ToobInputStageView.tsx
src/XxxSnippet.tsx
src/NoChangePassword.tsx
src/react-app-env.d.ts
src/PiPedalError.tsx
src/AlsaDeviceInfo.tsx
src/index.tsx
src/SettingsDialog.tsx
src/PluginControlView.tsx
src/PresetSelector.tsx
src/OkCancelDialog.tsx
public/css/roboto.css
public/fonts/Roboto-BlackItalic.woff2
public/fonts/Roboto-Black.woff2
public/fonts/Roboto-BoldItalic.woff2
public/fonts/Roboto-Bold.woff2
public/fonts/Roboto-Italic.woff2
public/fonts/Roboto-LightItalic.woff2
public/fonts/Roboto-Light.woff2
public/fonts/Roboto-MediumItalic.woff2
public/fonts/Roboto-Medium.woff2
public/fonts/Roboto-Regular.woff2
public/fonts/Roboto-ThinItalic.woff2
public/fonts/Roboto-Thin.woff2
public/iso_codes.json
public/logo512.png
public/index.html
public/manifest.json
public/var
public/var/current_pedalboard.json
public/var/uiplugins.json
public/var/config.json
public/var/plugin_classes.json
public/logo192.png
public/serve.json
public/robots.txt
public/sample_lv2_plugins.json
public/logo192x.png
public/img/fx_analyzer.svg
public/img/fx_flanger.svg
public/img/cx_stereo.svg
public/img/fx_split_a.svg
public/img/fx_dial.svg
public/img/drive_file_rename_outline_black_24dp.svg
public/img/fx_filter.svg
public/img/fx_filter_hp.svg
public/img/cx_mono.svg
public/img/fx_limiter.svg
public/img/fx_converter.svg
public/img/fx_simulator.svg
public/img/fx_delay.svg
public/img/fx_reverb.svg
public/img/fx_empty.svg
public/img/fx_eq.svg
public/img/edit_banks.svg
public/img/fx_gate.svg
public/img/settings_black_24dp.svg
public/img/help_outline_black_24dp.svg
public/img/fx_oscillator.svg
public/img/fx_split_b.svg
public/img/fx_phaser.svg
public/img/fx_amplifier.svg
public/img/fx_plugin.svg
public/img/ic_drawer.svg
public/img/ic_drawer_2.png
public/img/fx_terminal.svg
public/img/fx_spatial.svg
public/img/fx_pitch.svg
public/img/ic_logo.svg
public/img/fx_flanger2.svg
public/img/fx_function.svg
public/img/fx_lr.svg
public/img/fx_generator.svg
public/img/fx_spectral.svg
public/img/fx_chorus.svg
public/img/fx_utility.svg
public/img/fx_mixer.svg
public/img/ic_presets.svg
public/img/fx_instrument.svg
public/img/fx_modulator.svg
public/img/fx_compressor.svg
public/img/fx_constant.svg
public/img/fx_distortion.svg
public/img/save_bank_as.svg
public/favicon.ico
src/ToobCabSimView.tsx
src/Utility.tsx
src/Lv2Plugin.tsx
src/Jack.tsx
src/JackStatusView.tsx
src/AboutDialog.tsx
src/setupTests.ts
src/DraggableGrid.tsx
src/SvgPathBuilder.tsx
src/LoadPluginDialog.tsx
src/MidiBindingView.tsx
src/PluginIcon.tsx
src/UploadFileDialog.tsx
public/
public/css
public/css/roboto.css
public/logo192x.png
public/robots.txt
public/img
public/img/ic_drawer_2.png
public/img/fx_constant.svg
public/img/cx_mono.svg
public/img/cx_stereo.svg
public/img/fx_distortion.svg
public/img/fx_oscillator.svg
public/img/settings_black_24dp.svg
public/img/fx_filter.svg
public/img/delete_outline_black_24dp.svg
public/img/fx_function.svg
public/img/fx_generator.svg
public/img/old_delete_outline_black_24dp.svg
public/img/ic_bank.svg
public/img/fx_compressor.svg
public/img/file_download_black_24dp.svg
public/img/fx_filter_hp.svg
public/img/fx_plugin.svg
public/img/fx_error.svg
public/img/fx_gate.svg
public/img/cc-by.png
public/img/ic_midi.svg
public/img/ic_pluginpreset.svg
public/img/fx_split_a.svg
public/img/fx_utility.svg
public/img/ic_navigate_before.svg
public/img/ic_drawer_2.svg
public/img/ic_pluginpreset2.svg
public/img/fx_parametric_eq.svg
public/img/fx_terminal.svg
public/img/ic_presets.svg
public/img/VST_Logo_Steinberg.ico
public/img/fx_flanger.svg
public/img/fx_analyzer.svg
public/img/fx_delay.svg
public/img/fx_spectral.svg
public/img/edit_banks.svg
public/img/fx_chorus.svg
public/img/fx_simulator.svg
public/img/drive_file_rename_outline_black_24dp.svg
public/img/fx_mixer.svg
public/img/fx_eq.svg
public/img/fx_modulator.svg
public/img/file_upload_black_24dp.svg
public/img/fx_pitch.svg
public/img/ic_navigate_next.svg
public/img/fx_phaser.svg
public/img/ic_drawer.svg
public/img/fx_amplifier.svg
public/img/save_bank_as.svg
public/img/fx_lr.svg
public/img/fx_instrument.svg
public/img/fx_reverb.svg
public/img/fx_limiter.svg
public/img/VST_Logo_Steinberg.png
public/img/fx_empty.svg
public/img/fx_dial.svg
public/img/ic_logo.svg
public/img/help_outline_black_24dp.svg
public/img/fx_flanger2.svg
public/img/old_delete_outline_white_24dp.svg
public/img/fx_split_b.svg
public/img/fx_spatial.svg
public/img/fx_converter.svg
public/img/vst.svg
public/img/vst.png
public/sample_lv2_plugins.json
public/serve.json
public/fonts
public/fonts/Roboto-LightItalic.woff2
public/fonts/Roboto-Light.woff2
public/fonts/Roboto-BlackItalic.woff2
public/fonts/Roboto-ThinItalic.woff2
public/fonts/Roboto-Bold.woff2
public/fonts/Roboto-Italic.woff2
public/fonts/Roboto-Black.woff2
public/fonts/Roboto-BoldItalic.woff2
public/fonts/Roboto-Regular.woff2
public/fonts/Roboto-Medium.woff2
public/fonts/Roboto-Thin.woff2
public/fonts/LICENSE.txt
public/fonts/Roboto-MediumItalic.woff2
public/favicon.ico
public/iso_codes.json
public/logo192.png
public/logo512.png
public/index.html
public/manifest.json
public/var
public/var/config.json
public/var/current_pedalboard.json
public/var/uiplugins.json
public/var/plugin_classes.json
)
add_custom_target (
+5 -3
View File
@@ -837,9 +837,11 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
>
<DialogContent>
<DialogContentText id="alert-dialog-description">
{
this.model_.alertMessage.get()
}
<Typography variant="body2">
{
this.state.alertDialogMessage
}
</Typography>
</DialogContentText>
</DialogContent>
<DialogActions>
+27 -16
View File
@@ -27,15 +27,12 @@ import { Theme } from '@mui/material/styles';
import { WithStyles } from '@mui/styles';
import createStyles from '@mui/styles/createStyles';
import withStyles from '@mui/styles/withStyles';
import { PiPedalFileProperty } from './Lv2Plugin';
import { UiFileProperty } from './Lv2Plugin';
import Typography from '@mui/material/Typography';
import { PiPedalModel, PiPedalModelFactory, ListenHandle, StateChangedHandle } from './PiPedalModel';
import ButtonBase from '@mui/material/ButtonBase'
import MoreHorizIcon from '@mui/icons-material/MoreHoriz';
import {PedalboardItem} from './Pedalboard';
export const StandardItemSize = { width: 80, height: 140 }
@@ -73,13 +70,14 @@ const styles = (theme: Theme) => createStyles({
export interface FilePropertyControlProps extends WithStyles<typeof styles> {
instanceId: number;
fileProperty: PiPedalFileProperty;
onFileClick: (fileProperty: PiPedalFileProperty, value: string) => void;
fileProperty: UiFileProperty;
pedalboardItem: PedalboardItem;
onFileClick: (fileProperty: UiFileProperty, value: string) => void;
theme: Theme;
}
type FilePropertyControlState = {
error: boolean;
hasValue: boolean;
value: string;
};
@@ -96,6 +94,7 @@ const FilePropertyControl =
this.state = {
error: false,
hasValue: false,
value: "",
};
this.model = PiPedalModelFactory.getInstance();
@@ -108,12 +107,12 @@ const FilePropertyControl =
refreshPatchProperty()
{
this.model.getPatchProperty(this.props.instanceId, this.props.fileProperty.patchProperty)
this.model.getPatchProperty(this.props.pedalboardItem.instanceId, this.props.fileProperty.patchProperty)
.then(
(json: any) => {
if (json && json.otype_ === "Path") {
let path = json.value as string;
this.setState({ value: path });
this.setState({ value: path, hasValue: true });
}
}
)
@@ -138,7 +137,7 @@ const FilePropertyControl =
}
this.refreshPatchProperty();
this.stateChangedHandle = this.model.addLv2StateChangedListener(
this.props.instanceId,
this.props.pedalboardItem.instanceId,
() => {
this.refreshPatchProperty();
});
@@ -149,19 +148,25 @@ const FilePropertyControl =
this.model.removeLv2StateChangedListener(this.stateChangedHandle);
}
}
private mounted: boolean = false;
componentDidMount() {
this.mounted = true;
this.subscribeToPropertyGet();
}
componentWillUnmount() {
this.unsubscribeToPropertyGet();
this.mounted = false;
}
componentDidUpdate(prevProps: Readonly<FilePropertyControlProps>, prevState: Readonly<FilePropertyControlState>, snapshot?: any): void {
if (prevProps.fileProperty.patchProperty !== this.props.fileProperty.patchProperty
|| prevProps.instanceId !== this.props.instanceId) {
this.setState({ value: "" });
|| prevProps.pedalboardItem.instanceId !== this.props.pedalboardItem.instanceId
|| prevProps.pedalboardItem.stateUpdateCount !== this.props.pedalboardItem.stateUpdateCount
) {
this.unsubscribeToPropertyGet();
this.subscribeToPropertyGet();
}
}
@@ -193,9 +198,15 @@ const FilePropertyControl =
//let classes = this.props.classes;
let fileProperty = this.props.fileProperty;
let value = this.fileNameOnly(this.state.value);
if (!value || value.length === 0) {
value = "\u00A0";
let value = "\u00A0";
if (this.state.hasValue)
{
if (this.state.value.length === 0)
{
value = "<none>";
} else {
value = this.fileNameOnly(this.state.value);
}
}
let item_width = 264;
+98 -12
View File
@@ -33,7 +33,7 @@ import IconButton from '@mui/material/IconButton';
import OldDeleteIcon from './OldDeleteIcon';
import ResizeResponsiveComponent from './ResizeResponsiveComponent';
import { PiPedalFileProperty } from './Lv2Plugin';
import { UiFileProperty } from './Lv2Plugin';
import ButtonBase from '@mui/material/ButtonBase';
import Typography from '@mui/material/Typography';
import DialogEx from './DialogEx';
@@ -42,9 +42,9 @@ import OkCancelDialog from './OkCancelDialog';
export interface FilePropertyDialogProps {
open: boolean,
fileProperty: PiPedalFileProperty,
fileProperty: UiFileProperty,
selectedFile: string,
onOk: (fileProperty: PiPedalFileProperty, selectedItem: string) => void,
onOk: (fileProperty: UiFileProperty, selectedItem: string) => void,
onCancel: () => void
};
@@ -53,6 +53,8 @@ export interface FilePropertyDialogState {
selectedFile: string;
hasSelection: boolean;
files: string[];
columns: number;
columnWidth: number;
openUploadFileDialog: boolean;
openConfirmDeleteDialog: boolean;
};
@@ -70,13 +72,33 @@ export default class FilePropertyDialog extends ResizeResponsiveComponent<FilePr
fullScreen: false,
selectedFile: props.selectedFile,
hasSelection: false,
columns: 0,
columnWidth: 1,
files: [],
openUploadFileDialog: false,
openConfirmDeleteDialog: false
};
this.requestScroll = true;
this.requestFiles();
}
private scrollRef: HTMLDivElement | null = null;
onScrollRef(element: HTMLDivElement | null) {
this.scrollRef = element;
this.maybeScrollIntoView();
}
private maybeScrollIntoView()
{
if (this.scrollRef !== null && this.state.files.length !== 0 && this.mounted && this.requestScroll)
{
this.requestScroll = false;
let options: ScrollIntoViewOptions = { block: "nearest"};
options.block = "nearest";
this.scrollRef.scrollIntoView(options);
}
}
private mounted: boolean = false;
private model: PiPedalModel;
@@ -91,6 +113,7 @@ export default class FilePropertyDialog extends ResizeResponsiveComponent<FilePr
this.model.requestFileList(this.props.fileProperty)
.then((files) => {
if (this.mounted) {
files.splice(0,0,"");
this.setState({ files: files, hasSelection: this.isFileInList(files, this.state.selectedFile) });
}
}).catch((error) => {
@@ -98,10 +121,39 @@ export default class FilePropertyDialog extends ResizeResponsiveComponent<FilePr
});
}
private lastDivRef : HTMLDivElement | null = null;
onMeasureRef(div: HTMLDivElement | null)
{
this.lastDivRef = div;
if (div) {
let width = div.offsetWidth;
if (width === 0) return;
let columns = Math.floor((width-40)/280);
if(columns === 0)
{
columns = 1;
}
let columnWidth = (width-40)/columns;
if (columns !== this.state.columns || columnWidth !== this.state.columnWidth)
{
this.setState({columns: columns, columnWidth: columnWidth});
}
}
}
onWindowSizeChanged(width: number, height: number): void {
this.setState({ fullScreen: height < 200 })
this.setState({
fullScreen: height < 200
})
if (this.lastDivRef !== null)
{
this.onMeasureRef(this.lastDivRef);
}
}
private requestScroll: boolean = false;
componentDidMount() {
super.componentDidMount();
@@ -110,6 +162,7 @@ export default class FilePropertyDialog extends ResizeResponsiveComponent<FilePr
componentWillUnmount() {
super.componentWillUnmount();
this.mounted = false;
this.lastDivRef = null;
}
componentDidUpdate(prevProps: Readonly<FilePropertyDialogProps>, prevState: Readonly<FilePropertyDialogState>, snapshot?: any): void {
super.componentDidUpdate?.(prevProps, prevState, snapshot);
@@ -118,6 +171,11 @@ export default class FilePropertyDialog extends ResizeResponsiveComponent<FilePr
if (this.props.open)
{
this.requestFiles()
this.requestScroll = true;
if (this.state.selectedFile !== this.props.selectedFile)
{
this.setState({selectedFile: this.props.selectedFile});
}
}
} else if (prevProps.fileProperty !== this.props.fileProperty) {
this.requestFiles()
@@ -144,6 +202,7 @@ export default class FilePropertyDialog extends ResizeResponsiveComponent<FilePr
private isFileInList(files: string[], file: string) {
let hasSelection = false;
if (file === "") return true;
for (var listFile of files) {
if (listFile === file) {
hasSelection = true;
@@ -154,6 +213,7 @@ export default class FilePropertyDialog extends ResizeResponsiveComponent<FilePr
}
onSelectValue(selectedFile: string) {
this.requestScroll = true;
this.setState({ selectedFile: selectedFile, hasSelection: this.isFileInList(this.state.files, selectedFile) })
}
onDoubleClickValue(selectedFile: string) {
@@ -205,9 +265,13 @@ export default class FilePropertyDialog extends ResizeResponsiveComponent<FilePr
}
}
private wantsScrollRef: boolean = true;
mapKey: number = 0;
render() {
this.mapKey = 0;
let columnWidth = this.state.columnWidth;
return this.props.open &&
(
<DialogEx onClose={() => this.props.onCancel()} open={this.props.open} tag="FilePropertyDialog" fullWidth maxWidth="xl" style={{ height: "90%" }}
@@ -223,22 +287,40 @@ export default class FilePropertyDialog extends ResizeResponsiveComponent<FilePr
</div>
</DialogTitle>
<div style={{ flex: "0 0 auto", height: "1px", background: "rgba(0,0,0,0.2" }}>&nbsp;</div>
<div style={{ flex: "1 1 auto", height: "300", display: "flex", flexFlow: "row nowrap", overflowX: "auto", overflowY: "visible" }}>
<div style={{ flex: "1 1 100%", display: "flex", flexFlow: "column wrap", justifyContent: "start", alignItems: "flex-start", paddingLeft: 16, paddingTop: 16 }}>
<div style={{ flex: "1 1 auto", height: "300", display: "flex", flexFlow: "row wrap", overflowX: "hidden", overflowY: "auto" }}>
<div
ref={(element)=> this.onMeasureRef(element)}
style={{ flex: "1 1 100%", display: "flex", flexFlow: "row wrap",
justifyContent: "flex-start", alignContent: "flex-start", paddingLeft: 16, paddingTop: 16,paddingBottom: 16 }}>
{
(this.state.columns !== 0) && // don't render until we have number of columns derived from layout.
this.state.files.map(
(value: string, index: number) => {
let displayValue = value;
if (displayValue === "")
{
displayValue = "<none>";
} else {
displayValue = this.fileNameOnly(value);
}
let selected = value === this.state.selectedFile;
let selectBg = selected ? "rgba(0,0,0,0.15)" : "rgba(0,0,0,0.0)";
let scrollRef: ((element: HTMLDivElement | null) => void) | undefined = undefined;
if (selected)
{
scrollRef = (element)=> { this.onScrollRef(element)};
}
return (
<ButtonBase key={this.mapKey++}
style={{ width: "320px", flex: "0 0 48px", position: "relative" }}
style={{ width: columnWidth, flex: "0 0 auto", height: 48, position: "relative" }}
onClick={() => this.onSelectValue(value)} onDoubleClick={()=> {this.onDoubleClickValue(value);}}
>
<div style={{ position: "absolute", background: selectBg, width: "100%", height: "100%", borderRadius: 4 }} />
<div style={{ display: "flex", flexFlow: "row nowrap", justifyContent: "start", alignItems: "center", width: "100%", height: "100%" }}>
<div ref={scrollRef} style={{ position: "absolute", background: selectBg, width: "100%", height: "100%", borderRadius: 4 }} />
<div style={{ display: "flex", flexFlow: "row nowrap", textOverflow: "ellipsis", justifyContent: "start", alignItems: "center", width: "100%", height: "100%" }}>
<AudioFileIcon style={{ flex: "0 0 auto", opacity: 0.7, marginRight: 8, marginLeft: 8 }} />
<Typography noWrap style={{ flex: "1 1 auto", textAlign: "left" }}>{this.fileNameOnly(value)}</Typography>
<Typography noWrap style={{ flex: "1 1 auto", textAlign: "left" }}>{displayValue}</Typography>
</div>
</ButtonBase>
);
@@ -265,7 +347,11 @@ export default class FilePropertyDialog extends ResizeResponsiveComponent<FilePr
<Button onClick={() => { this.props.onCancel(); }} aria-label="cancel">
Cancel
</Button>
<Button style={{ flex: "0 0 auto" }} onClick={() => { this.props.onOk(this.props.fileProperty, this.state.selectedFile); }} color="secondary" disabled={!this.state.hasSelection} aria-label="select">
<Button style={{ flex: "0 0 auto" }}
onClick={() => { this.props.onOk(this.props.fileProperty, this.state.selectedFile); }}
color="secondary"
disabled={(!this.state.hasSelection) && this.state.selectedFile !== ""} aria-label="select"
>
Select
</Button>
</div>
+73 -18
View File
@@ -107,23 +107,78 @@ export class PortGroup {
program_list_id: number = -1;
};
export class PiPedalFileType {
deserialize(input: any): PiPedalFileType {
export class UiFileType {
deserialize(input: any): UiFileType {
this.name = input.name;
this.fileExtension = input.fileExtension;
this.mimeType = input.mimeType;
return this;
}
static deserialize_array(input: any): PiPedalFileType[]
static deserialize_array(input: any): UiFileType[]
{
let result: PiPedalFileType[] = [];
let result: UiFileType[] = [];
for (let i = 0; i < input.length; ++i)
{
result[i] = new PiPedalFileType().deserialize(input[i]);
result[i] = new UiFileType().deserialize(input[i]);
}
return result;
}
private static IsAndroid() : boolean
{
return /Android/i.test(navigator.userAgent);
}
static MergeMimeTypes(fileTypes: UiFileType[]): string
{
if (fileTypes.length === 0) {
return "";
}
let result = fileTypes[0].mimeType;
for (let i = 1; i < fileTypes.length; ++i)
{
let fileType = fileTypes[i];
if (fileType.mimeType !== result)
{
if (result.startsWith("audio/") && fileType.mimeType.startsWith("audio/"))
{
result = "audio/*";
} else if (result.startsWith("video/") && fileType.mimeType.startsWith("video/"))
{
result = "video/*";
} else if (result.startsWith("text/") && fileType.mimeType.startsWith("text/"))
{
result = "text/*";
} else {
result = "application/octet-stream";
}
}
}
if (this.IsAndroid())
{
if (result.startsWith("audio/")) result = "audio/*";
if (result.startsWith("video/")) result = "video/*";
if (result.startsWith("text/")) result = "text/*";
} else {
// chrome desktop thinks "application/octet-stream" is .exe, .com, or .bat.
// Feed it file extensions isntead.
if (result = "application/octet-stream")
{
result = "";
for (let i = 0; i < fileTypes.length; ++i)
{
if (i !== 0)
{
result += ',';
}
result += fileTypes[i].fileExtension;
}
}
}
return result;
}
name: string = "";
fileExtension: string = "";
mimeType: string = "";
}
export class UiPropertyNotification {
@@ -150,23 +205,23 @@ export class UiPropertyNotification {
protocol: string = "";
};
export class PiPedalFileProperty {
deserialize(input: any): PiPedalFileProperty
export class UiFileProperty {
deserialize(input: any): UiFileProperty
{
this.label = input.label;
this.fileTypes = PiPedalFileType.deserialize_array(input.fileTypes);
this.fileTypes = UiFileType.deserialize_array(input.fileTypes);
this.patchProperty = input.patchProperty;
this.directory = input.directory;
this.index = input.index;
this.portGroup = input.portGroup;
return this;
}
static deserialize_array(input: any): PiPedalFileProperty[]
static deserialize_array(input: any): UiFileProperty[]
{
let result: PiPedalFileProperty[] = [];
let result: UiFileProperty[] = [];
for (let i = 0; i < input.length; ++i)
{
result[i] = new PiPedalFileProperty().deserialize(input[i]);
result[i] = new UiFileProperty().deserialize(input[i]);
}
return result;
}
@@ -191,7 +246,7 @@ export class PiPedalFileProperty {
if (this.fileTypes.length === 0) {
return true;
}
let extension = PiPedalFileProperty.getFileExtension(filename);
let extension = UiFileProperty.getFileExtension(filename);
for (let fileType of this.fileTypes)
{
if (fileType.fileExtension === extension )
@@ -203,7 +258,7 @@ export class PiPedalFileProperty {
}
label: string = "";
fileTypes: PiPedalFileType[] = [];
fileTypes: UiFileType[] = [];
patchProperty: string = "";
directory: string = "";
index: number = -1;
@@ -226,7 +281,7 @@ export class Lv2Plugin implements Deserializable<Lv2Plugin> {
this.port_groups = PortGroup.deserialize_array(input.port_groups);
if (input.fileProperties)
{
this.fileProperties = PiPedalFileProperty.deserialize_array(input.fileProperties)
this.fileProperties = UiFileProperty.deserialize_array(input.fileProperties)
} else {
this.fileProperties = [];
}
@@ -251,7 +306,7 @@ export class Lv2Plugin implements Deserializable<Lv2Plugin> {
comment: string = "";
ports: Port[] = Port.EmptyPorts;
port_groups: PortGroup[] = [];
fileProperties: PiPedalFileProperty[] = [];
fileProperties: UiFileProperty[] = [];
uiPortNotifications: UiPropertyNotification[] = [];
}
@@ -508,7 +563,7 @@ export class UiControl implements Deserializable<UiControl> {
}
formatDisplayValue(value: number): string {
if (this.integer_property || this.enumeration_property) {
if (this.integer_property) {
value = Math.round(value);
}
@@ -614,7 +669,7 @@ export class UiPlugin implements Deserializable<UiPlugin> {
this.port_groups = PortGroup.deserialize_array(input.port_groups);
if (input.fileProperties)
{
this.fileProperties = PiPedalFileProperty.deserialize_array(input.fileProperties)
this.fileProperties = UiFileProperty.deserialize_array(input.fileProperties)
} else {
this.fileProperties = [];
}
@@ -682,7 +737,7 @@ export class UiPlugin implements Deserializable<UiPlugin> {
description: string = "";
controls: UiControl[] = [];
port_groups: PortGroup[] = [];
fileProperties: PiPedalFileProperty[] = [];
fileProperties: UiFileProperty[] = [];
is_vst3 : boolean = false;
}
+2
View File
@@ -67,6 +67,7 @@ export class PedalboardItem implements Deserializable<PedalboardItem> {
this.controlValues = ControlValue.deserializeArray(input.controlValues);
this.vstState = input.vstState ?? "";
this.stateUpdateCount = input.stateUpdateCount;
this.lv2State = input.lv2State;
return this;
}
@@ -195,6 +196,7 @@ export class PedalboardItem implements Deserializable<PedalboardItem> {
controlValues: ControlValue[] = ControlValue.EmptyArray;
midiBindings: MidiBinding[] = [];
vstState: string = "";
stateUpdateCount: number = 0;
lv2State: [boolean,any] = [false,{}]
};
+11 -3
View File
@@ -17,7 +17,7 @@
// 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 { UiPlugin, UiControl, PluginType, PiPedalFileProperty } from './Lv2Plugin';
import { UiPlugin, UiControl, PluginType, UiFileProperty } from './Lv2Plugin';
import { PiPedalArgumentError, PiPedalStateError } from './PiPedalError';
@@ -588,6 +588,10 @@ export class PiPedalModel //implements PiPedalModel
} else if (message === "onSystemMidiBindingsChanged") {
let bindings = MidiBinding.deserialize_array(body);
this.systemMidiBindings.set(bindings);
} else if (message === "onErrorMessage")
{
this.showAlert(body as string);
} else {
throw new PiPedalStateError("Unrecognized message received from server: " + message);
}
@@ -1054,6 +1058,8 @@ export class PiPedalModel //implements PiPedalModel
handleOnLoadPluginPreset(instanceId: number, controlValues: ControlValue[]) {
// note that plugins with state are dealt with server-side.
// if we made it here, we can just load the controls.
let pedalboard = this.pedalboard.get();
if (pedalboard === undefined) throw new PiPedalStateError("Pedalboard not ready.");
let newPedalboard = pedalboard.clone();
@@ -1342,13 +1348,15 @@ export class PiPedalModel //implements PiPedalModel
while (true) {
let v = it.next();
if (v.done) break;
let item = v.value;
let item = v.value;
if (item.instanceId === itemId) {
item.deserialize(new PedalboardItem()); // skeezy way to re-initialize.
item.instanceId = ++newPedalboard.nextInstanceId;
item.uri = selectedUri;
item.pluginName = plugin.name;
item.controlValues = this.getDefaultValues(item.uri);
item.isEnabled = true;
// lv2State: not valid. vstState : not valid.
this.pedalboard.set(newPedalboard);
this.updateServerPedalboard()
return item.instanceId;
@@ -1590,7 +1598,7 @@ export class PiPedalModel //implements PiPedalModel
});
}
requestFileList(piPedalFileProperty: PiPedalFileProperty): Promise<string[]> {
requestFileList(piPedalFileProperty: UiFileProperty): Promise<string[]> {
return nullCast(this.webSocket)
.request<string[]>('requestFileList', piPedalFileProperty);
}
+5 -5
View File
@@ -23,7 +23,7 @@ import { WithStyles } from '@mui/styles';
import createStyles from '@mui/styles/createStyles';
import withStyles from '@mui/styles/withStyles';
import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
import { UiPlugin, UiControl, PiPedalFileProperty, ScalePoint } from './Lv2Plugin';
import { UiPlugin, UiControl, UiFileProperty, ScalePoint } from './Lv2Plugin';
import {
Pedalboard, PedalboardItem, ControlValue
} from './Pedalboard';
@@ -239,7 +239,7 @@ type PluginControlViewState = {
imeCaption: string;
imeInitialHeight: number;
showFileDialog: boolean,
dialogFileProperty: PiPedalFileProperty,
dialogFileProperty: UiFileProperty,
dialogFileValue: string
};
@@ -260,7 +260,7 @@ const PluginControlView =
imeCaption: "",
imeInitialHeight: 0,
showFileDialog: false,
dialogFileProperty: new PiPedalFileProperty(),
dialogFileProperty: new UiFileProperty(),
dialogFileValue: ""
}
@@ -323,10 +323,10 @@ const PluginControlView =
});
}
makeFilePropertyUI(fileProperty: PiPedalFileProperty): ReactNode {
makeFilePropertyUI(fileProperty: UiFileProperty): ReactNode {
return ((
<FilePropertyControl instanceId={this.props.instanceId}
<FilePropertyControl pedalboardItem={this.props.item}
fileProperty={fileProperty}
onFileClick={(fileProperty, selectedFile) => {
this.setState({ showFileDialog: true, dialogFileProperty: fileProperty, dialogFileValue: selectedFile });
+1 -1
View File
@@ -259,7 +259,7 @@ const PluginPresetsDialog = withStyles(styles, { withTheme: true })(
<img src="img/ic_pluginpreset2.svg" className={classes.itemIcon} alt="" />
</div>
<div className={classes.itemLabel}>
<Typography> noWrap
<Typography noWrap>
{presetEntry.label}
</Typography>
</div>
+1 -6
View File
@@ -80,13 +80,10 @@ export const SelectHoverBackground =
}
handleMouseOver(e: SyntheticEvent): void {
console.log("onMouseOver")
if (this.props.showHover ?? true) {
if (this.hoverElementRef.current)
{
this.hoverElementRef.current.style.display = "block";
} else {
console.log("No hoverElementRef")
}
}
@@ -96,9 +93,7 @@ export const SelectHoverBackground =
if (this.hoverElementRef.current)
{
this.hoverElementRef.current.style.display = "none";
} else {
console.log("No hoverElementRef")
}
}
}
}
+20 -17
View File
@@ -27,7 +27,7 @@ import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent';
import ResizeResponsiveComponent from './ResizeResponsiveComponent';
import Typography from '@mui/material/Typography';
import { PiPedalFileProperty } from './Lv2Plugin';
import { UiFileProperty,UiFileType } from './Lv2Plugin';
import SvgIcon from '@mui/material/SvgIcon';
import ErrorIcon from '@mui/icons-material/Error';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
@@ -45,7 +45,7 @@ export interface UploadFileDialogProps {
onClose: () => void,
onUploaded: (fileName: string) => void,
uploadPage: string,
fileProperty: PiPedalFileProperty
fileProperty: UiFileProperty
};
@@ -204,6 +204,10 @@ export default class UploadFileDialog extends ResizeResponsiveComponent<UploadFi
this.updateUploadDisplayList();
try {
upload.abortController = new AbortController();
if (!this.wantsFile(this.uploadList[i].file))
{
throw new Error("Invalid file type.");
}
let filename = await this.model.uploadFile(this.props.uploadPage, this.uploadList[i].file, "application/octet-stream", upload.abortController);
this.props.onUploaded(filename);
upload.status = FileUploadStatus.Uploaded;
@@ -262,7 +266,12 @@ export default class UploadFileDialog extends ResizeResponsiveComponent<UploadFi
e.currentTarget.style.background = "#D8D8D8";
}
handleButtonSelect(e: React.ChangeEvent<HTMLInputElement>) {
private static IsAndroid() : boolean
{
return /Android/i.test(navigator.userAgent);
}
handleButtonSelect(e: any) {
if (e.currentTarget.files) {
this.uploadFiles(e.currentTarget.files);
}
@@ -290,20 +299,13 @@ export default class UploadFileDialog extends ResizeResponsiveComponent<UploadFi
}
}
makeBrowserAcceptList() {
let fileTypes = this.props.fileProperty.fileTypes;
let result = "";
for (let i = 0; i < fileTypes.length; ++i) {
if (result.length !== 0) {
result += ',';
}
result += fileTypes[i].fileExtension;
}
let result = UiFileType.MergeMimeTypes(this.props.fileProperty.fileTypes);
return result;
}
render() {
let isAndroid = UploadFileDialog.IsAndroid();
return (
<DialogEx tag="UploadFileDialog" open={this.props.open} fullWidth onClose={() => this.handleClose()}
fullScreen={this.state.fullScreen}
@@ -321,7 +323,7 @@ export default class UploadFileDialog extends ResizeResponsiveComponent<UploadFi
<DialogContent style={{ paddingBottom: 0 }}>
<div style={{
width: "100%", height: 140, marginBottom: 0,
border: "2px dashed #CCC",
border: (isAndroid? "2px solid #CCC" :"2px dashed #CCC"),
borderRadius: "10px",
fontFamily: "Roboto",
padding: 0
@@ -334,7 +336,8 @@ export default class UploadFileDialog extends ResizeResponsiveComponent<UploadFi
}}
>
{!this.hasFileList() && (
<Typography noWrap color="textSecondary" align="center" display="block" variant="caption" style={{ width: "100%", marginTop: 20, verticalAlign: "middle" }} >Drop files here</Typography>
<Typography noWrap color="textSecondary" align="center" display="block" variant="caption" style={{ width: "100%", marginTop: 20, verticalAlign: "middle" }} >
{ isAndroid? "Select files": "Drop files here" }</Typography>
)}
{this.hasFileList() && (
<div style={{ width: "100%", height: "100%", overflow: "auto" }}>
@@ -381,15 +384,15 @@ export default class UploadFileDialog extends ResizeResponsiveComponent<UploadFi
<DialogActions >
<Button
component="label" color="primary" style={{ marginLeft: 16, width: 120, flex: "0 0 auto" }}
component="label" color="primary" style={{ whiteSpace: "nowrap", textOverflow: "ellipsis", marginLeft: 16, width: 120, flex: "0 0 auto" }}
>
Select Files
Select&nbsp;Files
<input
type="file"
hidden
accept={this.makeBrowserAcceptList()}
multiple
onChange={(e) => this.handleButtonSelect(e)}
onInput={(e) => this.handleButtonSelect(e)}
/>
</Button>
<div style={{ flex: "1 1 20px" }} />
-81
View File
@@ -1,81 +0,0 @@
src/SearchControl.tsx
src/SplitControlView.tsx
src/WifiConfigSettings.tsx
src/FullScreenIME.tsx
src/JackHostStatus.tsx
src/SearchFilter.tsx
src/MainPage.tsx
src/PiPedalModel.tsx
src/PluginPresetSelector.tsx
src/Pedal.tsx
src/ToobMLView.tsx
src/SettingsDialog.tsx
src/PiPedalSocket.tsx
src/ToobFrequencyResponseView.tsx
src/ControlViewFactory.tsx
src/Utility.tsx
src/ToobToneStackView.tsx
src/SelectHoverBackground.tsx
src/MidiBindingsDialog.tsx
src/TemporaryDrawer.tsx
src/GxTunerView.tsx
src/ToobInputStageView.tsx
src/DraggableGrid.tsx
src/JackStatusView.tsx
src/PluginControl.tsx
src/XxxSnippet.tsx
src/PluginPreset.tsx
src/Jack.tsx
src/AlsaDeviceInfo.tsx
src/MidiBinding.tsx
src/PiPedalError.tsx
src/IControlViewFactory.tsx
src/Lv2Plugin.tsx
src/Pedalboard.tsx
src/PedalboardView.tsx
src/PresetDialog.tsx
src/AppThemed.tsx
src/ZoomedDial.tsx
src/RenameDialog.tsx
src/SplitUiControls.tsx
src/GovernorSettings.tsx
src/AboutDialog.tsx
src/ToobSpectrumResponseView.tsx
src/PluginControlView.tsx
src/NoChangePassword.tsx
src/ToobSpectrumAnalyzerView.tsx
src/MidiBindingView.tsx
src/GxTunerControl.tsx
src/Banks.tsx
src/PluginPresetsDialog.tsx
src/BankDialog.tsx
src/UploadPresetDialog.tsx
src/ToobPowerStage2View.tsx
src/index.tsx
src/Units.tsx
src/VuMeter.tsx
src/App.test.tsx
src/DialogEx.tsx
src/StringBuilder.tsx
src/SelectChannelsDialog.tsx
src/Draggable.tsx
src/ZoomedUiControl.tsx
src/Rect.tsx
src/PluginClass.tsx
src/PluginIcon.tsx
src/App.tsx
src/ResizeResponsiveComponent.tsx
src/SvgPathBuilder.tsx
src/NumericInput.tsx
src/JackServerSettings.tsx
src/ListSelectDialog.tsx
src/JackServerSettingsDialog.tsx
src/ObservableProperty.tsx
src/SelectMidiChannelsDialog.tsx
src/WifiChannel.tsx
src/LoadPluginDialog.tsx
src/WifiConfigDialog.tsx
src/PluginInfoDialog.tsx
src/ToobWaveShapeView.tsx
src/ToobCabSimView.tsx
src/PresetSelector.tsx