fix dirty file save logic
This commit is contained in:
parent
132be08553
commit
662ced6edd
File diff suppressed because one or more lines are too long
1
example_parts/test3.json
Normal file
1
example_parts/test3.json
Normal file
File diff suppressed because one or more lines are too long
1
example_parts/test4.json
Normal file
1
example_parts/test4.json
Normal file
File diff suppressed because one or more lines are too long
49
src/Scene.js
49
src/Scene.js
@ -36,12 +36,12 @@ export class Scene {
|
||||
this.sid = 1
|
||||
this.mid = 1
|
||||
|
||||
this.store = store;
|
||||
this.canvas = document.querySelector('#c');
|
||||
|
||||
this.rect = this.canvas.getBoundingClientRect().toJSON()
|
||||
|
||||
this.renderer = new THREE.WebGLRenderer({ canvas: this.canvas });
|
||||
this.store = store
|
||||
|
||||
const size = 1;
|
||||
const near = 0;
|
||||
@ -178,11 +178,6 @@ export class Scene {
|
||||
}
|
||||
|
||||
|
||||
saveScene() {
|
||||
return JSON.stringify([id, this.sid, this.mid, this.store.getState().treeEntries])
|
||||
}
|
||||
|
||||
|
||||
clearScene() {
|
||||
const deleted = this.obj3d.children.splice(1)
|
||||
|
||||
@ -240,7 +235,6 @@ export class Scene {
|
||||
}
|
||||
}
|
||||
|
||||
this.store.dispatch({ type: 'restore-state', state })
|
||||
return state
|
||||
}
|
||||
|
||||
@ -262,17 +256,10 @@ export class Scene {
|
||||
|
||||
this.obj3d.add(mesh)
|
||||
|
||||
this.store.dispatch({ type: 'rx-extrusion', mesh, sketchId: sketch.obj3d.name })
|
||||
|
||||
if (this.activeSketch == sketch) {
|
||||
this.store.dispatch({ type: 'finish-sketch' })
|
||||
sketch.deactivate()
|
||||
}
|
||||
this.render()
|
||||
|
||||
return mesh
|
||||
}
|
||||
|
||||
boolOp(m1, m2, op, refresh = false) {
|
||||
boolOp(m1, m2, op) {
|
||||
let bspA = CSG.fromMesh(m1)
|
||||
let bspB = CSG.fromMesh(m2)
|
||||
m1.visible = false
|
||||
@ -312,33 +299,16 @@ export class Scene {
|
||||
|
||||
mesh.add(vertices)
|
||||
|
||||
if (!refresh) {
|
||||
sc.obj3d.add(mesh)
|
||||
|
||||
this.store.dispatch({
|
||||
type: 'set-entry-visibility', obj: {
|
||||
[m1.name]: false,
|
||||
[m2.name]: false,
|
||||
[mesh.name]: true,
|
||||
}
|
||||
})
|
||||
|
||||
this.store.dispatch({
|
||||
type: 'rx-boolean', mesh, deps: [m1.name, m2.name]
|
||||
})
|
||||
} else {
|
||||
return mesh
|
||||
}
|
||||
return mesh
|
||||
|
||||
}
|
||||
|
||||
refreshNode(id) {
|
||||
refreshNode(id, { byId, tree }) {
|
||||
let curId
|
||||
let que = [id]
|
||||
let idx = 0
|
||||
// let newNodes = {}
|
||||
|
||||
const { byId, tree } = this.store.getState().treeEntries
|
||||
while (idx < que.length) {
|
||||
curId = que[idx++]
|
||||
|
||||
@ -348,7 +318,7 @@ export class Scene {
|
||||
if (info.length == 2) {
|
||||
newNode = extrude(byId[info[0]], info[1])
|
||||
} else if (info.length == 3) {
|
||||
newNode = this.boolOp(byId[info[0]], byId[info[1]], info[2], true)
|
||||
newNode = this.boolOp(byId[info[0]], byId[info[1]], info[2])
|
||||
}
|
||||
byId[curId].geometry.copy(newNode.geometry)
|
||||
byId[curId].geometry.parameters = newNode.geometry.parameters // took 2 hours to figure out
|
||||
@ -433,14 +403,9 @@ async function addSketch() {
|
||||
|
||||
this.clearSelection()
|
||||
|
||||
|
||||
sketch.obj3d.addEventListener('change', this.render);
|
||||
this.store.dispatch({ type: 'rx-sketch', obj: sketch })
|
||||
|
||||
sketch.activate()
|
||||
|
||||
this.render()
|
||||
|
||||
return sketch
|
||||
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,6 @@ import { onHover, onDrag, onPick, onRelease, clearSelection} from './mouseEvents
|
||||
import { setCoincident, setOrdinate, setTangent } from './constraintEvents'
|
||||
import { get3PtArc } from './drawArc'
|
||||
import { replacer, reviver } from './utils'
|
||||
import { AxesHelper } from './sketchAxes'
|
||||
import { drawDimension, _onMoveDimension, setDimLines, updateDim } from './drawDimension';
|
||||
|
||||
|
||||
@ -19,7 +18,6 @@ class Sketch {
|
||||
|
||||
constructor(scene, preload) {
|
||||
|
||||
|
||||
// [0]:x, [1]:y, [2]:z
|
||||
this.ptsBuf = new Float32Array(this.max_pts * 3).fill(NaN)
|
||||
|
||||
@ -96,7 +94,6 @@ class Sketch {
|
||||
this.camera = scene.camera
|
||||
this.canvas = scene.canvas
|
||||
this.rect = scene.rect
|
||||
this.store = scene.store;
|
||||
|
||||
|
||||
|
||||
@ -153,15 +150,28 @@ class Sketch {
|
||||
}
|
||||
|
||||
|
||||
setClean() {
|
||||
this.hasChanged = false
|
||||
this.idOnActivate = id
|
||||
this.c_idOnActivate = this.c_id
|
||||
|
||||
const changeDetector = (e) => {
|
||||
if (this.selected.length && e.buttons) {
|
||||
this.canvas.removeEventListener('pointermove', changeDetector)
|
||||
this.hasChanged = true
|
||||
}
|
||||
}
|
||||
|
||||
this.canvas.addEventListener('pointermove', changeDetector)
|
||||
}
|
||||
|
||||
|
||||
activate() {
|
||||
console.log('activate sketch')
|
||||
window.addEventListener('keydown', this.onKeyPress)
|
||||
this.canvas.addEventListener('pointerdown', this.onPick)
|
||||
this.canvas.addEventListener('pointermove', this.onHover)
|
||||
|
||||
|
||||
this.store.dispatch({ type: 'set-active-sketch', activeSketchId: this.obj3d.name })
|
||||
|
||||
this.setDimLines()
|
||||
|
||||
this.obj3d.traverse(e => e.layers.enable(2))
|
||||
@ -172,21 +182,12 @@ class Sketch {
|
||||
|
||||
window.sketcher = this
|
||||
|
||||
// overkill but good solution if this check was more costly
|
||||
this.hasChanged = false
|
||||
this.idOnActivate = id
|
||||
this.c_idOnActivate = this.c_id
|
||||
// console.log(this,this.selected)
|
||||
const changeDetector = (e) => {
|
||||
if (this.selected.length && e.buttons) {
|
||||
this.canvas.removeEventListener('pointermove', changeDetector)
|
||||
this.hasChanged = true
|
||||
}
|
||||
}
|
||||
this.canvas.addEventListener('pointermove', changeDetector)
|
||||
this.setClean()
|
||||
|
||||
}
|
||||
|
||||
deactivate() {
|
||||
console.log('deactivate')
|
||||
window.removeEventListener('keydown', this.onKeyPress)
|
||||
this.canvas.removeEventListener('pointerdown', this.onPick)
|
||||
this.canvas.removeEventListener('pointermove', this.onHover)
|
||||
|
@ -10,22 +10,29 @@ import * as Icon from "./icons";
|
||||
export const Dialog = () => {
|
||||
|
||||
const dialog = useSelector(state => state.ui.dialog)
|
||||
const treeEntries = useSelector(state => state.treeEntries)
|
||||
const dispatch = useDispatch()
|
||||
|
||||
const ref = useRef()
|
||||
|
||||
useEffect(() => {
|
||||
console.log(dialog)
|
||||
if (!ref.current) return
|
||||
ref.current.focus()
|
||||
}, [dialog])
|
||||
|
||||
const extrude = () => {
|
||||
sc.extrude(dialog.target, ref.current.value)
|
||||
sc.render()
|
||||
const mesh = sc.extrude(dialog.target, ref.current.value)
|
||||
|
||||
dispatch({ type: 'rx-extrusion', mesh, sketchId: dialog.target.obj3d.name })
|
||||
|
||||
if (sc.activeSketch == dialog.target) {
|
||||
dispatch({ type: 'finish-sketch' })
|
||||
dialog.target.deactivate()
|
||||
}
|
||||
|
||||
dispatch({ type: "clear-dialog" })
|
||||
|
||||
sc.render()
|
||||
}
|
||||
|
||||
const extrudeEdit = () => {
|
||||
@ -33,11 +40,12 @@ export const Dialog = () => {
|
||||
|
||||
dialog.target.userData.featureInfo[1] = ref.current.value
|
||||
|
||||
sc.refreshNode(dialog.target.name)
|
||||
sc.refreshNode(dialog.target.name, treeEntries)
|
||||
dispatch({ type: 'set-modified', status: true })
|
||||
|
||||
sc.render()
|
||||
dispatch({ type: "clear-dialog" })
|
||||
|
||||
sc.render()
|
||||
}
|
||||
|
||||
|
||||
@ -53,7 +61,13 @@ export const Dialog = () => {
|
||||
onClick={extrude}
|
||||
/>
|
||||
<MdClose className="btn w-auto h-full p-3.5 mr-6"
|
||||
onClick={() => dispatch({ type: "clear-dialog" })}
|
||||
onClick={() => {
|
||||
if (sc.activeSketch == dialog.target) { // if extrude dialog launched from sketch mode we set dialog back to the sketch dialog
|
||||
dispatch({ type: 'set-dialog', action: 'sketch' })
|
||||
} else {
|
||||
dispatch({ type: "clear-dialog" })
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
case 'extrude-edit':
|
||||
@ -79,7 +93,9 @@ export const Dialog = () => {
|
||||
|| sc.activeSketch.idOnActivate != id
|
||||
|| sc.activeSketch.c_idOnActivate != sc.activeSketch.c_id
|
||||
) {
|
||||
sc.refreshNode(sc.activeSketch.obj3d.name)
|
||||
sc.refreshNode(sc.activeSketch.obj3d.name, treeEntries)
|
||||
|
||||
dispatch({ type: 'set-modified', status: true })
|
||||
}
|
||||
|
||||
dispatch({ type: 'finish-sketch' })
|
||||
@ -96,10 +112,11 @@ export const Dialog = () => {
|
||||
|| sc.activeSketch.c_idOnActivate != sc.activeSketch.c_id
|
||||
) {
|
||||
dispatch({ type: "restore-sketch" })
|
||||
} else {
|
||||
dispatch({ type: 'finish-sketch' })
|
||||
// dispatch({ type: 'set-modified', status: false })
|
||||
}
|
||||
|
||||
dispatch({ type: 'finish-sketch' })
|
||||
|
||||
sc.activeSketch.deactivate()
|
||||
sc.render()
|
||||
dispatch({ type: "clear-dialog" })
|
||||
|
@ -22,6 +22,8 @@ export function STLExport(filename) {
|
||||
const time = (new Date(Date.now() - tzoffset)).toISOString().slice(0, -5).replace(/:/g, '-');
|
||||
|
||||
saveLegacy(new Blob([result], { type: 'model/stl' }), `${filename}_${time}.stl`);
|
||||
} else {
|
||||
alert('please select one body to export')
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,7 +50,7 @@ export async function saveFileAs(file, dispatch) {
|
||||
|
||||
const opts = {
|
||||
types: [{
|
||||
// description: 'Text file',
|
||||
description: 'Text file',
|
||||
accept: { 'application/json': ['.json'] },
|
||||
}],
|
||||
};
|
||||
@ -114,11 +116,12 @@ export async function openFile(dispatch) {
|
||||
try {
|
||||
const file = await fileHandle.getFile();
|
||||
const text = await file.text();;
|
||||
sc.loadState(text)
|
||||
|
||||
dispatch({ type: 'restore-state', state: sc.loadState(text) })
|
||||
dispatch({ type: 'set-file-handle', fileHandle })
|
||||
// app.setModified(false);
|
||||
|
||||
// app.setFocus(true);
|
||||
|
||||
} catch (ex) {
|
||||
const msg = `An error occured reading ${fileHandle}`;
|
||||
console.error(msg, ex);
|
||||
@ -127,3 +130,30 @@ export async function openFile(dispatch) {
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
export function confirmDiscard(modified) {
|
||||
if (!modified) {
|
||||
return true;
|
||||
}
|
||||
const confirmMsg = 'Discard changes? All changes will be lost.';
|
||||
return confirm(confirmMsg);
|
||||
};
|
||||
|
||||
|
||||
export async function verifyPermission(fileHandle) {
|
||||
const opts = {
|
||||
mode:'readwrite'
|
||||
};
|
||||
|
||||
// Check if we already have permission, if so, return true.
|
||||
if (await fileHandle.queryPermission(opts) === 'granted') {
|
||||
return true;
|
||||
}
|
||||
// Request permission to the file, if the user grants permission, return true.
|
||||
if (await fileHandle.requestPermission(opts) === 'granted') {
|
||||
return true;
|
||||
}
|
||||
// The user did nt grant permission, return false.
|
||||
return false;
|
||||
}
|
@ -4,43 +4,88 @@ import React, { useEffect, useReducer } from 'react';
|
||||
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
|
||||
import { FaEdit, FaFileDownload } from 'react-icons/fa'
|
||||
import { MdSave, MdFolder, MdFileUpload, MdInsertDriveFile } from 'react-icons/md'
|
||||
import { FaRegFolderOpen, FaFile } from 'react-icons/fa'
|
||||
import { FaEdit } from 'react-icons/fa'
|
||||
import { MdSave, MdFolder, MdInsertDriveFile } from 'react-icons/md'
|
||||
|
||||
import * as Icon from "./icons";
|
||||
import { Dialog } from './dialog'
|
||||
import { STLExport, saveFile, openFile } from './fileHelpers'
|
||||
import { STLExport, saveFile, openFile, verifyPermission } from './fileHelpers'
|
||||
|
||||
|
||||
|
||||
|
||||
export const NavBar = () => {
|
||||
const dispatch = useDispatch()
|
||||
const activeSketchId = useSelector(state => state.treeEntries.activeSketchId)
|
||||
const treeEntriesById = useSelector(state => state.treeEntries.byId)
|
||||
const sketchActive = useSelector(state => state.ui.sketchActive)
|
||||
const treeEntries = useSelector(state => state.treeEntries)
|
||||
const fileHandle = useSelector(state => state.ui.fileHandle)
|
||||
const modified = useSelector(state => state.ui.modified)
|
||||
|
||||
const boolOp = (code) => {
|
||||
if (sc.selected.length != 2 || !sc.selected.every(e => e.userData.type == 'mesh')) return
|
||||
const [m1, m2] = sc.selected
|
||||
sc.boolOp(m1, m2, code)
|
||||
|
||||
const mesh = sc.boolOp(m1, m2, code)
|
||||
|
||||
sc.obj3d.add(mesh)
|
||||
|
||||
dispatch({
|
||||
type: 'set-entry-visibility', obj: {
|
||||
[m1.name]: false,
|
||||
[m2.name]: false,
|
||||
[mesh.name]: true,
|
||||
}
|
||||
})
|
||||
|
||||
dispatch({
|
||||
type: 'rx-boolean', mesh, deps: [m1.name, m2.name]
|
||||
})
|
||||
|
||||
|
||||
sc.render()
|
||||
forceUpdate()
|
||||
}
|
||||
|
||||
const addSketch = () => {
|
||||
sc.addSketch()
|
||||
const addSketch = async () => {
|
||||
const sketch = await sc.addSketch()
|
||||
|
||||
dispatch({ type: 'rx-sketch', obj: sketch })
|
||||
|
||||
sketch.activate()
|
||||
|
||||
sc.render()
|
||||
|
||||
dispatch({ type: 'set-dialog', action: 'sketch' })
|
||||
|
||||
forceUpdate()
|
||||
}
|
||||
|
||||
const confirmDiscard = () => !modified ? true : confirm('Discard changes? All changes will be lost.')
|
||||
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const onBeforeUnload = (e) => {
|
||||
if (modified ||
|
||||
(sc.activeSketch &&
|
||||
(
|
||||
sc.activeSketch.hasChanged
|
||||
|| sc.activeSketch.idOnActivate != id
|
||||
|| sc.activeSketch.c_idOnActivate != sc.activeSketch.c_id
|
||||
)
|
||||
)
|
||||
) {
|
||||
e.preventDefault();
|
||||
e.returnValue = `There are unsaved changes. Are you sure you want to leave?`;
|
||||
}
|
||||
}
|
||||
window.addEventListener('beforeunload', onBeforeUnload)
|
||||
return () => window.removeEventListener('beforeunload', onBeforeUnload)
|
||||
}, [modified])
|
||||
|
||||
useEffect(() => { // hacky way to handle mounting and unmounting mouse listeners for feature mode
|
||||
if (!activeSketchId) {
|
||||
if (!sketchActive) {
|
||||
sc.canvas.addEventListener('pointermove', sc.onHover)
|
||||
sc.canvas.addEventListener('pointerdown', sc.onPick)
|
||||
return () => {
|
||||
@ -48,11 +93,10 @@ export const NavBar = () => {
|
||||
sc.canvas.removeEventListener('pointerdown', sc.onPick)
|
||||
}
|
||||
}
|
||||
}, [activeSketchId])
|
||||
}, [sketchActive])
|
||||
|
||||
const sketchModeButtons = [
|
||||
[Icon.Extrude, () => {
|
||||
dispatch({ type: 'finish-sketch' })
|
||||
dispatch({ type: 'set-dialog', action: 'extrude', target: sc.activeSketch })
|
||||
|
||||
}, 'Extrude [e]'],
|
||||
@ -63,32 +107,43 @@ export const NavBar = () => {
|
||||
[Icon.Vertical, () => sc.activeSketch.command('v'), 'Vertical [v]'],
|
||||
[Icon.Horizontal, () => sc.activeSketch.command('h'), 'Horizontal [h]'],
|
||||
[Icon.Tangent, () => sc.activeSketch.command('t'), 'Tangent [t]'],
|
||||
[Icon.Tangent, () => sc.activeSketch.command('t'), 'Tangent [t]'],
|
||||
[MdSave,
|
||||
async () => {
|
||||
if(await verifyPermission(fileHandle) === false) return
|
||||
sc.refreshNode(sc.activeSketch.obj3d.name, treeEntries)
|
||||
sc.activeSketch.clearSelection()
|
||||
saveFile(fileHandle, JSON.stringify([id, sc.sid, sc.mid, treeEntries]), dispatch)
|
||||
sc.render()
|
||||
sc.activeSketch.setClean()
|
||||
}
|
||||
, 'Save']
|
||||
]
|
||||
|
||||
|
||||
const partModeButtons = [
|
||||
[FaEdit, addSketch, 'Sketch [s]'],
|
||||
[Icon.Extrude, () => {
|
||||
dispatch({ type: 'set-dialog', action: 'extrude', target: treeEntriesById[sc.selected[0].name] })
|
||||
}, 'Extrude [e]'],
|
||||
dispatch({ type: 'set-dialog', action: 'extrude', target: treeEntries.byId[sc.selected[0].name] })
|
||||
}, 'Extrude'],
|
||||
|
||||
[Icon.Union, () => boolOp('u'), 'Union'],
|
||||
[Icon.Subtract, () => boolOp('s'), 'Subtract'],
|
||||
[Icon.Intersect, () => boolOp('i'), 'Intersect'],
|
||||
[MdInsertDriveFile, () => {
|
||||
if (!confirmDiscard()) return
|
||||
sc.newPart()
|
||||
dispatch({ type: 'new-part' })
|
||||
sc.render()
|
||||
}, 'New [ctrl+n]'],
|
||||
}, 'New'],
|
||||
[MdSave,
|
||||
() => {
|
||||
saveFile(fileHandle, sc.saveScene(), dispatch)
|
||||
saveFile(fileHandle, JSON.stringify([id, sc.sid, sc.mid, treeEntries]), dispatch)
|
||||
}
|
||||
, 'Save [ctrl+s]'],
|
||||
, 'Save'],
|
||||
[MdFolder, () => {
|
||||
if (!confirmDiscard()) return
|
||||
openFile(dispatch).then(
|
||||
()=>sc.render()
|
||||
sc.render
|
||||
)
|
||||
}, 'Open'],
|
||||
[Icon.Stl, () => {
|
||||
@ -106,7 +161,7 @@ export const NavBar = () => {
|
||||
</div>
|
||||
<div className='w-auto h-full flex-none'>
|
||||
{
|
||||
activeSketchId ?
|
||||
sketchActive ?
|
||||
sketchModeButtons.map(([Icon, fcn, txt, shortcut], idx) => (
|
||||
<Icon className="btn w-auto h-full p-3.5" tooltip={txt}
|
||||
onClick={fcn} key={idx}
|
||||
|
@ -10,7 +10,6 @@ const defaultState = {
|
||||
tree: {},
|
||||
order: {},
|
||||
visible: {},
|
||||
activeSketchId: ""
|
||||
}
|
||||
|
||||
let cache
|
||||
@ -33,21 +32,19 @@ export function treeEntries(state = defaultState, action) {
|
||||
}
|
||||
|
||||
case 'set-active-sketch':
|
||||
cache = JSON.stringify(state.byId[action.activeSketchId])
|
||||
cache = JSON.stringify(action.sketch)
|
||||
return update(state, {
|
||||
visible: { [action.activeSketchId]: { $set: true } },
|
||||
activeSketchId: { $set: action.activeSketchId },
|
||||
visible: { [action.sketch.obj3d.name]: { $set: true } },
|
||||
})
|
||||
case 'finish-sketch':
|
||||
return update(state, {
|
||||
activeSketchId: { $set: "" },
|
||||
visible: { [state.activeSketchId]: { $set: false } },
|
||||
visible: { [sc.activeSketch.obj3d.name]: { $set: false } },
|
||||
})
|
||||
case 'restore-sketch':
|
||||
|
||||
const sketch = sc.loadSketch(cache)
|
||||
|
||||
const deletedObj = sc.obj3d.children.splice(state.order[state.activeSketchId] + 1, 1,
|
||||
const deletedObj = sc.obj3d.children.splice(state.order[sc.activeSketch.obj3d.name] + 1, 1,
|
||||
sketch.obj3d
|
||||
)[0]
|
||||
|
||||
@ -59,9 +56,7 @@ export function treeEntries(state = defaultState, action) {
|
||||
sc.activeSketch = sketch
|
||||
|
||||
return update(state, {
|
||||
activeSketchId: { $set: "" },
|
||||
byId: { [state.activeSketchId]: { $set: sketch } },
|
||||
visible: { [state.activeSketchId]: { $set: false } },
|
||||
byId: { [sc.activeSketch.obj3d.name]: { $set: sketch } },
|
||||
})
|
||||
case 'rx-extrusion':
|
||||
|
||||
@ -108,7 +103,18 @@ export function treeEntries(state = defaultState, action) {
|
||||
|
||||
export function ui(state = { dialog: {}, filePane: false }, action) {
|
||||
switch (action.type) {
|
||||
|
||||
case 'set-active-sketch':
|
||||
return update(state, {
|
||||
sketchActive: { $set: true },
|
||||
})
|
||||
case 'rx-sketch':
|
||||
return update(state, {
|
||||
sketchActive: { $set: true },
|
||||
})
|
||||
case 'finish-sketch':
|
||||
return update(state, {
|
||||
sketchActive: { $set: false },
|
||||
})
|
||||
case 'set-dialog':
|
||||
return update(state, {
|
||||
dialog: { $set: { target: action.target, action: action.action } },
|
||||
@ -127,6 +133,18 @@ export function ui(state = { dialog: {}, filePane: false }, action) {
|
||||
fileHandle: { $set: null },
|
||||
modified: { $set: false },
|
||||
})
|
||||
case 'set-modified':
|
||||
return update(state, {
|
||||
modified: { $set: action.status },
|
||||
})
|
||||
case 'delete-node':
|
||||
return update(state, {
|
||||
modified: { $set: true },
|
||||
})
|
||||
case 'rx-extrusion':
|
||||
return update(state, {
|
||||
modified: { $set: true },
|
||||
})
|
||||
default:
|
||||
return state
|
||||
}
|
||||
|
@ -8,10 +8,12 @@ import { FaCube, FaEdit } from 'react-icons/fa'
|
||||
|
||||
export const Tree = () => {
|
||||
const treeEntries = useSelector(state => state.treeEntries)
|
||||
const ref = useRef()
|
||||
const fileHandle = useSelector(state => state.ui.fileHandle)
|
||||
|
||||
return <div className='sideNav flex flex-col bg-gray-800'>
|
||||
<input className='w-16 text-gray-50 h-7 mx-1 border-0 focus:outline-none bg-transparent' type="text" defaultValue="untitled" step="0.1" ref={ref} />
|
||||
<div className='w-16 text-gray-50 h-7 mx-1 border-0 focus:outline-none bg-transparent'>
|
||||
{fileHandle ? fileHandle.name.replace(/\.[^/.]+$/, "") : 'untitled'}
|
||||
</div>
|
||||
{treeEntries.allIds.map((entId, idx) => (
|
||||
<TreeEntry key={idx} entId={entId} />
|
||||
))}
|
||||
@ -55,7 +57,11 @@ const TreeEntry = ({ entId }) => {
|
||||
dispatch({ type: 'finish-sketch' })
|
||||
sc.activeSketch.deactivate()
|
||||
}
|
||||
|
||||
|
||||
sketch.activate()
|
||||
dispatch({ type: 'set-active-sketch', sketch })
|
||||
|
||||
sc.clearSelection()
|
||||
sc.activeSketch = sketch;
|
||||
dispatch({ type: 'set-dialog', action: 'sketch' })
|
||||
@ -120,14 +126,6 @@ const TreeEntry = ({ entId }) => {
|
||||
e.stopPropagation()
|
||||
}}
|
||||
/>
|
||||
{/* <MdRefresh className='btn-green h-full w-auto p-1.5'
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
|
||||
sc.refreshNode(entId)
|
||||
sc.render()
|
||||
}}
|
||||
/> */}
|
||||
|
||||
{
|
||||
visible ?
|
||||
|
Loading…
Reference in New Issue
Block a user