Merged PR 162: Implement symbols and other stuff (see desc)
Implement symbols - Add, Remove, Select Container - Form - Link with container - Symbol behavior application to container (move to x with xpositionreference) Important changes - Remove SelectedContainer from HistoryState, meaning that it will be slower for each load but will be faster for each operations* (SetHistory, SelectContainer, DeleteContainer, SymbolOperations) - ElementsSidebar now opens with isSidebarOpen meaning that both sidebar will open on toggle - Moved camelize, transformX, restoreX to different modules (stringtools.ts, svg.ts)
This commit is contained in:
parent
58ef28fe89
commit
8b8d88f885
48 changed files with 1453 additions and 188 deletions
180
src/Components/Editor/SymbolOperations.ts
Normal file
180
src/Components/Editor/SymbolOperations.ts
Normal file
|
@ -0,0 +1,180 @@
|
|||
import { Dispatch, SetStateAction } from 'react';
|
||||
import { IConfiguration } from '../../Interfaces/IConfiguration';
|
||||
import { IContainerModel } from '../../Interfaces/IContainerModel';
|
||||
import { IHistoryState } from '../../Interfaces/IHistoryState';
|
||||
import { ISymbolModel } from '../../Interfaces/ISymbolModel';
|
||||
import { DEFAULT_SYMBOL_HEIGHT, DEFAULT_SYMBOL_WIDTH } from '../../utils/default';
|
||||
import { findContainerById } from '../../utils/itertools';
|
||||
import { restoreX } from '../../utils/svg';
|
||||
import { ApplyBehaviors } from './Behaviors/Behaviors';
|
||||
import { getCurrentHistory, UpdateCounters } from './Editor';
|
||||
|
||||
export function AddSymbol(
|
||||
name: string,
|
||||
configuration: IConfiguration,
|
||||
fullHistory: IHistoryState[],
|
||||
historyCurrentStep: number,
|
||||
setHistory: Dispatch<SetStateAction<IHistoryState[]>>,
|
||||
setHistoryCurrentStep: Dispatch<SetStateAction<number>>
|
||||
): void {
|
||||
const history = getCurrentHistory(fullHistory, historyCurrentStep);
|
||||
const current = history[history.length - 1];
|
||||
|
||||
const symbolConfig = configuration.AvailableSymbols
|
||||
.find(option => option.Name === name);
|
||||
|
||||
if (symbolConfig === undefined) {
|
||||
throw new Error('[AddSymbol] Symbol could not be found in the config');
|
||||
}
|
||||
const type = `symbol-${name}`;
|
||||
const newCounters = structuredClone(current.TypeCounters);
|
||||
UpdateCounters(newCounters, type);
|
||||
|
||||
const newSymbols = structuredClone(current.Symbols);
|
||||
// TODO: Put this in default.ts as GetDefaultConfig
|
||||
const newSymbol: ISymbolModel = {
|
||||
id: `${name}-${newCounters[type]}`,
|
||||
type: name,
|
||||
config: structuredClone(symbolConfig),
|
||||
x: 0,
|
||||
width: symbolConfig.Width ?? DEFAULT_SYMBOL_WIDTH,
|
||||
height: symbolConfig.Height ?? DEFAULT_SYMBOL_HEIGHT,
|
||||
linkedContainers: new Set()
|
||||
};
|
||||
newSymbol.x = restoreX(newSymbol.x, newSymbol.width, newSymbol.config.XPositionReference);
|
||||
|
||||
newSymbols.set(newSymbol.id, newSymbol);
|
||||
|
||||
history.push({
|
||||
LastAction: `Add ${name}`,
|
||||
MainContainer: structuredClone(current.MainContainer),
|
||||
SelectedContainerId: current.SelectedContainerId,
|
||||
TypeCounters: newCounters,
|
||||
Symbols: newSymbols,
|
||||
SelectedSymbolId: newSymbol.id
|
||||
});
|
||||
setHistory(history);
|
||||
setHistoryCurrentStep(history.length - 1);
|
||||
}
|
||||
|
||||
export function SelectSymbol(
|
||||
symbolId: string,
|
||||
fullHistory: IHistoryState[],
|
||||
historyCurrentStep: number,
|
||||
setHistory: Dispatch<SetStateAction<IHistoryState[]>>,
|
||||
setHistoryCurrentStep: Dispatch<SetStateAction<number>>
|
||||
): void {
|
||||
const history = getCurrentHistory(fullHistory, historyCurrentStep);
|
||||
const current = history[history.length - 1];
|
||||
|
||||
history.push({
|
||||
LastAction: `Select ${symbolId}`,
|
||||
MainContainer: structuredClone(current.MainContainer),
|
||||
SelectedContainerId: current.SelectedContainerId,
|
||||
TypeCounters: structuredClone(current.TypeCounters),
|
||||
Symbols: structuredClone(current.Symbols),
|
||||
SelectedSymbolId: symbolId
|
||||
});
|
||||
setHistory(history);
|
||||
setHistoryCurrentStep(history.length - 1);
|
||||
}
|
||||
|
||||
export function DeleteSymbol(
|
||||
symbolId: string,
|
||||
fullHistory: IHistoryState[],
|
||||
historyCurrentStep: number,
|
||||
setHistory: Dispatch<SetStateAction<IHistoryState[]>>,
|
||||
setHistoryCurrentStep: Dispatch<SetStateAction<number>>
|
||||
): void {
|
||||
const history = getCurrentHistory(fullHistory, historyCurrentStep);
|
||||
const current = history[history.length - 1];
|
||||
|
||||
const newSymbols = structuredClone(current.Symbols);
|
||||
const symbol = newSymbols.get(symbolId);
|
||||
|
||||
if (symbol === undefined) {
|
||||
throw new Error(`[DeleteSymbol] Could not find symbol in the current state!: ${symbolId}`);
|
||||
}
|
||||
|
||||
const newMainContainer = structuredClone(current.MainContainer);
|
||||
|
||||
UnlinkContainers(symbol, newMainContainer);
|
||||
|
||||
newSymbols.delete(symbolId);
|
||||
|
||||
history.push({
|
||||
LastAction: `Select ${symbolId}`,
|
||||
MainContainer: newMainContainer,
|
||||
SelectedContainerId: current.SelectedContainerId,
|
||||
TypeCounters: structuredClone(current.TypeCounters),
|
||||
Symbols: newSymbols,
|
||||
SelectedSymbolId: symbolId
|
||||
});
|
||||
setHistory(history);
|
||||
setHistoryCurrentStep(history.length - 1);
|
||||
}
|
||||
|
||||
function UnlinkContainers(symbol: ISymbolModel, newMainContainer: IContainerModel) {
|
||||
symbol.linkedContainers.forEach((containerId) => {
|
||||
const container = findContainerById(newMainContainer, containerId);
|
||||
|
||||
if (container === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
container.properties.linkedSymbolId = '';
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handled the property change event in the properties form
|
||||
* @param key Property name
|
||||
* @param value New value of the property
|
||||
* @returns void
|
||||
*/
|
||||
export function OnPropertyChange(
|
||||
key: string,
|
||||
value: string | number | boolean,
|
||||
fullHistory: IHistoryState[],
|
||||
historyCurrentStep: number,
|
||||
setHistory: Dispatch<SetStateAction<IHistoryState[]>>,
|
||||
setHistoryCurrentStep: Dispatch<SetStateAction<number>>
|
||||
): void {
|
||||
const history = getCurrentHistory(fullHistory, historyCurrentStep);
|
||||
const current = history[history.length - 1];
|
||||
|
||||
if (current.SelectedSymbolId === '') {
|
||||
throw new Error('[OnSymbolPropertyChange] Property was changed before selecting a symbol');
|
||||
}
|
||||
|
||||
const newSymbols: Map<string, ISymbolModel> = structuredClone(current.Symbols);
|
||||
const symbol = newSymbols.get(current.SelectedSymbolId);
|
||||
|
||||
if (symbol === null || symbol === undefined) {
|
||||
throw new Error('[OnSymbolPropertyChange] Symbol model was not found in state!');
|
||||
}
|
||||
|
||||
(symbol as any)[key] = value;
|
||||
|
||||
const newMainContainer = structuredClone(current.MainContainer);
|
||||
symbol.linkedContainers.forEach((containerId) => {
|
||||
const container = findContainerById(newMainContainer, containerId);
|
||||
|
||||
if (container === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
ApplyBehaviors(container, newSymbols);
|
||||
});
|
||||
|
||||
history.push({
|
||||
LastAction: `Change ${key} of ${symbol.id}`,
|
||||
MainContainer: newMainContainer,
|
||||
SelectedContainerId: current.SelectedContainerId,
|
||||
TypeCounters: Object.assign({}, current.TypeCounters),
|
||||
Symbols: newSymbols,
|
||||
SelectedSymbolId: symbol.id
|
||||
});
|
||||
setHistory(history);
|
||||
setHistoryCurrentStep(history.length - 1);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue