Copy prests between banks; preset multi-select.
This commit is contained in:
+5
-1
@@ -228,7 +228,11 @@ namespace pipedal
|
|||||||
{
|
{
|
||||||
newSelection = presets_[i]->instanceId();
|
newSelection = presets_[i]->instanceId();
|
||||||
}
|
}
|
||||||
else if (presets_.size() > 1)
|
else if (i == presets_.size() && i != 0) {
|
||||||
|
newSelection = presets_[i-1]->instanceId();
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (presets_.size() >= 1)
|
||||||
{
|
{
|
||||||
newSelection = presets_[0]->instanceId();
|
newSelection = presets_[0]->instanceId();
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-5
@@ -1174,12 +1174,12 @@ int64_t PiPedalModel::DeleteBank(int64_t clientId, int64_t instanceId)
|
|||||||
return newSelection;
|
return newSelection;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t PiPedalModel::DeletePreset(int64_t clientId, int64_t instanceId)
|
int64_t PiPedalModel::DeletePresets(int64_t clientId, const std::vector<int64_t> &presetInstanceIds)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> guard{mutex};
|
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||||
int64_t oldSelection = storage.GetCurrentPresetId();
|
int64_t oldSelection = storage.GetCurrentPresetId();
|
||||||
int64_t newSelection = storage.DeletePreset(instanceId);
|
int64_t newSelection = storage.DeletePresets(presetInstanceIds);
|
||||||
this->FirePresetsChanged(clientId); // fire now.
|
this->FirePresetsChanged(clientId); // fire BEFORE we load a new preset.
|
||||||
if (oldSelection != newSelection)
|
if (oldSelection != newSelection)
|
||||||
{
|
{
|
||||||
this->LoadPreset(
|
this->LoadPreset(
|
||||||
@@ -3270,10 +3270,15 @@ int64_t PiPedalModel::ImportPresetsFromBank(int64_t bankInstanceId, const std::v
|
|||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(mutex);
|
std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||||
uint64_t lastAdded = storage.ImportPresetsFromBank(bankInstanceId, presets);
|
uint64_t lastAdded = storage.ImportPresetsFromBank(bankInstanceId, presets);
|
||||||
if (lastAdded != -1) {
|
|
||||||
|
|
||||||
}
|
|
||||||
FirePresetsChanged(-1);
|
FirePresetsChanged(-1);
|
||||||
return lastAdded;
|
return lastAdded;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
int64_t PiPedalModel::CopyPresetsToBank(int64_t bankInstanceId, const std::vector<int64_t> &presets)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||||
|
uint64_t lastAdded = storage.CopyPresetsToBank(bankInstanceId, presets);
|
||||||
|
return lastAdded;
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -385,7 +385,7 @@ namespace pipedal
|
|||||||
void LoadPreset(int64_t clientId, int64_t instanceId);
|
void LoadPreset(int64_t clientId, int64_t instanceId);
|
||||||
bool UpdatePresets(int64_t clientId, const PresetIndex &presets);
|
bool UpdatePresets(int64_t clientId, const PresetIndex &presets);
|
||||||
void UpdatePluginPresets(const PluginUiPresets &pluginPresets);
|
void UpdatePluginPresets(const PluginUiPresets &pluginPresets);
|
||||||
int64_t DeletePreset(int64_t clientId, int64_t instanceId);
|
int64_t DeletePresets(int64_t clientId, const std::vector<int64_t> &presetInstanceIds);
|
||||||
bool RenamePreset(int64_t clientId, int64_t instanceId, const std::string &name);
|
bool RenamePreset(int64_t clientId, int64_t instanceId, const std::string &name);
|
||||||
int64_t CopyPreset(int64_t clientId, int64_t fromIndex, int64_t toIndex);
|
int64_t CopyPreset(int64_t clientId, int64_t fromIndex, int64_t toIndex);
|
||||||
uint64_t CopyPluginPreset(const std::string &pluginUri, uint64_t presetId);
|
uint64_t CopyPluginPreset(const std::string &pluginUri, uint64_t presetId);
|
||||||
@@ -496,6 +496,7 @@ namespace pipedal
|
|||||||
|
|
||||||
std::vector<PresetIndexEntry> RequestBankPresets(int64_t bankInstanceId);
|
std::vector<PresetIndexEntry> RequestBankPresets(int64_t bankInstanceId);
|
||||||
int64_t ImportPresetsFromBank(int64_t bankInstanceId, const std::vector<int64_t> &presets);
|
int64_t ImportPresetsFromBank(int64_t bankInstanceId, const std::vector<int64_t> &presets);
|
||||||
|
int64_t CopyPresetsToBank(int64_t bankInstanceId, const std::vector<int64_t> &presets);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pipedal.
|
} // namespace pipedal.
|
||||||
+22
-5
@@ -46,6 +46,17 @@
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace pipedal;
|
using namespace pipedal;
|
||||||
|
|
||||||
|
class CopyPresetsToBankBody {
|
||||||
|
public:
|
||||||
|
int64_t bankInstanceId_;
|
||||||
|
std::vector<int64_t> presets_;
|
||||||
|
DECLARE_JSON_MAP(CopyPresetsToBankBody);
|
||||||
|
};
|
||||||
|
JSON_MAP_BEGIN(CopyPresetsToBankBody)
|
||||||
|
JSON_MAP_REFERENCE(CopyPresetsToBankBody, bankInstanceId)
|
||||||
|
JSON_MAP_REFERENCE(CopyPresetsToBankBody, presets)
|
||||||
|
JSON_MAP_END()
|
||||||
|
|
||||||
|
|
||||||
class ImportPresetsFromBankBody {
|
class ImportPresetsFromBankBody {
|
||||||
public:
|
public:
|
||||||
@@ -1470,12 +1481,12 @@ public:
|
|||||||
model.RequestShutdown(true);
|
model.RequestShutdown(true);
|
||||||
this->Reply(replyTo, "restart");
|
this->Reply(replyTo, "restart");
|
||||||
}
|
}
|
||||||
else if (message == "deletePresetItem")
|
else if (message == "deletePresetItems")
|
||||||
{
|
{
|
||||||
int64_t instanceId = 0;
|
std::vector<int64_t> items;
|
||||||
pReader->read(&instanceId);
|
pReader->read(&items);
|
||||||
int64_t result = model.DeletePreset(this->clientId, instanceId);
|
int64_t result = model.DeletePresets(this->clientId, items);
|
||||||
this->Reply(replyTo, "deletePresetItem", result);
|
this->Reply(replyTo, "deletePresetItems", result);
|
||||||
}
|
}
|
||||||
else if (message == "deleteBankItem")
|
else if (message == "deleteBankItem")
|
||||||
{
|
{
|
||||||
@@ -1831,6 +1842,12 @@ public:
|
|||||||
auto result = this->model.ImportPresetsFromBank(args.bankInstanceId_, args.presets_);
|
auto result = this->model.ImportPresetsFromBank(args.bankInstanceId_, args.presets_);
|
||||||
this->Reply(replyTo,"importPresetsFromBank",result);
|
this->Reply(replyTo,"importPresetsFromBank",result);
|
||||||
}
|
}
|
||||||
|
else if (message == "copyPresetsToBank") {
|
||||||
|
CopyPresetsToBankBody args;
|
||||||
|
pReader->read(&args);
|
||||||
|
auto result = this->model.CopyPresetsToBank(args.bankInstanceId_, args.presets_);
|
||||||
|
this->Reply(replyTo,"copyPresetsToBank",result);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Lv2Log::error("Unknown message received: %s", message.c_str());
|
Lv2Log::error("Unknown message received: %s", message.c_str());
|
||||||
|
|||||||
+34
-2
@@ -764,6 +764,35 @@ int64_t Storage::ImportPresetsFromBank(int64_t bankInstanceId, const std::vector
|
|||||||
SaveCurrentBank();
|
SaveCurrentBank();
|
||||||
return lastPresetId;
|
return lastPresetId;
|
||||||
}
|
}
|
||||||
|
int64_t Storage::CopyPresetsToBank(int64_t bankInstanceId, const std::vector<int64_t> &presets)
|
||||||
|
{
|
||||||
|
if (bankIndex.selectedBank() == bankInstanceId) {
|
||||||
|
throw std::runtime_error("Can't copy to self.");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto indexEntry = this->bankIndex.getBankIndexEntry(bankInstanceId);
|
||||||
|
BankFile bankFile;
|
||||||
|
LoadBankFile(indexEntry.name(),&bankFile);
|
||||||
|
|
||||||
|
std::set<int64_t> presetsSet { presets.begin(), presets.end()};
|
||||||
|
|
||||||
|
std::set<std::string> existingNames;
|
||||||
|
|
||||||
|
for (auto&preset: bankFile.presets()) {
|
||||||
|
existingNames.insert(preset->preset().name());
|
||||||
|
}
|
||||||
|
for (auto &presetEntry: this->currentBank.presets()) {
|
||||||
|
if (presetsSet.contains(presetEntry->instanceId())) {
|
||||||
|
std::string uniqueName = makeUniqueName(presetEntry->preset().name(),existingNames);
|
||||||
|
existingNames.insert(uniqueName);
|
||||||
|
Pedalboard t = presetEntry->preset();
|
||||||
|
t.name(uniqueName);
|
||||||
|
bankFile.addPreset(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SaveBankFile(indexEntry.name(),bankFile);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<PresetIndexEntry> Storage::RequestBankPresets(int64_t bankInstanceId)
|
std::vector<PresetIndexEntry> Storage::RequestBankPresets(int64_t bankInstanceId)
|
||||||
{
|
{
|
||||||
@@ -852,9 +881,12 @@ Pedalboard Storage::GetPreset(int64_t instanceId) const
|
|||||||
throw PiPedalException("Not found.");
|
throw PiPedalException("Not found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t Storage::DeletePreset(int64_t presetId)
|
int64_t Storage::DeletePresets(const std::vector<int64_t> &presetInstanceIds)
|
||||||
{
|
{
|
||||||
int64_t newSelection = currentBank.deletePreset(presetId);
|
int64_t newSelection = currentBank.selectedPreset();
|
||||||
|
for (auto presetId: presetInstanceIds) {
|
||||||
|
newSelection = currentBank.deletePreset(presetId);
|
||||||
|
}
|
||||||
SaveCurrentBank();
|
SaveCurrentBank();
|
||||||
return newSelection;
|
return newSelection;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -162,7 +162,7 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
bool LoadPreset(int64_t presetId);
|
bool LoadPreset(int64_t presetId);
|
||||||
int64_t DeletePreset(int64_t presetId);
|
int64_t DeletePresets(const std::vector<int64_t>& presetInstanceIds);
|
||||||
bool RenamePreset(int64_t presetId, const std::string&name);
|
bool RenamePreset(int64_t presetId, const std::string&name);
|
||||||
int64_t CopyPreset(int64_t fromId, int64_t toId = -1);
|
int64_t CopyPreset(int64_t fromId, int64_t toId = -1);
|
||||||
int64_t CreateNewPreset();
|
int64_t CreateNewPreset();
|
||||||
@@ -271,6 +271,7 @@ public:
|
|||||||
|
|
||||||
std::vector<PresetIndexEntry> RequestBankPresets(int64_t bankInstanceId);
|
std::vector<PresetIndexEntry> RequestBankPresets(int64_t bankInstanceId);
|
||||||
int64_t ImportPresetsFromBank(int64_t bankInstanceId, const std::vector<int64_t> &presets);
|
int64_t ImportPresetsFromBank(int64_t bankInstanceId, const std::vector<int64_t> &presets);
|
||||||
|
int64_t CopyPresetsToBank(int64_t bankInstanceId, const std::vector<int64_t> &presets);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Executable
+4
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sudo /bin/bash
|
||||||
|
rm -rf /etc/pipedal/react
|
||||||
|
mkdir -p /etc/pipedal/react
|
||||||
|
cp -r dist/* /etc/pipedal/react/
|
||||||
@@ -39,6 +39,12 @@ declare module '@mui/material/styles' {
|
|||||||
mainBackground?: React.CSSProperties['color'];
|
mainBackground?: React.CSSProperties['color'];
|
||||||
toolbarColor?: React.CSSProperties['color'];
|
toolbarColor?: React.CSSProperties['color'];
|
||||||
}
|
}
|
||||||
|
interface Palette {
|
||||||
|
actionBar: Palette['primary'];
|
||||||
|
}
|
||||||
|
interface PaletteOptions {
|
||||||
|
actionBar: PaletteOptions['primary'];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,7 +149,12 @@ const theme = createTheme(
|
|||||||
},
|
},
|
||||||
secondary: {
|
secondary: {
|
||||||
main: "#FF6060"
|
main: "#FF6060"
|
||||||
|
},
|
||||||
|
actionBar: {
|
||||||
|
main: '#130b22ff',
|
||||||
|
contrastText: '#FFFFFF'
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
mainBackground: "#222",
|
mainBackground: "#222",
|
||||||
toolbarColor: '#222'
|
toolbarColor: '#222'
|
||||||
@@ -209,8 +220,14 @@ const theme = createTheme(
|
|||||||
},
|
},
|
||||||
secondary: {
|
secondary: {
|
||||||
main: "#FF6060"
|
main: "#FF6060"
|
||||||
|
},
|
||||||
|
actionBar: {
|
||||||
|
main: '#130b22ff',
|
||||||
|
contrastText: '#FFFFFF'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
mainBackground: "#FFFFFF",
|
mainBackground: "#FFFFFF",
|
||||||
toolbarColor: '#FFFFFF'
|
toolbarColor: '#FFFFFF'
|
||||||
|
|||||||
@@ -0,0 +1,180 @@
|
|||||||
|
// Copyright (c) Robin E. R. 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 Toolbar from "@mui/material/Toolbar";
|
||||||
|
import IconButtonEx from "./IconButtonEx";
|
||||||
|
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
|
||||||
|
import Typography from "@mui/material/Typography";
|
||||||
|
import Select from '@mui/material/Select';
|
||||||
|
import Button from '@mui/material/Button';
|
||||||
|
import InputLabel from '@mui/material/InputLabel';
|
||||||
|
import DialogEx from './DialogEx';
|
||||||
|
import DialogTitle from '@mui/material/DialogTitle';
|
||||||
|
import MenuItem from '@mui/material/MenuItem';
|
||||||
|
import DialogActions from '@mui/material/DialogActions';
|
||||||
|
import DialogContent from '@mui/material/DialogContent';
|
||||||
|
import ResizeResponsiveComponent from './ResizeResponsiveComponent';
|
||||||
|
import { PiPedalModel } from './PiPedalModel';
|
||||||
|
import { BankIndexEntry } from './Banks';
|
||||||
|
|
||||||
|
|
||||||
|
export interface CopyPresetsToBankDialogProps {
|
||||||
|
open: boolean,
|
||||||
|
onOk: (bankInstanceId: number) => void,
|
||||||
|
onClose: () => void
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface CopyPresetsToBankDialogState {
|
||||||
|
selectedBank: number;
|
||||||
|
banks: BankIndexEntry[];
|
||||||
|
fullScreen: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
function setSavedDefaultBankSelection(bankInstanceId: number) {
|
||||||
|
localStorage.setItem('pipedal_copyTo_defaultBankSelection', bankInstanceId.toString());
|
||||||
|
}
|
||||||
|
function getSavedDefaultBankSelection() {
|
||||||
|
let defaultValue = localStorage.getItem('pipedal_copyTo_defaultBankSelection');
|
||||||
|
if (defaultValue) {
|
||||||
|
return parseInt(defaultValue);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
export default class CopyPresetsToBankDialog extends ResizeResponsiveComponent<CopyPresetsToBankDialogProps, CopyPresetsToBankDialogState> {
|
||||||
|
|
||||||
|
model: PiPedalModel;
|
||||||
|
constructor(props: CopyPresetsToBankDialogProps) {
|
||||||
|
super(props);
|
||||||
|
this.model = PiPedalModel.getInstance();
|
||||||
|
let banks = this.getBanks();
|
||||||
|
let selectedBank = this.getDefaultBankSelection(banks);
|
||||||
|
this.state = {
|
||||||
|
banks: banks,
|
||||||
|
selectedBank: selectedBank,
|
||||||
|
fullScreen: false,
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
private getBanks() {
|
||||||
|
let bankIndex = this.model.banks.get();
|
||||||
|
let result: BankIndexEntry[] = [];
|
||||||
|
for (let entry of bankIndex.entries) {
|
||||||
|
if (entry.instanceId === bankIndex.selectedBank) continue;
|
||||||
|
result.push(entry);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
private getDefaultBankSelection(banks: BankIndexEntry[]) {
|
||||||
|
if (banks.length === 0) return -1;
|
||||||
|
let defaultSelection = getSavedDefaultBankSelection();
|
||||||
|
for (let bank of banks) {
|
||||||
|
if (bank.instanceId === defaultSelection) return defaultSelection;
|
||||||
|
}
|
||||||
|
return banks[0].instanceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
super.componentDidMount();
|
||||||
|
}
|
||||||
|
componentWillUnmount() {
|
||||||
|
super.componentWillUnmount();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate() {
|
||||||
|
}
|
||||||
|
|
||||||
|
handleBankChanged(bankId: number) {
|
||||||
|
setSavedDefaultBankSelection(bankId);
|
||||||
|
this.setState({ selectedBank: bankId });
|
||||||
|
}
|
||||||
|
|
||||||
|
handleOk() {
|
||||||
|
this.props.onOk(this.state.selectedBank);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let props = this.props;
|
||||||
|
let { open, onClose } = props;
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
onClose();
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<DialogEx tag="importPreset" open={open} fullWidth maxWidth="xs" onClose={handleClose} aria-labelledby="Rename-dialog-title"
|
||||||
|
fullScreen={this.state.fullScreen}
|
||||||
|
style={{ userSelect: "none" }}
|
||||||
|
onEnterKey={() => { }}
|
||||||
|
>
|
||||||
|
<div style={{ display: "flex", flexFlow: "column nowrap", height: this.state.fullScreen ? "100vh" : undefined }}>
|
||||||
|
{!this.state.fullScreen && (
|
||||||
|
<DialogTitle style={{ paddingTop: 8, paddingBottom: 0 }}>
|
||||||
|
<Toolbar style={{ padding: 0 }}>
|
||||||
|
<IconButtonEx
|
||||||
|
tooltip="Close"
|
||||||
|
edge="start"
|
||||||
|
color="inherit"
|
||||||
|
aria-label="cancel"
|
||||||
|
style={{ opacity: 0.6 }}
|
||||||
|
onClick={() => { onClose(); }}
|
||||||
|
>
|
||||||
|
<ArrowBackIcon style={{ width: 24, height: 24 }} />
|
||||||
|
</IconButtonEx>
|
||||||
|
|
||||||
|
<Typography noWrap component="div" sx={{ flexGrow: 1 }}>
|
||||||
|
Copy Presets to Bank
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
</Toolbar>
|
||||||
|
</DialogTitle>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<DialogContent style={{ flex: "0 0 auto", paddingTop: 8, paddingBottom: 8, }}>
|
||||||
|
<InputLabel style={{ fontSize: "0.75rem", fontWeight: 400, marginTop: 0 }}>Bank</InputLabel>
|
||||||
|
|
||||||
|
<Select variant="standard" fullWidth value={this.state.selectedBank} style={{ marginBottom: 8 }}
|
||||||
|
onChange={(e) => { this.handleBankChanged(e.target.value as number); }}>
|
||||||
|
{this.state.banks.map((bankEntry) => {
|
||||||
|
return (
|
||||||
|
<MenuItem key={bankEntry.instanceId} value={bankEntry.instanceId}
|
||||||
|
selected={bankEntry.instanceId === this.state.selectedBank}
|
||||||
|
>
|
||||||
|
{bankEntry.name}
|
||||||
|
</MenuItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions style={{ flex: "0 0 auto" }}>
|
||||||
|
<Button onClick={handleClose} variant="dialogSecondary" >
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() => { this.handleOk(); }} variant="dialogPrimary"
|
||||||
|
disabled={false}
|
||||||
|
>
|
||||||
|
OK
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</div>
|
||||||
|
</DialogEx>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -82,7 +82,7 @@ export interface DraggableGridProps
|
|||||||
|
|
||||||
defaultSelectedIndex?: number;
|
defaultSelectedIndex?: number;
|
||||||
|
|
||||||
onLongPress?: (itemIndex: number) => void;
|
onLongPress?: (event: PointerEvent<HTMLDivElement>, itemIndex: number) => void;
|
||||||
|
|
||||||
canDrag?: boolean;
|
canDrag?: boolean;
|
||||||
|
|
||||||
@@ -209,7 +209,7 @@ const DraggableGrid =
|
|||||||
}
|
}
|
||||||
|
|
||||||
bringSelectedItemIntoView() {
|
bringSelectedItemIntoView() {
|
||||||
if (this.state.indexToSelect && this.state.indexToSelect >= 0)
|
if (this.state.indexToSelect !== undefined && this.state.indexToSelect >= 0)
|
||||||
{
|
{
|
||||||
let grid = this.refGrid.current;
|
let grid = this.refGrid.current;
|
||||||
if (grid)
|
if (grid)
|
||||||
@@ -295,6 +295,7 @@ const DraggableGrid =
|
|||||||
startClientX: number = 0;
|
startClientX: number = 0;
|
||||||
startClientY: number = 0;
|
startClientY: number = 0;
|
||||||
dragStarted: boolean = false;
|
dragStarted: boolean = false;
|
||||||
|
dragThresholdWasExceeded: boolean = false;
|
||||||
savedIndex: string = "";
|
savedIndex: string = "";
|
||||||
savedBackground: string = "";
|
savedBackground: string = "";
|
||||||
lastPointerDown: number = 0;
|
lastPointerDown: number = 0;
|
||||||
@@ -529,6 +530,11 @@ const DraggableGrid =
|
|||||||
if (this.startIndex !== this.currentIndex) {
|
if (this.startIndex !== this.currentIndex) {
|
||||||
this.props.moveElement(this.startIndex, this.currentIndex);
|
this.props.moveElement(this.startIndex, this.currentIndex);
|
||||||
}
|
}
|
||||||
|
if (!this.dragThresholdWasExceeded) {
|
||||||
|
if (this.props.onLongPress) {
|
||||||
|
this.props.onLongPress(e,this.startIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.cancelDrag();
|
this.cancelDrag();
|
||||||
}
|
}
|
||||||
@@ -693,6 +699,7 @@ const DraggableGrid =
|
|||||||
///window.addEventListener("touchstart",this.handleTouchStart, {passive: false});
|
///window.addEventListener("touchstart",this.handleTouchStart, {passive: false});
|
||||||
|
|
||||||
this.dragStarted = false;
|
this.dragStarted = false;
|
||||||
|
this.dragThresholdWasExceeded = false;
|
||||||
this.startX = e.clientX;
|
this.startX = e.clientX;
|
||||||
this.startY = e.clientY;
|
this.startY = e.clientY;
|
||||||
this.startClientX = e.clientX;
|
this.startClientX = e.clientX;
|
||||||
@@ -756,9 +763,12 @@ const DraggableGrid =
|
|||||||
|
|
||||||
handlePointerMove(e: PointerEvent<HTMLDivElement>): boolean {
|
handlePointerMove(e: PointerEvent<HTMLDivElement>): boolean {
|
||||||
if (this.isCapturedPointer(e)) {
|
if (this.isCapturedPointer(e)) {
|
||||||
if (!this.dragStarted && this.dragThresholdExceeded(e)) {
|
if (this.dragThresholdExceeded(e)) {
|
||||||
|
if (!this.dragStarted) {
|
||||||
this.startDrag();
|
this.startDrag();
|
||||||
}
|
}
|
||||||
|
this.dragThresholdWasExceeded = true;
|
||||||
|
}
|
||||||
if (this.dragStarted) {
|
if (this.dragStarted) {
|
||||||
this.lastX = e.clientX;
|
this.lastX = e.clientX;
|
||||||
this.lastY = e.clientY;
|
this.lastY = e.clientY;
|
||||||
|
|||||||
@@ -158,7 +158,8 @@ export default class ImportPresetFromBankDialog extends ResizeResponsiveComponen
|
|||||||
onEnterKey={() => { }}
|
onEnterKey={() => { }}
|
||||||
>
|
>
|
||||||
<div style={{ display: "flex", flexFlow: "column nowrap", height: this.state.fullScreen ? "100vh" : "80vh" }}>
|
<div style={{ display: "flex", flexFlow: "column nowrap", height: this.state.fullScreen ? "100vh" : "80vh" }}>
|
||||||
{!this.state.fullScreen && (
|
{!this.state.fullScreen ? (
|
||||||
|
<>
|
||||||
<DialogTitle style={{ paddingTop: 8, paddingBottom: 0 }}>
|
<DialogTitle style={{ paddingTop: 8, paddingBottom: 0 }}>
|
||||||
<Toolbar style={{ padding: 0 }}>
|
<Toolbar style={{ padding: 0 }}>
|
||||||
<IconButtonEx
|
<IconButtonEx
|
||||||
@@ -178,8 +179,6 @@ export default class ImportPresetFromBankDialog extends ResizeResponsiveComponen
|
|||||||
|
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
)}
|
|
||||||
|
|
||||||
<DialogContent style={{ flex: "0 0 auto", paddingTop: 8, paddingBottom: 8, }}>
|
<DialogContent style={{ flex: "0 0 auto", paddingTop: 8, paddingBottom: 8, }}>
|
||||||
<InputLabel style={{ fontSize: "0.75rem", fontWeight: 400, marginTop: 0 }}>Bank</InputLabel>
|
<InputLabel style={{ fontSize: "0.75rem", fontWeight: 400, marginTop: 0 }}>Bank</InputLabel>
|
||||||
|
|
||||||
@@ -196,6 +195,41 @@ export default class ImportPresetFromBankDialog extends ResizeResponsiveComponen
|
|||||||
})}
|
})}
|
||||||
</Select>
|
</Select>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div style={{ display: "flex", flexFlow: "row nowrap", alignItems: "top", flex: "0 0 auto", paddingTop: 8, paddingBottom: 8, paddingLeft: 16, paddingRight: 16 }}>
|
||||||
|
<IconButtonEx
|
||||||
|
tooltip="Close"
|
||||||
|
edge="start"
|
||||||
|
color="inherit"
|
||||||
|
aria-label="cancel"
|
||||||
|
style={{ opacity: 0.6 }}
|
||||||
|
onClick={() => { onClose(); }}
|
||||||
|
>
|
||||||
|
<ArrowBackIcon style={{ width: 24, height: 24 }} />
|
||||||
|
</IconButtonEx>
|
||||||
|
|
||||||
|
<div style={{ marginLeft: 24, display: "flex", flex: "0 0 auto", flexFlow: "column nowrap", justifyContent: "start" }}>
|
||||||
|
<InputLabel style={{ fontSize: "0.75rem", fontWeight: 400, marginTop: 0 }}>Bank</InputLabel>
|
||||||
|
|
||||||
|
<Select variant="standard" fullWidth value={this.state.selectedBank} style={{ marginBottom: 8 }}
|
||||||
|
onChange={(e) => { this.handleBankChanged(e.target.value as number); }}>
|
||||||
|
{this.state.banks.map((bankEntry) => {
|
||||||
|
return (
|
||||||
|
<MenuItem key={bankEntry.instanceId} value={bankEntry.instanceId}
|
||||||
|
selected={bankEntry.instanceId === this.state.selectedBank}
|
||||||
|
>
|
||||||
|
{bankEntry.name}
|
||||||
|
</MenuItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
)}
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
<List sx={{ flex: "1 1 auto", width: '100%', bgColor: 'background.paper', overflowX: 'auto' }}>
|
<List sx={{ flex: "1 1 auto", width: '100%', bgColor: 'background.paper', overflowX: 'auto' }}>
|
||||||
{this.state.bankPresets?.map((presetEntry) => {
|
{this.state.bankPresets?.map((presetEntry) => {
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import { PiPedalModel, PiPedalModelFactory, PresetIndex } from './PiPedalModel';
|
|||||||
import ResizeResponsiveComponent from './ResizeResponsiveComponent';
|
import ResizeResponsiveComponent from './ResizeResponsiveComponent';
|
||||||
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
||||||
import IconButtonEx from './IconButtonEx';
|
import IconButtonEx from './IconButtonEx';
|
||||||
import AppBar from '@mui/material/AppBar';
|
|
||||||
import SnapshotPanel from './SnapshotPanel';
|
import SnapshotPanel from './SnapshotPanel';
|
||||||
import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos';
|
import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos';
|
||||||
import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos';
|
import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos';
|
||||||
@@ -250,7 +249,6 @@ export const PerformanceView =
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const classes = withStyles.getClasses(this.props);
|
const classes = withStyles.getClasses(this.props);
|
||||||
let wrapSelects = this.state.wrapSelects;
|
|
||||||
let presets = this.state.presets;
|
let presets = this.state.presets;
|
||||||
let banks = this.state.banks;
|
let banks = this.state.banks;
|
||||||
let appBarIconSize: "large" | undefined = this.state.largeAppBar ? undefined : "large";
|
let appBarIconSize: "large" | undefined = this.state.largeAppBar ? undefined : "large";
|
||||||
|
|||||||
@@ -2192,8 +2192,8 @@ export class PiPedalModel //implements PiPedalModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
deletePresetItem(instanceId: number): Promise<number> {
|
deletePresetItems(instanceIds: Set<number>): Promise<number> {
|
||||||
return nullCast(this.webSocket).request<number>("deletePresetItem", instanceId);
|
return nullCast(this.webSocket).request<number>("deletePresetItems", Array.from(instanceIds));
|
||||||
|
|
||||||
}
|
}
|
||||||
deleteBankItem(instanceId: number): Promise<number> {
|
deleteBankItem(instanceId: number): Promise<number> {
|
||||||
@@ -3549,6 +3549,9 @@ export class PiPedalModel //implements PiPedalModel
|
|||||||
importPresetsFromBank(bankInstanceId: number, presets: number[]): Promise<number> {
|
importPresetsFromBank(bankInstanceId: number, presets: number[]): Promise<number> {
|
||||||
return nullCast(this.webSocket).request<number>("importPresetsFromBank", {bankInstanceId: bankInstanceId, presets: presets});
|
return nullCast(this.webSocket).request<number>("importPresetsFromBank", {bankInstanceId: bankInstanceId, presets: presets});
|
||||||
}
|
}
|
||||||
|
copyPresetsToBank(bankInstanceId: number, presets: number[]): Promise<number> {
|
||||||
|
return nullCast(this.webSocket).request<number>("copyPresetsToBank", {bankInstanceId: bankInstanceId, presets: presets});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let instance: PiPedalModel | undefined = undefined;
|
let instance: PiPedalModel | undefined = undefined;
|
||||||
|
|||||||
@@ -17,8 +17,9 @@
|
|||||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
// 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.
|
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
import React, { SyntheticEvent, Component } from 'react';
|
import React, { SyntheticEvent } from 'react';
|
||||||
import ImportPresetFromBankDialog from './ImportPresetFromBankDialog';
|
import ImportPresetFromBankDialog from './ImportPresetFromBankDialog';
|
||||||
|
import CopyPresetsToBankDialog from './CopyPresetsToBankDialog';
|
||||||
import Icon from '@mui/material/Icon';
|
import Icon from '@mui/material/Icon';
|
||||||
import Divider from '@mui/material/Divider';
|
import Divider from '@mui/material/Divider';
|
||||||
import { css } from '@emotion/react';
|
import { css } from '@emotion/react';
|
||||||
@@ -27,23 +28,22 @@ import IconButtonEx from './IconButtonEx';
|
|||||||
import Typography from '@mui/material/Typography';
|
import Typography from '@mui/material/Typography';
|
||||||
import { PiPedalModel, PiPedalModelFactory, PresetIndexEntry, PresetIndex } from './PiPedalModel';
|
import { PiPedalModel, PiPedalModelFactory, PresetIndexEntry, PresetIndex } from './PiPedalModel';
|
||||||
import Button from '@mui/material/Button';
|
import Button from '@mui/material/Button';
|
||||||
import ButtonBase from "@mui/material/ButtonBase";
|
|
||||||
import DialogEx from './DialogEx';
|
import DialogEx from './DialogEx';
|
||||||
import AppBar from '@mui/material/AppBar';
|
import AppBar from '@mui/material/AppBar';
|
||||||
import Toolbar from '@mui/material/Toolbar';
|
import Toolbar from '@mui/material/Toolbar';
|
||||||
import DraggableGrid, { ScrollDirection } from './DraggableGrid';
|
import DraggableGrid, { ScrollDirection } from './DraggableGrid';
|
||||||
|
import CloseIcon from '@mui/icons-material/Close';
|
||||||
import MoreVertIcon from '@mui/icons-material/MoreVert';
|
import MoreVertIcon from '@mui/icons-material/MoreVert';
|
||||||
|
import ListItemButton from '@mui/material/ListItemButton';
|
||||||
import ListItemIcon from '@mui/material/ListItemIcon';
|
import ListItemIcon from '@mui/material/ListItemIcon';
|
||||||
import ListItemText from '@mui/material/ListItemText';
|
import ListItemText from '@mui/material/ListItemText';
|
||||||
import Menu from '@mui/material/Menu';
|
import Menu from '@mui/material/Menu';
|
||||||
import MenuItem from '@mui/material/MenuItem';
|
import MenuItem from '@mui/material/MenuItem';
|
||||||
import Fade from '@mui/material/Fade';
|
import Fade from '@mui/material/Fade';
|
||||||
import UploadPresetDialog from './UploadPresetDialog';
|
import UploadPresetDialog from './UploadPresetDialog';
|
||||||
|
import ResizeResponsiveComponent from './ResizeResponsiveComponent';
|
||||||
|
|
||||||
import SelectHoverBackground from './SelectHoverBackground';
|
|
||||||
import CloseIcon from '@mui/icons-material/Close';
|
|
||||||
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
||||||
import EditIcon from '@mui/icons-material/Edit';
|
|
||||||
import RenameDialog from './RenameDialog';
|
import RenameDialog from './RenameDialog';
|
||||||
|
|
||||||
import Slide, { SlideProps } from '@mui/material/Slide';
|
import Slide, { SlideProps } from '@mui/material/Slide';
|
||||||
@@ -56,10 +56,13 @@ import { withStyles } from "tss-react/mui";
|
|||||||
import DownloadIcon from './svg/file_download_black_24dp.svg?react';
|
import DownloadIcon from './svg/file_download_black_24dp.svg?react';
|
||||||
import UploadIcon from './svg/file_upload_black_24dp.svg?react';
|
import UploadIcon from './svg/file_upload_black_24dp.svg?react';
|
||||||
|
|
||||||
|
// function isTouchUi() {
|
||||||
|
// return 'ontouchstart' in window || navigator.maxTouchPoints > 0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
interface PresetDialogProps extends WithStyles<typeof styles> {
|
interface PresetDialogProps extends WithStyles<typeof styles> {
|
||||||
show: boolean;
|
show: boolean;
|
||||||
isEditDialog: boolean;
|
|
||||||
onDialogClose: () => void;
|
onDialogClose: () => void;
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -67,13 +70,16 @@ interface PresetDialogProps extends WithStyles<typeof styles> {
|
|||||||
interface PresetDialogState {
|
interface PresetDialogState {
|
||||||
presets: PresetIndex;
|
presets: PresetIndex;
|
||||||
|
|
||||||
showActionBar: boolean;
|
multiSelect: boolean;
|
||||||
|
showTouchActionBar: boolean;
|
||||||
|
|
||||||
|
|
||||||
currentItem: number;
|
currentItem: number;
|
||||||
selectedItems: Set<number>;
|
selectedItems: Set<number>;
|
||||||
|
|
||||||
renameOpen: boolean;
|
renameOpen: boolean;
|
||||||
importOpen: boolean;
|
importOpen: boolean;
|
||||||
|
copyToOpen: boolean;
|
||||||
|
|
||||||
moreMenuAnchorEl: HTMLElement | null;
|
moreMenuAnchorEl: HTMLElement | null;
|
||||||
openUploadPresetDialog: boolean;
|
openUploadPresetDialog: boolean;
|
||||||
@@ -93,7 +99,8 @@ const styles = (theme: Theme) => createStyles({
|
|||||||
dialogActionBar: css({
|
dialogActionBar: css({
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
top: 0, left: 0,
|
top: 0, left: 0,
|
||||||
background: "black"
|
background: theme.palette.actionBar.main,
|
||||||
|
color: theme.palette.actionBar.contrastText
|
||||||
}),
|
}),
|
||||||
dialogTitle: css({
|
dialogTitle: css({
|
||||||
marginLeft: theme.spacing(2),
|
marginLeft: theme.spacing(2),
|
||||||
@@ -111,7 +118,7 @@ const styles = (theme: Theme) => createStyles({
|
|||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
textAlign: "left",
|
textAlign: "left",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
paddingLeft: 8
|
paddibomngLeft: 8
|
||||||
}),
|
}),
|
||||||
iconFrame: css({
|
iconFrame: css({
|
||||||
flex: "0 0 auto",
|
flex: "0 0 auto",
|
||||||
@@ -136,7 +143,7 @@ const Transition = React.forwardRef(function Transition(
|
|||||||
|
|
||||||
|
|
||||||
const PresetDialog = withStyles(
|
const PresetDialog = withStyles(
|
||||||
class extends Component<PresetDialogProps, PresetDialogState> {
|
class extends ResizeResponsiveComponent<PresetDialogProps, PresetDialogState> {
|
||||||
|
|
||||||
model: PiPedalModel;
|
model: PiPedalModel;
|
||||||
|
|
||||||
@@ -150,11 +157,13 @@ const PresetDialog = withStyles(
|
|||||||
let presets = this.model.presets.get();
|
let presets = this.model.presets.get();
|
||||||
this.state = {
|
this.state = {
|
||||||
presets: presets,
|
presets: presets,
|
||||||
showActionBar: false,
|
multiSelect: false,
|
||||||
|
showTouchActionBar: false,
|
||||||
currentItem: presets.selectedInstanceId,
|
currentItem: presets.selectedInstanceId,
|
||||||
selectedItems: new Set<number>(),
|
selectedItems: new Set<number>([presets.selectedInstanceId]),
|
||||||
renameOpen: false,
|
renameOpen: false,
|
||||||
importOpen: false,
|
importOpen: false,
|
||||||
|
copyToOpen: false,
|
||||||
moreMenuAnchorEl: null,
|
moreMenuAnchorEl: null,
|
||||||
openUploadPresetDialog: false
|
openUploadPresetDialog: false
|
||||||
|
|
||||||
@@ -162,20 +171,35 @@ const PresetDialog = withStyles(
|
|||||||
this.handlePresetsChanged = this.handlePresetsChanged.bind(this);
|
this.handlePresetsChanged = this.handlePresetsChanged.bind(this);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onWindowSizeChanged(width: number, height: number) {
|
||||||
|
super.onWindowSizeChanged(width, height);
|
||||||
|
}
|
||||||
|
handleSelectionUpdated(instanceIds: Set<number>) {
|
||||||
|
this.setState({
|
||||||
|
multiSelect: instanceIds.size > 1
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
setSelections(instanceIds: Set<number>) {
|
||||||
|
this.setState({
|
||||||
|
selectedItems: instanceIds,
|
||||||
|
});
|
||||||
|
this.handleSelectionUpdated(instanceIds);
|
||||||
|
}
|
||||||
setSelection(instanceId: number) {
|
setSelection(instanceId: number) {
|
||||||
|
let selectedItems = new Set<number>([instanceId]);
|
||||||
this.setState({
|
this.setState({
|
||||||
currentItem: instanceId,
|
currentItem: instanceId,
|
||||||
selectedItems: new Set<number>([instanceId])
|
selectedItems: selectedItems
|
||||||
});
|
});
|
||||||
|
this.handleSelectionUpdated(selectedItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
selectItemAtIndex(index: number) {
|
selectItemAtIndex(index: number) {
|
||||||
let instanceId = this.state.presets.presets[index].instanceId;
|
let instanceId = this.state.presets.presets[index].instanceId;
|
||||||
this.setSelection(instanceId);
|
this.setSelection(instanceId);
|
||||||
}
|
}
|
||||||
isEditMode() {
|
|
||||||
return this.state.showActionBar || this.props.isEditDialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
onMoreClick(e: SyntheticEvent): void {
|
onMoreClick(e: SyntheticEvent): void {
|
||||||
this.setState({ moreMenuAnchorEl: e.currentTarget as HTMLElement })
|
this.setState({ moreMenuAnchorEl: e.currentTarget as HTMLElement })
|
||||||
@@ -203,7 +227,8 @@ const PresetDialog = withStyles(
|
|||||||
{
|
{
|
||||||
// if we don't have a valid selection, then use the current preset.
|
// if we don't have a valid selection, then use the current preset.
|
||||||
if (this.state.presets.getItem(this.state.currentItem) == null) {
|
if (this.state.presets.getItem(this.state.currentItem) == null) {
|
||||||
this.setState({ presets: presets, currentItem: presets.selectedInstanceId,
|
this.setState({
|
||||||
|
presets: presets, currentItem: presets.selectedInstanceId,
|
||||||
selectedItems: new Set<number>([presets.selectedInstanceId])
|
selectedItems: new Set<number>([presets.selectedInstanceId])
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -222,8 +247,10 @@ const PresetDialog = withStyles(
|
|||||||
this.model.presets.removeOnChangedHandler(this.handlePresetsChanged);
|
this.model.presets.removeOnChangedHandler(this.handlePresetsChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
getSelectedIndex() {
|
getSelectedIndex(instanceId?: number): number {
|
||||||
let instanceId = this.isEditMode() ? this.state.currentItem : this.state.presets.selectedInstanceId;
|
if (instanceId === undefined) {
|
||||||
|
instanceId = this.state.currentItem;
|
||||||
|
}
|
||||||
let presets = this.state.presets;
|
let presets = this.state.presets;
|
||||||
for (let i = 0; i < presets.presets.length; ++i) {
|
for (let i = 0; i < presets.presets.length; ++i) {
|
||||||
if (presets.presets[i].instanceId === instanceId) return i;
|
if (presets.presets[i].instanceId === instanceId) return i;
|
||||||
@@ -232,33 +259,59 @@ const PresetDialog = withStyles(
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleDeleteClick() {
|
handleDeleteClick() {
|
||||||
if (this.state.currentItem === -1) return;
|
if (this.state.selectedItems.size === 0) {
|
||||||
let currentItem = this.state.currentItem;
|
return;
|
||||||
if (currentItem !== -1) {
|
}
|
||||||
this.model.deletePresetItem(currentItem)
|
this.model.deletePresetItems(this.state.selectedItems)
|
||||||
.then((currentItem: number) => {
|
.then((currentItem: number) => {
|
||||||
this.setSelection(currentItem);
|
this.setSelection(currentItem);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.model.showAlert(error);
|
this.model.showAlert(error);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
handleDialogClose() {
|
handleDialogClose() {
|
||||||
this.props.onDialogClose();
|
this.props.onDialogClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
handleItemClick(instanceId: number): void {
|
handleItemClick(e: React.MouseEvent<HTMLElement>, instanceId: number): void {
|
||||||
if (this.isEditMode()) {
|
e.stopPropagation();
|
||||||
this.setSelection(instanceId);
|
if (e.ctrlKey || this.state.showTouchActionBar) {
|
||||||
|
let selectedItems = new Set<number>(this.state.selectedItems);
|
||||||
|
if (selectedItems.has(instanceId)) {
|
||||||
|
selectedItems.delete(instanceId);
|
||||||
|
this.setSelections(selectedItems);
|
||||||
} else {
|
} else {
|
||||||
this.model.loadPreset(instanceId);
|
selectedItems.add(instanceId);
|
||||||
this.props.onDialogClose();
|
this.setState({
|
||||||
|
selectedItems: selectedItems,
|
||||||
|
currentItem: instanceId
|
||||||
|
});
|
||||||
|
this.handleSelectionUpdated(selectedItems);
|
||||||
|
}
|
||||||
|
} else if (e.shiftKey) {
|
||||||
|
let presets = this.state.presets;
|
||||||
|
let startIndex = this.getSelectedIndex();
|
||||||
|
let endIndex = this.getSelectedIndex(instanceId);
|
||||||
|
if (startIndex === -1 || endIndex === -1) return; // should not happen.
|
||||||
|
|
||||||
|
let selectedItems = new Set<number>();
|
||||||
|
|
||||||
|
if (endIndex < startIndex) {
|
||||||
|
let t = startIndex;
|
||||||
|
startIndex = endIndex;
|
||||||
|
endIndex = t;
|
||||||
|
}
|
||||||
|
for (let i = startIndex; i <= endIndex; ++i) {
|
||||||
|
selectedItems.add(presets.presets[i].instanceId);
|
||||||
|
}
|
||||||
|
this.setSelections(selectedItems);
|
||||||
|
} else {
|
||||||
|
this.setSelection(instanceId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
showActionBar(show: boolean): void {
|
showTouchActionBar(show: boolean): void {
|
||||||
this.setState({ showActionBar: show });
|
this.setState({ showTouchActionBar: show });
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,29 +319,23 @@ const PresetDialog = withStyles(
|
|||||||
mapElement(el: any): React.ReactNode {
|
mapElement(el: any): React.ReactNode {
|
||||||
let presetEntry = el as PresetIndexEntry;
|
let presetEntry = el as PresetIndexEntry;
|
||||||
const classes = withStyles.getClasses(this.props);
|
const classes = withStyles.getClasses(this.props);
|
||||||
let selected =
|
let selected = this.state.selectedItems.has(presetEntry.instanceId);
|
||||||
this.isEditMode() ? this.state.selectedItems.has(presetEntry.instanceId) :
|
|
||||||
(presetEntry.instanceId === this.state.presets.selectedInstanceId);
|
|
||||||
return (
|
return (
|
||||||
<div key={presetEntry.instanceId} id={"psetdlgItem_" + presetEntry.instanceId} className="itemBackground">
|
<div key={presetEntry.instanceId} id={"psetdlgItem_" + presetEntry.instanceId} className="itemBackground">
|
||||||
|
<ListItemButton
|
||||||
<ButtonBase style={{ width: "100%", height: 48 }}
|
selected={selected}
|
||||||
onClick={() => this.handleItemClick(presetEntry.instanceId)}
|
onClick={(e) => this.handleItemClick(e, presetEntry.instanceId)}
|
||||||
|
style={{ height: 48 }}
|
||||||
>
|
>
|
||||||
<SelectHoverBackground selected={selected} showHover={true} />
|
<ListItemIcon>
|
||||||
<div className={classes.itemFrame}>
|
|
||||||
<div className={classes.iconFrame}>
|
|
||||||
<img
|
<img
|
||||||
src={isDarkMode() ? "img/ic_presets_white.svg" : "img/ic_presets.svg"}
|
src={isDarkMode() ? "img/ic_presets_white.svg" : "img/ic_presets.svg"}
|
||||||
className={classes.itemIcon} alt="" />
|
className={classes.itemIcon} alt="" />
|
||||||
</div>
|
</ListItemIcon>
|
||||||
<div className={classes.itemLabel}>
|
<ListItemText primary={presetEntry.name}
|
||||||
<Typography>
|
/>
|
||||||
{presetEntry.name}
|
|
||||||
</Typography>
|
</ListItemButton>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ButtonBase>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
);
|
);
|
||||||
@@ -356,8 +403,15 @@ const PresetDialog = withStyles(
|
|||||||
this.model?.showAlert(error);
|
this.model?.showAlert(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleImportPresetsFromBank()
|
handleCloseActionBar(e: SyntheticEvent) {
|
||||||
{
|
e.stopPropagation();
|
||||||
|
this.setState({
|
||||||
|
showTouchActionBar: false,
|
||||||
|
selectedItems: new Set<number>([this.state.currentItem]),
|
||||||
|
multiSelect: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
handleImportPresetsFromBank() {
|
||||||
this.handleMoreClose();
|
this.handleMoreClose();
|
||||||
this.setState({ importOpen: true });
|
this.setState({ importOpen: true });
|
||||||
}
|
}
|
||||||
@@ -379,14 +433,33 @@ const PresetDialog = withStyles(
|
|||||||
this.model.showAlert(error);
|
this.model.showAlert(error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
handleCopyToBankDialogOk(bankInstanceId: number): void {
|
||||||
|
this.setState({ copyToOpen: false });
|
||||||
|
let selectedItems: number[] = [];
|
||||||
|
for (let i = 0; i < this.state.presets.presets.length; ++i) {
|
||||||
|
let preset = this.state.presets.presets[i];
|
||||||
|
if (this.state.selectedItems.has(preset.instanceId)) {
|
||||||
|
selectedItems.push(preset.instanceId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.model.copyPresetsToBank(bankInstanceId, selectedItems)
|
||||||
|
.then((instanceId) => {
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.model.showAlert(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleCopyPresetsToBank() {
|
||||||
|
this.handleMoreClose();
|
||||||
|
this.setState({ copyToOpen: true });
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const classes = withStyles.getClasses(this.props);
|
const classes = withStyles.getClasses(this.props);
|
||||||
|
|
||||||
let actionBarClass = this.props.isEditDialog ? classes.dialogAppBar : classes.dialogActionBar;
|
const showActionBar = this.state.multiSelect || this.state.showTouchActionBar;
|
||||||
let defaultSelectedIndex = this.getSelectedIndex();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DialogEx tag="preset" fullScreen open={this.props.show}
|
<DialogEx tag="preset" fullScreen open={this.props.show}
|
||||||
onClose={() => { this.handleDialogClose() }} TransitionComponent={Transition}
|
onClose={() => { this.handleDialogClose() }} TransitionComponent={Transition}
|
||||||
@@ -395,37 +468,37 @@ const PresetDialog = withStyles(
|
|||||||
>
|
>
|
||||||
<div style={{ display: "flex", flexDirection: "column", flexWrap: "nowrap", width: "100%", height: "100%", overflow: "hidden" }}>
|
<div style={{ display: "flex", flexDirection: "column", flexWrap: "nowrap", width: "100%", height: "100%", overflow: "hidden" }}>
|
||||||
<div style={{ flex: "0 0 auto" }}>
|
<div style={{ flex: "0 0 auto" }}>
|
||||||
<AppBar className={classes.dialogAppBar} style={{ display: this.isEditMode() ? "none" : "block" }} >
|
<AppBar className={classes.dialogActionBar} style={{ display: showActionBar ? "block" : "none" }}
|
||||||
<Toolbar>
|
|
||||||
<IconButtonEx tooltip="Back" edge="start" color="inherit" onClick={this.handleDialogClose} aria-label="back"
|
|
||||||
disabled={this.isEditMode()}
|
|
||||||
>
|
>
|
||||||
<ArrowBackIcon />
|
<Toolbar>
|
||||||
|
<IconButtonEx tooltip="Back" edge="start" color="inherit" aria-label="back"
|
||||||
|
onClick={(e) => { this.handleCloseActionBar(e); }}
|
||||||
|
>
|
||||||
|
<CloseIcon />
|
||||||
</IconButtonEx>
|
</IconButtonEx>
|
||||||
<Typography variant="h6" className={classes.dialogTitle}>
|
<Typography variant="h6" className={classes.dialogTitle} noWrap>
|
||||||
Presets
|
{this.state.selectedItems.size.toString() + " items selected"}
|
||||||
</Typography>
|
</Typography>
|
||||||
<IconButtonEx tooltip="Edit" color="inherit" onClick={(e) => this.showActionBar(true)} >
|
<Button color="inherit"
|
||||||
<EditIcon />
|
onClick={() => {
|
||||||
|
this.handleCopyPresetsToBank();
|
||||||
|
}} >
|
||||||
|
Copy to
|
||||||
|
</Button>
|
||||||
|
<IconButtonEx tooltip="Delete" color="inherit" onClick={(e) => { this.handleDeleteClick(); }} >
|
||||||
|
<img src="/img/old_delete_outline_white_24dp.svg" alt="Delete" style={{ width: 24, height: 24, opacity: 0.6 }} />
|
||||||
</IconButtonEx>
|
</IconButtonEx>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
</AppBar>
|
</AppBar>
|
||||||
<AppBar className={actionBarClass} style={{ display: this.isEditMode() ? "block" : "none" }}
|
<AppBar className={classes.dialogAppBar} style={{ display: showActionBar ? "none" : "block" }}
|
||||||
onClick={(e) => { e.stopPropagation(); e.preventDefault(); }}
|
onClick={(e) => { e.stopPropagation(); e.preventDefault(); }}
|
||||||
>
|
>
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
{(!this.props.isEditDialog) ? (
|
|
||||||
<IconButtonEx tooltip="Close" edge="start" color="inherit" onClick={(e) => this.showActionBar(false)} aria-label="close">
|
|
||||||
<CloseIcon />
|
|
||||||
</IconButtonEx>
|
|
||||||
) : (
|
|
||||||
<IconButtonEx edge="start" tooltip="Back" color="inherit" onClick={this.handleDialogClose} aria-label="back"
|
<IconButtonEx edge="start" tooltip="Back" color="inherit" onClick={this.handleDialogClose} aria-label="back"
|
||||||
>
|
>
|
||||||
<ArrowBackIcon />
|
<ArrowBackIcon />
|
||||||
</IconButtonEx>
|
</IconButtonEx>
|
||||||
|
<Typography variant="h6" className={classes.dialogTitle} noWrap>
|
||||||
)}
|
|
||||||
<Typography variant="h6" className={classes.dialogTitle}>
|
|
||||||
Presets
|
Presets
|
||||||
</Typography>
|
</Typography>
|
||||||
{(this.state.presets.getItem(this.state.currentItem) != null)
|
{(this.state.presets.getItem(this.state.currentItem) != null)
|
||||||
@@ -435,12 +508,20 @@ const PresetDialog = withStyles(
|
|||||||
flex: "0 0 auto", display: "flex", flexFlow: "row nowrap", alignItems: "center"
|
flex: "0 0 auto", display: "flex", flexFlow: "row nowrap", alignItems: "center"
|
||||||
|
|
||||||
}}>
|
}}>
|
||||||
<Button color="inherit" onClick={(e) => this.handleCopy()}>
|
{this.state.selectedItems.size === 1 && (
|
||||||
|
<Button color="inherit" onClick={(e) => this.handleCopy()}
|
||||||
|
>
|
||||||
Copy
|
Copy
|
||||||
</Button>
|
</Button>
|
||||||
<Button color="inherit" onClick={() => this.handleRenameClick()}>
|
)}
|
||||||
|
{this.state.selectedItems.size === 1 && (
|
||||||
|
|
||||||
|
<Button color="inherit" onClick={() => this.handleRenameClick()}
|
||||||
|
>
|
||||||
Rename
|
Rename
|
||||||
</Button>
|
</Button>
|
||||||
|
)}
|
||||||
|
{this.state.renameOpen && (
|
||||||
<RenameDialog
|
<RenameDialog
|
||||||
title="Rename"
|
title="Rename"
|
||||||
open={this.state.renameOpen}
|
open={this.state.renameOpen}
|
||||||
@@ -452,9 +533,14 @@ const PresetDialog = withStyles(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<IconButtonEx tooltip="Delete" color="inherit" onClick={(e) => this.handleDeleteClick()} >
|
)}
|
||||||
|
{this.state.selectedItems.size === 1 && (
|
||||||
|
<IconButtonEx tooltip="Delete" color="inherit" onClick={(e) => this.handleDeleteClick()}
|
||||||
|
style={{ opacity: this.state.selectedItems.size !== 1 ? 0.5 : 1.0 }}
|
||||||
|
>
|
||||||
<img src="/img/old_delete_outline_white_24dp.svg" alt="Delete" style={{ width: 24, height: 24, opacity: 0.6 }} />
|
<img src="/img/old_delete_outline_white_24dp.svg" alt="Delete" style={{ width: 24, height: 24, opacity: 0.6 }} />
|
||||||
</IconButtonEx>
|
</IconButtonEx>
|
||||||
|
)}
|
||||||
<IconButtonEx tooltip="More..." color="inherit" onClick={(e) => { this.onMoreClick(e) }} >
|
<IconButtonEx tooltip="More..." color="inherit" onClick={(e) => { this.onMoreClick(e) }} >
|
||||||
<MoreVertIcon />
|
<MoreVertIcon />
|
||||||
</IconButtonEx>
|
</IconButtonEx>
|
||||||
@@ -466,7 +552,12 @@ const PresetDialog = withStyles(
|
|||||||
onClose={() => this.handleMoreClose()}
|
onClose={() => this.handleMoreClose()}
|
||||||
TransitionComponent={Fade}
|
TransitionComponent={Fade}
|
||||||
>
|
>
|
||||||
<MenuItem onClick={() => { this.handleDownloadPreset(); }} >
|
{this.state.selectedItems.size !== 0 && (
|
||||||
|
<MenuItem onClick={() => {
|
||||||
|
this.handleMoreClose();
|
||||||
|
this.handleCopyPresetsToBank();
|
||||||
|
}}
|
||||||
|
>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<Icon />
|
<Icon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
@@ -475,6 +566,7 @@ const PresetDialog = withStyles(
|
|||||||
</ListItemText>
|
</ListItemText>
|
||||||
|
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
)}
|
||||||
<MenuItem onClick={() => { this.handleImportPresetsFromBank(); }} >
|
<MenuItem onClick={() => { this.handleImportPresetsFromBank(); }} >
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<Icon />
|
<Icon />
|
||||||
@@ -486,6 +578,7 @@ const PresetDialog = withStyles(
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
{this.state.selectedItems.size !== 0 && (
|
||||||
<MenuItem onClick={() => { this.handleDownloadPreset(); }} >
|
<MenuItem onClick={() => { this.handleDownloadPreset(); }} >
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<DownloadIcon className={classes.listIcon} />
|
<DownloadIcon className={classes.listIcon} />
|
||||||
@@ -495,6 +588,7 @@ const PresetDialog = withStyles(
|
|||||||
</ListItemText>
|
</ListItemText>
|
||||||
|
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
)}
|
||||||
<MenuItem onClick={() => { this.handleUploadPreset() }}>
|
<MenuItem onClick={() => { this.handleUploadPreset() }}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<UploadIcon className={classes.listIcon} />
|
<UploadIcon className={classes.listIcon} />
|
||||||
@@ -516,12 +610,16 @@ const PresetDialog = withStyles(
|
|||||||
</div>
|
</div>
|
||||||
<div style={{ flex: "1 1 auto", position: "relative", overflow: "hidden" }} >
|
<div style={{ flex: "1 1 auto", position: "relative", overflow: "hidden" }} >
|
||||||
<DraggableGrid
|
<DraggableGrid
|
||||||
onLongPress={(item) => this.showActionBar(true)}
|
onLongPress={(e,item) => {
|
||||||
canDrag={this.isEditMode()}
|
if (e.pointerType === "touch")
|
||||||
|
{
|
||||||
|
this.showTouchActionBar(true);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
canDrag={!this.state.multiSelect && !this.state.showTouchActionBar}
|
||||||
onDragStart={(index, x, y) => { this.selectItemAtIndex(index) }}
|
onDragStart={(index, x, y) => { this.selectItemAtIndex(index) }}
|
||||||
moveElement={(from, to) => { this.moveElement(from, to); }}
|
moveElement={(from, to) => { this.moveElement(from, to); }}
|
||||||
scroll={ScrollDirection.Y}
|
scroll={ScrollDirection.Y}
|
||||||
defaultSelectedIndex={defaultSelectedIndex}
|
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
this.state.presets.presets.map((element) => {
|
this.state.presets.presets.map((element) => {
|
||||||
@@ -546,6 +644,13 @@ const PresetDialog = withStyles(
|
|||||||
onOk={(bankInstanceId, presets) => this.handleImportDialogOk(bankInstanceId, presets)}
|
onOk={(bankInstanceId, presets) => this.handleImportDialogOk(bankInstanceId, presets)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{this.state.copyToOpen && (
|
||||||
|
<CopyPresetsToBankDialog
|
||||||
|
open={this.state.copyToOpen}
|
||||||
|
onClose={() => this.setState({ copyToOpen: false })}
|
||||||
|
onOk={(bankInstanceId) => this.handleCopyToBankDialogOk(bankInstanceId)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
</DialogEx>
|
</DialogEx>
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,8 @@
|
|||||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
// 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.
|
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
import { SyntheticEvent, Component } from 'react';
|
import { SyntheticEvent } from 'react';
|
||||||
|
import ArrowRightIcon from '@mui/icons-material/ArrowRight';
|
||||||
import IconButtonEx from './IconButtonEx';
|
import IconButtonEx from './IconButtonEx';
|
||||||
import { PiPedalModel, PiPedalModelFactory, PresetIndex } from './PiPedalModel';
|
import { PiPedalModel, PiPedalModelFactory, PresetIndex } from './PiPedalModel';
|
||||||
import SaveIconOutline from '@mui/icons-material/Save';
|
import SaveIconOutline from '@mui/icons-material/Save';
|
||||||
@@ -39,6 +40,7 @@ import ImportPresetFromBankDialog from './ImportPresetFromBankDialog';
|
|||||||
import Select from '@mui/material/Select';
|
import Select from '@mui/material/Select';
|
||||||
import UploadPresetDialog from './UploadPresetDialog';
|
import UploadPresetDialog from './UploadPresetDialog';
|
||||||
import { isDarkMode } from './DarkMode';
|
import { isDarkMode } from './DarkMode';
|
||||||
|
import ResizeResponsiveComponent from './ResizeResponsiveComponent';
|
||||||
|
|
||||||
interface PresetSelectorProps extends WithStyles<typeof styles> {
|
interface PresetSelectorProps extends WithStyles<typeof styles> {
|
||||||
|
|
||||||
@@ -51,6 +53,8 @@ interface PresetSelectorState {
|
|||||||
showPresetsDialog: boolean;
|
showPresetsDialog: boolean;
|
||||||
showEditPresetsDialog: boolean;
|
showEditPresetsDialog: boolean;
|
||||||
presetsMenuAnchorRef: HTMLElement | null;
|
presetsMenuAnchorRef: HTMLElement | null;
|
||||||
|
presetsSubmenuAnchorRef: HTMLElement | null;
|
||||||
|
compactHorizontalLayoutMenu: boolean;
|
||||||
|
|
||||||
saveAsDialogOpen: boolean;
|
saveAsDialogOpen: boolean;
|
||||||
importDialogOpen: boolean;
|
importDialogOpen: boolean;
|
||||||
@@ -87,8 +91,8 @@ const styles = (theme: Theme) => createStyles({
|
|||||||
|
|
||||||
const PresetSelector =
|
const PresetSelector =
|
||||||
withStyles(
|
withStyles(
|
||||||
class extends Component<PresetSelectorProps, PresetSelectorState> {
|
class extends ResizeResponsiveComponent<PresetSelectorProps, PresetSelectorState> {
|
||||||
|
private MENU_THRESHOLD: number = 570;
|
||||||
model: PiPedalModel;
|
model: PiPedalModel;
|
||||||
|
|
||||||
constructor(props: PresetSelectorProps) {
|
constructor(props: PresetSelectorProps) {
|
||||||
@@ -98,9 +102,11 @@ const PresetSelector =
|
|||||||
presets:
|
presets:
|
||||||
this.model.presets.get(),
|
this.model.presets.get(),
|
||||||
enabled: false,
|
enabled: false,
|
||||||
|
compactHorizontalLayoutMenu: this.windowSize.height < this.MENU_THRESHOLD,
|
||||||
showPresetsDialog: false,
|
showPresetsDialog: false,
|
||||||
showEditPresetsDialog: false,
|
showEditPresetsDialog: false,
|
||||||
presetsMenuAnchorRef: null,
|
presetsMenuAnchorRef: null,
|
||||||
|
presetsSubmenuAnchorRef: null,
|
||||||
renameDialogOpen: false,
|
renameDialogOpen: false,
|
||||||
saveAsDialogOpen: false,
|
saveAsDialogOpen: false,
|
||||||
importDialogOpen: false,
|
importDialogOpen: false,
|
||||||
@@ -117,12 +123,28 @@ const PresetSelector =
|
|||||||
this.handlePresetsMenuClose = this.handlePresetsMenuClose.bind(this);
|
this.handlePresetsMenuClose = this.handlePresetsMenuClose.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onWindowSizeChanged(width: number, height: number): void {
|
||||||
|
super.onWindowSizeChanged(width,height);
|
||||||
|
this.setState({ compactHorizontalLayoutMenu: height < this.MENU_THRESHOLD });
|
||||||
|
}
|
||||||
|
|
||||||
handlePresetMenuClick(event: SyntheticEvent): void {
|
handlePresetsMenuClick(event: SyntheticEvent): void {
|
||||||
this.setState({ presetsMenuAnchorRef: (event.currentTarget as HTMLElement) });
|
this.setState({ presetsMenuAnchorRef: (event.currentTarget as HTMLElement) });
|
||||||
}
|
}
|
||||||
|
handlePresetsSubmenuClick(event: SyntheticEvent): void {
|
||||||
|
this.setState({ presetsSubmenuAnchorRef: (event.currentTarget as HTMLElement) });
|
||||||
|
}
|
||||||
handlePresetsMenuClose(): void {
|
handlePresetsMenuClose(): void {
|
||||||
this.setState({ presetsMenuAnchorRef: null });
|
this.setState({
|
||||||
|
presetsMenuAnchorRef: null,
|
||||||
|
presetsSubmenuAnchorRef: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
handlePresetsSubmenuClose(): void {
|
||||||
|
this.setState({
|
||||||
|
presetsSubmenuAnchorRef: null,
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePresetsMenuImport(e: SyntheticEvent): void {
|
handlePresetsMenuImport(e: SyntheticEvent): void {
|
||||||
@@ -284,11 +306,13 @@ const PresetSelector =
|
|||||||
this.updatePresetState();
|
this.updatePresetState();
|
||||||
}
|
}
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
super.componentDidMount();
|
||||||
this.model.presets.addOnChangedHandler(this.handlePresetsChanged);
|
this.model.presets.addOnChangedHandler(this.handlePresetsChanged);
|
||||||
this.updatePresetState();
|
this.updatePresetState();
|
||||||
}
|
}
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this.model.presets.removeOnChangedHandler(this.handlePresetsChanged)
|
this.model.presets.removeOnChangedHandler(this.handlePresetsChanged)
|
||||||
|
super.componentWillUnmount();
|
||||||
}
|
}
|
||||||
showPresetDialog(show: boolean) {
|
showPresetDialog(show: boolean) {
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -368,7 +392,7 @@ const PresetSelector =
|
|||||||
<IconButtonEx
|
<IconButtonEx
|
||||||
tooltip="More..."
|
tooltip="More..."
|
||||||
style={{ flex: "0 0 auto", color: "#FFFFFF" }}
|
style={{ flex: "0 0 auto", color: "#FFFFFF" }}
|
||||||
onClick={(e) => this.handlePresetMenuClick(e)}
|
onClick={(e) => this.handlePresetsMenuClick(e)}
|
||||||
size="large"
|
size="large"
|
||||||
>
|
>
|
||||||
<MoreVertIcon style={{ opacity: 0.75 }} color="inherit" />
|
<MoreVertIcon style={{ opacity: 0.75 }} color="inherit" />
|
||||||
@@ -381,10 +405,24 @@ const PresetSelector =
|
|||||||
TransitionComponent={Fade}
|
TransitionComponent={Fade}
|
||||||
>
|
>
|
||||||
<MenuItem onClick={(e) => this.handlePresetsMenuSave(e)}>Save preset</MenuItem>
|
<MenuItem onClick={(e) => this.handlePresetsMenuSave(e)}>Save preset</MenuItem>
|
||||||
<MenuItem onClick={(e) => this.handlePresetsMenuSaveAs(e)}>Save preset as...</MenuItem>
|
|
||||||
<MenuItem onClick={(e) => this.handlePresetsMenuRename(e)}>Rename...</MenuItem>
|
{this.state.compactHorizontalLayoutMenu ? (
|
||||||
<MenuItem onClick={(e) => this.handlePresetsMenuImport(e)}>Import from bank...</MenuItem>
|
<MenuItem key="a" onClick={(e) => this.handlePresetsSubmenuClick(e)}
|
||||||
<MenuItem onClick={(e) => this.handlePresetsMenuNew(e)}>New...</MenuItem>
|
style={{ display: 'flex', flexFlow: "row nowrap", alignItems: 'center', justifyContent: 'space-between' }}
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
<ArrowRightIcon/>
|
||||||
|
</MenuItem>
|
||||||
|
)
|
||||||
|
:(
|
||||||
|
[
|
||||||
|
(<MenuItem key="b" onClick={(e) => this.handlePresetsMenuSaveAs(e)}>Save preset as...</MenuItem>),
|
||||||
|
(<MenuItem key="c" onClick={(e) => this.handlePresetsMenuRename(e)}>Rename...</MenuItem>),
|
||||||
|
(<MenuItem key="d" onClick={(e) => this.handlePresetsMenuImport(e)}>Import from bank...</MenuItem>),
|
||||||
|
(<MenuItem key="e" onClick={(e) => this.handlePresetsMenuNew(e)}>New...</MenuItem>),
|
||||||
|
]
|
||||||
|
|
||||||
|
)}
|
||||||
<Divider />
|
<Divider />
|
||||||
<MenuItem onClick={(e) => { this.handleDownloadPreset(e); }} >Download preset</MenuItem>
|
<MenuItem onClick={(e) => { this.handleDownloadPreset(e); }} >Download preset</MenuItem>
|
||||||
<MenuItem onClick={(e) => { this.handleUploadPreset(e) }}>Upload preset</MenuItem>
|
<MenuItem onClick={(e) => { this.handleUploadPreset(e) }}>Upload preset</MenuItem>
|
||||||
@@ -392,8 +430,24 @@ const PresetSelector =
|
|||||||
<MenuItem onClick={(e) => this.handleMenuEditPresets()}>Manage presets...</MenuItem>
|
<MenuItem onClick={(e) => this.handleMenuEditPresets()}>Manage presets...</MenuItem>
|
||||||
</Menu>
|
</Menu>
|
||||||
</div>
|
</div>
|
||||||
<PresetDialog show={this.state.showPresetsDialog} isEditDialog={this.state.showEditPresetsDialog} onDialogClose={() => this.handleDialogClose()}
|
|
||||||
|
{/* Submenu */}
|
||||||
|
<Menu key="b" onClose={() => this.handlePresetsSubmenuClose()}
|
||||||
|
anchorOrigin={{ vertical: 'top', horizontal: 'right' }}
|
||||||
|
anchorPosition={{left: 48, top: 0}}
|
||||||
|
anchorEl={this.state.presetsSubmenuAnchorRef}
|
||||||
|
open={this.state.presetsSubmenuAnchorRef !== null} >
|
||||||
|
<MenuItem onClick={(e) => this.handlePresetsMenuSaveAs(e)}>Save preset as...</MenuItem>
|
||||||
|
<MenuItem onClick={(e) => this.handlePresetsMenuRename(e)}>Rename...</MenuItem>
|
||||||
|
<MenuItem onClick={(e) => this.handlePresetsMenuImport(e)}>Import from bank...</MenuItem>
|
||||||
|
<MenuItem onClick={(e) => this.handlePresetsMenuNew(e)}>New...</MenuItem>
|
||||||
|
</Menu>
|
||||||
|
|
||||||
|
|
||||||
|
{this.state.showPresetsDialog&& (
|
||||||
|
<PresetDialog show={this.state.showPresetsDialog} onDialogClose={() => this.handleDialogClose()}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
{this.state.saveAsDialogOpen && (
|
{this.state.saveAsDialogOpen && (
|
||||||
<SavePresetAsDialog open={this.state.saveAsDialogOpen}
|
<SavePresetAsDialog open={this.state.saveAsDialogOpen}
|
||||||
defaultName={presets.getItem(presets.selectedInstanceId)?.name ?? "My Preset"}
|
defaultName={presets.getItem(presets.selectedInstanceId)?.name ?? "My Preset"}
|
||||||
|
|||||||
Reference in New Issue
Block a user