mirror of
https://github.com/billsonnn/nitro-react.git
synced 2025-01-18 21:36:27 +01:00
Floor editor updates
This commit is contained in:
parent
04e6d3eeea
commit
fed35dd1f0
@ -83,6 +83,9 @@ $nitro-doorbell-height: 200px;
|
||||
|
||||
$nitro-guide-tool-width: 250px;
|
||||
|
||||
$nitro-floor-editor-width: 760px;
|
||||
$nitro-floor-editor-height: 500px;
|
||||
|
||||
.nitro-app {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
25
src/views/floorplan-editor/FloorplanEditorContext.tsx
Normal file
25
src/views/floorplan-editor/FloorplanEditorContext.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
import { createContext, Dispatch, FC, ProviderProps, SetStateAction, useContext } from 'react';
|
||||
import { IFloorplanSettings } from './common/IFloorplanSettings';
|
||||
import { IVisualizationSettings } from './common/IVisualizationSettings';
|
||||
|
||||
interface IFloorplanEditorContext
|
||||
{
|
||||
originalFloorplanSettings: IFloorplanSettings;
|
||||
setOriginalFloorplanSettings: Dispatch<SetStateAction<IFloorplanSettings>>;
|
||||
visualizationSettings: IVisualizationSettings;
|
||||
setVisualizationSettings: Dispatch<SetStateAction<IVisualizationSettings>>;
|
||||
}
|
||||
|
||||
const FloorplanEditorContext = createContext<IFloorplanEditorContext>({
|
||||
originalFloorplanSettings: null,
|
||||
setOriginalFloorplanSettings: null,
|
||||
visualizationSettings: null,
|
||||
setVisualizationSettings: null
|
||||
});
|
||||
|
||||
export const FloorplanEditorContextProvider: FC<ProviderProps<IFloorplanEditorContext>> = props =>
|
||||
{
|
||||
return <FloorplanEditorContext.Provider value={ props.value }>{ props.children }</FloorplanEditorContext.Provider>
|
||||
}
|
||||
|
||||
export const useFloorplanEditorContext = () => useContext(FloorplanEditorContext);
|
@ -1,20 +1,6 @@
|
||||
.nitro-floorplan-editor {
|
||||
width: 760px;
|
||||
height: 575px;
|
||||
|
||||
.editor-area {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
min-height: 300px;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.arrow-button {
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
width: $nitro-floor-editor-width;
|
||||
height: $nitro-floor-editor-height;
|
||||
}
|
||||
|
||||
.floorplan-import-export {
|
||||
|
@ -1,29 +1,37 @@
|
||||
import { FloorHeightMapEvent, NitroPoint, RoomEngineEvent, RoomVisualizationSettingsEvent, UpdateFloorPropertiesMessageComposer } from '@nitrots/nitro-renderer';
|
||||
import { FC, useCallback, useState } from 'react';
|
||||
import { FC, useCallback, useEffect, useState } from 'react';
|
||||
import { LocalizeText, SendMessageComposer } from '../../api';
|
||||
import { Column, Flex, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../common';
|
||||
import { Button, ButtonGroup, Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../common';
|
||||
import { FloorplanEditorEvent } from '../../events';
|
||||
import { UseMessageEventHook, UseMountEffect, UseRoomEngineEvent, UseUiEvent } from '../../hooks';
|
||||
import { UseMessageEventHook, UseRoomEngineEvent, UseUiEvent } from '../../hooks';
|
||||
import { FloorplanEditor } from './common/FloorplanEditor';
|
||||
import { IFloorplanSettings } from './common/IFloorplanSettings';
|
||||
import { IVisualizationSettings } from './common/IVisualizationSettings';
|
||||
import { convertNumbersForSaving, convertSettingToNumber } from './common/Utils';
|
||||
import { FloorplanEditorContextProvider } from './context/FloorplanEditorContext';
|
||||
import { IFloorplanSettings, initialFloorplanSettings, IVisualizationSettings } from './context/FloorplanEditorContext.types';
|
||||
import { FloorplanEditorContextProvider } from './FloorplanEditorContext';
|
||||
import { FloorplanCanvasView } from './views/FloorplanCanvasView';
|
||||
import { FloorplanImportExportView } from './views/FloorplanImportExportView';
|
||||
import { FloorplanOptionsView } from './views/FloorplanOptionsView';
|
||||
|
||||
export const FloorplanEditorView: FC<{}> = props =>
|
||||
{
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
const [ isVisible, setIsVisible ] = useState(false);
|
||||
const [ importExportVisible, setImportExportVisible ] = useState(false);
|
||||
const [originalFloorplanSettings, setOriginalFloorplanSettings] = useState<IFloorplanSettings>(initialFloorplanSettings);
|
||||
const [visualizationSettings, setVisualizationSettings] = useState<IVisualizationSettings>(
|
||||
{
|
||||
entryPointDir: 2,
|
||||
wallHeight: -1,
|
||||
thicknessWall: 1,
|
||||
thicknessFloor: 1
|
||||
});
|
||||
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 onFloorplanEditorEvent = useCallback((event: FloorplanEditorEvent) =>
|
||||
{
|
||||
@ -36,20 +44,15 @@ export const FloorplanEditorView: FC<{}> = props =>
|
||||
setIsVisible(true);
|
||||
break;
|
||||
case FloorplanEditorEvent.TOGGLE_FLOORPLAN_EDITOR:
|
||||
setIsVisible(!isVisible);
|
||||
setIsVisible(prevValue => !prevValue);
|
||||
break;
|
||||
}
|
||||
}, [isVisible]);
|
||||
}, []);
|
||||
|
||||
UseUiEvent(FloorplanEditorEvent.HIDE_FLOORPLAN_EDITOR, onFloorplanEditorEvent);
|
||||
UseUiEvent(FloorplanEditorEvent.SHOW_FLOORPLAN_EDITOR, onFloorplanEditorEvent);
|
||||
UseUiEvent(FloorplanEditorEvent.TOGGLE_FLOORPLAN_EDITOR, onFloorplanEditorEvent);
|
||||
|
||||
UseMountEffect(() =>
|
||||
{
|
||||
FloorplanEditor.instance.initialize();
|
||||
});
|
||||
|
||||
const onRoomEngineEvent = useCallback((event: RoomEngineEvent) =>
|
||||
{
|
||||
setIsVisible(false);
|
||||
@ -61,18 +64,25 @@ export const FloorplanEditorView: FC<{}> = props =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
if(!parser) return;
|
||||
setOriginalFloorplanSettings(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
const settings = Object.assign({}, originalFloorplanSettings);
|
||||
settings.tilemap = parser.model;
|
||||
settings.wallHeight = parser.wallHeight + 1;
|
||||
setOriginalFloorplanSettings(settings);
|
||||
newValue.tilemap = parser.model;
|
||||
newValue.wallHeight = (parser.wallHeight + 1);
|
||||
|
||||
const vSettings = Object.assign({}, visualizationSettings);
|
||||
vSettings.wallHeight = parser.wallHeight + 1;
|
||||
setVisualizationSettings(vSettings);
|
||||
return newValue;
|
||||
});
|
||||
|
||||
}, [originalFloorplanSettings, visualizationSettings]);
|
||||
setVisualizationSettings(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.wallHeight = (parser.wallHeight + 1);
|
||||
|
||||
return newValue;
|
||||
});
|
||||
}, []);
|
||||
|
||||
UseMessageEventHook(FloorHeightMapEvent, onFloorHeightMapEvent);
|
||||
|
||||
@ -80,23 +90,30 @@ export const FloorplanEditorView: FC<{}> = props =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
if(!parser) return;
|
||||
setOriginalFloorplanSettings(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
const settings = Object.assign({}, originalFloorplanSettings);
|
||||
settings.thicknessFloor = convertSettingToNumber(parser.thicknessFloor);
|
||||
settings.thicknessWall = convertSettingToNumber(parser.thicknessWall);
|
||||
newValue.thicknessFloor = convertSettingToNumber(parser.thicknessFloor);
|
||||
newValue.thicknessWall = convertSettingToNumber(parser.thicknessWall);
|
||||
|
||||
setOriginalFloorplanSettings(settings);
|
||||
return newValue;
|
||||
});
|
||||
|
||||
const vSettings = Object.assign({}, visualizationSettings);
|
||||
vSettings.thicknessFloor = convertSettingToNumber(parser.thicknessFloor);
|
||||
vSettings.thicknessWall = convertSettingToNumber(parser.thicknessWall);
|
||||
setVisualizationSettings(vSettings);
|
||||
}, [originalFloorplanSettings, visualizationSettings]);
|
||||
setVisualizationSettings(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.thicknessFloor = convertSettingToNumber(parser.thicknessFloor);
|
||||
newValue.thicknessWall = convertSettingToNumber(parser.thicknessWall);
|
||||
|
||||
return newValue;
|
||||
});
|
||||
}, []);
|
||||
|
||||
UseMessageEventHook(RoomVisualizationSettingsEvent, onRoomVisualizationSettingsEvent);
|
||||
|
||||
const saveFloorChanges = useCallback(() =>
|
||||
const saveFloorChanges = () =>
|
||||
{
|
||||
SendMessageComposer(new UpdateFloorPropertiesMessageComposer(
|
||||
FloorplanEditor.instance.getCurrentTilemapString(),
|
||||
@ -105,47 +122,44 @@ export const FloorplanEditorView: FC<{}> = props =>
|
||||
visualizationSettings.entryPointDir,
|
||||
convertNumbersForSaving(visualizationSettings.thicknessWall),
|
||||
convertNumbersForSaving(visualizationSettings.thicknessFloor),
|
||||
visualizationSettings.wallHeight - 1
|
||||
(visualizationSettings.wallHeight - 1)
|
||||
));
|
||||
}, [visualizationSettings.entryPointDir, visualizationSettings.thicknessFloor, visualizationSettings.thicknessWall, visualizationSettings.wallHeight]);
|
||||
}
|
||||
|
||||
const revertChanges = useCallback(() =>
|
||||
const revertChanges = () =>
|
||||
{
|
||||
setVisualizationSettings({ wallHeight: originalFloorplanSettings.wallHeight, thicknessWall: originalFloorplanSettings.thicknessWall, thicknessFloor: originalFloorplanSettings.thicknessFloor, entryPointDir: originalFloorplanSettings.entryPointDir });
|
||||
|
||||
FloorplanEditor.instance.doorLocation = new NitroPoint(originalFloorplanSettings.entryPoint[0], originalFloorplanSettings.entryPoint[1]);
|
||||
FloorplanEditor.instance.setTilemap(originalFloorplanSettings.tilemap, originalFloorplanSettings.reservedTiles);
|
||||
FloorplanEditor.instance.renderTiles();
|
||||
}, [originalFloorplanSettings.entryPoint, originalFloorplanSettings.entryPointDir, originalFloorplanSettings.reservedTiles, originalFloorplanSettings.thicknessFloor, originalFloorplanSettings.thicknessWall, originalFloorplanSettings.tilemap, originalFloorplanSettings.wallHeight])
|
||||
}
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
FloorplanEditor.instance.initialize();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<FloorplanEditorContextProvider value={{ originalFloorplanSettings: originalFloorplanSettings, setOriginalFloorplanSettings: setOriginalFloorplanSettings, visualizationSettings: visualizationSettings, setVisualizationSettings: setVisualizationSettings }}>
|
||||
{isVisible &&
|
||||
<NitroCardView uniqueKey="floorpan-editor" className="nitro-floorplan-editor" theme="primary-slim">
|
||||
<NitroCardHeaderView headerText={LocalizeText('floor.plan.editor.title')} onCloseClick={() => setIsVisible(false)} />
|
||||
<NitroCardContentView>
|
||||
<Grid>
|
||||
<Column size={12}>
|
||||
<FloorplanOptionsView />
|
||||
<FloorplanCanvasView />
|
||||
<Flex className="justify-content-between">
|
||||
<div className="btn-group">
|
||||
<button className="btn btn-primary" onClick={revertChanges}>{LocalizeText('floor.plan.editor.reload')}</button>
|
||||
</div>
|
||||
<div className="btn-group">
|
||||
<button className="btn btn-primary" disabled={true}>{LocalizeText('floor.plan.editor.preview')}</button>
|
||||
<button className="btn btn-primary" onClick={ () => setImportExportVisible(true) }>{LocalizeText('floor.plan.editor.import.export')}</button>
|
||||
<button className="btn btn-primary" onClick={saveFloorChanges}>{LocalizeText('floor.plan.editor.save')}</button>
|
||||
</div>
|
||||
</Flex>
|
||||
</Column>
|
||||
</Grid>
|
||||
</NitroCardContentView>
|
||||
</NitroCardView>
|
||||
}
|
||||
{importExportVisible && <FloorplanImportExportView onCloseClick={ () => setImportExportVisible(false)}/>}
|
||||
</FloorplanEditorContextProvider>
|
||||
</>
|
||||
<FloorplanEditorContextProvider value={{ originalFloorplanSettings: originalFloorplanSettings, setOriginalFloorplanSettings: setOriginalFloorplanSettings, visualizationSettings: visualizationSettings, setVisualizationSettings: setVisualizationSettings }}>
|
||||
{ isVisible &&
|
||||
<NitroCardView uniqueKey="floorpan-editor" className="nitro-floorplan-editor" theme="primary-slim">
|
||||
<NitroCardHeaderView headerText={ LocalizeText('floor.plan.editor.title') } onCloseClick={ () => setIsVisible(false) } />
|
||||
<NitroCardContentView overflow="hidden">
|
||||
<FloorplanOptionsView />
|
||||
<FloorplanCanvasView overflow="hidden" />
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
1
src/views/floorplan-editor/common/ConvertMapToString.ts
Normal file
1
src/views/floorplan-editor/common/ConvertMapToString.ts
Normal file
@ -0,0 +1 @@
|
||||
export const ConvertTileMapToString = (map: string) => map.replace(/\r\n|\r|\n/g, '\n').toLowerCase();
|
8
src/views/floorplan-editor/common/IFloorplanSettings.ts
Normal file
8
src/views/floorplan-editor/common/IFloorplanSettings.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { IVisualizationSettings } from './IVisualizationSettings';
|
||||
|
||||
export interface IFloorplanSettings extends IVisualizationSettings
|
||||
{
|
||||
tilemap: string;
|
||||
reservedTiles: boolean[][];
|
||||
entryPoint: [ number, number ];
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
export interface IVisualizationSettings
|
||||
{
|
||||
entryPointDir: number;
|
||||
wallHeight: number;
|
||||
thicknessWall: number;
|
||||
thicknessFloor: number;
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
import { createContext, FC, useContext } from 'react';
|
||||
import { FloorplanEditorContextProps, IFloorplanEditorContext } from './FloorplanEditorContext.types';
|
||||
|
||||
const FloorplanEditorContext = createContext<IFloorplanEditorContext>({
|
||||
originalFloorplanSettings: null,
|
||||
setOriginalFloorplanSettings: null,
|
||||
visualizationSettings: null,
|
||||
setVisualizationSettings: null
|
||||
});
|
||||
|
||||
export const FloorplanEditorContextProvider: FC<FloorplanEditorContextProps> = props =>
|
||||
{
|
||||
return <FloorplanEditorContext.Provider value={ props.value }>{ props.children }</FloorplanEditorContext.Provider>
|
||||
}
|
||||
|
||||
export const useFloorplanEditorContext = () => useContext(FloorplanEditorContext);
|
@ -1,37 +0,0 @@
|
||||
import { ProviderProps } from 'react';
|
||||
|
||||
export interface IFloorplanEditorContext
|
||||
{
|
||||
originalFloorplanSettings: IFloorplanSettings;
|
||||
setOriginalFloorplanSettings: React.Dispatch<React.SetStateAction<IFloorplanSettings>>;
|
||||
visualizationSettings: IVisualizationSettings;
|
||||
setVisualizationSettings: React.Dispatch<React.SetStateAction<IVisualizationSettings>>;
|
||||
}
|
||||
|
||||
export interface IFloorplanSettings extends IVisualizationSettings {
|
||||
tilemap: string;
|
||||
reservedTiles: boolean[][];
|
||||
entryPoint: [number, number];
|
||||
}
|
||||
|
||||
export interface IVisualizationSettings {
|
||||
entryPointDir: number;
|
||||
wallHeight: number;
|
||||
thicknessWall: number;
|
||||
thicknessFloor: number;
|
||||
}
|
||||
|
||||
export const initialFloorplanSettings: IFloorplanSettings = {
|
||||
tilemap: '',
|
||||
reservedTiles: [],
|
||||
entryPoint: [0, 0],
|
||||
entryPointDir: 2,
|
||||
wallHeight: -1,
|
||||
thicknessWall: 1,
|
||||
thicknessFloor: 1
|
||||
}
|
||||
|
||||
export interface FloorplanEditorContextProps extends ProviderProps<IFloorplanEditorContext>
|
||||
{
|
||||
|
||||
}
|
@ -1,51 +1,49 @@
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { GetOccupiedTilesMessageComposer, GetRoomEntryTileMessageComposer, NitroPoint, RoomEntryTileMessageEvent, RoomOccupiedTilesMessageEvent } from '@nitrots/nitro-renderer';
|
||||
import { FC, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { SendMessageComposer } from '../../../api';
|
||||
import { Flex } from '../../../common';
|
||||
import { UseMessageEventHook, UseMountEffect } from '../../../hooks';
|
||||
import { Base, Button, Column, ColumnProps, Flex, Grid } from '../../../common';
|
||||
import { UseMessageEventHook } from '../../../hooks';
|
||||
import { FloorplanEditor } from '../common/FloorplanEditor';
|
||||
import { useFloorplanEditorContext } from '../context/FloorplanEditorContext';
|
||||
import { IFloorplanSettings } from '../common/IFloorplanSettings';
|
||||
import { useFloorplanEditorContext } from '../FloorplanEditorContext';
|
||||
|
||||
export const FloorplanCanvasView: FC<{}> = props =>
|
||||
interface FloorplanCanvasViewProps extends ColumnProps
|
||||
{
|
||||
const { originalFloorplanSettings = null, setOriginalFloorplanSettings = null, visualizationSettings = null, setVisualizationSettings = null } = useFloorplanEditorContext();
|
||||
|
||||
}
|
||||
|
||||
export const FloorplanCanvasView: FC<FloorplanCanvasViewProps> = props =>
|
||||
{
|
||||
const { gap = 1, children = null, ...rest } = props;
|
||||
const [ occupiedTilesReceived , setOccupiedTilesReceived ] = useState(false);
|
||||
const [ entryTileReceived, setEntryTileReceived ] = useState(false);
|
||||
const { originalFloorplanSettings = null, setOriginalFloorplanSettings = null, setVisualizationSettings = null } = useFloorplanEditorContext();
|
||||
const elementRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
return ( () =>
|
||||
{
|
||||
FloorplanEditor.instance.clear();
|
||||
setVisualizationSettings( prev => {return { wallHeight: originalFloorplanSettings.wallHeight, thicknessWall: originalFloorplanSettings.thicknessWall, thicknessFloor: originalFloorplanSettings.thicknessFloor, entryPointDir: prev.entryPointDir } });
|
||||
});
|
||||
}, [originalFloorplanSettings.thicknessFloor, originalFloorplanSettings.thicknessWall, originalFloorplanSettings.wallHeight, setVisualizationSettings]);
|
||||
|
||||
UseMountEffect(() =>
|
||||
{
|
||||
SendMessageComposer(new GetRoomEntryTileMessageComposer());
|
||||
SendMessageComposer(new GetOccupiedTilesMessageComposer());
|
||||
FloorplanEditor.instance.tilemapRenderer.interactive = true;
|
||||
elementRef.current.appendChild(FloorplanEditor.instance.renderer.view);
|
||||
});
|
||||
|
||||
const onRoomOccupiedTilesMessageEvent = useCallback((event: RoomOccupiedTilesMessageEvent) =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
if(!parser) return;
|
||||
let newFloorPlanSettings: IFloorplanSettings = null;
|
||||
|
||||
const settings = Object.assign({}, originalFloorplanSettings);
|
||||
settings.reservedTiles = parser.blockedTilesMap;
|
||||
setOriginalFloorplanSettings(settings);
|
||||
setOriginalFloorplanSettings(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.reservedTiles = parser.blockedTilesMap;
|
||||
|
||||
newFloorPlanSettings = newValue;
|
||||
|
||||
return newValue;
|
||||
});
|
||||
|
||||
FloorplanEditor.instance.setTilemap(originalFloorplanSettings.tilemap, parser.blockedTilesMap);
|
||||
FloorplanEditor.instance.setTilemap(newFloorPlanSettings.tilemap, parser.blockedTilesMap);
|
||||
|
||||
setOccupiedTilesReceived(true);
|
||||
|
||||
elementRef.current.scrollTo(FloorplanEditor.instance.view.width / 3, 0);
|
||||
}, [originalFloorplanSettings, setOriginalFloorplanSettings]);
|
||||
elementRef.current.scrollTo((FloorplanEditor.instance.view.width / 3), 0);
|
||||
}, [ setOriginalFloorplanSettings ]);
|
||||
|
||||
UseMessageEventHook(RoomOccupiedTilesMessageEvent, onRoomOccupiedTilesMessageEvent);
|
||||
|
||||
@ -53,24 +51,33 @@ export const FloorplanCanvasView: FC<{}> = props =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
if(!parser) return;
|
||||
setOriginalFloorplanSettings(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
const settings = Object.assign({}, originalFloorplanSettings);
|
||||
settings.entryPoint = [parser.x, parser.y];
|
||||
settings.entryPointDir = parser.direction;
|
||||
setOriginalFloorplanSettings(settings);
|
||||
newValue.entryPoint = [ parser.x, parser.y ];
|
||||
newValue.entryPointDir = parser.direction;
|
||||
|
||||
const vSettings = Object.assign({}, visualizationSettings);
|
||||
vSettings.entryPointDir = parser.direction;
|
||||
setVisualizationSettings(vSettings);
|
||||
return newValue;
|
||||
});
|
||||
|
||||
setVisualizationSettings(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.entryPointDir = parser.direction;
|
||||
|
||||
return newValue;
|
||||
});
|
||||
|
||||
FloorplanEditor.instance.doorLocation = new NitroPoint(parser.x, parser.y);
|
||||
|
||||
setEntryTileReceived(true);
|
||||
}, [originalFloorplanSettings, setOriginalFloorplanSettings, setVisualizationSettings, visualizationSettings]);
|
||||
}, [ setOriginalFloorplanSettings, setVisualizationSettings ]);
|
||||
|
||||
UseMessageEventHook(RoomEntryTileMessageEvent, onRoomEntryTileMessageEvent);
|
||||
|
||||
const onClickArrowButton = useCallback((scrollDirection: string) =>
|
||||
const onClickArrowButton = (scrollDirection: string) =>
|
||||
{
|
||||
const element = elementRef.current;
|
||||
|
||||
@ -91,29 +98,92 @@ export const FloorplanCanvasView: FC<{}> = props =>
|
||||
element.scrollBy({ left: 10 });
|
||||
break;
|
||||
}
|
||||
}, []);
|
||||
}
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(entryTileReceived && occupiedTilesReceived)
|
||||
FloorplanEditor.instance.renderTiles();
|
||||
}, [entryTileReceived, occupiedTilesReceived])
|
||||
return () =>
|
||||
{
|
||||
FloorplanEditor.instance.clear();
|
||||
|
||||
setVisualizationSettings(prevValue =>
|
||||
{
|
||||
return {
|
||||
wallHeight: originalFloorplanSettings.wallHeight,
|
||||
thicknessWall: originalFloorplanSettings.thicknessWall,
|
||||
thicknessFloor: originalFloorplanSettings.thicknessFloor,
|
||||
entryPointDir: prevValue.entryPointDir
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [ originalFloorplanSettings.thicknessFloor, originalFloorplanSettings.thicknessWall, originalFloorplanSettings.wallHeight, setVisualizationSettings ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!entryTileReceived || !occupiedTilesReceived) return;
|
||||
|
||||
FloorplanEditor.instance.renderTiles();
|
||||
}, [ entryTileReceived, occupiedTilesReceived ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
SendMessageComposer(new GetRoomEntryTileMessageComposer());
|
||||
SendMessageComposer(new GetOccupiedTilesMessageComposer());
|
||||
|
||||
FloorplanEditor.instance.tilemapRenderer.interactive = true;
|
||||
|
||||
if(!elementRef.current) return;
|
||||
|
||||
elementRef.current.appendChild(FloorplanEditor.instance.renderer.view);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex className="align-items-center justify-content-center">
|
||||
<div className="arrow-button"><button className="btn btn-primary" onClick={() => onClickArrowButton('up')}><i className="fas fa-arrow-up"/></button></div>
|
||||
</Flex>
|
||||
<Flex className="align-items-center justify-content-center">
|
||||
<div className="arrow-button"><button className="btn btn-primary" onClick={() => onClickArrowButton('left')}><i className="fas fa-arrow-left"/></button></div>
|
||||
<div className="rounded-2 overflow-hidden">
|
||||
<div ref={elementRef} className="editor-area" />
|
||||
</div>
|
||||
<div className="arrow-button"><button className="btn btn-primary" onClick={() => onClickArrowButton('right')}><i className="fas fa-arrow-right"/></button></div>
|
||||
</Flex>
|
||||
<Flex className="align-items-center justify-content-center">
|
||||
<div className="arrow-button"><button className="btn btn-primary" onClick={() => onClickArrowButton('down')}><i className="fas fa-arrow-down"/></button></div>
|
||||
</Flex>
|
||||
</>
|
||||
<Column gap={ gap } { ...rest }>
|
||||
<Grid overflow="hidden" gap={ 1 }>
|
||||
<Column center size={ 1 }>
|
||||
<Button className="d-md-none" onClick={ event => onClickArrowButton('left') }>
|
||||
<FontAwesomeIcon icon="arrow-left" />
|
||||
</Button>
|
||||
</Column>
|
||||
<Column overflow="hidden" size={ 10 } gap={ 1 }>
|
||||
<Flex justifyContent="center" className="d-md-none">
|
||||
<Button shrink onClick={ event => onClickArrowButton('up') }>
|
||||
<FontAwesomeIcon icon="arrow-up" />
|
||||
</Button>
|
||||
</Flex>
|
||||
<Base overflow="auto" innerRef={ elementRef } />
|
||||
<Flex justifyContent="center" className="d-md-none">
|
||||
<Button shrink onClick={ event => onClickArrowButton('down') }>
|
||||
<FontAwesomeIcon icon="arrow-down" />
|
||||
</Button>
|
||||
</Flex>
|
||||
</Column>
|
||||
<Column center size={ 1 }>
|
||||
<Button className="d-md-none" onClick={ event => onClickArrowButton('right') }>
|
||||
<FontAwesomeIcon icon="arrow-right" />
|
||||
</Button>
|
||||
</Column>
|
||||
</Grid>
|
||||
{/* <Flex center className="d-md-none">
|
||||
<Button onClick={ event => onClickArrowButton('up') }>
|
||||
<FontAwesomeIcon icon="arrow-up" />
|
||||
</Button>
|
||||
</Flex>
|
||||
<Flex center gap={ 1 }>
|
||||
<Button className="d-md-none" onClick={ event => onClickArrowButton('left') }>
|
||||
<FontAwesomeIcon icon="arrow-left" />
|
||||
</Button>
|
||||
<Base overflow="auto" innerRef={ elementRef } />
|
||||
<Button className="d-md-none" onClick={ event => onClickArrowButton('right') }>
|
||||
<FontAwesomeIcon icon="arrow-right" />
|
||||
</Button>
|
||||
</Flex>
|
||||
<Flex center className="d-md-none">
|
||||
<Button onClick={ event => onClickArrowButton('down') }>
|
||||
<FontAwesomeIcon icon="arrow-down" />
|
||||
</Button>
|
||||
</Flex> */}
|
||||
{ children }
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
@ -1,29 +1,24 @@
|
||||
import { UpdateFloorPropertiesMessageComposer } from '@nitrots/nitro-renderer';
|
||||
import { FC, useCallback, useState } from 'react';
|
||||
import { FC, useState } from 'react';
|
||||
import { LocalizeText, SendMessageComposer } from '../../../api';
|
||||
import { Column, Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../common';
|
||||
import { Button, Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../common';
|
||||
import { UseMountEffect } from '../../../hooks';
|
||||
import { ConvertTileMapToString } from '../common/ConvertMapToString';
|
||||
import { convertNumbersForSaving } from '../common/Utils';
|
||||
import { useFloorplanEditorContext } from '../context/FloorplanEditorContext';
|
||||
import { useFloorplanEditorContext } from '../FloorplanEditorContext';
|
||||
|
||||
interface FloorplanImportExportViewProps
|
||||
{
|
||||
onCloseClick(): void;
|
||||
}
|
||||
|
||||
export const FloorplanImportExportView: FC<FloorplanImportExportViewProps> = props =>
|
||||
{
|
||||
const { originalFloorplanSettings = null, setOriginalFloorplanSettings = null } = useFloorplanEditorContext();
|
||||
|
||||
const { onCloseClick = null } = props;
|
||||
const [ map, setMap ] = useState<string>('');
|
||||
const { originalFloorplanSettings = null } = useFloorplanEditorContext();
|
||||
|
||||
const convertMapToString = useCallback((map: string) =>
|
||||
{
|
||||
return map.replace(/\r\n|\r|\n/g, '\n').toLowerCase();
|
||||
}, []);
|
||||
|
||||
const revertChanges= useCallback(() =>
|
||||
{
|
||||
setMap(convertMapToString(originalFloorplanSettings.tilemap));
|
||||
}, [convertMapToString, originalFloorplanSettings.tilemap]);
|
||||
|
||||
const saveFloorChanges = useCallback(() =>
|
||||
const saveFloorChanges = () =>
|
||||
{
|
||||
SendMessageComposer(new UpdateFloorPropertiesMessageComposer(
|
||||
map.split('\n').join('\r'),
|
||||
@ -34,35 +29,27 @@ export const FloorplanImportExportView: FC<FloorplanImportExportViewProps> = pro
|
||||
convertNumbersForSaving(originalFloorplanSettings.thicknessFloor),
|
||||
originalFloorplanSettings.wallHeight - 1
|
||||
));
|
||||
}, [map, originalFloorplanSettings.entryPoint, originalFloorplanSettings.entryPointDir, originalFloorplanSettings.thicknessFloor, originalFloorplanSettings.thicknessWall, originalFloorplanSettings.wallHeight]);
|
||||
}
|
||||
|
||||
UseMountEffect(() =>
|
||||
{
|
||||
revertChanges();
|
||||
setMap(ConvertTileMapToString(originalFloorplanSettings.tilemap));
|
||||
});
|
||||
|
||||
return (
|
||||
<NitroCardView theme="primary-slim" className="floorplan-import-export">
|
||||
<NitroCardHeaderView headerText={LocalizeText('floor.plan.editor.import.export')} onCloseClick={ onCloseClick } />
|
||||
<NitroCardHeaderView headerText={ LocalizeText('floor.plan.editor.import.export') } onCloseClick={ onCloseClick } />
|
||||
<NitroCardContentView>
|
||||
<Column size={ 12 } className="h-100">
|
||||
<textarea className="h-100" value={map} onChange={ event => setMap(event.target.value) }></textarea>
|
||||
<Flex className="justify-content-between">
|
||||
<div className="btn-group">
|
||||
<button className="btn btn-primary" onClick={revertChanges}>{LocalizeText('floor.plan.editor.revert.to.last.received.map')}</button>
|
||||
</div>
|
||||
<div className="btn-group">
|
||||
<button className="btn btn-primary" onClick={saveFloorChanges}>{LocalizeText('floor.plan.editor.save')}</button>
|
||||
</div>
|
||||
</Flex>
|
||||
</Column>
|
||||
|
||||
<textarea className="h-100" value={ map } onChange={ event => setMap(event.target.value) } />
|
||||
<Flex justifyContent="between">
|
||||
<Button onClick={ event => setMap(ConvertTileMapToString(originalFloorplanSettings.tilemap))}>
|
||||
{ LocalizeText('floor.plan.editor.revert.to.last.received.map') }
|
||||
</Button>
|
||||
<Button onClick={ saveFloorChanges }>
|
||||
{ LocalizeText('floor.plan.editor.save') }
|
||||
</Button>
|
||||
</Flex>
|
||||
</NitroCardContentView>
|
||||
</NitroCardView>
|
||||
)
|
||||
}
|
||||
|
||||
export interface FloorplanImportExportViewProps
|
||||
{
|
||||
onCloseClick(): void;
|
||||
);
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { FC, useCallback, useState } from 'react';
|
||||
import ReactSlider from 'react-slider';
|
||||
import { LocalizeText } from '../../../api';
|
||||
import { Base, Column, Flex, Grid, LayoutGridItem } from '../../../common';
|
||||
import { Column, Flex, LayoutGridItem, Text } from '../../../common';
|
||||
import { COLORMAP, FloorAction } from '../common/Constants';
|
||||
import { FloorplanEditor } from '../common/FloorplanEditor';
|
||||
import { useFloorplanEditorContext } from '../context/FloorplanEditorContext';
|
||||
import { useFloorplanEditorContext } from '../FloorplanEditorContext';
|
||||
|
||||
const MIN_WALL_HEIGHT: number = 0;
|
||||
const MAX_WALL_HEIGHT: number = 16;
|
||||
@ -111,77 +112,75 @@ export const FloorplanOptionsView: FC<{}> = props =>
|
||||
}
|
||||
|
||||
return (
|
||||
<Grid className="h-auto">
|
||||
<Column size={ 5 }>
|
||||
<Column gap={ 2 } overflow="hidden">
|
||||
<Base className="flex-shrink-0 fw-bold text-black text-truncate">{ LocalizeText('floor.plan.editor.draw.mode') }</Base>
|
||||
<Grid>
|
||||
<LayoutGridItem itemActive={ (floorAction === FloorAction.SET) } onClick={ event => selectAction(FloorAction.SET) }>
|
||||
<i className="icon icon-set-tile" />
|
||||
</LayoutGridItem>
|
||||
<LayoutGridItem itemActive={ (floorAction === FloorAction.UNSET) } onClick={ event => selectAction(FloorAction.UNSET) }>
|
||||
<i className="icon icon-unset-tile" />
|
||||
</LayoutGridItem>
|
||||
<LayoutGridItem itemActive={ (floorAction === FloorAction.UP) } onClick={ event => selectAction(FloorAction.UP) }>
|
||||
<i className="icon icon-increase-height" />
|
||||
</LayoutGridItem>
|
||||
<LayoutGridItem itemActive={ (floorAction === FloorAction.DOWN) } onClick={ event => selectAction(FloorAction.DOWN) }>
|
||||
<i className="icon icon-decrease-height" />
|
||||
</LayoutGridItem>
|
||||
<Column>
|
||||
<Flex gap={ 1 }>
|
||||
<Column size={ 5 } gap={ 1 }>
|
||||
<Text bold>{ LocalizeText('floor.plan.editor.draw.mode') }</Text>
|
||||
<Flex gap={ 3 }>
|
||||
<Flex gap={ 1 }>
|
||||
<LayoutGridItem itemActive={ (floorAction === FloorAction.SET) } onClick={ event => selectAction(FloorAction.SET) }>
|
||||
<i className="icon icon-set-tile" />
|
||||
</LayoutGridItem>
|
||||
<LayoutGridItem itemActive={ (floorAction === FloorAction.UNSET) } onClick={ event => selectAction(FloorAction.UNSET) }>
|
||||
<i className="icon icon-unset-tile" />
|
||||
</LayoutGridItem>
|
||||
</Flex>
|
||||
<Flex gap={ 1 }>
|
||||
<LayoutGridItem itemActive={ (floorAction === FloorAction.UP) } onClick={ event => selectAction(FloorAction.UP) }>
|
||||
<i className="icon icon-increase-height" />
|
||||
</LayoutGridItem>
|
||||
<LayoutGridItem itemActive={ (floorAction === FloorAction.DOWN) } onClick={ event => selectAction(FloorAction.DOWN) }>
|
||||
<i className="icon icon-decrease-height" />
|
||||
</LayoutGridItem>
|
||||
</Flex>
|
||||
<LayoutGridItem itemActive={ (floorAction === FloorAction.DOOR) } onClick={ event => selectAction(FloorAction.DOOR) }>
|
||||
<i className="icon icon-set-door" />
|
||||
</LayoutGridItem>
|
||||
</Grid>
|
||||
</Column>
|
||||
</Column>
|
||||
<Column className="align-items-center overflow-hidden" size={ 4 }>
|
||||
<Column gap={ 2 } overflow="hidden">
|
||||
<Base className="flex-shrink-0 fw-bold text-black text-truncate">{ LocalizeText('floor.plan.editor.enter.direction') }</Base>
|
||||
<i className={ `icon icon-door-direction-${ visualizationSettings.entryPointDir } cursor-pointer` } onClick={ changeDoorDirection } />
|
||||
</Column>
|
||||
</Column>
|
||||
<Column className="align-items-center" size={ 3 }>
|
||||
<Column gap={ 2 } overflow="hidden">
|
||||
<Base className="flex-shrink-0 fw-bold text-black text-truncate">{ LocalizeText('floor.editor.wall.height') }</Base>
|
||||
<Flex className="align-items-center">
|
||||
<i className="fas fa-caret-left cursor-pointer me-1 text-black" onClick={ decreaseWallHeight } />
|
||||
<input type="number" className="form-control form-control-sm quantity-input" value={ visualizationSettings.wallHeight } onChange={ event => onWallHeightChange(event.target.valueAsNumber)} />
|
||||
<i className="fas fa-caret-right cursor-pointer ms-1 text-black" onClick={ increaseWallHeight } />
|
||||
</Flex>
|
||||
</Column>
|
||||
</Column>
|
||||
<Column size={ 5 }>
|
||||
<Column gap={ 2 } overflow="hidden">
|
||||
<Base className="flex-shrink-0 fw-bold text-black text-truncate">{ LocalizeText('floor.plan.editor.tile.height') }: { floorHeight }</Base>
|
||||
<Column alignItems="center" size={ 4 }>
|
||||
<Text bold>{ LocalizeText('floor.plan.editor.enter.direction') }</Text>
|
||||
<i className={ `icon icon-door-direction-${ visualizationSettings.entryPointDir } cursor-pointer` } onClick={ changeDoorDirection } />
|
||||
</Column>
|
||||
<Column size={ 3 }>
|
||||
<Text bold>{ LocalizeText('floor.editor.wall.height') }</Text>
|
||||
<Flex alignItems="center" gap={ 1 }>
|
||||
<FontAwesomeIcon icon="caret-left" className="cursor-pointer" onClick={ decreaseWallHeight } />
|
||||
<input type="number" className="form-control form-control-sm quantity-input" value={ visualizationSettings.wallHeight } onChange={ event => onWallHeightChange(event.target.valueAsNumber)} />
|
||||
<FontAwesomeIcon icon="caret-right" className="cursor-pointer" onClick={ increaseWallHeight } />
|
||||
</Flex>
|
||||
</Column>
|
||||
</Flex>
|
||||
<Flex gap={ 1 }>
|
||||
<Column size={ 6 }>
|
||||
<Text bold>{ LocalizeText('floor.plan.editor.tile.height') }: { floorHeight }</Text>
|
||||
<ReactSlider
|
||||
className="nitro-slider"
|
||||
min={ MIN_FLOOR_HEIGHT }
|
||||
max={ MAX_FLOOR_HEIGHT }
|
||||
step={ 1 }
|
||||
value={ floorHeight }
|
||||
onChange={ event => onFloorHeightChange(event) }
|
||||
renderThumb={ ({ style, ...rest }, state) => <div style={ { backgroundColor: `#${COLORMAP[state.valueNow.toString(33)]}`, ...style } } { ...rest }>{ state.valueNow }</div> } />
|
||||
className="nitro-slider"
|
||||
min={ MIN_FLOOR_HEIGHT }
|
||||
max={ MAX_FLOOR_HEIGHT }
|
||||
step={ 1 }
|
||||
value={ floorHeight }
|
||||
onChange={ event => onFloorHeightChange(event) }
|
||||
renderThumb={ ({ style, ...rest }, state) => <div style={ { backgroundColor: `#${COLORMAP[state.valueNow.toString(33)]}`, ...style } } { ...rest }>{ state.valueNow }</div> } />
|
||||
</Column>
|
||||
</Column>
|
||||
<Column size={5}>
|
||||
<Column gap={ 2 } overflow="hidden">
|
||||
<Base className="flex-shrink-0 fw-bold text-black text-truncate">{ LocalizeText('floor.plan.editor.room.options') }</Base>
|
||||
<Flex className="align-items-center">
|
||||
<select className="form-control form-control-sm" value={visualizationSettings.thicknessWall} onChange={event => onWallThicknessChange(parseInt(event.target.value))}>
|
||||
<option value={0}>{ LocalizeText('navigator.roomsettings.wall_thickness.thinnest') }</option>
|
||||
<option value={1}>{ LocalizeText('navigator.roomsettings.wall_thickness.thin') }</option>
|
||||
<option value={2}>{ LocalizeText('navigator.roomsettings.wall_thickness.normal') }</option>
|
||||
<option value={3}>{ LocalizeText('navigator.roomsettings.wall_thickness.thick') }</option>
|
||||
</select>
|
||||
<select className="form-control form-control-sm" value={visualizationSettings.thicknessFloor} onChange={event => onFloorThicknessChange(parseInt(event.target.value))}>
|
||||
<option value={0}>{ LocalizeText('navigator.roomsettings.floor_thickness.thinnest') }</option>
|
||||
<option value={1}>{ LocalizeText('navigator.roomsettings.floor_thickness.thin') }</option>
|
||||
<option value={2}>{ LocalizeText('navigator.roomsettings.floor_thickness.normal') }</option>
|
||||
<option value={3}>{ LocalizeText('navigator.roomsettings.floor_thickness.thick') }</option>
|
||||
</select>
|
||||
</Flex>
|
||||
<Column size={ 6 }>
|
||||
<Text bold>{ LocalizeText('floor.plan.editor.room.options') }</Text>
|
||||
<Flex className="align-items-center">
|
||||
<select className="form-control form-control-sm" value={ visualizationSettings.thicknessWall } onChange={ event => onWallThicknessChange(parseInt(event.target.value)) }>
|
||||
<option value={ 0 }>{ LocalizeText('navigator.roomsettings.wall_thickness.thinnest') }</option>
|
||||
<option value={ 1 }>{ LocalizeText('navigator.roomsettings.wall_thickness.thin') }</option>
|
||||
<option value={ 2 }>{ LocalizeText('navigator.roomsettings.wall_thickness.normal') }</option>
|
||||
<option value={ 3 }>{ LocalizeText('navigator.roomsettings.wall_thickness.thick') }</option>
|
||||
</select>
|
||||
<select className="form-control form-control-sm" value={ visualizationSettings.thicknessFloor } onChange={ event => onFloorThicknessChange(parseInt(event.target.value)) }>
|
||||
<option value={ 0 }>{ LocalizeText('navigator.roomsettings.floor_thickness.thinnest') }</option>
|
||||
<option value={ 1 }>{ LocalizeText('navigator.roomsettings.floor_thickness.thin') }</option>
|
||||
<option value={ 2 }>{ LocalizeText('navigator.roomsettings.floor_thickness.normal') }</option>
|
||||
<option value={ 3 }>{ LocalizeText('navigator.roomsettings.floor_thickness.thick') }</option>
|
||||
</select>
|
||||
</Flex>
|
||||
</Column>
|
||||
</Column>
|
||||
</Grid>
|
||||
</Flex>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user