redo undo 작업중
This commit is contained in:
parent
c7238b2e27
commit
d68f92c5d5
@ -36,7 +36,12 @@ import {
|
|||||||
import { sessionStore } from '@/store/commonAtom'
|
import { sessionStore } from '@/store/commonAtom'
|
||||||
import { outerLinePointsState } from '@/store/outerLineAtom'
|
import { outerLinePointsState } from '@/store/outerLineAtom'
|
||||||
import { appMessageStore, globalLocaleStore } from '@/store/localeAtom'
|
import { appMessageStore, globalLocaleStore } from '@/store/localeAtom'
|
||||||
import { addedRoofsState, basicSettingState, selectedRoofMaterialSelector, settingModalFirstOptionsState } from '@/store/settingAtom'
|
import {
|
||||||
|
addedRoofsState,
|
||||||
|
basicSettingState,
|
||||||
|
selectedRoofMaterialSelector,
|
||||||
|
settingModalFirstOptionsState,
|
||||||
|
} from '@/store/settingAtom'
|
||||||
import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom'
|
import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom'
|
||||||
import { commonUtilsState } from '@/store/commonUtilsAtom'
|
import { commonUtilsState } from '@/store/commonUtilsAtom'
|
||||||
import { menusState } from '@/store/menuAtom'
|
import { menusState } from '@/store/menuAtom'
|
||||||
@ -572,23 +577,13 @@ export default function CanvasMenu(props) {
|
|||||||
{!['estimate', 'simulation'].some((num) => num === selectedMenu) && (
|
{!['estimate', 'simulation'].some((num) => num === selectedMenu) && (
|
||||||
<>
|
<>
|
||||||
<div className="undo-redo-wrap">
|
<div className="undo-redo-wrap">
|
||||||
<button
|
<button className={`undo-btn ${!canUndo ? 'disabled' : ''}`} onClick={undo} disabled={!canUndo} title="Undo">
|
||||||
className={`undo-btn ${!canUndo ? 'disabled' : ''}`}
|
|
||||||
onClick={undo}
|
|
||||||
disabled={!canUndo}
|
|
||||||
title="Undo (Ctrl+Z)"
|
|
||||||
>
|
|
||||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||||
<path d="M3 10h10c4.42 0 8 3.58 8 8v1" />
|
<path d="M3 10h10c4.42 0 8 3.58 8 8v1" />
|
||||||
<polyline points="7 14 3 10 7 6" />
|
<polyline points="7 14 3 10 7 6" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button className={`redo-btn ${!canRedo ? 'disabled' : ''}`} onClick={redo} disabled={!canRedo} title="Redo">
|
||||||
className={`redo-btn ${!canRedo ? 'disabled' : ''}`}
|
|
||||||
onClick={redo}
|
|
||||||
disabled={!canRedo}
|
|
||||||
title="Redo (Ctrl+Shift+Z)"
|
|
||||||
>
|
|
||||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||||
<path d="M21 10H11C6.58 10 3 13.58 3 18v1" />
|
<path d="M21 10H11C6.58 10 3 13.58 3 18v1" />
|
||||||
<polyline points="17 14 21 10 17 6" />
|
<polyline points="17 14 21 10 17 6" />
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import { useModuleSelection } from '@/hooks/module/useModuleSelection'
|
|||||||
import { useOrientation } from '@/hooks/module/useOrientation'
|
import { useOrientation } from '@/hooks/module/useOrientation'
|
||||||
import { useMessage } from '@/hooks/useMessage'
|
import { useMessage } from '@/hooks/useMessage'
|
||||||
import { usePopup } from '@/hooks/usePopup'
|
import { usePopup } from '@/hooks/usePopup'
|
||||||
|
import { useUndoRedo } from '@/hooks/useUndoRedo'
|
||||||
import {
|
import {
|
||||||
canvasState,
|
canvasState,
|
||||||
checkedModuleState,
|
checkedModuleState,
|
||||||
@ -32,6 +33,7 @@ import Trestle from './step/Trestle'
|
|||||||
export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
|
export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
const { closePopup } = usePopup()
|
const { closePopup } = usePopup()
|
||||||
|
const { clearStacks } = useUndoRedo()
|
||||||
const [tabNum, setTabNum] = useState(1)
|
const [tabNum, setTabNum] = useState(1)
|
||||||
const orientationRef = useRef(null)
|
const orientationRef = useRef(null)
|
||||||
const [isManualModuleSetup, setIsManualModuleSetup] = useRecoilState(isManualModuleSetupState)
|
const [isManualModuleSetup, setIsManualModuleSetup] = useRecoilState(isManualModuleSetupState)
|
||||||
@ -84,6 +86,11 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
|
|||||||
useModuleBasicSetting(tabNum)
|
useModuleBasicSetting(tabNum)
|
||||||
const { updateObjectDate } = useMasterController()
|
const { updateObjectDate } = useMasterController()
|
||||||
|
|
||||||
|
// 모듈/가대설정 팝업 첫 진입 시 undo/redo 스택 초기화
|
||||||
|
useEffect(() => {
|
||||||
|
clearStacks()
|
||||||
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const moduleTabNum = basicSetting.roofSizeSet != 3 ? 3 : 2
|
const moduleTabNum = basicSetting.roofSizeSet != 3 ? 3 : 2
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedM
|
|||||||
import { v4 as uuidv4 } from 'uuid'
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
|
||||||
import { useEstimate } from '@/hooks/useEstimate'
|
import { useEstimate } from '@/hooks/useEstimate'
|
||||||
|
import { useUndoRedo } from '@/hooks/useUndoRedo'
|
||||||
import { useCircuitTrestle } from '@/hooks/useCirCuitTrestle'
|
import { useCircuitTrestle } from '@/hooks/useCirCuitTrestle'
|
||||||
import { useImgLoader } from '@/hooks/floorPlan/useImgLoader'
|
import { useImgLoader } from '@/hooks/floorPlan/useImgLoader'
|
||||||
import { QcastContext } from '@/app/QcastProvider'
|
import { QcastContext } from '@/app/QcastProvider'
|
||||||
@ -34,6 +35,7 @@ export default function CircuitTrestleSetting({ id }) {
|
|||||||
const { apply, setViewCircuitNumberTexts, getEstimateData, clear: clearTrestle, setAllModuleSurfaceIsComplete } = useTrestle()
|
const { apply, setViewCircuitNumberTexts, getEstimateData, clear: clearTrestle, setAllModuleSurfaceIsComplete } = useTrestle()
|
||||||
const { swalFire } = useSwal()
|
const { swalFire } = useSwal()
|
||||||
const { saveEstimate } = useEstimate()
|
const { saveEstimate } = useEstimate()
|
||||||
|
const { clearStacks } = useUndoRedo()
|
||||||
const canvas = useRecoilValue(canvasState)
|
const canvas = useRecoilValue(canvasState)
|
||||||
const setCurrentMenu = useSetRecoilState(currentMenuState)
|
const setCurrentMenu = useSetRecoilState(currentMenuState)
|
||||||
const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState)
|
const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState)
|
||||||
@ -711,6 +713,7 @@ export default function CircuitTrestleSetting({ id }) {
|
|||||||
setIsGlobalLoading(false)
|
setIsGlobalLoading(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clearStacks()
|
||||||
// removeNotAllocationModules()
|
// removeNotAllocationModules()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -106,7 +106,6 @@ export function useModuleBasicSetting(tabNum) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//육지붕 일경우에는 바로 배치면 설치LL
|
//육지붕 일경우에는 바로 배치면 설치LL
|
||||||
saveSnapshot()
|
|
||||||
canvas
|
canvas
|
||||||
.getObjects()
|
.getObjects()
|
||||||
.filter((roof) => roof.name === POLYGON_TYPE.ROOF)
|
.filter((roof) => roof.name === POLYGON_TYPE.ROOF)
|
||||||
@ -120,7 +119,6 @@ export function useModuleBasicSetting(tabNum) {
|
|||||||
//가대 상세 데이터 들어오면 실행
|
//가대 상세 데이터 들어오면 실행
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (trestleDetailList.length > 0) {
|
if (trestleDetailList.length > 0) {
|
||||||
saveSnapshot()
|
|
||||||
let rowColArray = []
|
let rowColArray = []
|
||||||
//지붕을 가져옴
|
//지붕을 가져옴
|
||||||
canvas
|
canvas
|
||||||
|
|||||||
@ -13,7 +13,6 @@ import { usePopup } from '@/hooks/usePopup'
|
|||||||
import { calculateAngle, isSamePoint } from '@/util/qpolygon-utils'
|
import { calculateAngle, isSamePoint } from '@/util/qpolygon-utils'
|
||||||
import { POLYGON_TYPE } from '@/common/common'
|
import { POLYGON_TYPE } from '@/common/common'
|
||||||
import { useMessage } from '../useMessage'
|
import { useMessage } from '../useMessage'
|
||||||
import { useUndoRedo } from '@/hooks/useUndoRedo'
|
|
||||||
import {
|
import {
|
||||||
auxiliaryLineAngle1State,
|
auxiliaryLineAngle1State,
|
||||||
auxiliaryLineAngle2State,
|
auxiliaryLineAngle2State,
|
||||||
@ -37,7 +36,6 @@ export function useAuxiliaryDrawing(id, isUseEffect = true) {
|
|||||||
const { getAdsorptionPoints } = useAdsorptionPoint()
|
const { getAdsorptionPoints } = useAdsorptionPoint()
|
||||||
const { closePopup } = usePopup()
|
const { closePopup } = usePopup()
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
const { saveSnapshot } = useUndoRedo()
|
|
||||||
|
|
||||||
const adsorptionRange = useRecoilValue(adsorptionRangeState)
|
const adsorptionRange = useRecoilValue(adsorptionRangeState)
|
||||||
|
|
||||||
@ -654,8 +652,6 @@ export function useAuxiliaryDrawing(id, isUseEffect = true) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
saveSnapshot()
|
|
||||||
|
|
||||||
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
|
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
|
||||||
/*const allLines = [...auxiliaryLines]
|
/*const allLines = [...auxiliaryLines]
|
||||||
|
|
||||||
@ -917,7 +913,6 @@ export function useAuxiliaryDrawing(id, isUseEffect = true) {
|
|||||||
if (!confirm(getMessage('want.to.complete.auxiliary.creation'))) {
|
if (!confirm(getMessage('want.to.complete.auxiliary.creation'))) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
saveSnapshot()
|
|
||||||
|
|
||||||
// cutAuxiliary()
|
// cutAuxiliary()
|
||||||
|
|
||||||
|
|||||||
@ -26,7 +26,6 @@ import { useSurfaceShapeBatch } from './useSurfaceShapeBatch'
|
|||||||
import { roofDisplaySelector } from '@/store/settingAtom'
|
import { roofDisplaySelector } from '@/store/settingAtom'
|
||||||
import { useRoofFn } from '@/hooks/common/useRoofFn'
|
import { useRoofFn } from '@/hooks/common/useRoofFn'
|
||||||
import { useObject } from '@/hooks/useObject'
|
import { useObject } from '@/hooks/useObject'
|
||||||
import { useUndoRedo } from '@/hooks/useUndoRedo'
|
|
||||||
|
|
||||||
// 배치면 그리기
|
// 배치면 그리기
|
||||||
export function usePlacementShapeDrawing(id) {
|
export function usePlacementShapeDrawing(id) {
|
||||||
@ -75,7 +74,6 @@ export function usePlacementShapeDrawing(id) {
|
|||||||
const isFix = useRef(false)
|
const isFix = useRef(false)
|
||||||
|
|
||||||
const { closePopup, addPopup } = usePopup()
|
const { closePopup, addPopup } = usePopup()
|
||||||
const { saveSnapshot } = useUndoRedo()
|
|
||||||
|
|
||||||
const globalPitch = useRecoilValue(globalPitchState)
|
const globalPitch = useRecoilValue(globalPitchState)
|
||||||
|
|
||||||
@ -132,7 +130,6 @@ export function usePlacementShapeDrawing(id) {
|
|||||||
let pointer = getIntersectMousePoint(e)
|
let pointer = getIntersectMousePoint(e)
|
||||||
|
|
||||||
if (points.length === 0) {
|
if (points.length === 0) {
|
||||||
saveSnapshot()
|
|
||||||
setPoints((prev) => [...prev, pointer])
|
setPoints((prev) => [...prev, pointer])
|
||||||
} else {
|
} else {
|
||||||
const lastPoint = points[points.length - 1]
|
const lastPoint = points[points.length - 1]
|
||||||
|
|||||||
@ -304,7 +304,7 @@ export function useCanvasEvent() {
|
|||||||
case 'Escape':
|
case 'Escape':
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'z':
|
/*case 'z':
|
||||||
if (!e.ctrlKey && !e.metaKey) {
|
if (!e.ctrlKey && !e.metaKey) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -313,7 +313,7 @@ export function useCanvasEvent() {
|
|||||||
} else {
|
} else {
|
||||||
undo()
|
undo()
|
||||||
}
|
}
|
||||||
break
|
break*/
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return // 키 이벤트를 처리하지 않는다면 종료합니다.
|
return // 키 이벤트를 처리하지 않는다면 종료합니다.
|
||||||
|
|||||||
@ -18,7 +18,7 @@ import { selectedMenuState } from '@/store/menuAtom'
|
|||||||
import { popupState } from '@/store/popupAtom'
|
import { popupState } from '@/store/popupAtom'
|
||||||
import { POLYGON_TYPE, SAVE_KEY } from '@/common/common'
|
import { POLYGON_TYPE, SAVE_KEY } from '@/common/common'
|
||||||
|
|
||||||
const MAX_HISTORY = 20
|
const MAX_HISTORY = 3
|
||||||
|
|
||||||
// 모든 useUndoRedo 인스턴스가 공유하는 복원 플래그
|
// 모든 useUndoRedo 인스턴스가 공유하는 복원 플래그
|
||||||
// useRef는 인스턴스마다 독립적이므로, 모듈 레벨 변수로 전환
|
// useRef는 인스턴스마다 독립적이므로, 모듈 레벨 변수로 전환
|
||||||
@ -318,7 +318,6 @@ export function useUndoRedo() {
|
|||||||
if (!canvas || currentUndoStack.length === 0 || _isRestoring) return
|
if (!canvas || currentUndoStack.length === 0 || _isRestoring) return
|
||||||
|
|
||||||
_isRestoring = true
|
_isRestoring = true
|
||||||
closeAllPopups()
|
|
||||||
|
|
||||||
const currentCanvasJSON = getCanvasSnapshot()
|
const currentCanvasJSON = getCanvasSnapshot()
|
||||||
const currentAtomSnapshot = getAtomSnapshot()
|
const currentAtomSnapshot = getAtomSnapshot()
|
||||||
@ -330,18 +329,21 @@ export function useUndoRedo() {
|
|||||||
const newUndoStack = [...currentUndoStack]
|
const newUndoStack = [...currentUndoStack]
|
||||||
const snapshot = newUndoStack.pop()
|
const snapshot = newUndoStack.pop()
|
||||||
|
|
||||||
|
if (snapshot.atomSnapshot?.currentMenu !== currentMenu) {
|
||||||
|
closeAllPopups()
|
||||||
|
}
|
||||||
|
|
||||||
setUndoStack(newUndoStack)
|
setUndoStack(newUndoStack)
|
||||||
setRedoStack((prev) => [...prev, currentSnapshot])
|
setRedoStack((prev) => [...prev, currentSnapshot])
|
||||||
|
|
||||||
_restoreFromJSON(canvas, snapshot, restoreAtomSnapshot, rebuildCanvasAtoms, setCanvasZoom)
|
_restoreFromJSON(canvas, snapshot, restoreAtomSnapshot, rebuildCanvasAtoms, setCanvasZoom)
|
||||||
}, [canvas, getCanvasSnapshot, getAtomSnapshot, restoreAtomSnapshot, rebuildCanvasAtoms, closeAllPopups])
|
}, [canvas, currentMenu, getCanvasSnapshot, getAtomSnapshot, restoreAtomSnapshot, rebuildCanvasAtoms, closeAllPopups])
|
||||||
|
|
||||||
const redo = useCallback(() => {
|
const redo = useCallback(() => {
|
||||||
const currentRedoStack = redoStackRef.current
|
const currentRedoStack = redoStackRef.current
|
||||||
if (!canvas || currentRedoStack.length === 0 || _isRestoring) return
|
if (!canvas || currentRedoStack.length === 0 || _isRestoring) return
|
||||||
|
|
||||||
_isRestoring = true
|
_isRestoring = true
|
||||||
closeAllPopups()
|
|
||||||
|
|
||||||
const currentCanvasJSON = getCanvasSnapshot()
|
const currentCanvasJSON = getCanvasSnapshot()
|
||||||
const currentAtomSnapshot = getAtomSnapshot()
|
const currentAtomSnapshot = getAtomSnapshot()
|
||||||
@ -353,16 +355,26 @@ export function useUndoRedo() {
|
|||||||
const newRedoStack = [...currentRedoStack]
|
const newRedoStack = [...currentRedoStack]
|
||||||
const snapshot = newRedoStack.pop()
|
const snapshot = newRedoStack.pop()
|
||||||
|
|
||||||
|
if (snapshot.atomSnapshot?.currentMenu !== currentMenu) {
|
||||||
|
closeAllPopups()
|
||||||
|
}
|
||||||
|
|
||||||
setRedoStack(newRedoStack)
|
setRedoStack(newRedoStack)
|
||||||
setUndoStack((prev) => [...prev, currentSnapshot])
|
setUndoStack((prev) => [...prev, currentSnapshot])
|
||||||
|
|
||||||
_restoreFromJSON(canvas, snapshot, restoreAtomSnapshot, rebuildCanvasAtoms, setCanvasZoom)
|
_restoreFromJSON(canvas, snapshot, restoreAtomSnapshot, rebuildCanvasAtoms, setCanvasZoom)
|
||||||
}, [canvas, getCanvasSnapshot, getAtomSnapshot, restoreAtomSnapshot, rebuildCanvasAtoms, closeAllPopups])
|
}, [canvas, currentMenu, getCanvasSnapshot, getAtomSnapshot, restoreAtomSnapshot, rebuildCanvasAtoms, closeAllPopups])
|
||||||
|
|
||||||
|
const clearStacks = useCallback(() => {
|
||||||
|
setUndoStack([])
|
||||||
|
setRedoStack([])
|
||||||
|
}, [])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
saveSnapshot,
|
saveSnapshot,
|
||||||
undo,
|
undo,
|
||||||
redo,
|
redo,
|
||||||
|
clearStacks,
|
||||||
canUndo: undoStack.length > 0,
|
canUndo: undoStack.length > 0,
|
||||||
canRedo: redoStack.length > 0,
|
canRedo: redoStack.length > 0,
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user