223 lines
7.6 KiB
TypeScript
223 lines
7.6 KiB
TypeScript
import { useEffect, useRef, useState } from 'react';
|
|
import { useThree } from '@react-three/fiber';
|
|
import { CameraControls, Html, ScreenSpace } from '@react-three/drei';
|
|
import { useContextActionStore, useRenameModeStore, useSelectedAssets } from '../../../../store/builder/store';
|
|
import ContextMenu from '../../../../components/ui/menu/contextMenu';
|
|
|
|
function ContextControls() {
|
|
const { gl, controls } = useThree();
|
|
const [canRender, setCanRender] = useState(false);
|
|
const [visibility, setVisibility] = useState({ rename: true, focus: true, flipX: true, flipZ: true, move: true, rotate: true, duplicate: true, copy: true, paste: true, modifier: false, group: false, array: false, delete: true, });
|
|
const [menuPosition, setMenuPosition] = useState({ x: 0, y: 0 });
|
|
const { selectedAssets } = useSelectedAssets();
|
|
const { setContextAction } = useContextActionStore();
|
|
const { setIsRenameMode } = useRenameModeStore();
|
|
const rightDrag = useRef(false);
|
|
const isRightMouseDown = useRef(false);
|
|
|
|
useEffect(() => {
|
|
if (selectedAssets.length === 1) {
|
|
setVisibility({
|
|
rename: true,
|
|
focus: true,
|
|
flipX: true,
|
|
flipZ: true,
|
|
move: true,
|
|
rotate: true,
|
|
duplicate: true,
|
|
copy: true,
|
|
paste: true,
|
|
modifier: false,
|
|
group: false,
|
|
array: false,
|
|
delete: true,
|
|
});
|
|
} else if (selectedAssets.length > 1) {
|
|
setVisibility({
|
|
rename: false,
|
|
focus: true,
|
|
flipX: true,
|
|
flipZ: true,
|
|
move: true,
|
|
rotate: true,
|
|
duplicate: true,
|
|
copy: true,
|
|
paste: true,
|
|
modifier: false,
|
|
group: true,
|
|
array: false,
|
|
delete: true,
|
|
});
|
|
} else {
|
|
setVisibility({
|
|
rename: false,
|
|
focus: false,
|
|
flipX: false,
|
|
flipZ: false,
|
|
move: false,
|
|
rotate: false,
|
|
duplicate: false,
|
|
copy: false,
|
|
paste: false,
|
|
modifier: false,
|
|
group: false,
|
|
array: false,
|
|
delete: false,
|
|
});
|
|
}
|
|
}, [selectedAssets]);
|
|
|
|
useEffect(() => {
|
|
const canvasElement = gl.domElement;
|
|
|
|
const onPointerDown = (evt: any) => {
|
|
if (evt.button === 2) {
|
|
isRightMouseDown.current = true;
|
|
rightDrag.current = false;
|
|
}
|
|
};
|
|
|
|
const onPointerMove = () => {
|
|
if (isRightMouseDown.current) {
|
|
rightDrag.current = true;
|
|
}
|
|
};
|
|
|
|
const onPointerUp = (evt: any) => {
|
|
if (evt.button === 2) {
|
|
isRightMouseDown.current = false;
|
|
}
|
|
};
|
|
|
|
const handleContextClick = (event: MouseEvent) => {
|
|
event.preventDefault();
|
|
if (rightDrag.current) return;
|
|
if (selectedAssets.length > 0) {
|
|
setMenuPosition({ x: event.clientX - gl.domElement.width / 2, y: event.clientY - gl.domElement.height / 2 });
|
|
setCanRender(true);
|
|
if (controls) {
|
|
(controls as CameraControls).enabled = false;
|
|
}
|
|
} else {
|
|
setCanRender(false);
|
|
if (controls) {
|
|
(controls as CameraControls).enabled = true;
|
|
}
|
|
}
|
|
};
|
|
|
|
if (selectedAssets.length > 0) {
|
|
canvasElement.addEventListener('pointerdown', onPointerDown);
|
|
canvasElement.addEventListener('pointermove', onPointerMove);
|
|
canvasElement.addEventListener('pointerup', onPointerUp);
|
|
canvasElement.addEventListener('contextmenu', handleContextClick)
|
|
} else {
|
|
setCanRender(false);
|
|
if (controls) {
|
|
(controls as CameraControls).enabled = true;
|
|
}
|
|
setMenuPosition({ x: 0, y: 0 });
|
|
}
|
|
|
|
return () => {
|
|
canvasElement.removeEventListener('pointerdown', onPointerDown);
|
|
canvasElement.removeEventListener('pointermove', onPointerMove);
|
|
canvasElement.removeEventListener('pointerup', onPointerUp);
|
|
canvasElement.removeEventListener('contextmenu', handleContextClick);
|
|
};
|
|
}, [gl, selectedAssets]);
|
|
|
|
const handleAssetRename = () => {
|
|
setCanRender(false);
|
|
if (controls) {
|
|
(controls as CameraControls).enabled = true;
|
|
}
|
|
setContextAction("renameAsset");
|
|
setIsRenameMode(true);
|
|
}
|
|
const handleAssetFocus = () => {
|
|
setCanRender(false);
|
|
if (controls) {
|
|
(controls as CameraControls).enabled = true;
|
|
}
|
|
setContextAction("focusAsset");
|
|
}
|
|
const handleAssetMove = () => {
|
|
setCanRender(false);
|
|
if (controls) {
|
|
(controls as CameraControls).enabled = true;
|
|
}
|
|
setContextAction("moveAsset")
|
|
}
|
|
const handleAssetRotate = () => {
|
|
setCanRender(false);
|
|
if (controls) {
|
|
(controls as CameraControls).enabled = true;
|
|
}
|
|
setContextAction("rotateAsset")
|
|
}
|
|
const handleAssetCopy = () => {
|
|
setCanRender(false);
|
|
if (controls) {
|
|
(controls as CameraControls).enabled = true;
|
|
}
|
|
setContextAction("copyAsset")
|
|
}
|
|
const handleAssetPaste = () => {
|
|
setCanRender(false);
|
|
if (controls) {
|
|
(controls as CameraControls).enabled = true;
|
|
}
|
|
setContextAction("pasteAsset")
|
|
}
|
|
const handleAssetDelete = () => {
|
|
setCanRender(false);
|
|
if (controls) {
|
|
(controls as CameraControls).enabled = true;
|
|
}
|
|
setContextAction("deleteAsset")
|
|
}
|
|
const handleAssetDuplicate = () => {
|
|
setCanRender(false);
|
|
if (controls) {
|
|
(controls as CameraControls).enabled = true;
|
|
}
|
|
setContextAction("duplicateAsset")
|
|
}
|
|
|
|
return (
|
|
<>
|
|
{canRender && (
|
|
<ScreenSpace depth={1} >
|
|
<Html
|
|
style={{
|
|
position: 'fixed',
|
|
top: menuPosition.y,
|
|
left: menuPosition.x,
|
|
zIndex: 1000
|
|
}}
|
|
>
|
|
<ContextMenu
|
|
visibility={visibility}
|
|
onRename={() => handleAssetRename()}
|
|
onFocus={() => handleAssetFocus()}
|
|
onFlipX={() => console.log("Flip to X")}
|
|
onFlipZ={() => console.log("Flip to Z")}
|
|
onMove={() => handleAssetMove()}
|
|
onRotate={() => handleAssetRotate()}
|
|
onDuplicate={() => handleAssetDuplicate()}
|
|
onCopy={() => handleAssetCopy()}
|
|
onPaste={() => handleAssetPaste()}
|
|
onGroup={() => console.log("Group")}
|
|
onArray={() => console.log("Array")}
|
|
onDelete={() => handleAssetDelete()}
|
|
/>
|
|
</Html>
|
|
</ScreenSpace>
|
|
)}
|
|
</>
|
|
);
|
|
}
|
|
|
|
export default ContextControls;
|