Files
Nitro-V3/src/components/floorplan-editor/FloorplanEditorView.tsx
T
2026-02-20 09:04:42 +01:00

165 lines
7.1 KiB
TypeScript

import { AddLinkEventTracker, FloorHeightMapEvent, ILinkEventTracker, RemoveLinkEventTracker, RoomEngineEvent, RoomVisualizationSettingsEvent, UpdateFloorPropertiesMessageComposer } from '@nitrots/nitro-renderer';
import { FC, useEffect, useState } from 'react';
import { LocalizeText, SendMessageComposer } from '../../api';
import { Button, ButtonGroup, Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../common';
import { useMessageEvent, useNitroEvent } from '../../hooks';
import { FloorplanEditorContextProvider } from './FloorplanEditorContext';
import { FloorplanEditor } from '@nitrots/nitro-renderer';
import { IFloorplanSettings } from '@nitrots/nitro-renderer';
import { IVisualizationSettings } from '@nitrots/nitro-renderer';
import { convertNumbersForSaving, convertSettingToNumber } from '@nitrots/nitro-renderer';
import { FloorplanCanvasView } from './views/FloorplanCanvasView';
import { FloorplanImportExportView } from './views/FloorplanImportExportView';
import { FloorplanOptionsView } from './views/FloorplanOptionsView';
type ScrollDirection = 'up' | 'down' | 'left' | 'right';
export const FloorplanEditorView: FC<{}> = props =>
{
const [ isVisible, setIsVisible ] = useState(false);
const [ importExportVisible, setImportExportVisible ] = useState(false);
const [ originalFloorplanSettings, setOriginalFloorplanSettings ] = useState<IFloorplanSettings>({
tilemap: '',
reservedTiles: [],
entryPoint: [ 0, 0 ],
entryPointDir: 2,
wallHeight: -1,
thicknessWall: 1,
thicknessFloor: 1
});
const [ visualizationSettings, setVisualizationSettings ] = useState<IVisualizationSettings>({
entryPointDir: 2,
wallHeight: -1,
thicknessWall: 1,
thicknessFloor: 1
});
const [ canvasScrollHandler, setCanvasScrollHandler ] = useState<((direction: ScrollDirection) => void) | null>(null);
const saveFloorChanges = () =>
{
SendMessageComposer(new UpdateFloorPropertiesMessageComposer(
FloorplanEditor.instance.getCurrentTilemapString(),
FloorplanEditor.instance.doorLocation.x,
FloorplanEditor.instance.doorLocation.y,
visualizationSettings.entryPointDir,
convertNumbersForSaving(visualizationSettings.thicknessWall),
convertNumbersForSaving(visualizationSettings.thicknessFloor),
(visualizationSettings.wallHeight - 1)
));
}
const revertChanges = () =>
{
setVisualizationSettings({ wallHeight: originalFloorplanSettings.wallHeight, thicknessWall: originalFloorplanSettings.thicknessWall, thicknessFloor: originalFloorplanSettings.thicknessFloor, entryPointDir: originalFloorplanSettings.entryPointDir });
FloorplanEditor.instance.doorLocation = { x: originalFloorplanSettings.entryPoint[0], y: originalFloorplanSettings.entryPoint[1] };
FloorplanEditor.instance.setTilemap(originalFloorplanSettings.tilemap, originalFloorplanSettings.reservedTiles);
FloorplanEditor.instance.renderTiles();
}
useNitroEvent<RoomEngineEvent>(RoomEngineEvent.DISPOSED, event => setIsVisible(false));
useMessageEvent<FloorHeightMapEvent>(FloorHeightMapEvent, event =>
{
const parser = event.getParser();
setOriginalFloorplanSettings(prevValue =>
{
const newValue = { ...prevValue };
newValue.tilemap = parser.model;
newValue.wallHeight = (parser.wallHeight + 1);
return newValue;
});
setVisualizationSettings(prevValue =>
{
const newValue = { ...prevValue };
newValue.wallHeight = (parser.wallHeight + 1);
return newValue;
});
});
useMessageEvent<RoomVisualizationSettingsEvent>(RoomVisualizationSettingsEvent, event =>
{
const parser = event.getParser();
setOriginalFloorplanSettings(prevValue =>
{
const newValue = { ...prevValue };
newValue.thicknessFloor = convertSettingToNumber(parser.thicknessFloor);
newValue.thicknessWall = convertSettingToNumber(parser.thicknessWall);
return newValue;
});
setVisualizationSettings(prevValue =>
{
const newValue = { ...prevValue };
newValue.thicknessFloor = convertSettingToNumber(parser.thicknessFloor);
newValue.thicknessWall = convertSettingToNumber(parser.thicknessWall);
return newValue;
});
});
useEffect(() =>
{
const linkTracker: ILinkEventTracker = {
linkReceived: (url: string) =>
{
const parts = url.split('/');
if(parts.length < 2) return;
switch(parts[1])
{
case 'show':
setIsVisible(true);
return;
case 'hide':
setIsVisible(false);
return;
case 'toggle':
setIsVisible(prevValue => !prevValue);
return;
}
},
eventUrlPrefix: 'floor-editor/'
};
AddLinkEventTracker(linkTracker);
return () => RemoveLinkEventTracker(linkTracker);
}, []);
return (
<FloorplanEditorContextProvider value={ { originalFloorplanSettings: originalFloorplanSettings, setOriginalFloorplanSettings: setOriginalFloorplanSettings, visualizationSettings: visualizationSettings, setVisualizationSettings: setVisualizationSettings } }>
{ isVisible &&
<NitroCardView uniqueKey="floorpan-editor" className="w-[760px] h-[500px]" theme="primary-slim">
<NitroCardHeaderView headerText={ LocalizeText('floor.plan.editor.title') } onCloseClick={ () => setIsVisible(false) } />
<NitroCardContentView overflow="hidden">
<FloorplanOptionsView onCanvasScroll={ direction => canvasScrollHandler && canvasScrollHandler(direction) } />
<FloorplanCanvasView overflow="hidden" setScrollHandler={ setCanvasScrollHandler } />
<Flex justifyContent="between">
<Button onClick={ revertChanges }>{ LocalizeText('floor.plan.editor.reload') }</Button>
<ButtonGroup>
<Button disabled={ true }>{ LocalizeText('floor.plan.editor.preview') }</Button>
<Button onClick={ event => setImportExportVisible(true) }>{ LocalizeText('floor.plan.editor.import.export') }</Button>
<Button onClick={ saveFloorChanges }>{ LocalizeText('floor.plan.editor.save') }</Button>
</ButtonGroup>
</Flex>
</NitroCardContentView>
</NitroCardView> }
{ importExportVisible &&
<FloorplanImportExportView onCloseClick={ () => setImportExportVisible(false) } /> }
</FloorplanEditorContextProvider>
);
}