Dark Mode, Toob Neural Amp Modeler
@@ -21,6 +21,7 @@ add_custom_command(
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/react
|
||||
|
||||
DEPENDS
|
||||
src/SelectThemeDialog.tsx
|
||||
src/OkCancelDialog.tsx
|
||||
src/PluginControl.tsx
|
||||
src/reportWebVitals.ts
|
||||
@@ -133,9 +134,9 @@ add_custom_command(
|
||||
public/img/fx_distortion.svg
|
||||
public/img/Pi-Logo-3.png
|
||||
public/img/fx_oscillator.svg
|
||||
public/img/save_bank_as_white.svg
|
||||
public/img/edit_banks_white.svg
|
||||
public/img/settings_black_24dp.svg
|
||||
src/svg/ic_save_bank_as.svg
|
||||
src/svg/ic_edit_banks.svg
|
||||
src/svg/ic_settings.svg
|
||||
public/img/fx_filter.svg
|
||||
public/img/delete_outline_black_24dp.svg
|
||||
public/img/fx_function.svg
|
||||
@@ -150,7 +151,7 @@ add_custom_command(
|
||||
public/img/cc-by.png
|
||||
public/img/fx_split_a.svg
|
||||
public/img/fx_utility.svg
|
||||
public/img/help_outline_white_24dp.svg
|
||||
src/svg/ic_help_outline.svg
|
||||
public/img/ic_navigate_before.svg
|
||||
public/img/ic_drawer_2.svg
|
||||
public/img/fx_parametric_eq.svg
|
||||
@@ -161,10 +162,8 @@ add_custom_command(
|
||||
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
|
||||
@@ -173,7 +172,6 @@ add_custom_command(
|
||||
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/Pi-Logo-3.svg
|
||||
@@ -183,14 +181,11 @@ add_custom_command(
|
||||
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/settings_white_24dp.svg
|
||||
public/img/drive_file_rename_outline_white_24dp.svg
|
||||
public/img/vst.svg
|
||||
public/img/vst.png
|
||||
public/sample_lv2_plugins.json
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><rect fill="none" height="24" width="24"/></g><g><g><polygon points="15,16 11,20 21,20 21,16"/><path d="M12.06,7.19L3,16.25V20h3.75l9.06-9.06L12.06,7.19z M5.92,18H5v-0.92l7.06-7.06l0.92,0.92L5.92,18z"/><path d="M18.71,8.04c0.39-0.39,0.39-1.02,0-1.41l-2.34-2.34C16.17,4.09,15.92,4,15.66,4c-0.25,0-0.51,0.1-0.7,0.29l-1.83,1.83 l3.75,3.75L18.71,8.04z"/></g></g></svg>
|
||||
|
Before Width: | Height: | Size: 503 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#FFFFFF"><g><rect fill="none" height="24" width="24"/></g><g><g><polygon points="15,16 11,20 21,20 21,16"/><path d="M12.06,7.19L3,16.25V20h3.75l9.06-9.06L12.06,7.19z M5.92,18H5v-0.92l7.06-7.06l0.92,0.92L5.92,18z"/><path d="M18.71,8.04c0.39-0.39,0.39-1.02,0-1.41l-2.34-2.34C16.17,4.09,15.92,4,15.66,4c-0.25,0-0.51,0.1-0.7,0.29l-1.83,1.83 l3.75,3.75L18.71,8.04z"/></g></g></svg>
|
||||
|
Before Width: | Height: | Size: 503 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#FFFFFF"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M11 18h2v-2h-2v2zm1-16C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm0-14c-2.21 0-4 1.79-4 4h2c0-1.1.9-2 2-2s2 .9 2 2c0 2-3 1.75-3 5h2c0-2.25 3-2.5 3-5 0-2.21-1.79-4-4-4z"/></svg>
|
||||
|
Before Width: | Height: | Size: 402 B |
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve" fill="#FFFFFF">
|
||||
<path d="M16,1H4C2.9,1,2,1.9,2,3v14h2V3h12V1z"/>
|
||||
<path d="M20.993,10.993L20.99,7c0-1.1-0.891-2-1.99-2h-4h-3H8C6.9,5,6.01,5.9,6.01,7l-0.003,3.993L6,11v10c0,1.1,0.891,2,1.99,2H8
|
||||
h11h0.01c1.1,0,1.99-0.9,1.99-2V11L20.993,10.993z M19,12v9H8v-9V7h5h1h5V12z"/>
|
||||
<rect x="10" y="9" width="2" height="2"/>
|
||||
<rect x="14" y="9" width="3" height="2"/>
|
||||
<rect x="10" y="13" width="2" height="2"/>
|
||||
<rect x="14" y="13" width="3" height="2"/>
|
||||
<rect x="10" y="17" width="2" height="2"/>
|
||||
<rect x="14" y="17" width="3" height="2"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1012 B |
@@ -1,26 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="PiPedal Guitar Pedals"
|
||||
/>
|
||||
<!--
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta name="description" content="PiPedal Guitar Pedals" />
|
||||
<!--
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
|
||||
-->
|
||||
<link rel="stylesheet" href="/css/roboto.css" />
|
||||
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
<link rel="stylesheet" href="/css/roboto.css" />
|
||||
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
@@ -29,14 +27,30 @@
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>PiPedal</title>
|
||||
<style>
|
||||
BODY { background: #D0D0D0; }
|
||||
@media (prefers-color-scheme: dark) {
|
||||
BODY { background: #333; }
|
||||
}
|
||||
<title>PiPedal</title>
|
||||
<style>
|
||||
BODY {
|
||||
background: #D0D0D0;
|
||||
}
|
||||
</style>
|
||||
|
||||
</style>
|
||||
<style id="bgStyle">
|
||||
BODY {
|
||||
background: #333;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
const darkMode = localStorage.getItem("darkMode"); if (darkMode) { }
|
||||
if (darkMode)
|
||||
{
|
||||
let bgStyle = document.getElementById("bgStyle");
|
||||
if (bgStyle)
|
||||
{
|
||||
// disable the style block.
|
||||
bgStyle.setAttribute('media',"max-width: 1px");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body >
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
@@ -52,4 +66,4 @@
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@@ -25,10 +25,12 @@ import isDarkMode from './DarkMode';
|
||||
|
||||
declare module '@mui/material/styles' {
|
||||
interface Theme {
|
||||
mainBackground: string;
|
||||
mainBackground: React.CSSProperties['color'];
|
||||
toolbarColor: React.CSSProperties['color'];
|
||||
}
|
||||
interface ThemeOptions {
|
||||
mainBackground?: string;
|
||||
mainBackground?: React.CSSProperties['color'];
|
||||
toolbarColor?: React.CSSProperties['color'];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -50,13 +52,14 @@ const theme = createTheme(
|
||||
palette: {
|
||||
mode: 'dark',
|
||||
primary: {
|
||||
main: "#6750A4" // #5B5690 #60529A #5C5694
|
||||
main: '#A770E4'// #6750A4" // #5B5690 #60529A #5C5694
|
||||
},
|
||||
secondary: {
|
||||
main: "#FF6060"
|
||||
},
|
||||
},
|
||||
mainBackground: "#222"
|
||||
mainBackground: "#222",
|
||||
toolbarColor: '#FFFFFF'
|
||||
}
|
||||
:
|
||||
{
|
||||
@@ -69,7 +72,9 @@ const theme = createTheme(
|
||||
}
|
||||
|
||||
},
|
||||
mainBackground: "#FFFFFF"
|
||||
mainBackground: "#FFFFFF",
|
||||
toolbarColor: '#FFFFFF'
|
||||
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
@@ -16,8 +16,3 @@ div {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
color-scheme: dark;
|
||||
}
|
||||
}
|
||||
@@ -62,14 +62,27 @@ import JackStatusView from './JackStatusView';
|
||||
import { Theme } from '@mui/material/styles';
|
||||
import isDarkMode from './DarkMode';
|
||||
|
||||
|
||||
import {ReactComponent as RenameOutlineIcon} from './svg/drive_file_rename_outline_black_24dp.svg';
|
||||
import {ReactComponent as SaveBankAsIcon} from './svg/ic_save_bank_as.svg';
|
||||
import {ReactComponent as EditBanksIcon} from './svg/ic_edit_banks.svg';
|
||||
import {ReactComponent as SettingsIcon} from './svg/ic_settings.svg';
|
||||
import {ReactComponent as HelpOutlineIcon} from './svg/ic_help_outline.svg';
|
||||
|
||||
|
||||
const appStyles = (theme: Theme) => createStyles({
|
||||
menuIcon: {
|
||||
fill: "green"
|
||||
"&": { // :root
|
||||
colorScheme: (isDarkMode()? "dark": "light")
|
||||
},
|
||||
appBar: {
|
||||
menuListItem: {
|
||||
color: "#FE8!important" as any, //theme.palette.text.primary,
|
||||
fill: "#FE8!important" as any, //theme.palette.text.primary,
|
||||
},
|
||||
menuIcon: {
|
||||
fill: (theme.palette.text.primary + "!important") as any, //theme.palette.text.primary,
|
||||
opacity: 0.6
|
||||
},
|
||||
toolBar: {
|
||||
color: "white"
|
||||
},
|
||||
listSubheader: {
|
||||
backgroundImage: "linear-gradient(255,255,255,0.15),rgba(255,255,255,0.15)"
|
||||
@@ -499,7 +512,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
|
||||
|
||||
private unmountListener(e: Event) {
|
||||
e.preventDefault();
|
||||
if (this.model_.state.get() === State.Ready && !this.model_.isAndroidHosted()) {
|
||||
if ((!this.model_.reloadRequested) && this.model_.state.get() === State.Ready && !this.model_.isAndroidHosted()) {
|
||||
(e as any).returnValue = "Are you sure you want to leave this page?";
|
||||
return "Are you sure you want to leave this page?";
|
||||
}
|
||||
@@ -652,6 +665,7 @@ render() {
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
colorScheme: isDarkMode() ? "dark": "light", // affects scrollbar color
|
||||
minHeight: 345, minWidth: 390,
|
||||
position: "absolute", width: "100%", height: "100%", background: "#F88", userSelect: "none",
|
||||
display: "flex", flexDirection: "column", flexWrap: "nowrap",
|
||||
@@ -666,14 +680,15 @@ render() {
|
||||
<CssBaseline />
|
||||
{(!this.state.tinyToolBar) ?
|
||||
(
|
||||
<AppBar className="appBar" position="absolute" >
|
||||
<Toolbar variant="dense" >
|
||||
<AppBar position="absolute" >
|
||||
<Toolbar variant="dense" className={classes.toolBar} >
|
||||
<IconButton
|
||||
edge="start"
|
||||
aria-label="menu"
|
||||
color="inherit"
|
||||
onClick={() => { this.showDrawer() }}
|
||||
size="large">
|
||||
<MenuButton />
|
||||
<MenuButton style={{opacity: 0.75}} />
|
||||
</IconButton>
|
||||
<div style={{ flex: "0 1 400px", minWidth: 100 }}>
|
||||
<PresetSelector />
|
||||
@@ -683,11 +698,12 @@ render() {
|
||||
<IconButton
|
||||
aria-label="menu"
|
||||
onClick={() => { this.toggleFullScreen(); }}
|
||||
color="inherit"
|
||||
size="large">
|
||||
{this.state.isFullScreen ? (
|
||||
<FullscreenExitIcon />
|
||||
<FullscreenExitIcon style={{opacity: 0.75}} />
|
||||
) : (
|
||||
<FullscreenIcon />
|
||||
<FullscreenIcon style={{opacity: 0.75}} />
|
||||
|
||||
)}
|
||||
|
||||
@@ -701,6 +717,7 @@ render() {
|
||||
style={{ position: "absolute", left: 12, top: 8, zIndex: 2 }}
|
||||
aria-label="menu"
|
||||
onClick={() => { this.showDrawer() }}
|
||||
color="inherit"
|
||||
size="large">
|
||||
<MenuButton />
|
||||
</IconButton>
|
||||
@@ -708,6 +725,7 @@ render() {
|
||||
<IconButton
|
||||
style={{ position: "absolute", right: 8, top: 8, zIndex: 2 }}
|
||||
aria-label="menu"
|
||||
color="inherit"
|
||||
onClick={() => { this.toggleFullScreen(); }}
|
||||
size="large">
|
||||
{this.state.isFullScreen ? (
|
||||
@@ -756,26 +774,20 @@ render() {
|
||||
<Divider />
|
||||
<List>
|
||||
<ListItem button key='RenameBank' onClick={() => { this.handleDrawerRenameBank() }}>
|
||||
<ListItemIcon>
|
||||
<img className='menuIcon'
|
||||
src={isDarkMode()? "img/drive_file_rename_outline_white_24dp.svg" :"img/drive_file_rename_outline_black_24dp.svg"}
|
||||
alt="" style={{ opacity: 0.6 }} />
|
||||
<ListItemIcon >
|
||||
<RenameOutlineIcon color='inherit' className={classes.menuIcon} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary='Rename Bank' />
|
||||
</ListItem>
|
||||
<ListItem button key='SaveBank' onClick={() => { this.handleDrawerSaveBankAs() }} >
|
||||
<ListItemIcon>
|
||||
<img className='menuIcon'
|
||||
src={isDarkMode()? "img/save_bank_as_white.svg" :"img/save_bank_as.svg"}
|
||||
alt="" style={{ opacity: 0.6 }} />
|
||||
<SaveBankAsIcon color="inherit" className={classes.menuIcon}/>
|
||||
</ListItemIcon>
|
||||
<ListItemText primary='Save As New Bank' />
|
||||
</ListItem>
|
||||
<ListItem button key='CreateBank' onClick={() => { this.handleDrawerManageBanks(); }}>
|
||||
<ListItem button key='EditBanks' onClick={() => { this.handleDrawerManageBanks(); }}>
|
||||
<ListItemIcon>
|
||||
<img className='menuIcon'
|
||||
src={isDarkMode()? "img/edit_banks_white.svg" :"img/edit_banks.svg"}
|
||||
alt="" style={{ opacity: 0.6 }} />
|
||||
<EditBanksIcon color="inherit" className={classes.menuIcon}/>
|
||||
</ListItemIcon>
|
||||
<ListItemText primary='Manage Banks...' />
|
||||
</ListItem>
|
||||
@@ -784,23 +796,19 @@ render() {
|
||||
<List>
|
||||
<ListItem button key='Settings' onClick={() => { this.handleDrawerSettingsClick() }}>
|
||||
<ListItemIcon>
|
||||
<img className='menuIcon'
|
||||
src={isDarkMode()? "img/settings_white_24dp.svg" :"img/settings_black_24dp.svg"}
|
||||
alt="" style={{ opacity: 0.6 }} />
|
||||
<SettingsIcon color="inherit" className={classes.menuIcon}/>
|
||||
</ListItemIcon>
|
||||
<ListItemText primary='Settings' />
|
||||
</ListItem>
|
||||
<ListItem button key='About' onClick={() => { this.handleDrawerAboutClick() }}>
|
||||
<ListItemIcon>
|
||||
<img className='menuIcon'
|
||||
src= {isDarkMode() ? "img/help_outline_white_24dp.svg": "img/help_outline_black_24dp.svg"}
|
||||
alt="" style={{ opacity: 0.6 }} />
|
||||
<HelpOutlineIcon color="inherit" className={classes.menuIcon}/>
|
||||
</ListItemIcon>
|
||||
<ListItemText primary='About' />
|
||||
</ListItem>
|
||||
<ListItem button key='Donations' onClick={() => { this.handleDrawerDonationClick() }}>
|
||||
<ListItemIcon>
|
||||
<VolunteerActivismIcon style={{ opacity: 0.6 }}/>
|
||||
<ListItemIcon >
|
||||
<VolunteerActivismIcon className={classes.menuIcon} color="inherit" />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary='Donations' />
|
||||
</ListItem>
|
||||
|
||||
@@ -19,8 +19,10 @@
|
||||
|
||||
|
||||
export default function isDarkMode(): boolean {
|
||||
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
let value = localStorage.getItem("darkMode");
|
||||
return value === "true";
|
||||
}
|
||||
|
||||
export function setDarkMode(value: boolean): void {
|
||||
localStorage.setItem("darkMode",value? "true": "false");
|
||||
}
|
||||
|
||||
@@ -602,7 +602,7 @@ export const LoadPluginDialog =
|
||||
<SelectHoverBackground selected={value.uri === this.state.selected_uri} showHover={true} />
|
||||
<div className={classes.content}>
|
||||
<div className={classes.iconBorder} >
|
||||
<PluginIcon pluginType={value.plugin_type} size={24} />
|
||||
<PluginIcon pluginType={value.plugin_type} size={24} opacity={0.6} />
|
||||
</div>
|
||||
<div className={classes.content2}>
|
||||
<div className={classes.label} style={{ display: "flex", flexFlow: "row nowrap", alignItems: "center" }} >
|
||||
|
||||
@@ -204,6 +204,42 @@ export class UiPropertyNotification {
|
||||
plugin: string = "";
|
||||
protocol: string = "";
|
||||
|
||||
};
|
||||
|
||||
export class UiFrequencyPlot {
|
||||
deserialize(input: any): UiFrequencyPlot
|
||||
{
|
||||
this.patchProperty = input.patchProperty;
|
||||
this.index = input.index;
|
||||
this.portGroup = input.portGroup;
|
||||
this.xLeft = input.xLeft;
|
||||
this.xRight = input.xRight;
|
||||
this.xLog = input.xLog;
|
||||
this.yTop = input.yTop;
|
||||
this.yBottom = input.yBottom;
|
||||
this.width = input.width;
|
||||
return this;
|
||||
}
|
||||
static deserialize_array(input: any): UiFrequencyPlot[]
|
||||
{
|
||||
let result: UiFrequencyPlot[] = [];
|
||||
for (let i = 0; i < input.length; ++i)
|
||||
{
|
||||
result[i] = new UiFrequencyPlot().deserialize(input[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
patchProperty: string = "";
|
||||
index: number = -1;
|
||||
portGroup: string = "";
|
||||
xLeft: number = -1;
|
||||
xRight: number = -1;
|
||||
xLog: boolean = true;
|
||||
yTop: number = -1;
|
||||
yBottom: number = -1;
|
||||
width: number = -1;
|
||||
|
||||
};
|
||||
export class UiFileProperty {
|
||||
deserialize(input: any): UiFileProperty
|
||||
@@ -253,6 +289,10 @@ export class UiFileProperty {
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (fileType.fileExtension === "*" || fileType.fileExtension === "")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -270,6 +310,8 @@ export class Lv2Plugin implements Deserializable<Lv2Plugin> {
|
||||
{
|
||||
this.uri = input.uri;
|
||||
this.name = input.name;
|
||||
this.brand = input.name? input.name: "";
|
||||
this.label = input.label? input.label: this.name;
|
||||
this.plugin_class = input.plugin_class;
|
||||
this.supported_features = input.supported_features;
|
||||
this.required_features = input.required_features;
|
||||
@@ -285,6 +327,13 @@ export class Lv2Plugin implements Deserializable<Lv2Plugin> {
|
||||
} else {
|
||||
this.fileProperties = [];
|
||||
}
|
||||
if (input.frequencyPlots)
|
||||
{
|
||||
this.frequencyPlots = UiFrequencyPlot.deserialize_array(input.frequencyPlots)
|
||||
} else {
|
||||
this.frequencyPlots = [];
|
||||
}
|
||||
|
||||
if (input.uiPortNotifications)
|
||||
{
|
||||
this.uiPortNotifications = UiPropertyNotification.deserialize_array(input.uiPortNotifications);
|
||||
@@ -297,6 +346,8 @@ export class Lv2Plugin implements Deserializable<Lv2Plugin> {
|
||||
|
||||
uri: string = "";
|
||||
name: string = "";
|
||||
brand: string = "";
|
||||
label: string = "";
|
||||
plugin_class: string = "";
|
||||
supported_features: string[] = Lv2Plugin.EmptyFeatures;
|
||||
required_features: string[] = Lv2Plugin.EmptyFeatures;
|
||||
@@ -306,7 +357,8 @@ export class Lv2Plugin implements Deserializable<Lv2Plugin> {
|
||||
comment: string = "";
|
||||
ports: Port[] = Port.EmptyPorts;
|
||||
port_groups: PortGroup[] = [];
|
||||
fileProperties: UiFileProperty[] = [];
|
||||
fileProperties: UiFileProperty[] = [];
|
||||
frequencyPlots: UiFrequencyPlot[] = [];
|
||||
uiPortNotifications: UiPropertyNotification[] = [];
|
||||
}
|
||||
|
||||
@@ -668,6 +720,8 @@ export class UiPlugin implements Deserializable<UiPlugin> {
|
||||
{
|
||||
this.uri = input.uri;
|
||||
this.name = input.name;
|
||||
this.brand = input.brand ? input.brand: "";
|
||||
this.label = input.label? input.label: this.name;
|
||||
this.plugin_type = input.plugin_type as PluginType;
|
||||
this.plugin_display_type = input.plugin_display_type;
|
||||
this.author_name = input.author_name;
|
||||
@@ -685,6 +739,12 @@ export class UiPlugin implements Deserializable<UiPlugin> {
|
||||
} else {
|
||||
this.fileProperties = [];
|
||||
}
|
||||
if (input.frequencyPlots)
|
||||
{
|
||||
this.frequencyPlots = UiFrequencyPlot.deserialize_array(input.frequencyPlots)
|
||||
} else {
|
||||
this.frequencyPlots = [];
|
||||
}
|
||||
|
||||
this.is_vst3 = input.is_vst3;
|
||||
return this;
|
||||
@@ -738,6 +798,8 @@ export class UiPlugin implements Deserializable<UiPlugin> {
|
||||
|
||||
uri: string = "";
|
||||
name: string = "";
|
||||
brand: string = "";
|
||||
label: string = "";
|
||||
plugin_type: PluginType = PluginType.InvalidPlugin;
|
||||
plugin_display_type: string = "";
|
||||
author_name: string = "";
|
||||
@@ -749,7 +811,8 @@ export class UiPlugin implements Deserializable<UiPlugin> {
|
||||
description: string = "";
|
||||
controls: UiControl[] = [];
|
||||
port_groups: PortGroup[] = [];
|
||||
fileProperties: UiFileProperty[] = [];
|
||||
fileProperties: UiFileProperty[] = [];
|
||||
frequencyPlots: UiFrequencyPlot[] = [];
|
||||
is_vst3 : boolean = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ import MidiBindingsDialog from './MidiBindingsDialog';
|
||||
import PluginPresetSelector from './PluginPresetSelector';
|
||||
import {ReactComponent as OldDeleteIcon} from "./svg/old_delete_outline_24dp.svg";
|
||||
import {ReactComponent as MidiIcon} from "./svg/ic_midi.svg";
|
||||
|
||||
import isDarkMode from './DarkMode';
|
||||
|
||||
|
||||
const SPLIT_CONTROLBAR_THRESHHOLD = 650;
|
||||
@@ -463,7 +463,7 @@ export const MainPage =
|
||||
</div>
|
||||
<div style={{ flex: "0 0 auto", display: (canInsert || canAppend) ? "block" : "none", paddingRight: 8 }}>
|
||||
<IconButton onClick={(e) => { this.onAddClick(e) }} size="large">
|
||||
<AddIcon style={{opacity: 0.6}} />
|
||||
<AddIcon style={{height: 24, width: 24,fill: this.props.theme.palette.text.primary, opacity: 0.6}} />
|
||||
</IconButton>
|
||||
<Menu
|
||||
id="add-menu"
|
||||
@@ -495,7 +495,8 @@ export const MainPage =
|
||||
onClick={this.onLoadClick}
|
||||
disabled={this.state.selectedPedal === -1 || (!canLoad) || (this.getSelectedPedalboardItem()?.isSplit() ?? true)}
|
||||
startIcon={<InputIcon />}
|
||||
style={{ textTransform: "none" }}
|
||||
style={{ textTransform: "none",
|
||||
background: (isDarkMode() ? "#6750A4": undefined) }}
|
||||
>
|
||||
Load
|
||||
</Button>
|
||||
|
||||
@@ -298,7 +298,7 @@ class PedalLayout {
|
||||
if (uiPlugin != null) {
|
||||
this.pluginType = uiPlugin.plugin_type;
|
||||
this.iconUrl = SelectIconUri(uiPlugin.plugin_type);
|
||||
this.name = uiPlugin.name;
|
||||
this.name = uiPlugin.label;
|
||||
this.numberOfInputs = Math.max(uiPlugin.audio_inputs,2);
|
||||
this.numberOfOutputs = Math.max(uiPlugin.audio_outputs,2);
|
||||
} else {
|
||||
@@ -679,7 +679,7 @@ const PedalboardView =
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
if (!Utility.isTouchDevice()) {
|
||||
if (!Utility.needsZoomedControls()) {
|
||||
if (this.props.onDoubleClick && instanceId) {
|
||||
this.props.onDoubleClick(instanceId);
|
||||
}
|
||||
@@ -1014,7 +1014,7 @@ const PedalboardView =
|
||||
}}>
|
||||
<Typography variant="caption" display="block" noWrap={true}
|
||||
style={{ width: CELL_WIDTH - 4, textAlign: "center", flex: "0 1 auto" }}
|
||||
>{item.pedalItem?.pluginName}</Typography>
|
||||
>{item.name}</Typography>
|
||||
</div>
|
||||
)
|
||||
result.push(<div key={this.renderKey++} className={classes.pedalItem} style={{ left: item.bounds.x, top: item.bounds.y }} >
|
||||
|
||||
@@ -38,7 +38,12 @@ import GovernorSettings from './GovernorSettings';
|
||||
import WifiChannel from './WifiChannel';
|
||||
import AlsaDeviceInfo from './AlsaDeviceInfo';
|
||||
import { AndroidHostInterface, FakeAndroidHost } from './AndroidHost';
|
||||
import isDarkMode, {setDarkMode} from './DarkMode';
|
||||
|
||||
export enum ColorTheme {
|
||||
Light,
|
||||
Dark
|
||||
};
|
||||
|
||||
export enum State {
|
||||
Loading,
|
||||
@@ -470,8 +475,11 @@ export class PiPedalModel //implements PiPedalModel
|
||||
let value = body as number;
|
||||
this._setInputVolume(value,false);
|
||||
} else if (message === "onLv2StateChanged") {
|
||||
let instanceId = body as number;
|
||||
this.onLv2StateChanged(instanceId);
|
||||
|
||||
let instanceId = body.instanceId as number;
|
||||
let state = body.state as [boolean,any];
|
||||
|
||||
this.onLv2StateChanged(instanceId,state);
|
||||
} else if (message === "onVst3ControlChanged") {
|
||||
let controlChangedBody = body as Vst3ControlChangedBody;
|
||||
this._setVst3PedalboardControlValue(
|
||||
@@ -665,6 +673,10 @@ export class PiPedalModel //implements PiPedalModel
|
||||
this.getWebSocket().request<number>("hello")
|
||||
.then(clientId => {
|
||||
this.clientId = clientId;
|
||||
return this.getWebSocket().request<any>("plugins");
|
||||
})
|
||||
.then(data => {
|
||||
this.ui_plugins.set(UiPlugin.deserialize_array(data));
|
||||
return this.getWebSocket().request<Pedalboard>("currentPedalboard");
|
||||
})
|
||||
.then(data => {
|
||||
@@ -1116,7 +1128,9 @@ export class PiPedalModel //implements PiPedalModel
|
||||
}
|
||||
}
|
||||
|
||||
private onLv2StateChanged(instanceId: number): void {
|
||||
private onLv2StateChanged(instanceId: number, state: [boolean,any]): void {
|
||||
let item = this.pedalboard.get().getItem(instanceId);
|
||||
item.lv2State = state;
|
||||
for (let item of this.stateChangedListeners) {
|
||||
if (item.instanceId === instanceId) {
|
||||
item.onStateChanged(instanceId);
|
||||
@@ -2531,6 +2545,27 @@ export class PiPedalModel //implements PiPedalModel
|
||||
return nullCast(this.webSocket).request<number>("newPreset");
|
||||
}
|
||||
|
||||
getTheme(): ColorTheme {
|
||||
return isDarkMode() ? ColorTheme.Dark: ColorTheme.Light;
|
||||
}
|
||||
|
||||
setTheme(value: ColorTheme) {
|
||||
if (this.getTheme() !== value)
|
||||
{
|
||||
setDarkMode(value === ColorTheme.Dark);
|
||||
this.reloadPage();
|
||||
}
|
||||
}
|
||||
|
||||
reloadRequested: boolean = false;
|
||||
|
||||
reloadPage() {
|
||||
this.reloadRequested = true;
|
||||
// eslint-disable-next-line no-restricted-globals
|
||||
location.reload();
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
let instance: PiPedalModel | undefined = undefined;
|
||||
|
||||
@@ -137,7 +137,7 @@ const PluginControl =
|
||||
this.onInputKeyPress = this.onInputKeyPress.bind(this);
|
||||
}
|
||||
isTouchDevice(): boolean {
|
||||
return Utility.isTouchDevice();
|
||||
return Utility.needsZoomedControls();
|
||||
}
|
||||
|
||||
showZoomedControl()
|
||||
@@ -547,7 +547,7 @@ const PluginControl =
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Select variant="standard"
|
||||
<Select variant="standard"
|
||||
ref={this.selectRef}
|
||||
value={control.clampSelectValue(value)}
|
||||
onChange={this.onSelectChanged}
|
||||
@@ -556,7 +556,7 @@ const PluginControl =
|
||||
id: 'id' + control.symbol,
|
||||
style: { fontSize: FONT_SIZE }
|
||||
}}
|
||||
style={{ marginLeft: 4, marginRight: 4, width: 140 }}
|
||||
style={{ marginLeft: 4, marginRight: 4, width: 140,fontSize: 14 }}
|
||||
>
|
||||
{control.scale_points.map((scale_point: ScalePoint) => (
|
||||
<MenuItem key={scale_point.value} value={scale_point.value}>{scale_point.label}</MenuItem>
|
||||
|
||||
@@ -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, UiFileProperty, ScalePoint } from './Lv2Plugin';
|
||||
import { UiPlugin, UiControl, UiFileProperty,UiFrequencyPlot, ScalePoint } from './Lv2Plugin';
|
||||
import {
|
||||
Pedalboard, PedalboardItem, ControlValue
|
||||
} from './Pedalboard';
|
||||
@@ -39,6 +39,7 @@ import FilePropertyDialog from './FilePropertyDialog';
|
||||
import JsonAtom from './JsonAtom';
|
||||
import PluginOutputControl from './PluginOutputControl';
|
||||
import Units from './Units';
|
||||
import ToobFrequencyResponseView from './ToobFrequencyResponseView';
|
||||
|
||||
|
||||
export const StandardItemSize = { width: 80, height: 110 };
|
||||
@@ -335,6 +336,14 @@ const PluginControlView =
|
||||
/>
|
||||
));
|
||||
}
|
||||
makeFrequencyPlotUI(frequencyPlot: UiFrequencyPlot): ReactNode {
|
||||
return ((
|
||||
<ToobFrequencyResponseView instanceId={this.props.instanceId}
|
||||
propertyName={frequencyPlot.patchProperty}
|
||||
width={frequencyPlot.width}
|
||||
/>
|
||||
));
|
||||
}
|
||||
makeStandardControl(uiControl: UiControl, controlValues: ControlValue[]): ReactNode {
|
||||
let symbol = uiControl.symbol;
|
||||
if (!uiControl.is_input) {
|
||||
@@ -445,6 +454,48 @@ const PluginControlView =
|
||||
);
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < plugin.frequencyPlots.length; ++i) {
|
||||
let frequencyPlot = plugin.frequencyPlots[i];
|
||||
let frequencyPlotUi = this.makeFrequencyPlotUI(frequencyPlot);
|
||||
|
||||
if (frequencyPlot.portGroup !== "" && plugin.getPortGroupByUri(frequencyPlot.portGroup)) {
|
||||
let portGroup = nullCast(plugin.getPortGroupByUri(frequencyPlot.portGroup));
|
||||
let controlGroup = portGroupMap[portGroup.symbol];
|
||||
if (controlGroup) {
|
||||
let insertPosition = controlGroup.indexes.length;
|
||||
if (frequencyPlot.index !== -1) {
|
||||
for (let i = 0; i < controlGroup.controls.length; ++i) {
|
||||
if (controlGroup.indexes[i] >= frequencyPlot.index) {
|
||||
insertPosition = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
let index = frequencyPlot.index !== -1 ? frequencyPlot.index : 100;
|
||||
controlGroup.controls.splice(insertPosition, 0, frequencyPlotUi);
|
||||
controlGroup.indexes.splice(insertPosition, 0, index);
|
||||
|
||||
} else {
|
||||
let index = frequencyPlot.index !== -1 ? frequencyPlot.index : 100;
|
||||
let controlGroup = new ControlGroup(
|
||||
portGroup.name,
|
||||
[index],
|
||||
[frequencyPlotUi]);
|
||||
result.push(
|
||||
controlGroup
|
||||
);
|
||||
portGroupMap[portGroup.symbol] = controlGroup;
|
||||
|
||||
}
|
||||
} else if (frequencyPlot.index !== -1) {
|
||||
result.splice(frequencyPlot.index, 0, frequencyPlotUi);
|
||||
} else {
|
||||
result.push(
|
||||
frequencyPlotUi
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,10 @@ const styles = (theme: Theme) =>
|
||||
top: theme.spacing(1),
|
||||
color: theme.palette.grey[500],
|
||||
},
|
||||
icon: {
|
||||
fill: theme.palette.text.primary,
|
||||
opacity: 0.6
|
||||
}
|
||||
});
|
||||
};
|
||||
export interface PluginInfoDialogTitleProps extends WithStyles<typeof styles> {
|
||||
@@ -228,7 +232,7 @@ const PluginInfoDialog = withStyles(styles)((props: PluginInfoProps) => {
|
||||
style={{ display: (props.plugin_uri !== "") ? "inline-flex" : "none" }}
|
||||
onClick={handleClickOpen}
|
||||
size="large">
|
||||
<InfoOutlinedIcon style={{opacity: 0.6}} />
|
||||
<InfoOutlinedIcon className={classes.icon} color='inherit' />
|
||||
</IconButton>
|
||||
{open && (
|
||||
<Dialog onClose={handleClose} open={open} fullWidth >
|
||||
|
||||
@@ -25,6 +25,7 @@ import withStyles from '@mui/styles/withStyles';
|
||||
import { UiControl } from './Lv2Plugin';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { PiPedalModel, PiPedalModelFactory, MonitorPortHandle,State } from './PiPedalModel';
|
||||
import isDarkMode from './DarkMode';
|
||||
|
||||
|
||||
|
||||
@@ -77,11 +78,13 @@ const PluginOutputControl =
|
||||
|
||||
private model: PiPedalModel;
|
||||
private vuRef: React.RefObject<HTMLDivElement>;
|
||||
private lampRef: React.RefObject<HTMLDivElement>;
|
||||
|
||||
|
||||
constructor(props: PluginOutputControlProps) {
|
||||
super(props);
|
||||
this.vuRef = React.createRef<HTMLDivElement>();
|
||||
this.lampRef = React.createRef<HTMLDivElement>();
|
||||
this.state = {
|
||||
hasValue: false,
|
||||
value: 0
|
||||
@@ -130,6 +133,12 @@ const PluginOutputControl =
|
||||
private animationHandle: number | undefined = undefined;
|
||||
|
||||
private updateValue(value: number) {
|
||||
if (this.lampRef.current)
|
||||
{
|
||||
let control = this.props.uiControl;
|
||||
let range = (value-control.min_value)/(control.max_value-control.min_value);
|
||||
this.lampRef.current.style.opacity = range +"";
|
||||
}
|
||||
if (this.vuRef.current) {
|
||||
let control = this.props.uiControl;
|
||||
let range = (value-control.min_value)/(control.max_value-control.min_value);
|
||||
@@ -241,6 +250,38 @@ const PluginOutputControl =
|
||||
</div >
|
||||
|
||||
);
|
||||
} else if (control.toggled_property && control.scale_points.length === 0) {
|
||||
item_width = undefined;
|
||||
let attachedLamp = control.name === "" || control.name === "\u00A0" ;
|
||||
return (
|
||||
<div style={{ display: "flex", flexDirection: "column", width: item_width,
|
||||
marginTop: 8, marginBottom: 8, marginRight: 8,marginLeft: (attachedLamp? 0: 8), height: 98
|
||||
}}>
|
||||
{/* TITLE SECTION */}
|
||||
<div style={{ flex: "0 0 auto", width: "100%", marginBottom: 8, marginLeft: 0, marginRight: 0 }}>
|
||||
<Typography variant="caption" display="block" style={{
|
||||
width: "100%",
|
||||
textAlign: "center"
|
||||
}}> {control.name === "" ? "\u00A0": control.name}</Typography>
|
||||
</div>
|
||||
{/* CONTROL SECTION */}
|
||||
|
||||
<div style={{ flex: "1 1 auto", display: "flex", justifyContent: "left", alignItems: "start", flexFlow: "row nowrap" }}>
|
||||
<div style={{ width: 12, height: 12, background: isDarkMode()? "#111" : "#444", borderRadius: 5, position: "relative" }}>
|
||||
<div ref={this.lampRef} style={{ width: 8, height: 8,
|
||||
background: (isDarkMode()? "radial-gradient(circle at center, #F00 0, #F00 20%, #333 100%)"
|
||||
: "radial-gradient(circle at center, #F44 0, #F44 40%, #644 100%)"),
|
||||
opacity: 0, borderRadius: 3,margin: 2,position: "absolute" }} />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* LABEL/EDIT SECTION*, strictly a placeholder for visual alignment purposes.*/}
|
||||
<div style={{ flex: "0 0 auto", position: "relative", width: 30, height: 27 }}>
|
||||
|
||||
</div>
|
||||
</div >
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div style={{ display: "flex", flexDirection: "column", width: item_width, margin: 8, height: 98 }}>
|
||||
|
||||
@@ -58,7 +58,7 @@ interface PresetSelectorState {
|
||||
}
|
||||
|
||||
|
||||
const selectColor = isDarkMode()? "#888": "black";
|
||||
const selectColor = isDarkMode()? "#888": "#FFFFFF";
|
||||
|
||||
const styles = (theme: Theme) => createStyles({
|
||||
select: { // fu fu fu.Overrides for white selector on dark background.
|
||||
@@ -301,17 +301,17 @@ const PresetSelector =
|
||||
}}>
|
||||
<div style={{ flex: "0 0 auto" }}>
|
||||
<IconButton
|
||||
style={{ flex: "0 0 auto", opacity: this.state.presets.presetChanged ? 1.0 : 0.0 }}
|
||||
style={{ flex: "0 0 auto", opacity: this.state.presets.presetChanged ? 1.0 : 0.0, color: "#FFFFFF" }}
|
||||
onClick={(e) => { this.handleSave(); }}
|
||||
size="large">
|
||||
<SaveIconOutline style={{ opacity: 0.75 }} />
|
||||
<SaveIconOutline style={{ opacity: 0.75 }} color="inherit" />
|
||||
</IconButton>
|
||||
</div>
|
||||
|
||||
<div style={{ flex: "1 1 auto", minWidth: 60, maxWidth: 300, position: "relative", paddingRight: 12 }} >
|
||||
<Select variant="standard"
|
||||
className={classes.select}
|
||||
style={{ width: "100%", position: "relative", top: 0 }} disabled={!this.state.enabled}
|
||||
style={{ width: "100%", position: "relative", top: 0, color: "#FFFFFF" }} disabled={!this.state.enabled}
|
||||
onChange={(e, extra) => this.handleChange(e, extra)}
|
||||
onClose={(e) => this.handleSelectClose(e)}
|
||||
displayEmpty
|
||||
@@ -336,12 +336,13 @@ const PresetSelector =
|
||||
}
|
||||
</Select>
|
||||
</div>
|
||||
<div style={{ flex: "0 0 auto" }}>
|
||||
<div style={{ flex: "0 0 auto"}}>
|
||||
<IconButton
|
||||
style={{ flex: "0 0 auto" }}
|
||||
style={{ flex: "0 0 auto", color: "#FFFFFF" }}
|
||||
onClick={(e) => this.handlePresetMenuClick(e)}
|
||||
size="large">
|
||||
<MoreVertIcon style={{ opacity: 0.75 }} />
|
||||
size="large"
|
||||
>
|
||||
<MoreVertIcon style={{ opacity: 0.75 }} color="inherit" />
|
||||
</IconButton>
|
||||
<Menu
|
||||
id="edit-presets-menu"
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
// Copyright (c) 2023 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 { useState } from 'react';
|
||||
import Button from '@mui/material/Button';
|
||||
import DialogTitle from '@mui/material/DialogTitle';
|
||||
import DialogContent from '@mui/material/DialogContent';
|
||||
import DialogActions from '@mui/material/DialogActions';
|
||||
import Dialog from '@mui/material/Dialog';
|
||||
import FormControlLabel from '@mui/material/FormControlLabel';
|
||||
import FormControl from '@mui/material/FormControl';
|
||||
|
||||
import RadioGroup from '@mui/material/RadioGroup';
|
||||
import Radio from '@mui/material/Radio';
|
||||
import {ColorTheme} from './PiPedalModel';
|
||||
|
||||
|
||||
|
||||
export interface SelectThemesDialogProps {
|
||||
open: boolean;
|
||||
defaultTheme: ColorTheme;
|
||||
onClose: () => void;
|
||||
onOk: (value: ColorTheme) => void;
|
||||
}
|
||||
|
||||
function SelectThemesDialog(props: SelectThemesDialogProps) {
|
||||
//const classes = useStyles();
|
||||
const { onClose, defaultTheme, open,onOk } = props;
|
||||
const [ selectedTheme, setSelectedTheme ] = useState(defaultTheme);
|
||||
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
let value = ((event.target as HTMLInputElement).value) === '0' ? ColorTheme.Light: ColorTheme.Dark;
|
||||
setSelectedTheme(value);
|
||||
};
|
||||
const handleClose = (): void => {
|
||||
onClose();
|
||||
};
|
||||
const handleOk = (): void => {
|
||||
onOk(selectedTheme)
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<Dialog onClose={handleClose} open={open}>
|
||||
<DialogTitle id="simple-dialog-title">Theme</DialogTitle>
|
||||
<DialogContent>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
defaultValue={defaultTheme}
|
||||
onChange={handleChange}
|
||||
>
|
||||
<FormControlLabel value={ColorTheme.Light} control={<Radio size='small' />} label="Light" />
|
||||
<FormControlLabel value={ColorTheme.Dark} control={<Radio size='small' />} label="Dark" />
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={handleClose} color="primary">
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={handleOk} color="secondary" >
|
||||
OK
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
export default SelectThemesDialog;
|
||||
@@ -23,7 +23,7 @@ import OkCancelDialog from './OkCancelDialog';
|
||||
import ListSelectDialog from './ListSelectDialog';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { PiPedalModel, PiPedalModelFactory, State } from './PiPedalModel';
|
||||
import { PiPedalModel, PiPedalModelFactory, State, ColorTheme } from './PiPedalModel';
|
||||
import ButtonBase from "@mui/material/ButtonBase";
|
||||
import AppBar from '@mui/material/AppBar';
|
||||
import Button from '@mui/material/Button';
|
||||
@@ -45,6 +45,7 @@ import DialogEx from './DialogEx'
|
||||
import GovernorSettings from './GovernorSettings';
|
||||
import { AlsaMidiDeviceInfo } from './AlsaMidiDeviceInfo';
|
||||
import SystemMidiBindingsDialog from './SystemMidiBindingsDialog';
|
||||
import SelectThemeDialog from './SelectThemeDialog';
|
||||
|
||||
import Slide, { SlideProps } from '@mui/material/Slide';
|
||||
import { createStyles, Theme } from '@mui/material/styles';
|
||||
@@ -79,6 +80,7 @@ interface SettingsDialogState {
|
||||
showInputSelectDialog: boolean;
|
||||
showOutputSelectDialog: boolean;
|
||||
showMidiSelectDialog: boolean;
|
||||
showThemeSelectDialog: boolean;
|
||||
showJackServerSettingsDialog: boolean;
|
||||
shuttingDown: boolean;
|
||||
restarting: boolean;
|
||||
@@ -184,6 +186,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
showInputSelectDialog: false,
|
||||
showOutputSelectDialog: false,
|
||||
showMidiSelectDialog: false,
|
||||
showThemeSelectDialog: false,
|
||||
showJackServerSettingsDialog: false,
|
||||
shuttingDown: false,
|
||||
restarting: false,
|
||||
@@ -384,6 +387,11 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
showMidiSelectDialog: true
|
||||
})
|
||||
}
|
||||
handleThemeSelection() {
|
||||
this.setState({
|
||||
showThemeSelectDialog: true
|
||||
});
|
||||
}
|
||||
handleMidiMessageSettings() {
|
||||
this.setState({
|
||||
showSystemMidiBindingsDialog: true
|
||||
@@ -553,22 +561,22 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
}}
|
||||
>
|
||||
<div >
|
||||
{this.props.onboarding &&
|
||||
(
|
||||
<div>
|
||||
<Typography display="block" variant="body1" color="textSecondary" style={{paddingLeft: 24,paddingBottom: 8 }}>
|
||||
Select and configure an audio device. You may optionally configure MIDI inputs, and set up a Wi-Fi Direct Hotspot now as well.
|
||||
</Typography>
|
||||
<Typography display="block" variant="body1" color="textSecondary" style={{paddingLeft: 24,paddingBottom: 8 }}>
|
||||
Access and modify these settings later by selecting the <i>Settings</i> menu item on the main menu.
|
||||
</Typography>
|
||||
<Divider />
|
||||
</div>
|
||||
)}
|
||||
{this.props.onboarding &&
|
||||
(
|
||||
<div>
|
||||
<Typography display="block" variant="body1" color="textSecondary" style={{ paddingLeft: 24, paddingBottom: 8 }}>
|
||||
Select and configure an audio device. You may optionally configure MIDI inputs, and set up a Wi-Fi Direct Hotspot now as well.
|
||||
</Typography>
|
||||
<Typography display="block" variant="body1" color="textSecondary" style={{ paddingLeft: 24, paddingBottom: 8 }}>
|
||||
Access and modify these settings later by selecting the <i>Settings</i> menu item on the main menu.
|
||||
</Typography>
|
||||
<Divider />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<Typography className={classes.sectionHead} display="block" variant="caption" color="secondary">
|
||||
STATUS
|
||||
STATUS
|
||||
</Typography>
|
||||
{(!isConfigValid) ?
|
||||
(
|
||||
@@ -582,7 +590,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
(
|
||||
<div className={classes.cpuStatusColor} style={{ paddingLeft: 48, position: "relative", top: -12 }}>
|
||||
{JackHostStatus.getDisplayView("", this.state.jackStatus)}
|
||||
{ (!this.props.onboarding) && JackHostStatus.getCpuInfo("Governor:\u00A0", this.state.jackStatus)}
|
||||
{(!this.props.onboarding) && JackHostStatus.getCpuInfo("Governor:\u00A0", this.state.jackStatus)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -657,7 +665,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
<SelectHoverBackground selected={false} showHover={true} />
|
||||
<div style={{ width: "100%" }}>
|
||||
<Typography className={classes.primaryItem} display="block" variant="body2" noWrap>System MIDI Bindings</Typography>
|
||||
|
||||
|
||||
</div>
|
||||
</ButtonBase>
|
||||
|
||||
@@ -713,7 +721,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
</div>
|
||||
</ButtonBase>
|
||||
</div>
|
||||
{ (!this.props.onboarding) ? (
|
||||
{(!this.props.onboarding) ? (
|
||||
<div >
|
||||
<Divider />
|
||||
<Typography className={classes.sectionHead} display="block" variant="caption" color="secondary">SYSTEM</Typography>
|
||||
@@ -735,7 +743,23 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
|
||||
<ButtonBase
|
||||
className={classes.setting}
|
||||
onClick={() => { this.setState({ showStatusMonitorDialog: true }); }} >
|
||||
onClick={() => { this.handleThemeSelection(); }} >
|
||||
<SelectHoverBackground selected={false} showHover={true} />
|
||||
<div style={{ width: "100%" }}>
|
||||
<Typography className={classes.primaryItem} display="block" variant="body2" color="textPrimary" noWrap>
|
||||
Color Theme</Typography>
|
||||
<Typography className={classes.secondaryItem} display="block" variant="caption" color="textSecondary" noWrap>
|
||||
{ this.model.getTheme() === ColorTheme.Dark ? "Dark" :"Light"}
|
||||
</Typography>
|
||||
</div>
|
||||
</ButtonBase>
|
||||
|
||||
|
||||
<ButtonBase
|
||||
className={classes.setting}
|
||||
onClick={() => {
|
||||
this.model.setShowStatusMonitor(!this.state.showStatusMonitor)
|
||||
}} >
|
||||
<SelectHoverBackground selected={false} showHover={true} />
|
||||
<div style={{ width: "100%" }}>
|
||||
<div style={{
|
||||
@@ -746,6 +770,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
<Typography className={classes.primaryItem} display="block" variant="body2" color="textPrimary" noWrap>
|
||||
Show status monitor on main screen.</Typography>
|
||||
</div>
|
||||
|
||||
<div style={{ flex: "0 0 auto" }}>
|
||||
<Switch
|
||||
checked={this.state.showStatusMonitor}
|
||||
@@ -787,16 +812,18 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
</div >
|
||||
</ButtonBase>
|
||||
</div>
|
||||
): (
|
||||
) : (
|
||||
<div>
|
||||
<Divider/>
|
||||
<div style={{display: "grid", placeContent: "end", maxWidth: 550, marginLeft: 16,marginRight: 16,
|
||||
marginTop: 16,marginBottom: 16}}>
|
||||
<Button variant="outlined" onClick={()=> {this.onOnboardingContinue()}} disabled={this.state.continueDisabled} style={{width: 120}}>Continue</Button>
|
||||
<Divider />
|
||||
<div style={{
|
||||
display: "grid", placeContent: "end", maxWidth: 550, marginLeft: 16, marginRight: 16,
|
||||
marginTop: 16, marginBottom: 16
|
||||
}}>
|
||||
<Button variant="outlined" onClick={() => { this.onOnboardingContinue() }} disabled={this.state.continueDisabled} style={{ width: 120 }}>Continue</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -849,6 +876,20 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
|
||||
)
|
||||
}
|
||||
{
|
||||
(this.state.showThemeSelectDialog) &&
|
||||
(
|
||||
<SelectThemeDialog open={this.state.showThemeSelectDialog}
|
||||
onClose={()=> { this.setState({showThemeSelectDialog: false});} }
|
||||
onOk={(selectedTheme: ColorTheme) => {
|
||||
this.model.setTheme(selectedTheme);
|
||||
this.setState({showThemeSelectDialog: false});
|
||||
}}
|
||||
defaultTheme={this.model.getTheme()}
|
||||
/>
|
||||
|
||||
)
|
||||
}
|
||||
<WifiConfigDialog wifiConfigSettings={this.state.wifiConfigSettings} open={this.state.showWifiConfigDialog}
|
||||
onClose={() => this.setState({ showWifiConfigDialog: false })}
|
||||
onOk={(wifiConfigSettings) => this.handleApplyWifiConfig(wifiConfigSettings)}
|
||||
@@ -869,8 +910,8 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
/>
|
||||
<SystemMidiBindingsDialog
|
||||
open={this.state.showSystemMidiBindingsDialog}
|
||||
onClose={()=> { this.setState({showSystemMidiBindingsDialog: false});}}
|
||||
/>
|
||||
onClose={() => { this.setState({ showSystemMidiBindingsDialog: false }); }}
|
||||
/>
|
||||
</DialogEx >
|
||||
|
||||
);
|
||||
|
||||
@@ -25,11 +25,11 @@ import createStyles from '@mui/styles/createStyles';
|
||||
import withStyles from '@mui/styles/withStyles';
|
||||
|
||||
import { PiPedalModelFactory, PiPedalModel, State } from "./PiPedalModel";
|
||||
import { StandardItemSize } from './PluginControlView';
|
||||
import Utility from './Utility';
|
||||
import SvgPathBuilder from './SvgPathBuilder';
|
||||
|
||||
|
||||
const StandardItemSize = { width: 80, height: 110 };
|
||||
|
||||
const FREQUENCY_RESPONSE_VECTOR_URI = "http://two-play.com/plugins/toob#frequencyResponseVector";
|
||||
|
||||
@@ -47,13 +47,15 @@ const styles = (theme: Theme) => createStyles({
|
||||
|
||||
interface ToobFrequencyResponseProps extends WithStyles<typeof styles> {
|
||||
instanceId: number;
|
||||
maxDb?: number;
|
||||
minDb?: number;
|
||||
minFrequency?: number;
|
||||
maxFrequency?: number;
|
||||
propertyName?: string;
|
||||
width?: number;
|
||||
|
||||
}
|
||||
interface ToobFrequencyResponseState {
|
||||
minDb: number;
|
||||
maxDb: number;
|
||||
minF: number;
|
||||
maxF: number;
|
||||
path: string;
|
||||
}
|
||||
|
||||
@@ -70,7 +72,11 @@ const ToobFrequencyResponseView =
|
||||
super(props);
|
||||
this.model = PiPedalModelFactory.getInstance();
|
||||
this.state = {
|
||||
path: ""
|
||||
path: "",
|
||||
minDb: -30,
|
||||
maxDb: 5,
|
||||
minF: 30,
|
||||
maxF: 20000
|
||||
};
|
||||
|
||||
this.pathRef = React.createRef();
|
||||
@@ -146,24 +152,61 @@ const ToobFrequencyResponseView =
|
||||
onFrequencyResponseUpdated(data: number[]) {
|
||||
if (!this.mounted) return;
|
||||
let pathBuilder = new SvgPathBuilder();
|
||||
|
||||
let minF = data[0];
|
||||
let maxF = data[1];
|
||||
let dbMin = data[2];
|
||||
let dbMax = data[3];
|
||||
let logMin = Math.log(minF);
|
||||
let logMax = Math.log(maxF);
|
||||
|
||||
let toX_ = (frequency: number): number => {
|
||||
var logV = Math.log(frequency);
|
||||
return (this.xMax - this.xMin) * (logV - logMin) / (logMax - logMin) + this.xMin;
|
||||
|
||||
};
|
||||
let toY_ = (value: number): number => {
|
||||
|
||||
var db;
|
||||
if (value < this.MIN_DB_AF) {
|
||||
db = -192.0;
|
||||
} else {
|
||||
db = 20 * Math.log10(value);
|
||||
}
|
||||
var y = (db - dbMin) / (dbMax - dbMin) * (this.yMax - this.yMin) + this.yMin;
|
||||
return y;
|
||||
};
|
||||
|
||||
|
||||
|
||||
if (data.length > 2) {
|
||||
pathBuilder.moveTo(this.toX(data[0]), this.toY(data[1]))
|
||||
for (let i = 2; i < data.length; i += 2) {
|
||||
pathBuilder.lineTo(this.toX(data[i]), this.toY(data[i + 1]));
|
||||
pathBuilder.moveTo(toX_(data[4]), toY_(data[5]))
|
||||
for (let i = 6; i < data.length; i += 2) {
|
||||
pathBuilder.lineTo(toX_(data[i]), toY_(data[i + 1]));
|
||||
}
|
||||
}
|
||||
this.currentPath = pathBuilder.toString();
|
||||
this.setState({ path: this.currentPath });
|
||||
this.setState({
|
||||
minF: data[0],
|
||||
maxF: data[1],
|
||||
maxDb: data[2],
|
||||
minDb: data[3],
|
||||
path: this.currentPath
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private getPropertyUri()
|
||||
{
|
||||
return this.props.propertyName? this.props.propertyName: FREQUENCY_RESPONSE_VECTOR_URI;
|
||||
}
|
||||
updateAllWaveShapes() {
|
||||
if (this.requestOutstanding) { // throttling.
|
||||
this.requestDeferred = true;
|
||||
return;
|
||||
}
|
||||
this.requestOutstanding = true;
|
||||
this.model.getPatchProperty<any>(this.props.instanceId, FREQUENCY_RESPONSE_VECTOR_URI)
|
||||
this.model.getPatchProperty<any>(this.props.instanceId, this.getPropertyUri())
|
||||
.then((json) => {
|
||||
if (json && json.otype_ === "Vector" && json.vtype_ === "Float") {
|
||||
this.onFrequencyResponseUpdated(json.value as number[]);
|
||||
@@ -237,11 +280,11 @@ const ToobFrequencyResponseView =
|
||||
|
||||
render() {
|
||||
// deliberately reversed to flip up and down.
|
||||
this.dbMax = this.props.minDb ?? this.dbMinDefault;
|
||||
this.dbMin = this.props.maxDb ?? this.dbMaxDefault;
|
||||
this.dbMax = this.state.minDb;
|
||||
this.dbMin = this.state.maxDb;
|
||||
|
||||
this.fMin = this.props.minFrequency ?? 30;
|
||||
this.fMax = this.props.maxFrequency ?? 20000;
|
||||
this.fMin = this.state.minF;
|
||||
this.fMax = this.state.maxF;
|
||||
this.logMin = Math.log(this.fMin);
|
||||
this.logMax = Math.log(this.fMax);
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ const ToobMLView =
|
||||
{
|
||||
let group = controls[4] as ControlGroup;
|
||||
group.controls.splice(0,0,
|
||||
( <ToobFrequencyResponseView instanceId={this.props.instanceId} minDb={-20} maxDb={20} />)
|
||||
( <ToobFrequencyResponseView instanceId={this.props.instanceId} />)
|
||||
);
|
||||
|
||||
let gainControl: React.ReactElement = controls[2] as React.ReactElement;
|
||||
|
||||
@@ -92,7 +92,7 @@ const ToobToneStackView =
|
||||
{
|
||||
controls.splice(0,0,
|
||||
( <ToobFrequencyResponseView instanceId={this.props.instanceId}
|
||||
minDb={-20} maxDb={20} />)
|
||||
/>)
|
||||
);
|
||||
} else {
|
||||
controls.splice(0,0,
|
||||
|
||||
@@ -206,7 +206,7 @@ export default class UploadFileDialog extends ResizeResponsiveComponent<UploadFi
|
||||
upload.abortController = new AbortController();
|
||||
if (!this.wantsFile(this.uploadList[i].file))
|
||||
{
|
||||
throw new Error("Invalid file type.");
|
||||
throw new Error("Invalid file extension.");
|
||||
}
|
||||
let filename = await this.model.uploadFile(this.props.uploadPage, this.uploadList[i].file, "application/octet-stream", upload.abortController);
|
||||
this.props.onUploaded(filename);
|
||||
|
||||
@@ -41,11 +41,11 @@ const Utility = class {
|
||||
static isLandscape(): boolean {
|
||||
return window.innerWidth > window.innerHeight;
|
||||
}
|
||||
static isTouchDevice(): boolean {
|
||||
static needsZoomedControls(): boolean {
|
||||
if (!this.isLandscape()) return false;
|
||||
|
||||
if (window.innerHeight > 500) return false;
|
||||
|
||||
if (window.innerHeight > 300) return true;
|
||||
return (('ontouchstart' in window) &&
|
||||
((navigator.maxTouchPoints??0) > 0) );
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import { WithStyles } from '@mui/styles';
|
||||
import withStyles from '@mui/styles/withStyles';
|
||||
import createStyles from '@mui/styles/createStyles';
|
||||
import { PiPedalModel, PiPedalModelFactory, ZoomedControlInfo } from './PiPedalModel';
|
||||
import {ReactComponent as DialIcon} from './svg/fx_dial.svg';
|
||||
|
||||
const SELECTED_OPACITY = 0.8;
|
||||
const DEFAULT_OPACITY = 0.6;
|
||||
@@ -34,6 +35,12 @@ const DEAD_ZONE_SIZE = 5;
|
||||
|
||||
|
||||
const styles = (theme: Theme) => createStyles({
|
||||
dialIcon: {
|
||||
overscrollBehavior: "none", touchAction: "none",
|
||||
fill: theme.palette.text.primary,
|
||||
opacity: DEFAULT_OPACITY,
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -56,7 +63,7 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
|
||||
class extends React.Component<ZoomedDialProps, ZoomedDialState> {
|
||||
|
||||
model: PiPedalModel = PiPedalModelFactory.getInstance();
|
||||
imgRef: React.RefObject<HTMLImageElement> = React.createRef();
|
||||
imgRef: React.RefObject<SVGSVGElement> = React.createRef();
|
||||
|
||||
constructor(props: ZoomedDialProps) {
|
||||
super(props);
|
||||
@@ -75,7 +82,7 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
|
||||
|
||||
}
|
||||
|
||||
onPointerUp(e: PointerEvent<HTMLImageElement>) {
|
||||
onPointerUp(e: PointerEvent<SVGSVGElement>) {
|
||||
|
||||
if (this.isCapturedPointer(e)) {
|
||||
--this.pointersDown;
|
||||
@@ -94,7 +101,7 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
|
||||
}
|
||||
|
||||
|
||||
releaseCapture(e: PointerEvent<HTMLImageElement>)
|
||||
releaseCapture(e: PointerEvent<SVGSVGElement>)
|
||||
{
|
||||
let img = this.imgRef.current;
|
||||
|
||||
@@ -118,7 +125,7 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
|
||||
}
|
||||
|
||||
|
||||
onPointerLostCapture(e: PointerEvent<HTMLImageElement>) {
|
||||
onPointerLostCapture(e: PointerEvent<SVGSVGElement>) {
|
||||
if (this.isCapturedPointer(e)) {
|
||||
--this.pointersDown;
|
||||
|
||||
@@ -128,10 +135,10 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
|
||||
|
||||
}
|
||||
|
||||
onTouchStart(e: TouchEvent<HTMLImageElement>) {
|
||||
onTouchStart(e: TouchEvent<SVGSVGElement>) {
|
||||
//must be defined to get onTouchMove
|
||||
}
|
||||
onTouchMove(e: TouchEvent<HTMLImageElement>) {
|
||||
onTouchMove(e: TouchEvent<SVGSVGElement>) {
|
||||
// e.preventDefault();
|
||||
e.stopPropagation(); // cancels scroll!!!
|
||||
|
||||
@@ -150,7 +157,7 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
|
||||
currentAngle: number = 0;
|
||||
lastPointerAngle: number = 0;
|
||||
|
||||
isValidPointer(e: PointerEvent<HTMLImageElement>): boolean {
|
||||
isValidPointer(e: PointerEvent<SVGSVGElement>): boolean {
|
||||
if (e.pointerType === "mouse") {
|
||||
return e.button === 0;
|
||||
} else if (e.pointerType === "pen") {
|
||||
@@ -202,7 +209,7 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
|
||||
return 0;
|
||||
}
|
||||
|
||||
pointerToAngle(e: PointerEvent<HTMLImageElement>): number {
|
||||
pointerToAngle(e: PointerEvent<SVGSVGElement>): number {
|
||||
|
||||
if (this.imgRef.current) {
|
||||
let img = this.imgRef.current;
|
||||
@@ -220,10 +227,10 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
|
||||
}
|
||||
return NaN;
|
||||
}
|
||||
captureElement?: HTMLElement;
|
||||
captureElement?: SVGSVGElement;
|
||||
pointersDown: number = 0;
|
||||
|
||||
onPointerDown(e: PointerEvent<HTMLImageElement>): void {
|
||||
onPointerDown(e: PointerEvent<SVGSVGElement>): void {
|
||||
if (!this.mouseDown && this.isValidPointer(e)) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
@@ -262,7 +269,7 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
|
||||
}
|
||||
}
|
||||
|
||||
isCapturedPointer(e: PointerEvent<HTMLImageElement>): boolean {
|
||||
isCapturedPointer(e: PointerEvent<SVGSVGElement>): boolean {
|
||||
return this.mouseDown
|
||||
&& e.pointerId === this.pointerId
|
||||
&& e.pointerType === this.pointerType;
|
||||
@@ -271,7 +278,7 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
|
||||
|
||||
|
||||
|
||||
onPointerMove(e: PointerEvent<HTMLImageElement>): void {
|
||||
onPointerMove(e: PointerEvent<SVGSVGElement>): void {
|
||||
if (this.isCapturedPointer(e)) {
|
||||
e.preventDefault();
|
||||
this.updateAngle(e)
|
||||
@@ -286,7 +293,7 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
|
||||
|
||||
|
||||
}
|
||||
updateAngle(e: PointerEvent<HTMLImageElement>): void {
|
||||
updateAngle(e: PointerEvent<SVGSVGElement>): void {
|
||||
let angle: number = this.pointerToAngle(e);
|
||||
if (!isNaN(angle)) {
|
||||
if (!isNaN(this.lastPointerAngle)) {
|
||||
@@ -352,14 +359,13 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
|
||||
|
||||
|
||||
render() {
|
||||
let classes = this.props.classes;
|
||||
return (
|
||||
<img ref={this.imgRef} src="img/fx_dial.svg" alt=""
|
||||
<DialIcon ref={this.imgRef} className={classes.dialIcon}
|
||||
style={{
|
||||
overscrollBehavior: "none", touchAction: "none",
|
||||
width: this.props.size, height: this.props.size, opacity: DEFAULT_OPACITY,
|
||||
transform: this.getDefaultRotationTransform()
|
||||
transform: this.getDefaultRotationTransform(),
|
||||
width: this.props.size, height: this.props.size,
|
||||
}}
|
||||
draggable="true"
|
||||
onTouchStart={this.onTouchStart} onTouchMove={this.onTouchMove}
|
||||
onPointerDown={this.onPointerDown} onPointerUp={this.onPointerUp}
|
||||
onPointerMoveCapture={this.onPointerMove} onDrag={this.onDrag}
|
||||
|
||||
@@ -215,8 +215,8 @@ const ZoomedUiControl = withStyles(styles, { withTheme: true })(
|
||||
onClose={() => { this.props.onDialogClose() }}
|
||||
onAbort={() => { this.props.onDialogClose() }}
|
||||
>
|
||||
<div style={{
|
||||
width: 380, height: 300, background: "FFFF",
|
||||
<div style={{
|
||||
width: 380, height: 300,
|
||||
display: "flex", flexFlow: "row", alignItems: "center", alignContent: " center", justifyContent: "center"
|
||||
}}>
|
||||
<IconButton sx={{ height: "100%", width: 48, borderRadius: "0% 50% 50% 0%" }} onClick={
|
||||
@@ -227,7 +227,7 @@ const ZoomedUiControl = withStyles(styles, { withTheme: true })(
|
||||
<NavigateBeforeIcon />
|
||||
</IconButton>
|
||||
<div style={{
|
||||
width: 200, flexGrow: 1, height: 300, background: "#FFF",
|
||||
width: 200, flexGrow: 1, height: 300,
|
||||
display: "flex", flexFlow: "column", alignItems: "center", alignContent: "center", justifyContent: "center"
|
||||
|
||||
}}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px">
|
||||
<g>
|
||||
<g>
|
||||
<polygon points="15,16 11,20 21,20 21,16"/>
|
||||
<path d="M12.06,7.19L3,16.25V20h3.75l9.06-9.06L12.06,7.19z M5.92,18H5v-0.92l7.06-7.06l0.92,0.92L5.92,18z"/>
|
||||
<path d="M18.71,8.04c0.39-0.39,0.39-1.02,0-1.41l-2.34-2.34C16.17,4.09,15.92,4,15.66,4c-0.25,0-0.51,0.1-0.7,0.29l-1.83,1.83 l3.75,3.75L18.71,8.04z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 507 B |
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||
<rect x="6" y="9" width="2" height="2"/>
|
||||
<rect x="6" y="13" width="2" height="2"/>
|
||||
<rect x="6" y="17" width="2" height="2"/>
|
||||
<rect x="10" y="17" width="3" height="2"/>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M17.059,5.19l-7.061,7.06V16h3.75l7.061-7.061L17.059,5.19z M12.918,14h-0.92v-0.92l5.061-5.061l0.92,0.92L12.918,14z"/>
|
||||
<path d="M23.708,6.04c0.39-0.39,0.39-1.02,0-1.41l-2.34-2.34c-0.2-0.2-0.45-0.29-0.71-0.29c-0.25,0-0.51,0.1-0.7,0.29l-1.83,1.83
|
||||
l3.75,3.75L23.708,6.04z"/>
|
||||
</g>
|
||||
</g>
|
||||
<path d="M15,16.641V21H4v-9V7h5h1h3.672l1.904-1.904C15.393,5.04,15.202,5,15,5h-4H8H4C2.9,5,2.01,5.9,2.01,7l-0.003,3.993L2,11v10
|
||||
c0,1.1,0.891,2,1.99,2H4h11h0.01c1.1,0,1.99-0.9,1.99-2v-6.359L15,16.641z"/>
|
||||
<polygon points="11.672,9 10,9 10,10.672 "/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 402 B After Width: | Height: | Size: 402 B |
|
Before Width: | Height: | Size: 997 B After Width: | Height: | Size: 997 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M19.43 12.98c.04-.32.07-.64.07-.98 0-.34-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.09-.16-.26-.25-.44-.25-.06 0-.12.01-.17.03l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.06-.02-.12-.03-.18-.03-.17 0-.34.09-.43.25l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98 0 .33.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.09.16.26.25.44.25.06 0 .12-.01.17-.03l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.06.02.12.03.18.03.17 0 .34-.09.43-.25l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zm-1.98-1.71c.04.31.05.52.05.73 0 .21-.02.43-.05.73l-.14 1.13.89.7 1.08.84-.7 1.21-1.27-.51-1.04-.42-.9.68c-.43.32-.84.56-1.25.73l-1.06.43-.16 1.13-.2 1.35h-1.4l-.19-1.35-.16-1.13-1.06-.43c-.43-.18-.83-.41-1.23-.71l-.91-.7-1.06.43-1.27.51-.7-1.21 1.08-.84.89-.7-.14-1.13c-.03-.31-.05-.54-.05-.74s.02-.43.05-.73l.14-1.13-.89-.7-1.08-.84.7-1.21 1.27.51 1.04.42.9-.68c.43-.32.84-.56 1.25-.73l1.06-.43.16-1.13.2-1.35h1.39l.19 1.35.16 1.13 1.06.43c.43.18.83.41 1.23.71l.91.7 1.06-.43 1.27-.51.7 1.21-1.07.85-.89.7.14 1.13zM12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 6c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |