diff --git a/app/src/components/layout/scenes/MainScene.tsx b/app/src/components/layout/scenes/MainScene.tsx
index 350c9e9..cc88095 100644
--- a/app/src/components/layout/scenes/MainScene.tsx
+++ b/app/src/components/layout/scenes/MainScene.tsx
@@ -1,13 +1,12 @@
import React, { useEffect } from "react";
import {
- useLoadingProgress,
- useRenameModeStore,
- useSaveVersion,
- useSelectedAssets,
- useSelectedComment,
- useSelectedFloorItem,
- useSocketStore,
- useWidgetSubOption,
+ useLoadingProgress,
+ useRenameModeStore,
+ useSaveVersion,
+ useSelectedAssets,
+ useSelectedComment,
+ useSocketStore,
+ useWidgetSubOption,
} from "../../../store/builder/store";
import useModuleStore, { useThreeDStore } from "../../../store/useModuleStore";
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
@@ -27,10 +26,7 @@ import ControlsPlayer from "../controls/ControlsPlayer";
import SelectFloorPlan from "../../temporary/SelectFloorPlan";
import { createHandleDrop } from "../../../modules/visualization/functions/handleUiDrop";
import Scene from "../../../modules/scene/scene";
-import {
- useComparisonProduct,
- useMainProduct,
-} from "../../../store/simulation/useSimulationStore";
+import { useComparisonProduct, useMainProduct } from "../../../store/simulation/useSimulationStore";
import { useProductContext } from "../../../modules/simulation/products/productContext";
import RegularDropDown from "../../ui/inputs/RegularDropDown";
import RenameTooltip from "../../ui/features/RenameTooltip";
@@ -42,184 +38,173 @@ import { useVersionContext } from "../../../modules/builder/version/versionConte
import VersionSaved from "../sidebarRight/versionHisory/VersionSaved";
import Footer from "../../footer/Footer";
import ThreadChat from "../../ui/collaboration/ThreadChat";
+import { useBuilderStore } from "../../../store/builder/useBuilderStore";
function MainScene() {
- const { setMainProduct } = useMainProduct();
- const { selectedProductStore } = useProductContext();
- const { selectedProduct } = selectedProductStore();
- const { isVersionSaved, setIsVersionSaved } = useSaveVersion();
- const { activeModule } = useModuleStore();
- const { selectedUser } = useSelectedUserStore();
- const { loadingProgress } = useLoadingProgress();
- const { toggleThreeD } = useThreeDStore();
- const { isPlaying } = usePlayButtonStore();
- const { widgetSubOption } = useWidgetSubOption();
- const { visualizationSocket } = useSocketStore();
- const { selectedZone } = useSelectedZoneStore();
- const { setFloatingWidget } = useFloatingWidget();
- const { clearComparisonProduct } = useComparisonProduct();
- const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
- const { selectedAssets, setSelectedAssets } = useSelectedAssets();
- const { assetStore, productStore } = useSceneContext();
- const { products } = productStore();
- const { setName } = assetStore();
- const { projectId } = useParams()
- const { isRenameMode, setIsRenameMode } = useRenameModeStore();
- const { versionHistory } = useVersionHistoryStore();
- const { selectedVersionStore } = useVersionContext();
- const { selectedVersion, setSelectedVersion } = selectedVersionStore();
- const { selectedComment, commentPositionState } = useSelectedComment();
+ const { setMainProduct } = useMainProduct();
+ const { selectedProductStore } = useProductContext();
+ const { selectedProduct } = selectedProductStore();
+ const { isVersionSaved, setIsVersionSaved } = useSaveVersion();
+ const { activeModule } = useModuleStore();
+ const { selectedUser } = useSelectedUserStore();
+ const { loadingProgress } = useLoadingProgress();
+ const { toggleThreeD } = useThreeDStore();
+ const { isPlaying } = usePlayButtonStore();
+ const { widgetSubOption } = useWidgetSubOption();
+ const { visualizationSocket } = useSocketStore();
+ const { selectedZone } = useSelectedZoneStore();
+ const { setFloatingWidget } = useFloatingWidget();
+ const { clearComparisonProduct } = useComparisonProduct();
+ const { selectedFloorAsset, setSelectedFloorAsset } = useBuilderStore();
+ const { selectedAssets, setSelectedAssets } = useSelectedAssets();
+ const { assetStore, productStore } = useSceneContext();
+ const { products } = productStore();
+ const { setName } = assetStore();
+ const { projectId } = useParams()
+ const { isRenameMode, setIsRenameMode } = useRenameModeStore();
+ const { versionHistory } = useVersionHistoryStore();
+ const { selectedVersionStore } = useVersionContext();
+ const { selectedVersion, setSelectedVersion } = selectedVersionStore();
+ const { selectedComment, commentPositionState } = useSelectedComment();
- useEffect(() => {
- if (activeModule !== 'simulation') {
- clearComparisonProduct();
- setIsVersionSaved(false);
- }
- }, [activeModule, clearComparisonProduct, setIsVersionSaved])
-
- useEffect(() => {
- if (versionHistory.length > 0) {
- setSelectedVersion(versionHistory[0])
- }
- }, [setSelectedVersion, versionHistory])
-
- const handleSelectVersion = (option: string) => {
- const version = versionHistory.find((version) => version.versionName === option);
- if (version) {
- setSelectedVersion(version);
- }
- };
-
- const handleSelectProduct = (option: string) => {
- const product = products.find((product) => product.productName === option);
- if (product) {
- setMainProduct(product.productUuid, product.productName);
- }
- };
-
- const handleObjectRename = async (newName: string) => {
- if (!projectId) return
- if (selectedFloorItem) {
- console.log('selectedFloorItem.userData.modelUuid: ', selectedFloorItem.userData.modelUuid);
- console.log(' newName: ', newName);
- console.log('projectId: ', projectId);
- setAssetsApi({
- modelUuid: selectedFloorItem.userData.modelUuid,
- modelName: newName,
- projectId,
- versionId: selectedVersion?.versionId || ''
- }).then(() => {
- selectedFloorItem.userData = {
- ...selectedFloorItem.userData,
- modelName: newName
- };
- setSelectedFloorItem(selectedFloorItem);
- setIsRenameMode(false);
- setName(selectedFloorItem.userData.modelUuid, newName);
- })
- } else if (selectedAssets.length === 1) {
- setAssetsApi({
- modelUuid: selectedAssets[0].userData.modelUuid,
- modelName: newName,
- projectId,
- versionId: selectedVersion?.versionId || ''
- }).then(() => {
- selectedAssets[0].userData = {
- ...selectedAssets[0].userData,
- modelName: newName
- };
- setSelectedAssets(selectedAssets);
- setIsRenameMode(false);
- setName(selectedAssets[0].userData.modelUuid, newName);
- })
- }
- }
-
- return (
- <>
- {!selectedUser && (
- <>
-
- {loadingProgress > 0 && }
- {!isPlaying && (
- <>
- {toggleThreeD && !isVersionSaved && }
-
-
- >
- )}
-
- {activeModule === "market" && }
- {activeModule !== "market" && !isPlaying && !isVersionSaved && (
-
- )}
- {(isPlaying) &&
- activeModule === "simulation" &&
- loadingProgress === 0 && }
- {(isPlaying) &&
- activeModule !== "simulation" && }
-
- {isRenameMode && (selectedFloorItem?.userData.modelName || selectedAssets.length === 1) && }
- {/* remove this later */}
- {activeModule === "builder" && !toggleThreeD && }
- >
- )}
-
- createHandleDrop({
- widgetSubOption,
- visualizationSocket,
- selectedZone,
- setFloatingWidget,
- event,
- projectId,
- versionId: selectedVersion?.versionId || '',
- })
+ useEffect(() => {
+ if (activeModule !== 'simulation') {
+ clearComparisonProduct();
+ setIsVersionSaved(false);
}
- onDragOver={(event) => event.preventDefault()}
- >
-
-
+ }, [activeModule, clearComparisonProduct, setIsVersionSaved])
- {selectedProduct && selectedVersion && isVersionSaved && !isPlaying && activeModule === "simulation" && (
-
- v.versionName)} // Pass layout names as options
- onSelect={handleSelectVersion}
- search={false}
- />
-
- l.productName)} // Pass layout names as options
- onSelect={handleSelectProduct}
- search={false}
- />
-
- )}
+ useEffect(() => {
+ if (versionHistory.length > 0) {
+ setSelectedVersion(versionHistory[0])
+ }
+ }, [setSelectedVersion, versionHistory])
- {activeModule !== "market" && !selectedUser && }
+ const handleSelectVersion = (option: string) => {
+ const version = versionHistory.find((version) => version.versionName === option);
+ if (version) {
+ setSelectedVersion(version);
+ }
+ };
-
+ const handleSelectProduct = (option: string) => {
+ const product = products.find((product) => product.productName === option);
+ if (product) {
+ setMainProduct(product.productUuid, product.productName);
+ }
+ };
- {
- (commentPositionState !== null || selectedComment !== null) &&
-
- }
+ const handleObjectRename = async (newName: string) => {
+ if (!projectId) return
+ if (selectedFloorAsset) {
+ setAssetsApi({
+ modelUuid: selectedFloorAsset.userData.modelUuid,
+ modelName: newName,
+ projectId,
+ versionId: selectedVersion?.versionId || ''
+ }).then(() => {
+ selectedFloorAsset.userData = { ...selectedFloorAsset.userData, modelName: newName };
+ setSelectedFloorAsset(selectedFloorAsset);
+ setIsRenameMode(false);
+ setName(selectedFloorAsset.userData.modelUuid, newName);
+ })
+ } else if (selectedAssets.length === 1) {
+ setAssetsApi({
+ modelUuid: selectedAssets[0].userData.modelUuid,
+ modelName: newName,
+ projectId,
+ versionId: selectedVersion?.versionId || ''
+ }).then(() => {
+ selectedAssets[0].userData = { ...selectedAssets[0].userData, modelName: newName };
+ setSelectedAssets(selectedAssets);
+ setIsRenameMode(false);
+ setName(selectedAssets[0].userData.modelUuid, newName);
+ })
+ }
+ }
- >
- );
+ return (
+ <>
+ {!selectedUser && (
+ <>
+
+ {loadingProgress > 0 && }
+ {!isPlaying && (
+ <>
+ {toggleThreeD && !isVersionSaved && }
+
+
+ >
+ )}
+
+ {activeModule === "market" && }
+ {activeModule !== "market" && !isPlaying && !isVersionSaved && (
+
+ )}
+ {(isPlaying) && activeModule === "simulation" && loadingProgress === 0 && }
+ {(isPlaying) && activeModule !== "simulation" && }
+
+ {isRenameMode && (selectedFloorAsset?.userData.modelName || selectedAssets.length === 1) && }
+ {/* remove this later */}
+ {activeModule === "builder" && !toggleThreeD && }
+ >
+ )}
+
+ createHandleDrop({
+ widgetSubOption,
+ visualizationSocket,
+ selectedZone,
+ setFloatingWidget,
+ event,
+ projectId,
+ versionId: selectedVersion?.versionId || '',
+ })
+ }
+ onDragOver={(event) => event.preventDefault()}
+ >
+
+
+
+ {selectedProduct && selectedVersion && isVersionSaved && !isPlaying && activeModule === "simulation" && (
+
+ v.versionName)} // Pass layout names as options
+ onSelect={handleSelectVersion}
+ search={false}
+ />
+
+ l.productName)} // Pass layout names as options
+ onSelect={handleSelectProduct}
+ search={false}
+ />
+
+ )}
+
+ {activeModule !== "market" && !selectedUser && }
+
+
+
+ {
+ (commentPositionState !== null || selectedComment !== null) &&
+
+ }
+
+ >
+ );
}
export default MainScene;
diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx
index 37b255a..2d88241 100644
--- a/app/src/components/layout/sidebarRight/SideBarRight.tsx
+++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx
@@ -6,7 +6,7 @@ import { useToggleStore } from "../../../store/useUIToggleStore";
import Visualization from "./visualization/Visualization";
import Analysis from "./analysis/Analysis";
import Simulations from "./simulation/Simulations";
-import useVersionHistoryVisibleStore, { useSaveVersion, useSelectedFloorItem, useToolMode } from "../../../store/builder/store";
+import useVersionHistoryVisibleStore, { useSaveVersion, useToolMode } from "../../../store/builder/store";
import { useSelectedEventData, useSelectedEventSphere, } from "../../../store/simulation/useSimulationStore";
import { useBuilderStore } from "../../../store/builder/useBuilderStore";
import GlobalProperties from "./properties/GlobalProperties";
@@ -48,8 +48,7 @@ const SideBarRight: React.FC = () => {
const { toggleUIRight } = useToggleStore();
const { toolMode } = useToolMode();
const { subModule, setSubModule } = useSubModuleStore();
- const { selectedFloorItem } = useSelectedFloorItem();
- const { selectedWall, selectedFloor, selectedAisle } = useBuilderStore();
+ const { selectedWall, selectedFloor, selectedAisle, selectedFloorAsset } = useBuilderStore();
const { selectedEventData } = useSelectedEventData();
const { selectedEventSphere } = useSelectedEventSphere();
const { viewVersionHistory, setVersionHistoryVisible } = useVersionHistoryVisibleStore();
@@ -108,31 +107,31 @@ const SideBarRight: React.FC = () => {
}
if (subModule === "properties" && activeModule !== "visualization") {
- if (selectedFloorItem) {
+ if (selectedFloorAsset) {
setDisplayComponent("assetProperties");
return;
}
- if (!selectedFloorItem && !selectedFloor && !selectedAisle && !selectedDecal && selectedWall) {
+ if (!selectedFloorAsset && !selectedFloor && !selectedAisle && !selectedDecal && selectedWall) {
setDisplayComponent("selectedWallProperties");
return;
}
- if (!selectedFloorItem && !selectedWall && !selectedAisle && !selectedDecal && selectedFloor) {
+ if (!selectedFloorAsset && !selectedWall && !selectedAisle && !selectedDecal && selectedFloor) {
setDisplayComponent("selectedFloorProperties");
return;
}
- if (viewVersionHistory && !selectedFloorItem && !selectedWall && !selectedAisle && !selectedFloor && !selectedDecal) {
+ if (viewVersionHistory && !selectedFloorAsset && !selectedWall && !selectedAisle && !selectedFloor && !selectedDecal) {
setDisplayComponent("versionHistory");
return;
}
- if (!selectedFloorItem && !selectedFloor && !selectedAisle && !selectedWall && selectedDecal) {
+ if (!selectedFloorAsset && !selectedFloor && !selectedAisle && !selectedWall && selectedDecal) {
setDisplayComponent("selectedDecalProperties");
return;
}
- if (!selectedFloorItem && !selectedFloor && !selectedWall && !selectedDecal && selectedAisle) {
+ if (!selectedFloorAsset && !selectedFloor && !selectedWall && !selectedDecal && selectedAisle) {
setDisplayComponent("selectedAisleProperties");
return;
}
- if (!selectedFloorItem && !selectedFloor && !selectedWall && !selectedDecal && !selectedAisle) {
+ if (!selectedFloorAsset && !selectedFloor && !selectedWall && !selectedDecal && !selectedAisle) {
if (toolMode === "Aisle") {
setDisplayComponent("aisleProperties");
return;
@@ -156,7 +155,7 @@ const SideBarRight: React.FC = () => {
}
setDisplayComponent("none");
- }, [viewVersionHistory, activeModule, subModule, isVersionSaved, selectedFloorItem, selectedWall, selectedFloor, selectedAisle, toolMode, selectedDecal]);
+ }, [viewVersionHistory, activeModule, subModule, isVersionSaved, selectedFloorAsset, selectedWall, selectedFloor, selectedAisle, toolMode, selectedDecal]);
const renderComponent = () => {
switch (displayComponent) {
diff --git a/app/src/components/layout/sidebarRight/properties/AssetProperties.tsx b/app/src/components/layout/sidebarRight/properties/AssetProperties.tsx
index 3a36e6c..729977f 100644
--- a/app/src/components/layout/sidebarRight/properties/AssetProperties.tsx
+++ b/app/src/components/layout/sidebarRight/properties/AssetProperties.tsx
@@ -4,143 +4,138 @@ import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
import { RemoveIcon } from "../../../icons/ExportCommonIcons";
import PositionInput from "../customInput/PositionInputs";
import RotationInput from "../customInput/RotationInput";
-import {
- useSelectedFloorItem,
- useObjectPosition,
- useObjectRotation,
-} from "../../../../store/builder/store";
+import { useObjectPosition, useObjectRotation } from "../../../../store/builder/store";
import { useSceneContext } from "../../../../modules/scene/sceneContext";
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
interface UserData {
- id: number;
- label: string;
- value: string;
+ id: number;
+ label: string;
+ value: string;
}
const AssetProperties: React.FC = () => {
- const [userData, setUserData] = useState([]);
- const { selectedFloorItem } = useSelectedFloorItem();
- const { objectPosition } = useObjectPosition();
- const { objectRotation } = useObjectRotation();
- const { assetStore } = useSceneContext();
- const { assets, setCurrentAnimation } = assetStore();
- const { loopAnimation } = useBuilderStore();
- const [hoveredIndex, setHoveredIndex] = useState(null);
+ const [userData, setUserData] = useState([]);
+ const { objectPosition } = useObjectPosition();
+ const { objectRotation } = useObjectRotation();
+ const { assetStore } = useSceneContext();
+ const { assets, setCurrentAnimation } = assetStore();
+ const { loopAnimation, selectedFloorAsset } = useBuilderStore();
+ const [hoveredIndex, setHoveredIndex] = useState(null);
- const handleAddUserData = () => {
- setUserData([]);
- };
+ const handleAddUserData = () => {
+ setUserData([]);
+ };
- const handleUserDataChange = (id: number, newValue: string) => { };
+ const handleUserDataChange = (id: number, newValue: string) => { };
- const handleRemoveUserData = (id: number) => { };
+ const handleRemoveUserData = (id: number) => { };
- const handleAnimationClick = (animation: string) => {
- if (selectedFloorItem) {
- setCurrentAnimation(
- selectedFloorItem.uuid,
- animation,
- true,
- loopAnimation,
- true
- );
- }
- };
-
- if (!selectedFloorItem) return null;
-
- return (
-
- {/* Name */}
-
{selectedFloorItem.userData.modelName}
-
- {objectPosition && (
- { }}
- value1={parseFloat(objectPosition.x.toFixed(5))}
- value2={parseFloat(objectPosition.z.toFixed(5))}
- />
- )}
- {objectRotation && (
- { }}
- value={parseFloat(objectRotation.y.toFixed(5))}
- />
- )}
-
-
-
Render settings
-
-
-
- User Data
- {userData.map((data, i) => (
-
-
handleUserDataChange(data.id, newValue)}
- />
- handleRemoveUserData(data.id)}
- >
-
-
-
- ))}
-
- {/* Add new user data */}
-
- + Add
-
-
-
Animations
-
- {assets.map((asset, i) => {
- if (asset.modelUuid !== selectedFloorItem.uuid || !asset.animations)
- return (
- i === 0 && (
-
- Looks like there are no preset animations yet. Stay tuned for
- future additions!
-
- )
+ const handleAnimationClick = (animation: string) => {
+ if (selectedFloorAsset) {
+ setCurrentAnimation(
+ selectedFloorAsset.uuid,
+ animation,
+ true,
+ loopAnimation,
+ true
);
+ }
+ };
- return asset.animations.map((animation, index) => (
-
-
handleAnimationClick(animation)}
- onMouseEnter={() => setHoveredIndex(index)}
- onMouseLeave={() => setHoveredIndex(null)}
- className="animations-list"
- style={{
- background:
- hoveredIndex === index
- ? "var(--background-color-button)"
- : "var(--background-color)",
- color:
- hoveredIndex === index ? "var(--text-button-color)" : "",
- }}
- >
- {animation.charAt(0).toUpperCase() +
- animation.slice(1).toLowerCase()}
-
-
- ));
- })}
-
-
- );
+ if (!selectedFloorAsset) return null;
+
+ return (
+
+ {/* Name */}
+
{selectedFloorAsset.userData.modelName}
+
+ {objectPosition && (
+ { }}
+ value1={parseFloat(objectPosition.x.toFixed(5))}
+ value2={parseFloat(objectPosition.z.toFixed(5))}
+ />
+ )}
+ {objectRotation && (
+ { }}
+ value={parseFloat(objectRotation.y.toFixed(5))}
+ />
+ )}
+
+
+
Render settings
+
+
+
+ User Data
+ {userData.map((data, i) => (
+
+
handleUserDataChange(data.id, newValue)}
+ />
+ handleRemoveUserData(data.id)}
+ >
+
+
+
+ ))}
+
+ {/* Add new user data */}
+
+ + Add
+
+
+
Animations
+
+ {assets.map((asset, i) => {
+ if (asset.modelUuid !== selectedFloorAsset.uuid || !asset.animations)
+ return (
+ i === 0 && (
+
+ Looks like there are no preset animations yet. Stay tuned for
+ future additions!
+
+ )
+ );
+
+ return asset.animations.map((animation, index) => (
+
+
handleAnimationClick(animation)}
+ onMouseEnter={() => setHoveredIndex(index)}
+ onMouseLeave={() => setHoveredIndex(null)}
+ className="animations-list"
+ style={{
+ background:
+ hoveredIndex === index
+ ? "var(--background-color-button)"
+ : "var(--background-color)",
+ color:
+ hoveredIndex === index ? "var(--text-button-color)" : "",
+ }}
+ >
+ {animation.charAt(0).toUpperCase() +
+ animation.slice(1).toLowerCase()}
+
+
+ ));
+ })}
+
+
+ );
};
export default AssetProperties;
diff --git a/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx b/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx
index 15d32ce..fea8f47 100644
--- a/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx
+++ b/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx
@@ -3,27 +3,13 @@ import InputRange from "../../../ui/inputs/InputRange";
import InputToggle from "../../../ui/inputs/InputToggle";
import { AIIcon } from "../../../icons/ExportCommonIcons";
import LabeledButton from "../../../ui/inputs/LabledButton";
-import {
- useAzimuth,
- useElevation,
- useLimitDistance,
- useRenderDistance,
- useResetCamera,
- useRoofVisibility,
- useSelectedWallItem,
- useShadows,
- useSocketStore,
- useTileDistance,
- useToggleView,
- useWallVisibility,
-} from "../../../../store/builder/store";
+import { useAzimuth, useElevation, useLimitDistance, useRenderDistance, useResetCamera, useRoofVisibility, useShadows, useSocketStore, useTileDistance, useToggleView, useWallVisibility } from "../../../../store/builder/store";
import { setEnvironment } from "../../../../services/factoryBuilder/environment/setEnvironment";
import * as CONSTANTS from "../../../../types/world/worldConstants";
import { useParams } from "react-router-dom";
import { getUserData } from "../../../../functions/getUserData";
const GlobalProperties: React.FC = () => {
const { toggleView, setToggleView } = useToggleView();
- const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem();
const { roofVisibility, setRoofVisibility } = useRoofVisibility();
const { wallVisibility, setWallVisibility } = useWallVisibility();
const { shadows, setShadows } = useShadows();
@@ -90,16 +76,6 @@ const GlobalProperties: React.FC = () => {
setDistance(value);
setRenderDistance(value);
}
- function updateGridDistance(value: number) {
- setGridDistance(value);
- // setGridValue({ size: value * 100, divisions: (value * 100) / 4 });
- // setPlaneValue({ height: value * 100, width: value * 100 });
- }
- function updatedGrid(value: number) {
- // console.log(" (value * 100) / 4 : ", (value * 100) / 4);
- setGridValue({ size: value * 100, divisions: (value * 100) / 4 });
- setPlaneValue({ height: value * 100, width: value * 100 });
- }
const updatedDist = async (value: number) => {
setRenderDistance(value);
@@ -145,7 +121,7 @@ const GlobalProperties: React.FC = () => {
setRoofVisibility(!roofVisibility); // Toggle roof visibility
};
- // Function to toggle wall visibility
+
const changeWallVisibility = async () => {
//using REST
const data = await setEnvironment(
@@ -203,20 +179,10 @@ const GlobalProperties: React.FC = () => {
const toggleResetCamera = () => {
if (!toggleView) {
- setResetCamera(true); // Trigger reset camera action
+ setResetCamera(true);
}
};
- // function changeRenderDistance(e: any) {
- // if (parseInt(e.target.value) < 20) {
- // setRenderDistance(20);
- // } else if (parseInt(e.target.value) > 75) {
- // setRenderDistance(75);
- // } else {
- // setRenderDistance(parseInt(e.target.value));
- // }
- // }
-
return (
@@ -253,16 +219,10 @@ const GlobalProperties: React.FC = () => {
/>
- {/* //visibleEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor} */}
{
- // setLimitDistance(!limitDistance);
- // // setDistance(75);
- // // setRenderDistance(75);
- // }}
onClick={async () => {
await limitRenderDistance(); // Call the function here
}}
@@ -277,26 +237,6 @@ const GlobalProperties: React.FC = () => {
onPointerUp={updatedDist}
key={"6"}
/>
-
- {/*
- {
- setLimitGridDistance(!limitGridDistance);
- }}
- />
- updateGridDistance(value)}
- onPointerUp={updatedGrid}
- /> */}
);
diff --git a/app/src/components/ui/Tools.tsx b/app/src/components/ui/Tools.tsx
index 4d29ad0..6ae7a81 100644
--- a/app/src/components/ui/Tools.tsx
+++ b/app/src/components/ui/Tools.tsx
@@ -1,17 +1,17 @@
import React, { useEffect, useRef, useState } from "react";
import {
- AsileIcon,
- CommentIcon,
- CursorIcon,
- DeleteIcon,
- FloorIcon,
- FreeMoveIcon,
- MeasureToolIcon,
- PenIcon,
- PlayIcon,
- SaveTemplateIcon,
- WallIcon,
- ZoneIcon,
+ AsileIcon,
+ CommentIcon,
+ CursorIcon,
+ DeleteIcon,
+ FloorIcon,
+ FreeMoveIcon,
+ MeasureToolIcon,
+ PenIcon,
+ PlayIcon,
+ SaveTemplateIcon,
+ WallIcon,
+ ZoneIcon,
} from "../icons/ExportToolsIcons";
import { ArrowIcon, TickIcon } from "../icons/ExportCommonIcons";
import useModuleStore, { useThreeDStore } from "../../store/useModuleStore";
@@ -20,420 +20,417 @@ import { usePlayButtonStore } from "../../store/usePlayButtonStore";
import useTemplateStore from "../../store/useTemplateStore";
import { useSelectedZoneStore } from "../../store/visualization/useZoneStore";
import {
- useActiveTool,
- useAddAction,
- useSelectedWallItem,
- useSocketStore,
- useToggleView,
- useToolMode,
- useActiveSubTool,
- useShortcutStore,
+ useActiveTool,
+ useAddAction,
+ useSocketStore,
+ useToggleView,
+ useToolMode,
+ useActiveSubTool,
+ useShortcutStore,
} from "../../store/builder/store";
import { useToggleStore } from "../../store/useUIToggleStore";
import {
- use3DWidget,
- useFloatingWidget,
+ use3DWidget,
+ useFloatingWidget,
} from "../../store/visualization/useDroppedObjectsStore";
import { useParams } from "react-router-dom";
import { useVersionContext } from "../../modules/builder/version/versionContext";
import { MoveIcon, RotateIcon } from "../icons/ShortcutIcons";
+import { useBuilderStore } from "../../store/builder/useBuilderStore";
// Utility component
const ToolButton = ({
- toolKey,
- toolId,
- icon: Icon,
- active,
- onClick,
- tooltip,
+ toolKey,
+ toolId,
+ icon: Icon,
+ active,
+ onClick,
+ tooltip,
}: any) => (
-
+
);
const Tools: React.FC = () => {
- const { activeModule } = useModuleStore();
- const { toggleThreeD, setToggleThreeD } = useThreeDStore();
- const { isPlaying, setIsPlaying } = usePlayButtonStore();
- const { showShortcuts } = useShortcutStore();
+ const { activeModule } = useModuleStore();
+ const { toggleThreeD, setToggleThreeD } = useThreeDStore();
+ const { isPlaying, setIsPlaying } = usePlayButtonStore();
+ const { showShortcuts } = useShortcutStore();
+ const { activeTool, setActiveTool, setToolMode, setAddAction } = useStoreHooks();
+ const { setSelectedWallAsset } = useBuilderStore();
+ const { setActiveSubTool, activeSubTool } = useActiveSubTool();
+ const { setToggleUI } = useToggleStore();
+ const { setToggleView, toggleView } = useToggleView();
- const { activeTool, setActiveTool, setToolMode, setAddAction } =
- useStoreHooks();
+ const { addTemplate, templates } = useTemplateStore();
+ const { selectedZone } = useSelectedZoneStore();
+ const { floatingWidget } = useFloatingWidget();
+ const { widgets3D } = use3DWidget();
- const { setActiveSubTool, activeSubTool } = useActiveSubTool();
- const { setSelectedWallItem } = useSelectedWallItem();
- const { setToggleUI } = useToggleStore();
- const { setToggleView, toggleView } = useToggleView();
+ const { visualizationSocket } = useSocketStore();
+ const { selectedVersionStore } = useVersionContext();
+ const { selectedVersion } = selectedVersionStore();
+ const { projectId } = useParams();
- const { addTemplate, templates } = useTemplateStore();
- const { selectedZone } = useSelectedZoneStore();
- const { floatingWidget } = useFloatingWidget();
- const { widgets3D } = use3DWidget();
+ const dropdownRef = useRef(null);
+ const [openDrop, setOpenDrop] = useState(false);
- const { visualizationSocket } = useSocketStore();
- const { selectedVersionStore } = useVersionContext();
- const { selectedVersion } = selectedVersionStore();
- const { projectId } = useParams();
+ // 1. Set UI toggles on initial render
+ useEffect(() => {
+ setToggleUI(
+ localStorage.getItem("navBarUiLeft") !== "false",
+ localStorage.getItem("navBarUiRight") !== "false"
+ );
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
- const dropdownRef = useRef(null);
- const [openDrop, setOpenDrop] = useState(false);
+ // 2. Update tool based on subtool and module
+ useEffect(() => {
+ setActiveTool(activeSubTool);
+ setActiveSubTool(activeSubTool);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [activeModule]);
- // 1. Set UI toggles on initial render
- useEffect(() => {
- setToggleUI(
- localStorage.getItem("navBarUiLeft") !== "false",
- localStorage.getItem("navBarUiRight") !== "false"
- );
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, []);
+ // 3. Update tools behavior based on selected tool and view mode
+ useEffect(() => {
+ resetTools();
+ updateToolBehavior(activeTool, toggleView);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [activeTool, toggleView]);
- // 2. Update tool based on subtool and module
- useEffect(() => {
- setActiveTool(activeSubTool);
- setActiveSubTool(activeSubTool);
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [activeModule]);
+ // 4. Dropdown auto-close
+ useEffect(() => {
+ const handleClickOutside = (e: MouseEvent) => {
+ if (
+ dropdownRef.current &&
+ !dropdownRef.current.contains(e.target as Node)
+ ) {
+ setOpenDrop(false);
+ }
+ };
+ document.addEventListener("mousedown", handleClickOutside);
+ return () => document.removeEventListener("mousedown", handleClickOutside);
+ }, []);
- // 3. Update tools behavior based on selected tool and view mode
- useEffect(() => {
- resetTools();
- updateToolBehavior(activeTool, toggleView);
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [activeTool, toggleView]);
-
- // 4. Dropdown auto-close
- useEffect(() => {
- const handleClickOutside = (e: MouseEvent) => {
- if (
- dropdownRef.current &&
- !dropdownRef.current.contains(e.target as Node)
- ) {
- setOpenDrop(false);
- }
+ const resetTools = () => {
+ setToolMode(null);
+ setAddAction(null);
};
- document.addEventListener("mousedown", handleClickOutside);
- return () => document.removeEventListener("mousedown", handleClickOutside);
- }, []);
- const resetTools = () => {
- setToolMode(null);
- setAddAction(null);
- };
-
- const updateToolBehavior = (tool: string, is2D: boolean) => {
- switch (tool) {
- case "cursor":
- is2D ? setToolMode("move") : setToolMode("cursor");
- break;
- case "draw-wall":
- is2D && setToolMode("Wall");
- break;
- case "draw-aisle":
- is2D && setToolMode("Aisle");
- break;
- case "draw-zone":
- is2D && setToolMode("Zone");
- break;
- case "draw-floor":
- is2D && setToolMode("Floor");
- break;
- case "move":
- if (!is2D) setToolMode("Move-Asset");
- break;
- case "rotate":
- if (!is2D) setToolMode("Rotate-Asset");
- break;
- case "measure":
- setToolMode("MeasurementScale");
- break;
- case "Add pillar":
- if (!is2D) setAddAction("Pillar");
- break;
- case "delete":
- is2D ? setToolMode("2D-Delete") : setToolMode("3D-Delete");
- break;
- }
- };
-
- const toggle2D3D = () => {
- const toggleTo2D = toggleView;
- setToggleView(!toggleTo2D);
- setToggleThreeD(toggleTo2D);
- setToggleUI(toggleTo2D, toggleTo2D);
- if (toggleTo2D) {
- setSelectedWallItem(null);
- setAddAction(null);
- }
- setActiveTool("cursor");
- setActiveSubTool("cursor");
- setToggleUI(
- localStorage.getItem("navBarUiLeft") !== "false",
- localStorage.getItem("navBarUiRight") !== "false"
- );
- };
-
- const renderBuilderTools = () => (
- <>
- {!toggleThreeD && (
-
- setActiveTool("draw-wall")}
- />
- setActiveTool("draw-zone")}
- />
- setActiveTool("draw-aisle")}
- />
- setActiveTool("draw-floor")}
- />
-
- )}
-
- setActiveTool("measure")}
- />
-
- >
- );
-
- const renderSimulationTools = () => (
-
- setActiveTool("pen")}
- />
-
- );
-
- const renderVisualizationTools = () => (
-
-
- handleSaveTemplate({
- addTemplate,
- floatingWidget,
- widgets3D,
- selectedZone,
- templates,
- visualizationSocket,
- projectId,
- versionId: selectedVersion?.versionId || "",
- })
+ const updateToolBehavior = (tool: string, is2D: boolean) => {
+ switch (tool) {
+ case "cursor":
+ is2D ? setToolMode("move") : setToolMode("cursor");
+ break;
+ case "draw-wall":
+ is2D && setToolMode("Wall");
+ break;
+ case "draw-aisle":
+ is2D && setToolMode("Aisle");
+ break;
+ case "draw-zone":
+ is2D && setToolMode("Zone");
+ break;
+ case "draw-floor":
+ is2D && setToolMode("Floor");
+ break;
+ case "move":
+ if (!is2D) setToolMode("Move-Asset");
+ break;
+ case "rotate":
+ if (!is2D) setToolMode("Rotate-Asset");
+ break;
+ case "measure":
+ setToolMode("MeasurementScale");
+ break;
+ case "Add pillar":
+ if (!is2D) setAddAction("Pillar");
+ break;
+ case "delete":
+ is2D ? setToolMode("2D-Delete") : setToolMode("3D-Delete");
+ break;
}
- />
-
- );
+ };
- const renderModeSwitcher = () => (
-
- );
+ const toggle2D3D = () => {
+ const toggleTo2D = toggleView;
+ setToggleView(!toggleTo2D);
+ setToggleThreeD(toggleTo2D);
+ setToggleUI(toggleTo2D, toggleTo2D);
+ if (toggleTo2D) {
+ setSelectedWallAsset(null);
+ setAddAction(null);
+ }
+ setActiveTool("cursor");
+ setActiveSubTool("cursor");
+ setToggleUI(
+ localStorage.getItem("navBarUiLeft") !== "false",
+ localStorage.getItem("navBarUiRight") !== "false"
+ );
+ };
- const getIconByTool = (tool: string) => {
- switch (tool) {
- case "cursor":
- return CursorIcon;
- case "free-hand":
- return FreeMoveIcon;
- case "delete":
- return DeleteIcon;
- case "move":
- return MoveIcon;
- case "rotate":
- return RotateIcon;
- default:
- return CursorIcon;
- }
- };
-
- const getTooltipShortcut = (tool: string) => {
- switch (tool) {
- case "cursor":
- return "v";
- case "free-hand":
- return "h";
- case "delete":
- return "x";
- default:
- return "";
- }
- };
-
- const getIconComponent = (option: string) => {
- switch (option) {
- case "cursor":
- return ;
- case "free-hand":
- return ;
- case "delete":
- return ;
- case "move":
- return ;
- case "rotate":
- return ;
- default:
- return null;
- }
- };
-
- return (
-
-
- {/* Tool Picker (cursor, delete, etc.) */}
- {["cursor", "free-hand", "delete"].map(
- (tool) =>
- activeSubTool === tool && (
-
setActiveTool(tool)}
- />
- )
- )}
- {/* Dropdown Menu */}
- {activeModule !== "visualization" && (
-
- )}
-
-
- {toggleThreeD && activeModule !== "visualization" && (
- <>
-
-
- {["move", "rotate"].map((tool) => (
- setActiveTool(tool)}
- />
- ))}
-
+
+ setActiveTool("measure")}
+ />
+
>
- )}
+ );
-
- {activeModule === "builder" && renderBuilderTools()}
- {activeModule === "simulation" && renderSimulationTools()}
- {activeModule === "visualization" && renderVisualizationTools()}
+ const renderSimulationTools = () => (
+
+ setActiveTool("pen")}
+ />
+
+ );
-
-
- setActiveTool("comment")}
- />
- {toggleThreeD && (
- setIsPlaying(!isPlaying)}
- />
- )}
-
+ const renderVisualizationTools = () => (
+
+
+ handleSaveTemplate({
+ addTemplate,
+ floatingWidget,
+ widgets3D,
+ selectedZone,
+ templates,
+ visualizationSocket,
+ projectId,
+ versionId: selectedVersion?.versionId || "",
+ })
+ }
+ />
+
+ );
- {activeModule === "builder" && (
- <>
-
- {renderModeSwitcher()}
- >
- )}
-
- );
+ const renderModeSwitcher = () => (
+
+ toggle view (tab)
+ 2d
+ 3d
+
+ );
+
+ const getIconByTool = (tool: string) => {
+ switch (tool) {
+ case "cursor":
+ return CursorIcon;
+ case "free-hand":
+ return FreeMoveIcon;
+ case "delete":
+ return DeleteIcon;
+ case "move":
+ return MoveIcon;
+ case "rotate":
+ return RotateIcon;
+ default:
+ return CursorIcon;
+ }
+ };
+
+ const getTooltipShortcut = (tool: string) => {
+ switch (tool) {
+ case "cursor":
+ return "v";
+ case "free-hand":
+ return "h";
+ case "delete":
+ return "x";
+ default:
+ return "";
+ }
+ };
+
+ const getIconComponent = (option: string) => {
+ switch (option) {
+ case "cursor":
+ return ;
+ case "free-hand":
+ return ;
+ case "delete":
+ return ;
+ case "move":
+ return ;
+ case "rotate":
+ return ;
+ default:
+ return null;
+ }
+ };
+
+ return (
+
+
+ {/* Tool Picker (cursor, delete, etc.) */}
+ {["cursor", "free-hand", "delete"].map(
+ (tool) =>
+ activeSubTool === tool && (
+
setActiveTool(tool)}
+ />
+ )
+ )}
+ {/* Dropdown Menu */}
+ {activeModule !== "visualization" && (
+ setOpenDrop(!openDrop)}
+ >
+
+ {openDrop && (
+
+ {["cursor", "free-hand", "delete"].map((option) => (
+
{
+ setActiveTool(option);
+ setActiveSubTool(option);
+ setOpenDrop(false);
+ }}
+ >
+
+ {activeSubTool === option && }
+
+ {getIconComponent(option)}
+ {option}
+
+ ))}
+
+ )}
+
+ )}
+
+
+ {toggleThreeD && activeModule !== "visualization" && (
+ <>
+
+
+ {["move", "rotate"].map((tool) => (
+ setActiveTool(tool)}
+ />
+ ))}
+
+ >
+ )}
+
+
+ {activeModule === "builder" && renderBuilderTools()}
+ {activeModule === "simulation" && renderSimulationTools()}
+ {activeModule === "visualization" && renderVisualizationTools()}
+
+
+
+ setActiveTool("comment")}
+ />
+ {toggleThreeD && (
+ setIsPlaying(!isPlaying)}
+ />
+ )}
+
+
+ {activeModule === "builder" && (
+ <>
+
+ {renderModeSwitcher()}
+ >
+ )}
+
+ );
};
// Extracted common store logic
const useStoreHooks = () => {
- return {
- ...useActiveTool(),
- ...useToolMode(),
- ...useAddAction(),
- };
+ return {
+ ...useActiveTool(),
+ ...useToolMode(),
+ ...useAddAction(),
+ };
};
export default Tools;
diff --git a/app/src/modules/builder/Decal/eventHandler/useDecalEventHandlers.ts b/app/src/modules/builder/Decal/eventHandler/useDecalEventHandlers.ts
index 9a860b9..fc7e75d 100644
--- a/app/src/modules/builder/Decal/eventHandler/useDecalEventHandlers.ts
+++ b/app/src/modules/builder/Decal/eventHandler/useDecalEventHandlers.ts
@@ -1,7 +1,7 @@
import * as THREE from 'three';
import { CameraControls } from '@react-three/drei';
import { ThreeEvent, useFrame, useThree } from '@react-three/fiber';
-import { useEffect, useRef } from 'react';
+import { useEffect, useState } from 'react';
import { useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store';
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
import useModuleStore from '../../../../store/useModuleStore';
@@ -10,6 +10,9 @@ import { useVersionContext } from '../../version/versionContext';
import { useParams } from 'react-router-dom';
import { useSceneContext } from '../../../scene/sceneContext';
+import { detectModifierKeys } from '../../../../utils/shortcutkeys/detectModifierKeys';
+import handleDecalPositionSnap from '../functions/handleDecalPositionSnap';
+
// import { upsertWallApi } from '../../../../services/factoryBuilder/wall/upsertWallApi';
// import { upsertFloorApi } from '../../../../services/factoryBuilder/floor/upsertFloorApi';
@@ -34,6 +37,7 @@ export function useDecalEventHandlers({
const { selectedVersion } = selectedVersionStore();
const { projectId } = useParams();
const { socket } = useSocketStore();
+ const [keyEvent, setKeyEvent] = useState<"Ctrl" | "">("");
const { raycaster, pointer, camera, scene, gl, controls } = useThree();
useFrame(() => {
@@ -51,14 +55,22 @@ export function useDecalEventHandlers({
const wallUuid = wallIntersect.object.userData.wallUuid;
const point = wallIntersect.object.worldToLocal(wallIntersect.point.clone());
+ let finalPos;
+
+ if (keyEvent === "Ctrl") {
+ finalPos = handleDecalPositionSnap(point, offset, parent, decal, 0.05)
+ } else {
+ finalPos = point
+ }
+
if ("wallUuid" in parent && parent.wallUuid === wallUuid && decal.decalType.type === 'Wall') {
- updateDecalPositionInWall(decal.decalUuid, [point.x + offset.x, point.y + offset.y, decal.decalPosition[2]]);
+ updateDecalPositionInWall(decal.decalUuid, [finalPos.x + offset.x, finalPos.y + offset.y, decal.decalPosition[2]]);
} else if (decal.decalType.type === 'Wall' && wallUuid) {
deleteDecal(decal.decalUuid, parent);
const addedDecal = addDecalToWall(wallUuid, {
...decal,
- decalPosition: [point.x + offset.x, point.y + offset.y, decal.decalPosition[2]],
+ decalPosition: [finalPos.x + offset.x, finalPos.y + offset.y, decal.decalPosition[2]],
decalType: { type: 'Wall', wallUuid: wallUuid }
});
@@ -72,7 +84,7 @@ export function useDecalEventHandlers({
const addedDecal = addDecalToWall(wallUuid, {
...decal,
- decalPosition: [point.x + offset.x, point.y + offset.y, wall.wallThickness / 2 + 0.001],
+ decalPosition: [finalPos.x + offset.x, finalPos.y + offset.y, wall.wallThickness / 2 + 0.001],
decalType: { type: 'Wall', wallUuid: wallUuid }
});
@@ -84,14 +96,22 @@ export function useDecalEventHandlers({
const floorUuid = floorIntersect.object.userData.floorUuid;
const point = floorIntersect.object.worldToLocal(floorIntersect.point.clone());
+ let finalPos;
+
+ if (keyEvent === "Ctrl") {
+ finalPos = handleDecalPositionSnap(point, offset, parent, decal, 0.25)
+ } else {
+ finalPos = point
+ }
+
if ("floorUuid" in parent && parent.floorUuid === floorUuid && decal.decalType.type === 'Floor') {
- updateDecalPositionInFloor(decal.decalUuid, [point.x + offset.x, point.y + offset.y, decal.decalPosition[2]]);
+ updateDecalPositionInFloor(decal.decalUuid, [finalPos.x + offset.x, finalPos.y + offset.y, decal.decalPosition[2]]);
} else if (decal.decalType.type === 'Floor' && floorUuid) {
deleteDecal(decal.decalUuid, parent);
const addedDecal = addDecalToFloor(floorUuid, {
...decal,
- decalPosition: [point.x + offset.x, point.y + offset.y, decal.decalPosition[2]],
+ decalPosition: [finalPos.x + offset.x, finalPos.y + offset.y, decal.decalPosition[2]],
decalType: { type: 'Floor', floorUuid: floorUuid }
});
@@ -105,7 +125,7 @@ export function useDecalEventHandlers({
const addedDecal = addDecalToFloor(floorUuid, {
...decal,
- decalPosition: [point.x + offset.x, point.y + offset.y, -0.001],
+ decalPosition: [finalPos.x + offset.x, finalPos.y + offset.y, -0.001],
decalType: { type: 'Floor', floorUuid: floorUuid }
});
@@ -283,18 +303,44 @@ export function useDecalEventHandlers({
const handlePointerMissed = () => {
if (selectedDecal && selectedDecal.decalMesh && selectedDecal.decalMesh.userData.decalUuid === decal.decalUuid) {
setSelectedDecal(null);
+ setKeyEvent("");
}
};
+ const onKeyUp = (event: KeyboardEvent) => {
+ const keyCombination = detectModifierKeys(event);
+
+ if (keyCombination === "") {
+ setKeyEvent("");
+ } else if (keyCombination === "Ctrl") {
+ setKeyEvent(keyCombination);
+ }
+ };
+
+ const onKeyDown = (event: KeyboardEvent) => {
+ const keyCombination = detectModifierKeys(event);
+ if (keyCombination !== keyEvent) {
+ if (keyCombination === "Ctrl") {
+ setKeyEvent(keyCombination);
+ } else {
+ setKeyEvent("");
+ }
+ }
+ }
+
useEffect(() => {
const canvasElement = gl.domElement;
if (activeModule === 'builder' && !toggleView && selectedDecal && selectedDecal.decalData.decalUuid === decal.decalUuid) {
canvasElement.addEventListener('pointerup', handlePointerUp);
+ canvasElement?.addEventListener("keyup", onKeyUp);
+ canvasElement.addEventListener("keydown", onKeyDown);
}
return () => {
canvasElement.removeEventListener('pointerup', handlePointerUp);
+ canvasElement?.removeEventListener("keyup", onKeyUp);
+ canvasElement.removeEventListener("keydown", onKeyDown);
};
}, [gl, activeModule, toggleView, selectedDecal, camera, controls, visible, parent, decal, decalDragState]);
diff --git a/app/src/modules/builder/Decal/functions/handleDecalPositionSnap.ts b/app/src/modules/builder/Decal/functions/handleDecalPositionSnap.ts
new file mode 100644
index 0000000..63d6d2c
--- /dev/null
+++ b/app/src/modules/builder/Decal/functions/handleDecalPositionSnap.ts
@@ -0,0 +1,43 @@
+import * as THREE from 'three';
+
+function snapToFixedPoint(
+ position: [number, number, number],
+ snapInterval: number = 0.1
+): [number, number, number] {
+ return [
+ Math.round(position[0] / snapInterval) * snapInterval,
+ Math.round(position[1] / snapInterval) * snapInterval,
+ Math.round(position[2] / snapInterval) * snapInterval,
+ ];
+}
+
+function handleDecalPositionSnap(
+ point: THREE.Vector3,
+ offset: THREE.Vector3,
+ parent: Wall | Floor,
+ decal: Decal,
+ snapInterval: number = 0.1
+): THREE.Vector3 {
+ let rawPos: [number, number, number];
+
+ if ("wallUuid" in parent) {
+ // snap relative to wall
+ rawPos = [
+ point.x + offset.x,
+ point.y + offset.y,
+ decal.decalPosition[2], // keep depth as-is
+ ];
+ } else {
+ // snap relative to floor
+ rawPos = [
+ point.x + offset.x,
+ point.y + offset.y,
+ decal.decalPosition[2],
+ ];
+ }
+
+ const snapped = snapToFixedPoint(rawPos, snapInterval);
+ return new THREE.Vector3(snapped[0], snapped[1], snapped[2]);
+}
+
+export default handleDecalPositionSnap;
\ No newline at end of file
diff --git a/app/src/modules/builder/asset/assetsGroup.tsx b/app/src/modules/builder/asset/assetsGroup.tsx
index 0205a4c..dfad400 100644
--- a/app/src/modules/builder/asset/assetsGroup.tsx
+++ b/app/src/modules/builder/asset/assetsGroup.tsx
@@ -1,7 +1,7 @@
import * as THREE from "three"
import { useEffect } from 'react'
import { getFloorAssets } from '../../../services/factoryBuilder/asset/floorAsset/getFloorItemsApi';
-import { useLoadingProgress, useRenameModeStore, useSelectedFloorItem, useSelectedItem, useSocketStore } from '../../../store/builder/store';
+import { useLoadingProgress, useRenameModeStore, useSelectedItem, useSocketStore } from '../../../store/builder/store';
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
import { FloorItems, RefMesh } from "../../../types/world/worldTypes";
@@ -15,6 +15,7 @@ import { useLeftData, useTopData } from "../../../store/visualization/useZone3DW
import { getUserData } from "../../../functions/getUserData";
import { useSceneContext } from "../../scene/sceneContext";
import { useVersionContext } from "../version/versionContext";
+import { useBuilderStore } from "../../../store/builder/useBuilderStore";
const gltfLoaderWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js", import.meta.url));
@@ -28,7 +29,7 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
const { selectedVersion } = selectedVersionStore();
const { setAssets, addAsset, clearAssets } = assetStore();
const { addEvent, clearEvents } = eventStore();
- const { setSelectedFloorItem } = useSelectedFloorItem();
+ const { setSelectedFloorAsset } = useBuilderStore();
const { selectedItem, setSelectedItem } = useSelectedItem();
const { projectId } = useParams();
const { isRenameMode, setIsRenameMode } = useRenameModeStore();
@@ -377,7 +378,7 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
if ((controls as CameraControls)) {
const target = (controls as CameraControls).getTarget(new THREE.Vector3());
(controls as CameraControls).setTarget(target.x, 0, target.z, true);
- setSelectedFloorItem(null);
+ setSelectedFloorAsset(null);
}
}
diff --git a/app/src/modules/builder/asset/models/model/eventHandlers/useEventHandlers.ts b/app/src/modules/builder/asset/models/model/eventHandlers/useEventHandlers.ts
index 85b5b4b..edd9f4e 100644
--- a/app/src/modules/builder/asset/models/model/eventHandlers/useEventHandlers.ts
+++ b/app/src/modules/builder/asset/models/model/eventHandlers/useEventHandlers.ts
@@ -3,7 +3,7 @@ import { CameraControls } from '@react-three/drei';
import { ThreeEvent, useThree } from '@react-three/fiber';
import { useCallback, useEffect, useRef } from 'react';
-import { useActiveTool, useDeletableFloorItem, useResourceManagementId, useSelectedFloorItem, useToggleView, useZoneAssetId } from '../../../../../../store/builder/store';
+import { useActiveTool, useResourceManagementId, useToggleView, useZoneAssetId } from '../../../../../../store/builder/store';
import useModuleStore, { useSubModuleStore } from '../../../../../../store/useModuleStore';
import { useSocketStore } from '../../../../../../store/builder/store';
import { useSceneContext } from '../../../../../scene/sceneContext';
@@ -13,8 +13,9 @@ import { useParams } from 'react-router-dom';
import { getUserData } from '../../../../../../functions/getUserData';
import { useLeftData, useTopData } from '../../../../../../store/visualization/useZone3DWidgetStore';
import { useSelectedAsset } from '../../../../../../store/simulation/useSimulationStore';
-import { upsertProductOrEventApi } from '../../../../../../services/simulation/products/UpsertProductOrEventApi';
+import { useBuilderStore } from '../../../../../../store/builder/useBuilderStore';
+import { upsertProductOrEventApi } from '../../../../../../services/simulation/products/UpsertProductOrEventApi';
// import { deleteFloorItem } from '../../../../../../services/factoryBuilder/asset/floorAsset/deleteFloorItemApi';
export function useModelEventHandlers({
@@ -40,8 +41,7 @@ export function useModelEventHandlers({
const { removeEvent, getEventByModelUuid } = eventStore();
const { getIsEventInProduct, addPoint, deleteEvent } = productStore();
const { setSelectedAsset, clearSelectedAsset } = useSelectedAsset();
- const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
- const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
+ const { deletableFloorAsset, setDeletableFloorAsset, selectedFloorAsset, setSelectedFloorAsset } = useBuilderStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { selectedVersionStore } = useVersionContext();
@@ -89,10 +89,10 @@ export function useModelEventHandlers({
}, [resourceManagementId])
useEffect(() => {
- if (!selectedFloorItem) {
+ if (!selectedFloorAsset) {
setZoneAssetId(null);
}
- }, [selectedFloorItem])
+ }, [selectedFloorAsset])
const handleDblClick = (asset: Asset) => {
if (asset && activeTool === "cursor" && boundingBox && groupRef.current && (activeModule === 'builder' || (activeModule === 'simulation' && resourceManagementId))) {
@@ -137,14 +137,14 @@ export function useModelEventHandlers({
(controls as CameraControls).setLookAt(newCameraPos.x, newCameraPos.y, newCameraPos.z, collisionPos.x, 0, collisionPos.z, true);
}
- setSelectedFloorItem(groupRef.current);
+ setSelectedFloorAsset(groupRef.current);
setResourceManagementId("");
}
};
const handleClick = async (evt: ThreeEvent, asset: Asset) => {
if (leftDrag.current || toggleView) return;
- if (activeTool === 'delete' && deletableFloorItem && deletableFloorItem.uuid === asset.modelUuid) {
+ if (activeTool === 'delete' && deletableFloorAsset && deletableFloorAsset.uuid === asset.modelUuid) {
//REST
@@ -236,19 +236,19 @@ export function useModelEventHandlers({
const handlePointerOver = useCallback((asset: Asset) => {
if (activeTool === "delete" && activeModule === 'builder') {
- if (deletableFloorItem && deletableFloorItem.uuid === asset.modelUuid) {
+ if (deletableFloorAsset && deletableFloorAsset.uuid === asset.modelUuid) {
return;
} else {
- setDeletableFloorItem(groupRef.current);
+ setDeletableFloorAsset(groupRef.current);
}
}
- }, [activeTool, activeModule, deletableFloorItem]);
+ }, [activeTool, activeModule, deletableFloorAsset]);
const handlePointerOut = useCallback((evt: ThreeEvent, asset: Asset) => {
- if (evt.intersections.length === 0 && activeTool === "delete" && deletableFloorItem && deletableFloorItem.uuid === asset.modelUuid) {
- setDeletableFloorItem(null);
+ if (evt.intersections.length === 0 && activeTool === "delete" && deletableFloorAsset && deletableFloorAsset.uuid === asset.modelUuid) {
+ setDeletableFloorAsset(null);
}
- }, [activeTool, deletableFloorItem]);
+ }, [activeTool, deletableFloorAsset]);
const handleContextMenu = (asset: Asset, evt: ThreeEvent) => {
if (rightDrag.current || toggleView) return;
diff --git a/app/src/modules/builder/asset/models/model/model.tsx b/app/src/modules/builder/asset/models/model/model.tsx
index ca1b406..24ddff4 100644
--- a/app/src/modules/builder/asset/models/model/model.tsx
+++ b/app/src/modules/builder/asset/models/model/model.tsx
@@ -2,8 +2,9 @@ import * as THREE from 'three';
import { useEffect, useRef, useState } from 'react';
import { retrieveGLTF, storeGLTF } from '../../../../../utils/indexDB/idbUtils';
import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
-import { useDeletableFloorItem, useSelectedAssets, useSelectedFloorItem, useToggleView, useToolMode } from '../../../../../store/builder/store';
+import { useSelectedAssets, useToggleView, useToolMode } from '../../../../../store/builder/store';
import { AssetBoundingBox } from '../../functions/assetBoundingBox';
+import { useBuilderStore } from '../../../../../store/builder/useBuilderStore';
import useModuleStore from '../../../../../store/useModuleStore';
import { useSceneContext } from '../../../../scene/sceneContext';
import { SkeletonUtils } from 'three-stdlib';
@@ -20,8 +21,7 @@ function Model({ asset, isRendered, loader }: { readonly asset: Asset, isRendere
const { activeModule } = useModuleStore();
const { assetStore } = useSceneContext();
const { resetAnimation } = assetStore();
- const { setDeletableFloorItem } = useDeletableFloorItem();
- const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
+ const { setDeletableFloorAsset, selectedFloorAsset, setSelectedFloorAsset } = useBuilderStore();
const [gltfScene, setGltfScene] = useState(null);
const [boundingBox, setBoundingBox] = useState(null);
const [isSelected, setIsSelected] = useState(false);
@@ -53,17 +53,17 @@ function Model({ asset, isRendered, loader }: { readonly asset: Asset, isRendere
}, [asset.modelUuid, fieldData])
useEffect(() => {
- setDeletableFloorItem(null);
- if (selectedFloorItem === null || selectedFloorItem.userData.modelUuid !== asset.modelUuid) {
+ setDeletableFloorAsset(null);
+ if (selectedFloorAsset === null || selectedFloorAsset.userData.modelUuid !== asset.modelUuid) {
resetAnimation(asset.modelUuid);
}
- }, [activeModule, toolMode, selectedFloorItem])
+ }, [activeModule, toolMode, selectedFloorAsset])
useEffect(() => {
- if (selectedFloorItem && selectedFloorItem.userData.modelUuid === asset.modelUuid) {
- setSelectedFloorItem(groupRef.current);
+ if (selectedFloorAsset && selectedFloorAsset.userData.modelUuid === asset.modelUuid) {
+ setSelectedFloorAsset(groupRef.current);
}
- }, [isRendered, selectedFloorItem])
+ }, [isRendered, selectedFloorAsset])
useEffect(() => {
if (selectedAssets.length > 0) {
diff --git a/app/src/modules/builder/asset/models/models.tsx b/app/src/modules/builder/asset/models/models.tsx
index f29af55..e54e761 100644
--- a/app/src/modules/builder/asset/models/models.tsx
+++ b/app/src/modules/builder/asset/models/models.tsx
@@ -2,9 +2,10 @@ import { useEffect, useRef, useState } from "react";
import { useThree, useFrame } from "@react-three/fiber";
import { Group, Vector3 } from "three";
import { CameraControls } from '@react-three/drei';
-import { useLimitDistance, useRenderDistance, useSelectedFloorItem, useToggleView } from '../../../../store/builder/store';
+import { useLimitDistance, useRenderDistance } from '../../../../store/builder/store';
import { useSelectedAsset } from '../../../../store/simulation/useSimulationStore';
import { useSceneContext } from '../../../scene/sceneContext';
+import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
import Model from './model/model';
import { GLTFLoader } from "three/examples/jsm/Addons";
@@ -16,7 +17,7 @@ function Models({ loader }: { loader: GLTFLoader }) {
const assetGroupRef = useRef(null);
const { assetStore } = useSceneContext();
const { assets } = assetStore();
- const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
+ const { selectedFloorAsset, setSelectedFloorAsset } = useBuilderStore();
const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
const { limitDistance } = useLimitDistance();
const { renderDistance } = useRenderDistance();
@@ -49,10 +50,10 @@ function Models({ loader }: { loader: GLTFLoader }) {
ref={assetGroupRef}
onPointerMissed={(e) => {
e.stopPropagation();
- if (selectedFloorItem) {
+ if (selectedFloorAsset) {
const target = (controls as CameraControls).getTarget(new Vector3());
(controls as CameraControls).setTarget(target.x, 0, target.z, true);
- setSelectedFloorItem(null);
+ setSelectedFloorAsset(null);
}
if (selectedAsset) {
clearSelectedAsset();
diff --git a/app/src/modules/scene/controls/selectionControls/selection3D/selectionControls3D.tsx b/app/src/modules/scene/controls/selectionControls/selection3D/selectionControls3D.tsx
index 512b80f..2db55d1 100644
--- a/app/src/modules/scene/controls/selectionControls/selection3D/selectionControls3D.tsx
+++ b/app/src/modules/scene/controls/selectionControls/selection3D/selectionControls3D.tsx
@@ -17,6 +17,7 @@ import CopyPasteControls3D from "./copyPasteControls3D";
import MoveControls3D from "./moveControls3D";
import RotateControls3D from "./rotateControls3D";
import TransformControls3D from "./transformControls3D";
+import { useBuilderStore } from "../../../../../store/builder/useBuilderStore";
// import { deleteFloorItem } from '../../../../../services/factoryBuilder/asset/floorAsset/deleteFloorItemApi';
@@ -30,6 +31,7 @@ const SelectionControls3D: React.FC = () => {
const { socket } = useSocketStore();
const { contextAction, setContextAction } = useContextActionStore()
const { assetStore, eventStore, productStore, undoRedo3DStore } = useSceneContext();
+ const { selectedDecal, selectedWall, selectedAisle, selectedFloor, selectedFloorAsset, selectedWallAsset } = useBuilderStore();
const { push3D } = undoRedo3DStore();
const { removeAsset, getAssetById, movedObjects, rotatedObjects, copiedObjects, pastedObjects, duplicatedObjects, setPastedObjects, setDuplicatedObjects } = assetStore();
const selectionBox = useMemo(() => new SelectionBox(camera, scene), [camera, scene]);
@@ -203,7 +205,7 @@ const SelectionControls3D: React.FC = () => {
rightClickMoved.current = false;
};
- if (!toggleView && activeModule === "builder" && (toolMode === 'cursor' || toolMode === 'Move-Asset' || toolMode === 'Rotate-Asset')) {
+ if (!toggleView && activeModule === "builder" && (toolMode === 'cursor' || toolMode === 'Move-Asset' || toolMode === 'Rotate-Asset') && (!selectedDecal && !selectedWall && !selectedAisle && !selectedFloor && !selectedFloorAsset && !selectedWallAsset) && duplicatedObjects.length === 0 && pastedObjects.length === 0) {
helper.enabled = true;
canvasElement.addEventListener("pointermove", onPointerMove);
canvasElement.addEventListener("pointerup", onPointerUp);
@@ -225,7 +227,7 @@ const SelectionControls3D: React.FC = () => {
helper.dispose();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [camera, controls, scene, toggleView, selectedAssets, copiedObjects, pastedObjects, duplicatedObjects, movedObjects, socket, rotatedObjects, activeModule, toolMode]);
+ }, [camera, controls, scene, toggleView, selectedAssets, copiedObjects, pastedObjects, duplicatedObjects, movedObjects, socket, rotatedObjects, activeModule, toolMode, selectedDecal, selectedWall, selectedAisle, selectedFloor, selectedFloorAsset, selectedWallAsset]);
useEffect(() => {
if (activeModule !== "builder" || (toolMode !== 'cursor' && toolMode !== 'Move-Asset' && toolMode !== 'Rotate-Asset') || toggleView) {
diff --git a/app/src/modules/scene/controls/transformControls/transformControls.tsx b/app/src/modules/scene/controls/transformControls/transformControls.tsx
index 8428a63..61f264e 100644
--- a/app/src/modules/scene/controls/transformControls/transformControls.tsx
+++ b/app/src/modules/scene/controls/transformControls/transformControls.tsx
@@ -7,7 +7,8 @@ import { useProductContext } from "../../../simulation/products/productContext";
import { getUserData } from "../../../../functions/getUserData";
import { useSceneContext } from "../../sceneContext";
import { useVersionContext } from "../../../builder/version/versionContext";
-import { useSelectedFloorItem, useObjectPosition, useObjectRotation, useActiveTool, useSocketStore } from "../../../../store/builder/store";
+import { useObjectPosition, useObjectRotation, useActiveTool, useSocketStore } from "../../../../store/builder/store";
+import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys";
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
@@ -17,7 +18,7 @@ export default function TransformControl() {
const state = useThree();
const ref = useRef(null);
const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null);
- const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
+ const { selectedFloorAsset, setSelectedFloorAsset } = useBuilderStore();
const { setObjectPosition } = useObjectPosition();
const { setObjectRotation } = useObjectRotation();
const { activeTool } = useActiveTool();
@@ -48,26 +49,27 @@ export default function TransformControl() {
};
function handleObjectChange() {
- if (selectedFloorItem) {
- setObjectPosition(selectedFloorItem.position);
+ if (selectedFloorAsset) {
+ setObjectPosition(selectedFloorAsset.position);
setObjectRotation({
- x: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.x),
- y: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.y),
- z: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.z),
+ x: THREE.MathUtils.radToDeg(selectedFloorAsset.rotation.x),
+ y: THREE.MathUtils.radToDeg(selectedFloorAsset.rotation.y),
+ z: THREE.MathUtils.radToDeg(selectedFloorAsset.rotation.z),
});
}
}
function handleMouseUp() {
- if (selectedFloorItem) {
- setObjectPosition(selectedFloorItem.position);
+ if (!selectedProduct || !selectedFloorAsset) return;
+ if (selectedFloorAsset) {
+ setObjectPosition(selectedFloorAsset.position);
setObjectRotation({
- x: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.x),
- y: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.y),
- z: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.z),
+ x: THREE.MathUtils.radToDeg(selectedFloorAsset.rotation.x),
+ y: THREE.MathUtils.radToDeg(selectedFloorAsset.rotation.y),
+ z: THREE.MathUtils.radToDeg(selectedFloorAsset.rotation.z),
});
}
- const asset = getAssetById(selectedFloorItem?.uuid);
+ const asset = getAssetById(selectedFloorAsset.uuid);
if (asset) {
if (asset.eventData) {
const eventData = eventStore.getState().getEventByModelUuid(asset.modelUuid);
@@ -75,8 +77,8 @@ export default function TransformControl() {
if (eventData) {
eventStore.getState().updateEvent(asset.modelUuid, {
- position: [selectedFloorItem.position.x, 0, selectedFloorItem.position.z] as [number, number, number],
- rotation: [selectedFloorItem.rotation.x, selectedFloorItem.rotation.y, selectedFloorItem.rotation.z] as [number, number, number],
+ position: [selectedFloorAsset.position.x, 0, selectedFloorAsset.position.z] as [number, number, number],
+ rotation: [selectedFloorAsset.rotation.x, selectedFloorAsset.rotation.y, selectedFloorAsset.rotation.z] as [number, number, number],
});
}
@@ -87,8 +89,8 @@ export default function TransformControl() {
selectedProduct.productUuid,
asset.modelUuid,
{
- position: [selectedFloorItem.position.x, 0, selectedFloorItem.position.z] as [number, number, number],
- rotation: [selectedFloorItem.rotation.x, selectedFloorItem.rotation.y, selectedFloorItem.rotation.z] as [number, number, number],
+ position: [selectedFloorAsset.position.x, 0, selectedFloorAsset.position.z] as [number, number, number],
+ rotation: [selectedFloorAsset.rotation.x, selectedFloorAsset.rotation.y, selectedFloorAsset.rotation.z] as [number, number, number],
}
);
@@ -104,8 +106,8 @@ export default function TransformControl() {
}
updateAsset(asset.modelUuid, {
- position: [selectedFloorItem.position.x, 0, selectedFloorItem.position.z],
- rotation: [selectedFloorItem.rotation.x, selectedFloorItem.rotation.y, selectedFloorItem.rotation.z] as [number, number, number],
+ position: [selectedFloorAsset.position.x, 0, selectedFloorAsset.position.z],
+ rotation: [selectedFloorAsset.rotation.x, selectedFloorAsset.rotation.y, selectedFloorAsset.rotation.z] as [number, number, number],
});
//REST
@@ -114,8 +116,8 @@ export default function TransformControl() {
// organization,
// asset.modelUuid,
// asset.modelName,
- // [selectedFloorItem.position.x, 0, selectedFloorItem.position.z,
- // { "x": selectedFloorItem.rotation.x, "y": selectedFloorItem.rotation.y, "z": selectedFloorItem.rotation.z },
+ // [selectedFloorAsset.position.x, 0, selectedFloorAsset.position.z,
+ // { "x": selectedFloorAsset.rotation.x, "y": selectedFloorAsset.rotation.y, "z": selectedFloorAsset.rotation.z },
// asset.assetId,
// false,
// true,
@@ -128,8 +130,8 @@ export default function TransformControl() {
modelUuid: asset.modelUuid,
modelName: asset.modelName,
assetId: asset.assetId,
- position: [selectedFloorItem.position.x, 0, selectedFloorItem.position.z] as [number, number, number],
- rotation: { x: selectedFloorItem.rotation.x, y: selectedFloorItem.rotation.y, z: selectedFloorItem.rotation.z },
+ position: [selectedFloorAsset.position.x, 0, selectedFloorAsset.position.z] as [number, number, number],
+ rotation: { x: selectedFloorAsset.rotation.x, y: selectedFloorAsset.rotation.y, z: selectedFloorAsset.rotation.z },
isLocked: false,
isVisible: true,
socketId: socket.id,
@@ -151,8 +153,8 @@ export default function TransformControl() {
assetData: asset,
newData: {
...asset,
- position: [selectedFloorItem.position.x, 0, selectedFloorItem.position.z],
- rotation: [selectedFloorItem.rotation.x, selectedFloorItem.rotation.y, selectedFloorItem.rotation.z],
+ position: [selectedFloorAsset.position.x, 0, selectedFloorAsset.position.z],
+ rotation: [selectedFloorAsset.rotation.x, selectedFloorAsset.rotation.y, selectedFloorAsset.rotation.z],
},
timeStap: new Date().toISOString()
}
@@ -170,7 +172,7 @@ export default function TransformControl() {
element?.getAttribute("contenteditable") === "true";
if (isTextInput(document.activeElement)) return;
const keyCombination = detectModifierKeys(e);
- if (!selectedFloorItem) return;
+ if (!selectedFloorAsset) return;
if (keyCombination === "G") {
setTransformMode((prev) => (prev === "translate" ? null : "translate"));
}
@@ -179,13 +181,13 @@ export default function TransformControl() {
}
};
- if (selectedFloorItem) {
+ if (selectedFloorAsset) {
window.addEventListener("keydown", handleKeyDown);
- setObjectPosition(selectedFloorItem.position);
+ setObjectPosition(selectedFloorAsset.position);
setObjectRotation({
- x: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.x),
- y: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.y),
- z: THREE.MathUtils.radToDeg(selectedFloorItem.rotation.z),
+ x: THREE.MathUtils.radToDeg(selectedFloorAsset.rotation.x),
+ y: THREE.MathUtils.radToDeg(selectedFloorAsset.rotation.y),
+ z: THREE.MathUtils.radToDeg(selectedFloorAsset.rotation.z),
});
} else {
setTransformMode(null);
@@ -194,7 +196,7 @@ export default function TransformControl() {
return () => {
window.removeEventListener("keydown", handleKeyDown);
};
- }, [selectedFloorItem]);
+ }, [selectedFloorAsset]);
useEffect(() => {
if (activeTool === "delete") {
@@ -202,7 +204,7 @@ export default function TransformControl() {
const target = (state.controls as any).getTarget(new THREE.Vector3());
(state.controls as any).setTarget(target.x, 0, target.z, true);
}
- setSelectedFloorItem(null);
+ setSelectedFloorAsset(null);
setObjectPosition({ x: undefined, y: undefined, z: undefined });
setObjectRotation({ x: undefined, y: undefined, z: undefined });
}
@@ -210,13 +212,13 @@ export default function TransformControl() {
return (
<>
- {(selectedFloorItem && transformMode) &&
+ {(selectedFloorAsset && transformMode) &&
+ );
+}
+
+export default OutlineInstance
\ No newline at end of file
diff --git a/app/src/modules/scene/postProcessing/outlineInstances/outlineInstances.tsx b/app/src/modules/scene/postProcessing/outlineInstances/outlineInstances.tsx
new file mode 100644
index 0000000..36ecfea
--- /dev/null
+++ b/app/src/modules/scene/postProcessing/outlineInstances/outlineInstances.tsx
@@ -0,0 +1,89 @@
+import { Object3D } from "three";
+import { useDeletableEventSphere, useSelectedEventSphere } from "../../../../store/simulation/useSimulationStore";
+import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
+import * as CONSTANTS from "../../../../types/world/worldConstants";
+import OutlineInstance from "./outlineInstance/outlineInstance";
+
+function flattenChildren(children: Object3D[]): Object3D[] {
+ return children.flatMap((child) => [child, ...flattenChildren(child.children)]);
+}
+
+function OutlineInstances() {
+ const { selectedEventSphere } = useSelectedEventSphere();
+ const { deletableEventSphere } = useDeletableEventSphere();
+ const { selectedAisle, selectedWall, selectedDecal, selectedFloor, selectedWallAsset, deletableWallAsset, selectedFloorAsset, deletableFloorAsset, deletableDecal } = useBuilderStore();
+
+ return (
+ <>
+
+
+
+
+
+ {/* Aisle / Wall / Floor */}
+
+
+
+
+ {/* Decals */}
+
+
+
+ {/* Event Spheres */}
+
+
+ >
+ )
+}
+
+export default OutlineInstances;
\ No newline at end of file
diff --git a/app/src/modules/scene/postProcessing/postProcessing.tsx b/app/src/modules/scene/postProcessing/postProcessing.tsx
index e6d656d..6f6cde8 100644
--- a/app/src/modules/scene/postProcessing/postProcessing.tsx
+++ b/app/src/modules/scene/postProcessing/postProcessing.tsx
@@ -1,273 +1,22 @@
-import { useEffect } from "react";
-import { BlendFunction } from "postprocessing";
-import { DepthOfField, Bloom, EffectComposer, N8AO, Outline } from "@react-three/postprocessing";
-import { useDeletableFloorItem, useSelectedWallItem, useSelectedFloorItem, } from "../../../store/builder/store";
-import { useDeletableEventSphere, useSelectedEventSphere, useSelectedPoints } from "../../../store/simulation/useSimulationStore";
-import { useBuilderStore } from "../../../store/builder/useBuilderStore";
-import * as CONSTANTS from "../../../types/world/worldConstants";
+import { DepthOfField, Bloom, EffectComposer, N8AO } from "@react-three/postprocessing";
+import OutlineInstances from "./outlineInstances/outlineInstances";
+import { useDeletableEventSphere, useSelectedEventSphere } from "../../../store/simulation/useSimulationStore";
export default function PostProcessing() {
- const { selectedPoints } = useSelectedPoints();
- const { deletableFloorItem } = useDeletableFloorItem();
- const { selectedWallItem } = useSelectedWallItem();
- const { selectedFloorItem } = useSelectedFloorItem();
- const { selectedEventSphere } = useSelectedEventSphere();
- const { deletableEventSphere } = useDeletableEventSphere();
- const { selectedAisle, selectedWall, selectedDecal, selectedFloor, selectedWallAsset, deletableWallAsset, deletableDecal } = useBuilderStore();
-
- function flattenChildren(children: any[]) {
- const allChildren: any[] = [];
- children.forEach((child) => {
- allChildren.push(child);
- if (child.children && child.children.length > 0) {
- allChildren.push(...flattenChildren(child.children));
- }
- });
- return allChildren;
- }
-
- useEffect(() => {
- // console.log('selectedFloorItem: ', selectedFloorItem);
- }, [selectedFloorItem])
-
- useEffect(() => {
- // console.log('selectedFloorItem: ', deletableFloorItem);
- }, [deletableFloorItem])
-
- useEffect(() => {
- // console.log('selectedAisle: ', selectedAisle);
- }, [selectedAisle])
-
- useEffect(() => {
- // console.log('selectedWall: ', selectedWall);
- }, [selectedWall])
-
- useEffect(() => {
- // console.log('selectedFloor: ', selectedFloor);
- }, [selectedFloor])
-
- useEffect(() => {
- // console.log('selectedWallAsset: ', selectedWallAsset);
- }, [selectedWallAsset])
-
- useEffect(() => {
- // console.log('deletableWallAsset: ', deletableWallAsset);
- }, [deletableWallAsset])
-
- useEffect(() => {
- // console.log('deletableEventSphere: ', deletableEventSphere);
- }, [deletableEventSphere])
-
- useEffect(() => {
- // console.log('selectedPoints: ', selectedPoints);
- }, [selectedPoints])
-
- useEffect(() => {
- // console.log('deletableDecal: ', deletableDecal);
- }, [deletableDecal])
+ const { } = useSelectedEventSphere();
+ const { } = useDeletableEventSphere();
return (
-
- {/* */}
- {/* */}
- {selectedWallAsset && (
-
- )}
- {deletableWallAsset && (
-
- )}
- {selectedAisle && (
-
- )}
- {selectedWall && (
-
- )}
- {selectedFloor && (
-
- )}
- {selectedDecal && (
-
- )}
- {deletableDecal && (
-
- )}
- {deletableFloorItem && (
-
- )}
- {selectedWallItem && (
-
- )}
- {selectedFloorItem && (
-
- )}
- {selectedEventSphere && (
-
- )}
- {deletableEventSphere && (
-
- )}
+
+
+
+ {/* */}
+
+ {/* */}
+
+
+
);
-}
+}
\ No newline at end of file
diff --git a/app/src/store/builder/store.ts b/app/src/store/builder/store.ts
index c022bb7..ac85949 100644
--- a/app/src/store/builder/store.ts
+++ b/app/src/store/builder/store.ts
@@ -73,61 +73,6 @@ export const useSocketStore = create((set: any, get: any) => ({
});
},
}));
-// export const useSocketStore = create((set: any, get: any) => ({
-// socket: null,
-// initializeSocket: (
-// email: string,
-// organization: string,
-// userId?: string,
-// token?: string
-// ) => {
-// const existingSocket = get().socket;
-// if (existingSocket) {
-// return;
-// }
-
-// const socket = io(
-// `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder`,
-// {
-// reconnection: true,
-// auth: { email, organization },
-// }
-// );
-
-// const visualizationSocket = io(
-// `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization`,
-// {
-// reconnection: true,
-// auth: { email, organization },
-// }
-// );
-
-// const dashBoardSocket = io(
-// `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/dashboard`,
-// {
-// reconnection: true,
-// auth: { token },
-// }
-// );
-// // const dashBoardSocket = io(
-// // `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/project`,
-// // {
-// // reconnection: true,
-// // auth: { token },
-// // }
-// // );
-
-// set({ socket, visualizationSocket, dashBoardSocket });
-// },
-// disconnectSocket: () => {
-// set((state: any) => {
-// state.socket?.disconnect();
-// state.visualizationSocket?.disconnect();
-// state.dashBoardSocket?.disconnect();
-// return { socket: null };
-// });
-// },
-// }));
export const useLoadingProgress = create<{
loadingProgress: number;
@@ -213,21 +158,6 @@ export const useToolMode = create((set: any) => ({
setToolMode: (x: any) => set(() => ({ toolMode: x })),
}));
-export const useSelectedWallItem = create((set: any) => ({
- selectedWallItem: null,
- setSelectedWallItem: (x: any) => set(() => ({ selectedWallItem: x })),
-}));
-
-export const useSelectedFloorItem = create((set: any) => ({
- selectedFloorItem: null,
- setSelectedFloorItem: (x: any) => set(() => ({ selectedFloorItem: x })),
-}));
-
-export const useDeletableFloorItem = create((set: any) => ({
- deletableFloorItem: null,
- setDeletableFloorItem: (x: any) => set(() => ({ deletableFloorItem: x })),
-}));
-
export const useSetScale = create((set: any) => ({
scale: null,
setScale: (x: any) => set(() => ({ scale: x })),
diff --git a/app/src/store/builder/useBuilderStore.ts b/app/src/store/builder/useBuilderStore.ts
index 1606c40..5e36d58 100644
--- a/app/src/store/builder/useBuilderStore.ts
+++ b/app/src/store/builder/useBuilderStore.ts
@@ -15,6 +15,7 @@ interface BuilderState {
// Floor Asset
selectedFloorAsset: Object3D | null;
+ deletableFloorAsset: Object3D | null;
loopAnimation: boolean;
// Wall Settings
@@ -47,7 +48,7 @@ interface BuilderState {
},
// Aisle General
- selectedAisle: {aisleMesh: Object3D | null, aisleData: Aisle} | null;
+ selectedAisle: { aisleMesh: Object3D | null, aisleData: Aisle } | null;
aisleType: AisleTypes;
aisleWidth: number;
aisleColor: AisleColors;
@@ -71,6 +72,7 @@ interface BuilderState {
// Setters - Floor Asset
setSelectedFloorAsset: (asset: Object3D | null) => void;
+ setDeletableFloorAsset: (asset: Object3D | null) => void;
setLoopAnimation: (loop: boolean) => void;
// Setters - Wall
@@ -97,7 +99,7 @@ interface BuilderState {
setDecalDragState: (isDragging: boolean, draggingDecalUuid: string | null, dragOffset: Vector3 | null) => void;
// Setters - Aisle General
- setSelectedAisle: (aisle: {aisleMesh: Object3D | null, aisleData: Aisle} | null) => void;
+ setSelectedAisle: (aisle: { aisleMesh: Object3D | null, aisleData: Aisle } | null) => void;
setAisleType: (type: AisleTypes) => void;
setAisleWidth: (width: number) => void;
setAisleColor: (color: AisleColors) => void;
@@ -128,6 +130,7 @@ export const useBuilderStore = create()(
deletableWallAsset: null,
selectedFloorAsset: null,
+ deletableFloorAsset: null,
loopAnimation: true,
selectedWall: null,
@@ -214,6 +217,12 @@ export const useBuilderStore = create()(
});
},
+ setDeletableFloorAsset(asset: Object3D | null) {
+ set((state) => {
+ state.deletableFloorAsset = asset;
+ });
+ },
+
setLoopAnimation(loopAnimation: boolean) {
set((state) => {
state.loopAnimation = loopAnimation;
@@ -325,7 +334,7 @@ export const useBuilderStore = create()(
// === Setters: Aisle General ===
- setSelectedAisle: (aisle: {aisleMesh: Object3D | null, aisleData: Aisle} | null) => {
+ setSelectedAisle: (aisle: { aisleMesh: Object3D | null, aisleData: Aisle } | null) => {
set((state) => {
state.selectedAisle = aisle;
});
diff --git a/app/src/utils/shortcutkeys/handleShortcutKeys.ts b/app/src/utils/shortcutkeys/handleShortcutKeys.ts
index 6a03563..88ada3f 100644
--- a/app/src/utils/shortcutkeys/handleShortcutKeys.ts
+++ b/app/src/utils/shortcutkeys/handleShortcutKeys.ts
@@ -1,293 +1,252 @@
import React, { useEffect } from "react";
-import useModuleStore, {
- useSubModuleStore,
- useThreeDStore,
-} from "../../store/useModuleStore";
+import useModuleStore, { useSubModuleStore, useThreeDStore } from "../../store/useModuleStore";
import { usePlayerStore, useToggleStore } from "../../store/useUIToggleStore";
-import useVersionHistoryVisibleStore, {
- useActiveSubTool,
- useActiveTool,
- useAddAction,
- useDfxUpload,
- useRenameModeStore,
- useSaveVersion,
- useSelectedAssets,
- useSelectedComment,
- useSelectedFloorItem,
- useSelectedWallItem,
- useShortcutStore,
- useToggleView,
- useToolMode,
- useViewSceneStore,
-} from "../../store/builder/store";
-import useCameraModeStore, {
- usePlayButtonStore,
-} from "../../store/usePlayButtonStore";
+import useVersionHistoryVisibleStore, { useActiveSubTool, useActiveTool, useAddAction, useDfxUpload, useRenameModeStore, useSaveVersion, useSelectedAssets, useSelectedComment, useShortcutStore, useToggleView, useToolMode, useViewSceneStore } from "../../store/builder/store";
+import useCameraModeStore, { usePlayButtonStore } from "../../store/usePlayButtonStore";
import { detectModifierKeys } from "./detectModifierKeys";
import { useSelectedZoneStore } from "../../store/visualization/useZoneStore";
import { useLogger } from "../../components/ui/log/LoggerContext";
import { useComparisonProduct } from "../../store/simulation/useSimulationStore";
import { useVersionHistoryStore } from "../../store/builder/useVersionHistoryStore";
+import { useBuilderStore } from "../../store/builder/useBuilderStore";
const KeyPressListener: React.FC = () => {
- const { comparisonProduct, clearComparisonProduct } = useComparisonProduct();
- const { activeModule, setActiveModule } = useModuleStore();
- const { setSubModule } = useSubModuleStore();
- const { setActiveSubTool } = useActiveSubTool();
- const { toggleUILeft, toggleUIRight, setToggleUI } = useToggleStore();
- const { setToggleThreeD } = useThreeDStore();
- const { setToolMode } = useToolMode();
- const { isPlaying, setIsPlaying } = usePlayButtonStore();
- const { toggleView, setToggleView } = useToggleView();
- const { setAddAction } = useAddAction();
- const { setSelectedWallItem } = useSelectedWallItem();
- const { setActiveTool } = useActiveTool();
- const { clearSelectedZone } = useSelectedZoneStore();
- const { showShortcuts, setShowShortcuts } = useShortcutStore();
- const { setWalkMode } = useCameraModeStore();
- const { setIsVersionSaved } = useSaveVersion();
- const { isLogListVisible, setIsLogListVisible } = useLogger();
- const { hidePlayer, setHidePlayer } = usePlayerStore();
- const { setViewSceneLabels } = useViewSceneStore();
- const { isRenameMode, setIsRenameMode } = useRenameModeStore();
- const { selectedFloorItem } = useSelectedFloorItem();
- const { selectedAssets } = useSelectedAssets();
- const { setCreateNewVersion } = useVersionHistoryStore();
- const { setVersionHistoryVisible } = useVersionHistoryVisibleStore();
- const { setSelectedComment } = useSelectedComment();
- const { setDfxUploaded } = useDfxUpload();
- const isTextInput = (element: Element | null): boolean =>
- element instanceof HTMLInputElement ||
- element instanceof HTMLTextAreaElement ||
- element?.getAttribute("contenteditable") === "true";
+ const { comparisonProduct, clearComparisonProduct } = useComparisonProduct();
+ const { activeModule, setActiveModule } = useModuleStore();
+ const { setSubModule } = useSubModuleStore();
+ const { setActiveSubTool } = useActiveSubTool();
+ const { toggleUILeft, toggleUIRight, setToggleUI } = useToggleStore();
+ const { setToggleThreeD } = useThreeDStore();
+ const { setToolMode } = useToolMode();
+ const { isPlaying, setIsPlaying } = usePlayButtonStore();
+ const { toggleView, setToggleView } = useToggleView();
+ const { setAddAction } = useAddAction();
+ const { setActiveTool } = useActiveTool();
+ const { clearSelectedZone } = useSelectedZoneStore();
+ const { showShortcuts, setShowShortcuts } = useShortcutStore();
+ const { setWalkMode } = useCameraModeStore();
+ const { setIsVersionSaved } = useSaveVersion();
+ const { isLogListVisible, setIsLogListVisible } = useLogger();
+ const { hidePlayer, setHidePlayer } = usePlayerStore();
+ const { setViewSceneLabels } = useViewSceneStore();
+ const { isRenameMode, setIsRenameMode } = useRenameModeStore();
+ const { selectedFloorAsset, setSelectedWallAsset } = useBuilderStore();
+ const { selectedAssets } = useSelectedAssets();
+ const { setCreateNewVersion } = useVersionHistoryStore();
+ const { setVersionHistoryVisible } = useVersionHistoryVisibleStore();
+ const { setSelectedComment } = useSelectedComment();
+ const { setDfxUploaded } = useDfxUpload();
+ const isTextInput = (element: Element | null): boolean => element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element?.getAttribute("contenteditable") === "true";
- const handleModuleSwitch = (keyCombination: string) => {
- const modules: Record = {
- "1": "builder",
- "2": "simulation",
- "3": "visualization",
- "4": "market",
- };
- const module = modules[keyCombination];
- if (module && !toggleView) {
- setActiveTool("cursor");
- setActiveSubTool("cursor");
- if (module === "market") setToggleUI(false, false);
- setActiveModule(module);
- }
- };
-
- const handlePrimaryTools = (key: string) => {
- const toolMap: Record = {
- V: "cursor",
- X: "delete",
- H: "free-hand",
- };
- const tool = toolMap[key];
- if (tool && selectedAssets.length === 0) {
- setActiveTool(tool);
- setActiveSubTool(tool);
- }
- };
-
- const handleBuilderShortcuts = (key: string) => {
- if (activeModule !== "builder" || isPlaying) return;
-
- if (key === "TAB") {
- const toggleTo2D = toggleView;
- setToggleView(!toggleTo2D);
- setToggleThreeD(toggleTo2D);
- if (toggleTo2D) {
- setSelectedWallItem(null);
- setAddAction(null);
- setToggleUI(
- localStorage.getItem("navBarUiLeft") !== "false",
- localStorage.getItem("navBarUiRight") !== "false"
- );
- } else {
- setToggleUI(false, false);
- }
- setActiveTool("cursor");
- setActiveSubTool("cursor");
- return;
- }
-
- // These should only apply in 2D view
- const twoDToolConfigs: Record = {
- Q: { tool: "draw-wall", mode: "Wall" },
- "6": { tool: "draw-wall", mode: "Wall" },
- R: { tool: "draw-aisle", mode: "Aisle" },
- "7": { tool: "draw-aisle", mode: "Aisle" },
- E: { tool: "draw-zone", mode: "Zone" },
- "8": { tool: "draw-zone", mode: "Zone" },
- T: { tool: "draw-floor", mode: "Floor" },
- "9": { tool: "draw-floor", mode: "Floor" },
- };
-
- const config = twoDToolConfigs[key];
- if (toggleView && config) {
- setActiveTool(config.tool);
- setToolMode(config.mode);
- }
-
- // Measurement tool should work in both 2D and 3D
- if (key === "M") {
- setActiveTool("measure");
- setToolMode("MeasurementScale");
- }
- if (key === "C") {
- setActiveTool("comment");
- }
- };
-
- const handleSidebarShortcuts = (key: string) => {
- if (activeModule === "market") return;
-
- const updateLocalStorage = (left: boolean, right: boolean) => {
- localStorage.setItem("navBarUiLeft", JSON.stringify(left));
- localStorage.setItem("navBarUiRight", JSON.stringify(right));
- };
-
- switch (key) {
- case "Ctrl+\\":
- if (toggleUILeft === toggleUIRight) {
- const newState = !toggleUILeft;
- setToggleUI(newState, newState);
- updateLocalStorage(newState, newState);
- } else {
- setToggleUI(true, true);
- updateLocalStorage(true, true);
+ const handleModuleSwitch = (keyCombination: string) => {
+ const modules: Record = {
+ "1": "builder",
+ "2": "simulation",
+ "3": "visualization",
+ "4": "market",
+ };
+ const module = modules[keyCombination];
+ if (module && !toggleView) {
+ setActiveTool("cursor");
+ setActiveSubTool("cursor");
+ if (module === "market") setToggleUI(false, false);
+ setActiveModule(module);
}
- break;
+ };
- case "Ctrl+]":
- setToggleUI(toggleUILeft, !toggleUIRight);
- updateLocalStorage(toggleUILeft, !toggleUIRight);
- break;
-
- case "Ctrl+[":
- setToggleUI(!toggleUILeft, toggleUIRight);
- updateLocalStorage(!toggleUILeft, toggleUIRight);
- break;
-
- case "Ctrl+Alt+S":
- setCreateNewVersion(true);
- setVersionHistoryVisible(true);
- setSubModule("properties");
- setActiveModule("builder");
- break;
-
- case "Ctrl+H":
- if (!isPlaying) {
- setVersionHistoryVisible(true);
- setSubModule("properties");
- setActiveModule("builder");
+ const handlePrimaryTools = (key: string) => {
+ const toolMap: Record = {
+ V: "cursor",
+ X: "delete",
+ H: "free-hand",
+ };
+ const tool = toolMap[key];
+ if (tool && selectedAssets.length === 0) {
+ setActiveTool(tool);
+ setActiveSubTool(tool);
}
- break;
+ };
- default:
- break;
- }
- };
+ const handleBuilderShortcuts = (key: string) => {
+ if (activeModule !== "builder" || isPlaying) return;
- const handleKeyPress = (event: KeyboardEvent) => {
- const keyCombination = detectModifierKeys(event);
+ if (key === "TAB") {
+ const toggleTo2D = toggleView;
+ setToggleView(!toggleTo2D);
+ setToggleThreeD(toggleTo2D);
+ if (toggleTo2D) {
+ setSelectedWallAsset(null);
+ setAddAction(null);
+ setToggleUI(
+ localStorage.getItem("navBarUiLeft") !== "false",
+ localStorage.getItem("navBarUiRight") !== "false"
+ );
+ } else {
+ setToggleUI(false, false);
+ }
+ setActiveTool("cursor");
+ setActiveSubTool("cursor");
+ return;
+ }
- if (isTextInput(document.activeElement) && keyCombination !== "ESCAPE") return;
+ // These should only apply in 2D view
+ const twoDToolConfigs: Record = {
+ Q: { tool: "draw-wall", mode: "Wall" },
+ "6": { tool: "draw-wall", mode: "Wall" },
+ R: { tool: "draw-aisle", mode: "Aisle" },
+ "7": { tool: "draw-aisle", mode: "Aisle" },
+ E: { tool: "draw-zone", mode: "Zone" },
+ "8": { tool: "draw-zone", mode: "Zone" },
+ T: { tool: "draw-floor", mode: "Floor" },
+ "9": { tool: "draw-floor", mode: "Floor" },
+ };
- if (keyCombination === "ESCAPE") {
- setWalkMode(false);
- setActiveTool("cursor");
- setActiveSubTool("cursor");
- setIsPlaying(false);
- clearSelectedZone();
- setShowShortcuts(false);
- setIsVersionSaved(false);
- clearComparisonProduct();
- setIsLogListVisible(false);
- setIsRenameMode(false);
- setDfxUploaded([]);
- setSelectedComment(null);
- }
+ const config = twoDToolConfigs[key];
+ if (toggleView && config) {
+ setActiveTool(config.tool);
+ setToolMode(config.mode);
+ }
- if (
- !keyCombination ||
- ["F5", "F11", "F12"].includes(event.key) ||
- keyCombination === "Ctrl+R"
- )
- return;
+ // Measurement tool should work in both 2D and 3D
+ if (key === "M") {
+ setActiveTool("measure");
+ setToolMode("MeasurementScale");
+ }
+ if (key === "C") {
+ setActiveTool("comment");
+ }
+ };
- event.preventDefault();
+ const handleSidebarShortcuts = (key: string) => {
+ if (activeModule === "market") return;
- // Shortcuts specific for sidebar visibility toggle and others specific to sidebar if added
- handleSidebarShortcuts(keyCombination);
+ const updateLocalStorage = (left: boolean, right: boolean) => {
+ localStorage.setItem("navBarUiLeft", JSON.stringify(left));
+ localStorage.setItem("navBarUiRight", JSON.stringify(right));
+ };
+
+ switch (key) {
+ case "Ctrl+\\":
+ if (toggleUILeft === toggleUIRight) {
+ const newState = !toggleUILeft;
+ setToggleUI(newState, newState);
+ updateLocalStorage(newState, newState);
+ } else {
+ setToggleUI(true, true);
+ updateLocalStorage(true, true);
+ }
+ break;
+
+ case "Ctrl+]":
+ setToggleUI(toggleUILeft, !toggleUIRight);
+ updateLocalStorage(toggleUILeft, !toggleUIRight);
+ break;
+
+ case "Ctrl+[":
+ setToggleUI(!toggleUILeft, toggleUIRight);
+ updateLocalStorage(!toggleUILeft, toggleUIRight);
+ break;
+
+ case "Ctrl+Alt+S":
+ setCreateNewVersion(true);
+ setVersionHistoryVisible(true);
+ setSubModule("properties");
+ setActiveModule("builder");
+ break;
+
+ case "Ctrl+H":
+ if (!isPlaying) {
+ setVersionHistoryVisible(true);
+ setSubModule("properties");
+ setActiveModule("builder");
+ }
+ break;
+
+ default:
+ break;
+ }
+ };
+
+ const handleKeyPress = (event: KeyboardEvent) => {
+ const keyCombination = detectModifierKeys(event);
+
+ if (isTextInput(document.activeElement) && keyCombination !== "ESCAPE") return;
+
+ if (keyCombination === "ESCAPE") {
+ setWalkMode(false);
+ setActiveTool("cursor");
+ setActiveSubTool("cursor");
+ setIsPlaying(false);
+ clearSelectedZone();
+ setShowShortcuts(false);
+ setIsVersionSaved(false);
+ clearComparisonProduct();
+ setIsLogListVisible(false);
+ setIsRenameMode(false);
+ setDfxUploaded([]);
+ setSelectedComment(null);
+ }
+
+ if (!keyCombination || ["F5", "F11", "F12"].includes(event.key) || keyCombination === "Ctrl+R")
+ return;
+
+ event.preventDefault();
+
+ // Shortcuts specific for sidebar visibility toggle and others specific to sidebar if added
+ handleSidebarShortcuts(keyCombination);
- // Active module selection (builder, simulation, etc.)
- if (event.location === 0) { // Location 0 = standard keyboard (not numpad)
- handleModuleSwitch(keyCombination);
- }
- // Common editing tools: cursor | delete | free-hand
- handlePrimaryTools(keyCombination);
- // Shortcuts specific to the builder module (e.g., drawing and measurement tools)
- handleBuilderShortcuts(keyCombination);
+ // Active module selection (builder, simulation, etc.)
+ if (event.location === 0) { // Location 0 = standard keyboard (not numpad)
+ handleModuleSwitch(keyCombination);
+ }
+ // Common editing tools: cursor | delete | free-hand
+ handlePrimaryTools(keyCombination);
+ // Shortcuts specific to the builder module (e.g., drawing and measurement tools)
+ handleBuilderShortcuts(keyCombination);
- // Shortcut to enter play mode
- if (keyCombination === "Ctrl+P" && !toggleView && !comparisonProduct) {
- setIsPlaying(true);
- }
+ // Shortcut to enter play mode
+ if (keyCombination === "Ctrl+P" && !toggleView && !comparisonProduct) {
+ setIsPlaying(true);
+ }
- if (keyCombination === "L") {
- setIsLogListVisible(!isLogListVisible);
- }
+ if (keyCombination === "L") {
+ setIsLogListVisible(!isLogListVisible);
+ }
- if (keyCombination === "H") {
- setHidePlayer(!hidePlayer);
- }
+ if (keyCombination === "H") {
+ setHidePlayer(!hidePlayer);
+ }
- if (keyCombination === "Ctrl+Shift+?") {
- setShowShortcuts(!showShortcuts);
- }
+ if (keyCombination === "Ctrl+Shift+?") {
+ setShowShortcuts(!showShortcuts);
+ }
- // if (keyCombination === "Ctrl+Shift+P") {
- // pref
- // }
+ // if (keyCombination === "Ctrl+Shift+P") {
+ // pref
+ // }
- if (keyCombination === "U") {
- setViewSceneLabels((prev) => !prev);
- }
+ if (keyCombination === "U") {
+ setViewSceneLabels((prev) => !prev);
+ }
- if ((selectedFloorItem || selectedAssets.length === 1) && keyCombination === "F2") {
- setIsRenameMode(true);
- }
+ if ((selectedFloorAsset || selectedAssets.length === 1) && keyCombination === "F2") {
+ setIsRenameMode(true);
+ }
- // Placeholder for future implementation
- if (
- ["Ctrl+Z", "Ctrl+Y", "Ctrl+Shift+Z", "Ctrl+F"].includes(keyCombination)
- ) {
- // Implement undo/redo/help/find/shortcuts
- }
- };
+ // Placeholder for future implementation
+ if (["Ctrl+Z", "Ctrl+Y", "Ctrl+Shift+Z", "Ctrl+F"].includes(keyCombination)) {
+ // Implement undo/redo/help/find/shortcuts
+ }
+ };
- useEffect(() => {
- window.addEventListener("keydown", handleKeyPress);
- return () => window.removeEventListener("keydown", handleKeyPress);
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [
- activeModule,
- toggleUIRight,
- toggleUILeft,
- toggleView,
- showShortcuts,
- isPlaying,
- isLogListVisible,
- hidePlayer,
- selectedFloorItem,
- isRenameMode,
- selectedAssets
- ]);
+ useEffect(() => {
+ window.addEventListener("keydown", handleKeyPress);
+ return () => window.removeEventListener("keydown", handleKeyPress);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [activeModule, toggleUIRight, toggleUILeft, toggleView, showShortcuts, isPlaying, isLogListVisible, hidePlayer, selectedFloorAsset, isRenameMode, selectedAssets]);
- return null;
+ return null;
};
export default KeyPressListener;