import { Dispatch, SetStateAction } from 'react'; import { IHistoryState } from '../../Interfaces/IHistoryState'; import { IConfiguration } from '../../Interfaces/IConfiguration'; import { ContainerModel, IContainerModel } from '../../Interfaces/IContainerModel'; import { findContainerById } from '../../utils/itertools'; import { getCurrentHistory } from './Editor'; /** * Select a container * @param container Selected container */ export function SelectContainer( container: ContainerModel, fullHistory: IHistoryState[], historyCurrentStep: number, setHistory: Dispatch>, setHistoryCurrentStep: Dispatch> ): void { const history = getCurrentHistory(fullHistory, historyCurrentStep); const current = history[history.length - 1]; const mainContainerClone = structuredClone(current.MainContainer); const selectedContainer = findContainerById(mainContainerClone, container.properties.id); if (selectedContainer === undefined) { throw new Error('[SelectContainer] Cannot find container among children of main container!'); } setHistory(history.concat([{ LastAction: `Select container ${selectedContainer.properties.id}`, MainContainer: mainContainerClone, SelectedContainer: selectedContainer, SelectedContainerId: selectedContainer.properties.id, TypeCounters: Object.assign({}, current.TypeCounters) }])); setHistoryCurrentStep(history.length); } /** * Delete a container * @param containerId containerId of the container to delete * @param fullHistory History of the editor * @param historyCurrentStep Current step * @param setHistory State setter for History * @param setHistoryCurrentStep State setter for current step */ export function DeleteContainer( containerId: string, fullHistory: IHistoryState[], historyCurrentStep: number, setHistory: Dispatch>, setHistoryCurrentStep: Dispatch> ): void { const history = getCurrentHistory(fullHistory, historyCurrentStep); const current = history[historyCurrentStep]; const mainContainerClone: IContainerModel = structuredClone(current.MainContainer); const container = findContainerById(mainContainerClone, containerId); if (container === undefined) { throw new Error(`[DeleteContainer] Tried to delete a container that is not present in the main container: ${containerId}`); } if (container === mainContainerClone || container.parent === undefined || container.parent === null) { // TODO: Implement alert throw new Error('[DeleteContainer] Tried to delete the main container! Deleting the main container is not allowed!'); } if (container === null || container === undefined) { throw new Error('[DeleteContainer] Container model was not found among children of the main container!'); } const index = container.parent.children.indexOf(container); if (index > -1) { container.parent.children.splice(index, 1); } else { throw new Error('[DeleteContainer] Could not find container among parent\'s children'); } // Select the previous container // or select the one above const SelectedContainer = findContainerById(mainContainerClone, current.SelectedContainerId) ?? container.parent.children.at(index - 1) ?? container.parent; const SelectedContainerId = SelectedContainer.properties.id; setHistory(history.concat([{ LastAction: `Delete container ${containerId}`, MainContainer: mainContainerClone, SelectedContainer, SelectedContainerId, TypeCounters: Object.assign({}, current.TypeCounters) }])); setHistoryCurrentStep(history.length); } /** * Add a new container to a selected container * @param type The type of container * @param configuration Configuration of the App * @param fullHistory History of the editor * @param historyCurrentStep Current step * @param setHistory State setter for History * @param setHistoryCurrentStep State setter for current step * @returns void */ export function AddContainerToSelectedContainer( type: string, configuration: IConfiguration, fullHistory: IHistoryState[], historyCurrentStep: number, setHistory: Dispatch>, setHistoryCurrentStep: Dispatch> ): void { const history = getCurrentHistory(fullHistory, historyCurrentStep); const current = history[history.length - 1]; if (current.SelectedContainer === null || current.SelectedContainer === undefined) { return; } const parent = current.SelectedContainer; AddContainer( parent.children.length, type, parent.properties.id, configuration, fullHistory, historyCurrentStep, setHistory, setHistoryCurrentStep ); } /** * Create and add a new container at `index` in children of parent of `parentId` * @param index Index where to insert to the new container * @param type Type of container * @param parentId Parent in which to insert the new container * @param configuration Configuration of the app * @param fullHistory History of the editor * @param historyCurrentStep Current step * @param setHistory State setter of History * @param setHistoryCurrentStep State setter of the current step * @returns void */ export function AddContainer( index: number, type: string, parentId: string, configuration: IConfiguration, fullHistory: IHistoryState[], historyCurrentStep: number, setHistory: Dispatch>, setHistoryCurrentStep: Dispatch> ): void { const history = getCurrentHistory(fullHistory, historyCurrentStep); const current = history[history.length - 1]; if (current.MainContainer === null || current.MainContainer === undefined) { return; } // Get the preset properties from the API const properties = configuration.AvailableContainers .find(option => option.Type === type); if (properties === undefined) { throw new Error(`[AddContainer] Object type not found. Found: ${type}`); } // Set the counter of the object type in order to assign an unique id const newCounters = Object.assign({}, current.TypeCounters); if (newCounters[type] === null || newCounters[type] === undefined) { newCounters[type] = 0; } else { newCounters[type]++; } const count = newCounters[type]; // Create maincontainer model const clone: IContainerModel = structuredClone(current.MainContainer); // Find the parent const parentClone: IContainerModel | undefined = findContainerById( clone, parentId ); if (parentClone === null || parentClone === undefined) { throw new Error('[AddContainer] Container model was not found among children of the main container!'); } let x = 0; if (index > 0) { const lastChild: IContainerModel | undefined = parentClone.children.at(index - 1); if (lastChild !== undefined) { x = lastChild.properties.x + Number(lastChild.properties.width); } } // Create the container const newContainer = new ContainerModel( parentClone, { id: `${type}-${count}`, parentId: parentClone.properties.id, x, y: 0, width: properties?.Width, height: parentClone.properties.height, isRigidBody: false, XPositionReference: properties.XPositionReference, ...properties.Style }, [], { type } ); // And push it the the parent children if (index === parentClone.children.length) { parentClone.children.push(newContainer); } else { parentClone.children.splice(index, 0, newContainer); } // Update the state setHistory(history.concat([{ LastAction: 'Add container', MainContainer: clone, SelectedContainer: parentClone, SelectedContainerId: parentClone.properties.id, TypeCounters: newCounters }])); setHistoryCurrentStep(history.length); }