외벽선, 배치면 Redo undo 수정
This commit is contained in:
parent
2074c4aa93
commit
80720fef2a
@ -9,6 +9,7 @@ import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
|
||||
import { subMenusState } from '@/store/menuAtom'
|
||||
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
|
||||
import { commonUtilsState } from '@/store/commonUtilsAtom'
|
||||
import { isUndoRedoRestoring } from '@/hooks/useUndoRedo'
|
||||
|
||||
export default function MenuDepth01() {
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
@ -29,6 +30,10 @@ export default function MenuDepth01() {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
// undo/redo 복원 중에는 메뉴 변경에 따른 팝업 자동 오픈을 건너뛴다.
|
||||
// 그렇지 않으면 그리기 팝업이 다시 열리며 setDrawing(true) 가 호출되어
|
||||
// redo 버튼이 비활성화되는 문제가 발생한다.
|
||||
if (isUndoRedoRestoring()) return
|
||||
handleMenu(selectedMenu)
|
||||
canvas?.discardActiveObject()
|
||||
}, [currentMenu])
|
||||
|
||||
@ -63,7 +63,7 @@ export function useOuterLineWall(id, propertiesId) {
|
||||
const { tempGridMode } = useTempGrid()
|
||||
const { addPolygonByLines } = usePolygon()
|
||||
const { handleSelectableObjects } = useObject()
|
||||
const { saveSnapshot } = useUndoRedo()
|
||||
const { saveSnapshot, setDrawing } = useUndoRedo()
|
||||
|
||||
const verticalHorizontalMode = useRecoilValue(verticalHorizontalModeState)
|
||||
const adsorptionPointAddMode = useRecoilValue(adsorptionPointAddModeState)
|
||||
@ -121,6 +121,15 @@ export function useOuterLineWall(id, propertiesId) {
|
||||
}
|
||||
}, [verticalHorizontalMode, points, adsorptionPointAddMode, adsorptionPointMode, adsorptionRange, interval, tempGridMode])
|
||||
|
||||
// 외벽선 그리기 진행 중에는 undo/redo/스냅샷을 차단한다.
|
||||
// 그리기 전 스냅샷은 첫 클릭(mouseDown) 에서 force 로 저장한다 (기존 동작 유지).
|
||||
useEffect(() => {
|
||||
setDrawing(true)
|
||||
return () => {
|
||||
setDrawing(false)
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
arrow1Ref.current = arrow1
|
||||
}, [arrow1])
|
||||
@ -158,7 +167,9 @@ export function useOuterLineWall(id, propertiesId) {
|
||||
pointer = { x: Big(pointer.x).toNumber(), y: Big(pointer.y).toNumber() }
|
||||
|
||||
if (points.length === 0) {
|
||||
saveSnapshot()
|
||||
// 그리기 진행 중에는 스냅샷이 차단되므로 force 로 저장한다.
|
||||
// (처음 한 번만 저장되고 이후 추가 클릭은 points.length > 0 분기로 빠지므로 중복 저장 안 됨)
|
||||
saveSnapshot(null, { force: true })
|
||||
setPoints((prev) => [...prev, pointer])
|
||||
} else {
|
||||
const lastPoint = points[points.length - 1]
|
||||
|
||||
@ -51,7 +51,7 @@ export function usePlacementShapeDrawing(id) {
|
||||
const { setSurfaceShapePattern } = useRoofFn()
|
||||
const { changeSurfaceLineType } = useSurfaceShapeBatch({})
|
||||
const { handleSelectableObjects } = useObject()
|
||||
const { saveSnapshot, popLastSnapshot } = useUndoRedo()
|
||||
const { saveSnapshot, popLastSnapshot, setDrawing } = useUndoRedo()
|
||||
const { swalFire } = useSwal()
|
||||
const { getMessage } = useMessage()
|
||||
|
||||
@ -98,12 +98,15 @@ export function usePlacementShapeDrawing(id) {
|
||||
}, [verticalHorizontalMode, points, adsorptionRange, adsorptionPointMode])
|
||||
|
||||
useEffect(() => {
|
||||
// 배치면 그리기 시작 시 스냅샷 저장 (undo 하면 그리기 전 상태로 복원)
|
||||
saveSnapshot()
|
||||
// 배치면 그리기 시작 시 스냅샷 저장 (undo 하면 그리기 전 상태로 복원).
|
||||
// 그리기 진행 중에는 undo/redo/snapshot 을 차단하므로 force 로 저장한다.
|
||||
setDrawing(true)
|
||||
saveSnapshot(null, { force: true })
|
||||
setPoints([])
|
||||
setType(OUTER_LINE_TYPE.OUTER_LINE)
|
||||
|
||||
return () => {
|
||||
setDrawing(false)
|
||||
const placementShapeDrawingStartPoint = canvas.getObjects().find((obj) => obj.name === 'placementShapeDrawingStartPoint')
|
||||
canvas.remove(placementShapeDrawingStartPoint)
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@ import {
|
||||
moduleSetupSurfaceState,
|
||||
redoStackState,
|
||||
roofPolygonArrayState,
|
||||
undoRedoDrawingState,
|
||||
undoStackState,
|
||||
} from '@/store/canvasAtom'
|
||||
import { outerLinePointsState } from '@/store/outerLineAtom'
|
||||
@ -25,6 +26,10 @@ const MAX_HISTORY = 3
|
||||
let _isRestoring = false
|
||||
let _restoreTimer = null
|
||||
|
||||
// 외벽선/배치면 등 그리기 진행 중에는 undo/redo/snapshot 을 차단한다.
|
||||
// (확정 시점부터 history 가 동작해야 하므로)
|
||||
let _isDrawing = false
|
||||
|
||||
/**
|
||||
* 외부 훅/모듈에서 현재 undo/redo 복원 중인지 확인할 때 사용
|
||||
*/
|
||||
@ -32,6 +37,21 @@ export function isUndoRedoRestoring() {
|
||||
return _isRestoring
|
||||
}
|
||||
|
||||
/**
|
||||
* 외벽선/배치면 등 그리기 진행 상태를 외부에서 설정한다.
|
||||
* 그리기가 시작될 때 true, 확정 또는 취소 시 false 로 설정한다.
|
||||
*/
|
||||
export function setUndoRedoDrawing(value) {
|
||||
_isDrawing = !!value
|
||||
}
|
||||
|
||||
/**
|
||||
* 외부 훅/모듈에서 현재 그리기 진행 중인지 확인할 때 사용
|
||||
*/
|
||||
export function isUndoRedoDrawing() {
|
||||
return _isDrawing
|
||||
}
|
||||
|
||||
// loadFromJSON 공통 처리 - 이벤트 일시 중단 후 복원
|
||||
function _restoreFromJSON(canvas, snapshot, restoreAtomSnapshot, rebuildCanvasAtoms, setCanvasZoom) {
|
||||
// 진행 중인 복원 타이머가 있으면 취소
|
||||
@ -98,6 +118,7 @@ export function useUndoRedo() {
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
const [undoStack, setUndoStack] = useRecoilState(undoStackState)
|
||||
const [redoStack, setRedoStack] = useRecoilState(redoStackState)
|
||||
const [isDrawing, setIsDrawing] = useRecoilState(undoRedoDrawingState)
|
||||
|
||||
const [, setModuleSetupSurface] = useRecoilState(moduleSetupSurfaceState)
|
||||
const [moduleIsSetup, setModuleIsSetup] = useRecoilState(moduleIsSetupState)
|
||||
@ -375,6 +396,9 @@ export function useUndoRedo() {
|
||||
// 지붕형상 수동설정 메뉴에서는 스냅샷을 쌓지 않는다 (force 시 예외)
|
||||
if (!force && currentMenu === MENU.ROOF_COVERING.ROOF_SHAPE_PASSIVITY_SETTINGS) return
|
||||
|
||||
// 외벽선/배치면 등 그리기 진행 중에는 스냅샷을 쌓지 않는다 (force 시 예외)
|
||||
if (!force && (_isDrawing || isDrawing)) return
|
||||
|
||||
// snapshot 전에 mouseLine 제거
|
||||
const mouseLines = canvas.getObjects().filter((obj) => obj.name === 'mouseLine')
|
||||
mouseLines.forEach((obj) => canvas.remove(obj))
|
||||
@ -402,7 +426,7 @@ export function useUndoRedo() {
|
||||
return newStack
|
||||
})
|
||||
setRedoStack([])
|
||||
}, [canvas, currentMenu, getCanvasSnapshot, getAtomSnapshot])
|
||||
}, [canvas, currentMenu, isDrawing, getCanvasSnapshot, getAtomSnapshot])
|
||||
|
||||
const closeAllPopups = useCallback(() => {
|
||||
setPopup((prev) => ({
|
||||
@ -416,6 +440,9 @@ export function useUndoRedo() {
|
||||
// 지붕형상 수동설정 중에는 undo 차단
|
||||
if (currentMenu === MENU.ROOF_COVERING.ROOF_SHAPE_PASSIVITY_SETTINGS) return
|
||||
|
||||
// 외벽선/배치면 등 그리기 진행 중에는 undo 차단
|
||||
if (_isDrawing || isDrawing) return
|
||||
|
||||
const currentUndoStack = undoStackRef.current
|
||||
if (!canvas || currentUndoStack.length === 0 || _isRestoring) return
|
||||
|
||||
@ -439,12 +466,15 @@ export function useUndoRedo() {
|
||||
setRedoStack((prev) => [...prev, currentSnapshot])
|
||||
|
||||
_restoreFromJSON(canvas, snapshot, restoreAtomSnapshot, rebuildCanvasAtoms, setCanvasZoom)
|
||||
}, [canvas, currentMenu, getCanvasSnapshot, getAtomSnapshot, restoreAtomSnapshot, rebuildCanvasAtoms, closeAllPopups])
|
||||
}, [canvas, currentMenu, isDrawing, getCanvasSnapshot, getAtomSnapshot, restoreAtomSnapshot, rebuildCanvasAtoms, closeAllPopups])
|
||||
|
||||
const redo = useCallback(() => {
|
||||
// 지붕형상 수동설정 중에는 redo 차단
|
||||
if (currentMenu === MENU.ROOF_COVERING.ROOF_SHAPE_PASSIVITY_SETTINGS) return
|
||||
|
||||
// 외벽선/배치면 등 그리기 진행 중에는 redo 차단
|
||||
if (_isDrawing || isDrawing) return
|
||||
|
||||
const currentRedoStack = redoStackRef.current
|
||||
if (!canvas || currentRedoStack.length === 0 || _isRestoring) return
|
||||
|
||||
@ -467,7 +497,7 @@ export function useUndoRedo() {
|
||||
setUndoStack((prev) => [...prev, currentSnapshot])
|
||||
|
||||
_restoreFromJSON(canvas, snapshot, restoreAtomSnapshot, rebuildCanvasAtoms, setCanvasZoom)
|
||||
}, [canvas, currentMenu, getCanvasSnapshot, getAtomSnapshot, restoreAtomSnapshot, rebuildCanvasAtoms, closeAllPopups])
|
||||
}, [canvas, currentMenu, isDrawing, getCanvasSnapshot, getAtomSnapshot, restoreAtomSnapshot, rebuildCanvasAtoms, closeAllPopups])
|
||||
|
||||
const clearStacks = useCallback(() => {
|
||||
setUndoStack([])
|
||||
@ -479,13 +509,27 @@ export function useUndoRedo() {
|
||||
setUndoStack((prev) => (prev.length > 0 ? prev.slice(0, -1) : prev))
|
||||
}, [])
|
||||
|
||||
/**
|
||||
* 외벽선/배치면 등 그리기 진행 중에는 undo/redo 를 차단한다.
|
||||
* 마운트 시 true, 언마운트 시 false 로 설정한다.
|
||||
*/
|
||||
const setDrawing = useCallback(
|
||||
(value) => {
|
||||
const v = !!value
|
||||
setIsDrawing(v)
|
||||
setUndoRedoDrawing(v)
|
||||
},
|
||||
[setIsDrawing],
|
||||
)
|
||||
|
||||
return {
|
||||
saveSnapshot,
|
||||
undo,
|
||||
redo,
|
||||
clearStacks,
|
||||
popLastSnapshot,
|
||||
canUndo: undoStack.length > 0,
|
||||
canRedo: redoStack.length > 0,
|
||||
setDrawing,
|
||||
canUndo: undoStack.length > 0 && !isDrawing,
|
||||
canRedo: redoStack.length > 0 && !isDrawing,
|
||||
}
|
||||
}
|
||||
|
||||
@ -421,3 +421,10 @@ export const redoStackState = atom({
|
||||
default: [],
|
||||
dangerouslyAllowMutability: true,
|
||||
})
|
||||
|
||||
// 외벽선/배치면 등 그리기 진행 중 여부.
|
||||
// true 동안에는 undo/redo 가 비활성화되고 새 스냅샷이 쌓이지 않는다.
|
||||
export const undoRedoDrawingState = atom({
|
||||
key: 'undoRedoDrawingState',
|
||||
default: false,
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user