diff --git a/src/views/floorplan-editor/FloorplanEditorView.scss b/src/views/floorplan-editor/FloorplanEditorView.scss index 356af6d1..b11b5107 100644 --- a/src/views/floorplan-editor/FloorplanEditorView.scss +++ b/src/views/floorplan-editor/FloorplanEditorView.scss @@ -5,6 +5,17 @@ .editor-area { width: 100%; height: 300px; + min-height: 300px; overflow-x: scroll; } + + .color { + height: 50px; + width: 10px; + } +} + +.floorplan-import-export { + width: 500px; + height: 475px; } diff --git a/src/views/floorplan-editor/FloorplanEditorView.tsx b/src/views/floorplan-editor/FloorplanEditorView.tsx index 49c7dddd..6006e8c1 100644 --- a/src/views/floorplan-editor/FloorplanEditorView.tsx +++ b/src/views/floorplan-editor/FloorplanEditorView.tsx @@ -1,20 +1,29 @@ -import { FloorHeightMapEvent, RoomVisualizationSettingsEvent, UpdateFloorPropertiesMessageComposer } from '@nitrots/nitro-renderer'; +import { FloorHeightMapEvent, NitroPoint, RoomVisualizationSettingsEvent, UpdateFloorPropertiesMessageComposer } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; import { LocalizeText } from '../../api'; import { FloorplanEditorEvent } from '../../events/floorplan-editor/FloorplanEditorEvent'; import { CreateMessageHook, SendMessageHook, useUiEvent } from '../../hooks'; -import { NitroCardContentView, NitroCardHeaderView, NitroCardView, NitroLayoutGrid, NitroLayoutGridColumn } from '../../layout'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardView, NitroLayoutFlex, NitroLayoutGrid, NitroLayoutGridColumn } from '../../layout'; import { FloorplanEditor } from './common/FloorplanEditor'; import { convertNumbersForSaving, convertSettingToNumber } from './common/Utils'; import { FloorplanEditorContextProvider } from './context/FloorplanEditorContext'; -import { IFloorplanSettings, initialFloorplanSettings } from './context/FloorplanEditorContext.types'; +import { IFloorplanSettings, initialFloorplanSettings, IVisualizationSettings } from './context/FloorplanEditorContext.types'; 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 [floorplanSettings, setFloorplanSettings ] = useState(initialFloorplanSettings); + const [ importExportVisible, setImportExportVisible ] = useState(false); + const [originalFloorplanSettings, setOriginalFloorplanSettings] = useState(initialFloorplanSettings); + const [visualizationSettings, setVisualizationSettings] = useState( + { + entryPointDir: 2, + wallHeight: -1, + thicknessWall: 1, + thicknessFloor: 1 + }); const onFloorplanEditorEvent = useCallback((event: FloorplanEditorEvent) => { @@ -47,11 +56,16 @@ export const FloorplanEditorView: FC<{}> = props => if(!parser) return; - const settings = Object.assign({}, floorplanSettings); + const settings = Object.assign({}, originalFloorplanSettings); settings.tilemap = parser.model; settings.wallHeight = parser.wallHeight + 1; - setFloorplanSettings(settings); - }, [floorplanSettings]); + setOriginalFloorplanSettings(settings); + + const vSettings = Object.assign({}, visualizationSettings); + vSettings.wallHeight = parser.wallHeight + 1; + setVisualizationSettings(vSettings); + + }, [originalFloorplanSettings, visualizationSettings]); CreateMessageHook(FloorHeightMapEvent, onFloorHeightMapEvent); @@ -61,12 +75,17 @@ export const FloorplanEditorView: FC<{}> = props => if(!parser) return; - const settings = Object.assign({}, floorplanSettings); - settings.thicknessFloor = convertSettingToNumber(parser.thicknessFloor) + const settings = Object.assign({}, originalFloorplanSettings); + settings.thicknessFloor = convertSettingToNumber(parser.thicknessFloor); settings.thicknessWall = convertSettingToNumber(parser.thicknessWall); - setFloorplanSettings(settings); - }, [floorplanSettings]); + setOriginalFloorplanSettings(settings); + + const vSettings = Object.assign({}, visualizationSettings); + vSettings.thicknessFloor = convertSettingToNumber(parser.thicknessFloor); + vSettings.thicknessWall = convertSettingToNumber(parser.thicknessWall); + setVisualizationSettings(vSettings); + }, [originalFloorplanSettings, visualizationSettings]); CreateMessageHook(RoomVisualizationSettingsEvent, onRoomVisualizationSettingsEvent); @@ -74,42 +93,53 @@ export const FloorplanEditorView: FC<{}> = props => { SendMessageHook(new UpdateFloorPropertiesMessageComposer( FloorplanEditor.instance.getCurrentTilemapString(), - floorplanSettings.entryPoint[0], - floorplanSettings.entryPoint[1], - floorplanSettings.entryPointDir, - convertNumbersForSaving(floorplanSettings.thicknessWall), - convertNumbersForSaving(floorplanSettings.thicknessFloor), - floorplanSettings.wallHeight - 1 + FloorplanEditor.instance.doorLocation.x, + FloorplanEditor.instance.doorLocation.y, + visualizationSettings.entryPointDir, + convertNumbersForSaving(visualizationSettings.thicknessWall), + convertNumbersForSaving(visualizationSettings.thicknessFloor), + visualizationSettings.wallHeight - 1 )); - }, [floorplanSettings.entryPoint, floorplanSettings.entryPointDir, floorplanSettings.thicknessFloor, floorplanSettings.thicknessWall, floorplanSettings.wallHeight]); + }, [visualizationSettings.entryPointDir, visualizationSettings.thicknessFloor, visualizationSettings.thicknessWall, visualizationSettings.wallHeight]); + + const revertChanges = useCallback(() => + { + 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]) return ( <> - - {isVisible && - - setIsVisible(false)} /> - - - - - - - - {/*
-
- -
-
- - - -
-
*/} -
-
- } -
+ + {isVisible && <> + + setIsVisible(false)} /> + + + + + + +
+ +
+
+ + + +
+
+
+
+
+
+ {importExportVisible && setImportExportVisible(false)}/>} + + } +
); } diff --git a/src/views/floorplan-editor/common/Constants.ts b/src/views/floorplan-editor/common/Constants.ts index 717f40d0..8f52f282 100644 --- a/src/views/floorplan-editor/common/Constants.ts +++ b/src/views/floorplan-editor/common/Constants.ts @@ -11,3 +11,34 @@ export class FloorAction public static readonly SET = 3; public static readonly UNSET = 4; } + +export const COLORMAP: object = { + 'x': '101010', + '0': '0065ff', + '1': '0091ff', + '2': '00bcff', + '3': '00e8ff', + '4': '00ffea', + '5': '00ffbf', + '6': '00ff93', + '7': '00ff68', + '8': '00ff3d', + '9': '19ff00', + 'a': '44ff00', + 'b': '70ff00', + 'c': '9bff00', + 'd': 'f2ff00', + 'e': 'ffe000', + 'f': 'ffb500', + 'g': 'ff8900', + 'h': 'ff5e00', + 'i': 'ff3200', + 'j': 'ff0700', + 'k': 'ff0023', + 'l': 'ff007a', + 'm': 'ff00a5', + 'n': 'ff00d1', + 'o': 'ff00fc', + 'p': 'd600ff', + 'q': 'aa00ff' +}; diff --git a/src/views/floorplan-editor/context/FloorplanEditorContext.tsx b/src/views/floorplan-editor/context/FloorplanEditorContext.tsx index 613c6fe6..8a8ce970 100644 --- a/src/views/floorplan-editor/context/FloorplanEditorContext.tsx +++ b/src/views/floorplan-editor/context/FloorplanEditorContext.tsx @@ -2,8 +2,10 @@ import { createContext, FC, useContext } from 'react'; import { FloorplanEditorContextProps, IFloorplanEditorContext } from './FloorplanEditorContext.types'; const FloorplanEditorContext = createContext({ - floorplanSettings: null, - setFloorplanSettings: null + originalFloorplanSettings: null, + setOriginalFloorplanSettings: null, + visualizationSettings: null, + setVisualizationSettings: null }); export const FloorplanEditorContextProvider: FC = props => diff --git a/src/views/floorplan-editor/context/FloorplanEditorContext.types.ts b/src/views/floorplan-editor/context/FloorplanEditorContext.types.ts index c6d8eb66..581ff6af 100644 --- a/src/views/floorplan-editor/context/FloorplanEditorContext.types.ts +++ b/src/views/floorplan-editor/context/FloorplanEditorContext.types.ts @@ -2,14 +2,19 @@ import { ProviderProps } from 'react'; export interface IFloorplanEditorContext { - floorplanSettings: IFloorplanSettings; - setFloorplanSettings: React.Dispatch>; + originalFloorplanSettings: IFloorplanSettings; + setOriginalFloorplanSettings: React.Dispatch>; + visualizationSettings: IVisualizationSettings; + setVisualizationSettings: React.Dispatch>; } -export interface IFloorplanSettings { +export interface IFloorplanSettings extends IVisualizationSettings { tilemap: string; reservedTiles: boolean[][]; entryPoint: [number, number]; +} + +export interface IVisualizationSettings { entryPointDir: number; wallHeight: number; thicknessWall: number; diff --git a/src/views/floorplan-editor/views/FloorplanCanvasView.tsx b/src/views/floorplan-editor/views/FloorplanCanvasView.tsx index a6f9969c..f9640a2c 100644 --- a/src/views/floorplan-editor/views/FloorplanCanvasView.tsx +++ b/src/views/floorplan-editor/views/FloorplanCanvasView.tsx @@ -6,7 +6,7 @@ import { useFloorplanEditorContext } from '../context/FloorplanEditorContext'; export const FloorplanCanvasView: FC<{}> = props => { - const { floorplanSettings = null, setFloorplanSettings = null } = useFloorplanEditorContext(); + const { originalFloorplanSettings = null, setOriginalFloorplanSettings = null, visualizationSettings = null, setVisualizationSettings = null } = useFloorplanEditorContext(); const [ occupiedTilesReceived , setOccupiedTilesReceived ] = useState(false); const [ entryTileReceived, setEntryTileReceived ] = useState(false); const elementRef = useRef(null); @@ -21,8 +21,9 @@ export const FloorplanCanvasView: FC<{}> = props => 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]); const onRoomOccupiedTilesMessageEvent = useCallback((event: RoomOccupiedTilesMessageEvent) => { @@ -30,16 +31,16 @@ export const FloorplanCanvasView: FC<{}> = props => if(!parser) return; - const settings = Object.assign({}, floorplanSettings); + const settings = Object.assign({}, originalFloorplanSettings); settings.reservedTiles = parser.blockedTilesMap; - setFloorplanSettings(settings); + setOriginalFloorplanSettings(settings); - FloorplanEditor.instance.setTilemap(floorplanSettings.tilemap, parser.blockedTilesMap); + FloorplanEditor.instance.setTilemap(originalFloorplanSettings.tilemap, parser.blockedTilesMap); setOccupiedTilesReceived(true); elementRef.current.scrollTo(FloorplanEditor.instance.view.width / 3, 0); - }, [floorplanSettings, setFloorplanSettings]); + }, [originalFloorplanSettings, setOriginalFloorplanSettings]); CreateMessageHook(RoomOccupiedTilesMessageEvent, onRoomOccupiedTilesMessageEvent); @@ -49,14 +50,18 @@ export const FloorplanCanvasView: FC<{}> = props => if(!parser) return; - const settings = Object.assign({}, floorplanSettings); + const settings = Object.assign({}, originalFloorplanSettings); settings.entryPoint = [parser.x, parser.y]; settings.entryPointDir = parser.direction; - setFloorplanSettings(settings); + setOriginalFloorplanSettings(settings); + + const vSettings = Object.assign({}, visualizationSettings); + vSettings.entryPointDir = parser.direction; + setVisualizationSettings(vSettings); - FloorplanEditor.instance.doorLocation = new NitroPoint(settings.entryPoint[0], settings.entryPoint[1]); + FloorplanEditor.instance.doorLocation = new NitroPoint(parser.x, parser.y); setEntryTileReceived(true); - }, [floorplanSettings, setFloorplanSettings]); + }, [originalFloorplanSettings, setOriginalFloorplanSettings, setVisualizationSettings, visualizationSettings]); CreateMessageHook(RoomEntryTileMessageEvent, onRoomEntryTileMessageEvent); diff --git a/src/views/floorplan-editor/views/FloorplanImportExportView.tsx b/src/views/floorplan-editor/views/FloorplanImportExportView.tsx new file mode 100644 index 00000000..c707ff15 --- /dev/null +++ b/src/views/floorplan-editor/views/FloorplanImportExportView.tsx @@ -0,0 +1,68 @@ +import { UpdateFloorPropertiesMessageComposer } from '@nitrots/nitro-renderer'; +import { FC, useCallback, useEffect, useState } from 'react'; +import { LocalizeText } from '../../../api'; +import { SendMessageHook } from '../../../hooks'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardView, NitroLayoutFlex, NitroLayoutGridColumn } from '../../../layout'; +import { convertNumbersForSaving } from '../common/Utils'; +import { useFloorplanEditorContext } from '../context/FloorplanEditorContext'; + +export const FloorplanImportExportView: FC = props => +{ + const { originalFloorplanSettings = null, setOriginalFloorplanSettings = null } = useFloorplanEditorContext(); + + const { onCloseClick = null } = props; + const [ map, setMap ] = useState(''); + + 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(() => + { + SendMessageHook(new UpdateFloorPropertiesMessageComposer( + map.split('\n').join('\r'), + originalFloorplanSettings.entryPoint[0], + originalFloorplanSettings.entryPoint[1], + originalFloorplanSettings.entryPointDir, + convertNumbersForSaving(originalFloorplanSettings.thicknessWall), + convertNumbersForSaving(originalFloorplanSettings.thicknessFloor), + originalFloorplanSettings.wallHeight - 1 + )); + }, [map, originalFloorplanSettings.entryPoint, originalFloorplanSettings.entryPointDir, originalFloorplanSettings.thicknessFloor, originalFloorplanSettings.thicknessWall, originalFloorplanSettings.wallHeight]); + + useEffect(() => + { + revertChanges(); + }, [revertChanges]); + + return ( + + + + + + +
+ +
+
+ +
+
+
+ +
+
+ ) +} + +export interface FloorplanImportExportViewProps +{ + onCloseClick(): void; +} diff --git a/src/views/floorplan-editor/views/FloorplanOptionsView.tsx b/src/views/floorplan-editor/views/FloorplanOptionsView.tsx index e15229cc..0c6fc18a 100644 --- a/src/views/floorplan-editor/views/FloorplanOptionsView.tsx +++ b/src/views/floorplan-editor/views/FloorplanOptionsView.tsx @@ -1,18 +1,23 @@ import { FC, useCallback, useState } from 'react'; +import ReactSlider from 'react-slider'; import { LocalizeText } from '../../../api'; import { NitroCardGridItemView, NitroCardGridView, NitroLayoutFlex, NitroLayoutFlexColumn, NitroLayoutGrid, NitroLayoutGridColumn } from '../../../layout'; import { NitroLayoutBase } from '../../../layout/base'; -import { FloorAction } from '../common/Constants'; +import { COLORMAP, FloorAction } from '../common/Constants'; import { FloorplanEditor } from '../common/FloorplanEditor'; import { useFloorplanEditorContext } from '../context/FloorplanEditorContext'; const MIN_WALL_HEIGHT: number = 0; const MAX_WALL_HEIGHT: number = 16; +const MIN_FLOOR_HEIGHT: number = 0; +const MAX_FLOOR_HEIGHT: number = 26; + export const FloorplanOptionsView: FC<{}> = props => { - const { floorplanSettings = null, setFloorplanSettings = null } = useFloorplanEditorContext(); + const { visualizationSettings = null, setVisualizationSettings = null } = useFloorplanEditorContext(); const [ floorAction, setFloorAction ] = useState(FloorAction.SET); + const [ floorHeight, setFloorHeight ] = useState(0); const selectAction = useCallback((action: number) => { @@ -22,7 +27,7 @@ export const FloorplanOptionsView: FC<{}> = props => const changeDoorDirection = useCallback(() => { - setFloorplanSettings(prevValue => + setVisualizationSettings(prevValue => { const newValue = Object.assign({}, prevValue); @@ -37,7 +42,40 @@ export const FloorplanOptionsView: FC<{}> = props => return newValue; }); - }, [ setFloorplanSettings ]); + }, [ setVisualizationSettings ]); + + const onFloorHeightChange = useCallback((value: number) => + { + if(isNaN(value) || (value <= 0)) value = 0; + + if(value > 26) value = 26; + + setFloorHeight(value); + + FloorplanEditor.instance.actionSettings.currentHeight = value.toString(36); + }, []); + + const onFloorThicknessChange = useCallback((value: number) => + { + setVisualizationSettings(prevValue => + { + const newValue = Object.assign({}, prevValue); + newValue.thicknessFloor = value; + + return newValue; + }); + }, [setVisualizationSettings]); + + const onWallThicknessChange = useCallback((value: number) => + { + setVisualizationSettings(prevValue => + { + const newValue = Object.assign({}, prevValue); + newValue.thicknessWall = value; + + return newValue; + }); + }, [setVisualizationSettings]); const onWallHeightChange = useCallback((value: number) => { @@ -45,7 +83,7 @@ export const FloorplanOptionsView: FC<{}> = props => if(value > MAX_WALL_HEIGHT) value = MAX_WALL_HEIGHT; - setFloorplanSettings(prevValue => + setVisualizationSettings(prevValue => { const newValue = Object.assign({}, prevValue); @@ -53,11 +91,11 @@ export const FloorplanOptionsView: FC<{}> = props => return newValue; }); - }, [ setFloorplanSettings ]); + }, [ setVisualizationSettings ]); function increaseWallHeight(): void { - let height = (floorplanSettings.wallHeight + 1); + let height = (visualizationSettings.wallHeight + 1); if(height > MAX_WALL_HEIGHT) height = MAX_WALL_HEIGHT; @@ -66,7 +104,7 @@ export const FloorplanOptionsView: FC<{}> = props => function decreaseWallHeight(): void { - let height = (floorplanSettings.wallHeight - 1); + let height = (visualizationSettings.wallHeight - 1); if(height <= 0) height = MIN_WALL_HEIGHT; @@ -97,10 +135,10 @@ export const FloorplanOptionsView: FC<{}> = props => - + { LocalizeText('floor.plan.editor.enter.direction') } - + @@ -108,41 +146,43 @@ export const FloorplanOptionsView: FC<{}> = props => { LocalizeText('floor.editor.wall.height') } - onWallHeightChange(event.target.valueAsNumber)} /> + onWallHeightChange(event.target.valueAsNumber)} /> + + + { LocalizeText('floor.plan.editor.tile.height') }: { floorHeight } + onFloorHeightChange(event) } + renderThumb={ ({ style, ...rest }, state) =>
{ state.valueNow }
} /> +
+
+ + + { LocalizeText('floor.plan.editor.room.options') } + + + + + + - // - // - // - // <> - //
- //
- // - // - // selectAction(FloorAction.SET)} className="tile-option set-tile" /> - // selectAction(FloorAction.UNSET)} className="tile-option unset-tile" /> - // selectAction(FloorAction.UP)} className="tile-option increase-height" /> - // selectAction(FloorAction.DOWN)} className="tile-option decrease-height" /> - // selectAction(FloorAction.DOOR)} className="tile-option set-door" /> - // - //
- //
- //
- // - // - //
- //
- // - // onWallHeightChange(event.target.valueAsNumber)} id="wallHeight"/> - //
- //
- //
- //
- - //
- // ); }