svg-layout-designer-react/src/Components/Editor/Actions/SymbolOperations.ts
Eric Nguyen 57e6c9a156 Merged PR 173: Implements API methods through right click + more (read desc)
- Implements API methods through right click
- Refactor events
- Refactor usage of setHistory and setHistoryCurrentStep into a single function
- Update ContainerOperations documentations
- Added AddContainers in order to add multiple containers + refactor AddContainer to use it
- Fix regression
- Fix AddContainer at index
2022-08-30 14:45:29 +00:00

164 lines
5.2 KiB
TypeScript

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 { GetDefaultSymbolModel } 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
): IHistoryState[] {
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);
const newSymbol: ISymbolModel = GetDefaultSymbolModel(name, newCounters, type, symbolConfig);
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
});
return history;
}
export function SelectSymbol(
symbolId: string,
fullHistory: IHistoryState[],
historyCurrentStep: number
): IHistoryState[] {
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
});
return history;
}
export function DeleteSymbol(
symbolId: string,
fullHistory: IHistoryState[],
historyCurrentStep: number
): IHistoryState[] {
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);
UnlinkSymbolFromContainers(symbol, newMainContainer);
newSymbols.delete(symbolId);
history.push({
lastAction: `Select ${symbolId}`,
mainContainer: newMainContainer,
selectedContainerId: current.selectedContainerId,
typeCounters: structuredClone(current.typeCounters),
symbols: newSymbols,
selectedSymbolId: symbolId
});
return history;
}
/**
* Unlink a symbol to a container and its children
* @param symbol Symbol to remove
* @param root Container and its children to remove a symbol from
*/
function UnlinkSymbolFromContainers(symbol: ISymbolModel, root: IContainerModel): void {
symbol.linkedContainers.forEach((containerId) => {
const container = FindContainerById(root, 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
): IHistoryState[] {
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
});
return history;
}