fix dirty file save logic
parent
132be08553
commit
662ced6edd
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
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