feat: Integrate active tool management across builder components; add deletableWallAsset state and related functionality

This commit is contained in:
2025-06-30 18:11:37 +05:30
parent 364b643c72
commit 0a039f34b1
8 changed files with 97 additions and 65 deletions

View File

@@ -1,5 +1,5 @@
import { useEffect } from 'react';
import { useToggleView } from '../../../store/builder/store'
import { useActiveTool, useToggleView } from '../../../store/builder/store'
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
import { useVersionContext } from '../version/versionContext';
import { useSceneContext } from '../../scene/sceneContext';
@@ -13,6 +13,7 @@ function FloorGroup() {
const { togglView } = useToggleView();
const { setSelectedFloor, setSelectedDecal } = useBuilderStore();
const { activeModule } = useModuleStore();
const { activeTool } = useActiveTool();
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
const { floorStore } = useSceneContext();
@@ -24,7 +25,7 @@ function FloorGroup() {
setSelectedFloor(null);
setSelectedDecal(null);
}
}, [togglView, activeModule])
}, [togglView, activeModule, activeTool])
useEffect(() => {
if (projectId && selectedVersion) {

View File

@@ -1,5 +1,5 @@
import { useEffect } from 'react';
import { useToggleView } from '../../../store/builder/store';
import { useActiveTool, useToggleView } from '../../../store/builder/store';
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
import { useVersionContext } from '../version/versionContext';
import { useSceneContext } from '../../scene/sceneContext';
@@ -14,6 +14,7 @@ function WallGroup() {
const { togglView } = useToggleView();
const { setSelectedWall, setSelectedDecal } = useBuilderStore();
const { activeModule } = useModuleStore();
const { activeTool } = useActiveTool();
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
const { wallStore } = useSceneContext();
@@ -25,7 +26,7 @@ function WallGroup() {
setSelectedWall(null);
setSelectedDecal(null);
}
}, [togglView, activeModule])
}, [togglView, activeModule, activeTool])
useEffect(() => {
if (projectId && selectedVersion) {

View File

@@ -1,5 +1,5 @@
import * as THREE from 'three';
import { useEffect, useMemo, useRef, useState } from 'react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { retrieveGLTF, storeGLTF } from '../../../../../utils/indexDB/idbUtils';
import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
@@ -7,7 +7,7 @@ import { Base, Geometry, Subtraction } from '@react-three/csg';
import useModuleStore from '../../../../../store/useModuleStore';
import { useSceneContext } from '../../../../scene/sceneContext';
import { useBuilderStore } from '../../../../../store/builder/useBuilderStore';
import { useToggleView } from '../../../../../store/builder/store';
import { useActiveTool, useToggleView } from '../../../../../store/builder/store';
import closestPointOnLineSegment from '../../../line/helpers/getClosestPointOnLineSegment';
import { useThree } from '@react-three/fiber';
@@ -16,10 +16,11 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
const { raycaster, pointer, camera, scene, controls, gl } = useThree();
const { wallStore, wallAssetStore } = useSceneContext();
const { walls, getWallById } = wallStore();
const { updateWallAsset } = wallAssetStore();
const { togglView } = useToggleView();
const { updateWallAsset, removeWallAsset } = wallAssetStore();
const { toggleView } = useToggleView();
const { activeTool } = useActiveTool();
const { activeModule } = useModuleStore();
const { selectedWallAsset, setSelectedWallAsset } = useBuilderStore();
const { selectedWallAsset, setSelectedWallAsset, setDeletableWallAsset, deletableWallAsset } = useBuilderStore();
const [gltfScene, setGltfScene] = useState<GLTF["scene"] | null>(null);
const [boundingBox, setBoundingBox] = useState<THREE.Box3 | null>(null);
const groupRef = useRef<THREE.Group>(null);
@@ -138,7 +139,7 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
}
};
if (selectedWallAsset && !togglView && activeModule === 'builder') {
if (selectedWallAsset && !toggleView && activeModule === 'builder') {
canvasElement.addEventListener('mousemove', onPointerMove);
canvasElement.addEventListener('pointerup', onPointerUp);
}
@@ -148,7 +149,29 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
canvasElement.removeEventListener('pointerup', onPointerUp);
};
}, [gl, camera, togglView, activeModule, selectedWallAsset])
}, [gl, camera, toggleView, activeModule, selectedWallAsset])
const handlePointerClick = useCallback((wallAsset: WallAsset) => {
if (activeTool === 'delete' && deletableWallAsset && deletableWallAsset.userData.modelUuid === wallAsset.modelUuid) {
removeWallAsset(wallAsset.modelUuid);
}
}, [activeTool, activeModule, deletableWallAsset])
const handlePointerOver = useCallback((wallAsset: WallAsset, currentObject: THREE.Object3D) => {
if (activeTool === "delete" && activeModule === 'builder') {
if (deletableWallAsset && deletableWallAsset.userData.modelUuid === wallAsset.modelUuid) {
return;
} else {
setDeletableWallAsset(currentObject);
}
}
}, [activeTool, activeModule, deletableWallAsset]);
const handlePointerOut = useCallback((wallAsset: WallAsset) => {
if (activeTool === "delete" && deletableWallAsset && deletableWallAsset.userData.modelUuid === wallAsset.modelUuid) {
setDeletableWallAsset(null);
}
}, [activeTool, deletableWallAsset]);
if (!gltfScene || !boundingBox || !wall) { return null }
const size = new THREE.Vector3();
@@ -175,7 +198,7 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
{gltfScene && (
<mesh
onPointerDown={(e) => {
if (!togglView && activeModule === 'builder' && selectedWallAsset && selectedWallAsset.userData.modelUuid === wallAsset.modelUuid) {
if (!toggleView && activeModule === 'builder' && selectedWallAsset && selectedWallAsset.userData.modelUuid === wallAsset.modelUuid) {
draggingRef.current = true;
e.stopPropagation();
setSelectedWallAsset(groupRef.current);
@@ -185,7 +208,7 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
}
}}
onClick={(e) => {
if (!togglView && activeModule === 'builder') {
if (!toggleView && activeModule === 'builder' && activeTool !== 'delete') {
if (e.object) {
e.stopPropagation();
let currentObject = e.object as THREE.Object3D;
@@ -197,6 +220,8 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
}
setSelectedWallAsset(currentObject);
}
} else if (!toggleView && activeModule === 'builder' && activeTool === 'delete') {
handlePointerClick(wallAsset);
}
}}
onPointerMissed={() => {
@@ -204,6 +229,25 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
setSelectedWallAsset(null);
}
}}
onPointerEnter={(e) => {
if (!toggleView) {
e.stopPropagation();
let currentObject = e.object as THREE.Object3D;
while (currentObject) {
if (currentObject.name === "Scene") {
break;
}
currentObject = currentObject.parent as THREE.Object3D;
}
handlePointerOver(wallAsset, currentObject);
}
}}
onPointerOut={(e) => {
if (!toggleView) {
e.stopPropagation();
handlePointerOut(wallAsset);
}
}}
userData={wallAsset}
>
<primitive userData={wallAsset} object={gltfScene} />

View File

@@ -5,54 +5,9 @@ import WallAssetInstance from './Instances/wallAssetInstance';
function WallAssetInstances() {
const { wallAssetStore } = useSceneContext();
const { wallAssets, setWallAssets } = wallAssetStore();
const { wallAssets } = wallAssetStore();
const { toggleView } = useToggleView();
useEffect(() => {
setWallAssets([
{
"modelName": "shutter_open",
"modelUuid": "23bf68d5-10c9-4cd0-807f-80e5016707b5",
"wallUuid": "7fc7984d-6d62-4cec-afaa-289673dcce43",
"wallAssetType": "fixed-move",
"assetId": "274f6c32aa861255c2947bea",
"position": [
-13.748701534598418,
0,
20.112805679001355
],
"rotation": [
0,
-3.141592653589793,
0
],
"isLocked": false,
"isVisible": true,
"opacity": 1
},
{
"modelName": "window",
"modelUuid": "5d73f98e-6f17-42b0-a53c-9a2c4472f2be",
"wallUuid": "7fc7984d-6d62-4cec-afaa-289673dcce43",
"wallAssetType": "free-move",
"assetId": "e44a85ff2021392f4c4a03f4",
"position": [
-4.522713460474861,
4.189202463272018,
20.112805679001355
],
"rotation": [
0,
-3.141592653589793,
0
],
"isLocked": false,
"isVisible": true,
"opacity": 1
}
])
}, [])
useEffect(() => {
// console.log('wallAssets: ', wallAssets);
}, [wallAssets])

View File

@@ -1,5 +1,5 @@
import { useEffect } from 'react';
import { useToggleView } from '../../../store/builder/store';
import { useActiveTool, useToggleView } from '../../../store/builder/store';
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
import { useVersionContext } from '../version/versionContext';
import { useSceneContext } from '../../scene/sceneContext';
@@ -10,8 +10,9 @@ import WallAssetInstances from './Instances/wallAssetInstances'
function WallAssetGroup() {
const { togglView } = useToggleView();
const { setSelectedFloorAsset } = useBuilderStore();
const { setSelectedFloorAsset, setDeletableWallAsset } = useBuilderStore();
const { activeModule } = useModuleStore();
const { activeTool } = useActiveTool();
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
const { wallAssetStore } = useSceneContext();
@@ -22,7 +23,8 @@ function WallAssetGroup() {
if (togglView || activeModule !== 'builder') {
setSelectedFloorAsset(null);
}
}, [togglView, activeModule])
setDeletableWallAsset(null);
}, [togglView, activeModule, activeTool])
return (
<>

View File

@@ -1,5 +1,5 @@
import { useEffect } from 'react';
import { useToggleView } from '../../../store/builder/store';
import { useActiveTool, useToggleView } from '../../../store/builder/store';
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
import { useVersionContext } from '../version/versionContext';
import { useSceneContext } from '../../scene/sceneContext';
@@ -14,6 +14,7 @@ function ZoneGroup() {
const { togglView } = useToggleView();
const { setSelectedZone } = useBuilderStore();
const { activeModule } = useModuleStore();
const { activeTool } = useActiveTool();
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
const { zoneStore } = useSceneContext();
@@ -24,7 +25,7 @@ function ZoneGroup() {
if (togglView || activeModule !== 'builder') {
setSelectedZone(null);
}
}, [togglView, activeModule])
}, [togglView, activeModule, activeTool])
useEffect(() => {
if (projectId && selectedVersion) {

View File

@@ -15,7 +15,7 @@ export default function PostProcessing() {
const { selectedWallItem } = useSelectedWallItem();
const { selectedFloorItem } = useSelectedFloorItem();
const { selectedEventSphere } = useSelectedEventSphere();
const { selectedAisle, selectedWall, selectedDecal, selectedFloor, selectedWallAsset } = useBuilderStore();
const { selectedAisle, selectedWall, selectedDecal, selectedFloor, selectedWallAsset, deletableWallAsset } = useBuilderStore();
function flattenChildren(children: any[]) {
const allChildren: any[] = [];
@@ -52,6 +52,10 @@ export default function PostProcessing() {
// console.log('selectedWallAsset: ', selectedWallAsset);
}, [selectedWallAsset])
useEffect(() => {
// console.log('deletableWallAsset: ', deletableWallAsset);
}, [deletableWallAsset])
return (
<EffectComposer autoClear={false}>
<N8AO
@@ -78,6 +82,21 @@ export default function PostProcessing() {
xRay={true}
/>
)}
{deletableWallAsset && (
<Outline
selection={flattenChildren(deletableWallAsset.children)}
selectionLayer={10}
width={2000}
blendFunction={BlendFunction.ALPHA}
edgeStrength={5}
resolutionScale={2}
pulseSpeed={0}
visibleEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor}
hiddenEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor}
blur={true}
xRay={true}
/>
)}
{selectedAisle && (
<Outline
selection={flattenChildren(selectedAisle.children)}

View File

@@ -11,6 +11,7 @@ interface BuilderState {
// Wall Asset
selectedWallAsset: Object3D | null;
deletableWallAsset: Object3D | null;
// Floor Asset
selectedFloorAsset: Object3D | null;
@@ -59,6 +60,7 @@ interface BuilderState {
// Setters - Wall Asset
setSelectedWallAsset: (asset: Object3D | null) => void;
setDeletableWallAsset: (asset: Object3D | null) => void;
// Setters - Floor Asset
setSelectedFloorAsset: (asset: Object3D | null) => void;
@@ -113,6 +115,7 @@ export const useBuilderStore = create<BuilderState>()(
hoveredLine: null,
selectedWallAsset: null,
deletableWallAsset: null,
selectedFloorAsset: null,
@@ -180,6 +183,12 @@ export const useBuilderStore = create<BuilderState>()(
});
},
setDeletableWallAsset(asset: Object3D | null) {
set((state) => {
state.deletableWallAsset = asset;
});
},
// === Setters: Floor Asset ===
setSelectedFloorAsset(asset: Object3D | null) {