@@ -184,7 +198,8 @@ export const NavBar = () => {
{(sketchActive ? sketchModeButtons : partModeButtons).map(
([Icon, fcn, txt], idx) => (
Icon !== undefined ?
-
:
diff --git a/src/react/reducer.js b/src/react/reducer.js
index 68c868a..40b20c4 100644
--- a/src/react/reducer.js
+++ b/src/react/reducer.js
@@ -5,7 +5,7 @@ import update from 'immutability-helper'
import { combineReducers } from 'redux';
import { sce } from './app'
-const defaultState = {
+const defaultTreeState = {
byId: {},
allIds: [],
tree: {},
@@ -15,7 +15,7 @@ const defaultState = {
let cache
-export function treeEntries(state = defaultState, action) {
+export function treeEntries(state = defaultTreeState, action) {
switch (action.type) {
case 'rx-sketch':
return update(state, {
@@ -96,13 +96,22 @@ export function treeEntries(state = defaultState, action) {
case 'restore-state':
return action.state
case 'new-part':
- return defaultState
+ return defaultTreeState
default:
return state
}
}
-export function ui(state = { dialog: {}, filePane: false }, action) {
+const defaultUIState = {
+ dialog: {},
+ fileHandle: null,
+ fileName: 'Untitled',
+ selectedList: [],
+ selectedSet: {},
+
+}
+
+export function ui(state = defaultUIState, action) {
switch (action.type) {
case 'set-active-sketch':
return update(state, {
@@ -119,10 +128,12 @@ export function ui(state = { dialog: {}, filePane: false }, action) {
case 'set-dialog':
return update(state, {
dialog: { $set: { target: action.target, action: action.action } },
+ mode: { $set: "" } // we clear the existing mode when entering dialog
})
case 'clear-dialog':
return update(state, {
dialog: { $set: {} },
+ mode: { $set: "" }
})
case 'set-file-handle':
return update(state, {
@@ -130,10 +141,7 @@ export function ui(state = { dialog: {}, filePane: false }, action) {
modified: { $set: false },
})
case 'new-part':
- return update(state, {
- fileHandle: { $set: null },
- modified: { $set: false },
- })
+ return defaultUIState
case 'set-modified':
return update(state, {
modified: { $set: action.status },
@@ -146,6 +154,55 @@ export function ui(state = { dialog: {}, filePane: false }, action) {
return update(state, {
modified: { $set: true },
})
+ case 'restore-state':
+ return update(state, {
+ fileName: { $set: action.fileName },
+ })
+ case 'on-pick':
+
+ console.log(action.obj.userData.type)
+ const idx = state.selectedList.indexOf(action.obj)
+
+ const setNeedsUpdate = action.obj.userData.type == 'mesh' || action.obj.userData.type == 'sketch'
+
+ if (idx == -1) {
+ return update(state, {
+ selectedList: { $push: [action.obj] },
+ // selectedSet: { [action.obj.name]: { $set: true } }
+ selectedSet: (curr) => setNeedsUpdate ? { ...curr, [action.obj.name]: true } : curr
+ })
+
+ } else {
+
+ if (action.obj.userData.type != 'selpoint') {
+ return update(state, {
+ selectedList: { $splice: [[idx, 1]] },
+ // selectedSet: { [action.obj.name]: { $set: false } }
+ selectedSet: (curr) => setNeedsUpdate ? { ...curr, [action.obj.name]: false } : curr
+ })
+ } else {
+ return state
+ }
+
+ }
+
+ case 'clear-selection':
+ if (state.selectedList.length) {
+ return update(state, {
+ selectedList: { $set: [] },
+ selectedSet: { $set: {} }
+ })
+ } else {
+ return state
+ }
+
+ case 'set-mode':
+
+
+ return update(state, {
+ mode: { $set: action.mode }
+ })
+
default:
return state
}
diff --git a/src/react/tree.jsx b/src/react/tree.jsx
index 5fb2af0..3b2aed3 100644
--- a/src/react/tree.jsx
+++ b/src/react/tree.jsx
@@ -2,23 +2,28 @@
import React, { useReducer, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux'
-import { MdVisibilityOff, MdVisibility, MdDelete } from 'react-icons/md'
-import { FaCube, FaEdit } from 'react-icons/fa'
+import { MdEdit, MdVisibility, MdDelete } from 'react-icons/md'
+import { FaCube, FaDrawPolygon } from 'react-icons/fa'
import { sce } from './app'
export const Tree = () => {
const treeEntries = useSelector(state => state.treeEntries)
const fileHandle = useSelector(state => state.ui.fileHandle)
+ const fileName = useSelector(state => state.ui.fileName)
- return
+ return
- {fileHandle ? fileHandle.name.replace(/\.[^/.]+$/, "") : 'Untitled'}
+ {
+ (fileHandle ? fileHandle.name : fileName).replace(/\.[^/.]+$/, "")
+ }
+
+
+ {treeEntries.allIds.map((entId, idx) => (
+
+ ))}
- {treeEntries.allIds.map((entId, idx) => (
-
- ))}
}
@@ -26,147 +31,145 @@ export const Tree = () => {
const treeIcons = {
'mesh': FaCube,
- 'sketch': FaEdit
+ 'sketch': FaDrawPolygon
}
const TreeEntry = ({ entId }) => {
-
-
- const treeEntriesById = useSelector(state => state.treeEntries.byId)
const dispatch = useDispatch()
+
+ const entry = useSelector(state => state.treeEntries.byId[entId])
const visible = useSelector(state => state.treeEntries.visible[entId])
+ const selected = useSelector(state => state.ui.selectedSet[entId])
+ const activeId = useSelector(state => state.ui.dialog.target)
- let obj3d, sketch;
+ // console.log(entId)
- if (treeEntriesById[entId].obj3d) {
- obj3d = treeEntriesById[entId].obj3d
- sketch = treeEntriesById[entId]
+ let obj, sketch;
+
+ if (entry.obj3d) {
+ obj = entry.obj3d
+ sketch = entry
} else {
- obj3d = treeEntriesById[entId]
+ obj = entry
}
- let Icon = treeIcons[obj3d.userData.type]
+ let Icon = treeIcons[obj.userData.type]
const [_, forceUpdate] = useReducer(x => x + 1, 0);
const [mouseOn, setMouseOn] = useState(false)
- return
{
- if (obj3d.userData.type == 'sketch') {
- if (sce.activeSketch) {
- dispatch({ type: 'finish-sketch' })
- sce.activeSketch.deactivate()
- }
-
-
- sketch.activate()
- dispatch({ type: 'set-active-sketch', sketch })
-
- sce.clearSelection()
- sce.activeSketch = sketch;
- dispatch({ type: 'set-dialog', action: 'sketch' })
- sce.render()
- } else if (obj3d.userData.featureInfo.length == 2) {
- dispatch({ type: 'set-dialog', action: 'extrude-edit', target: treeEntriesById[entId] })
+ const edit = (e) => {
+ e.stopPropagation()
+ if (obj.userData.type == 'sketch') {
+ if (sce.activeSketch) {
+ dispatch({ type: 'finish-sketch' })
+ sce.activeSketch.deactivate()
}
- }}
- onPointerEnter={() => {
+
+ sketch.activate()
+ dispatch({ type: 'set-active-sketch', sketch })
+
+ sce.clearSelection()
+ sce.activeSketch = sketch;
+ dispatch({ type: 'set-dialog', action: 'sketch', target: obj.name })
+ sce.render()
+ } else if (obj.userData.featureInfo.length == 2) {
+ dispatch({ type: 'set-dialog', action: 'extrude-edit', target: obj.name })
+ }
+
+ }
+
+ const del = (e) => {
+ e.stopPropagation()
+ dispatch({ type: 'delete-node', id: entId })
+ sce.render()
+ }
+
+ const toggleVis = (e) => {
+ e.stopPropagation()
+ dispatch({ type: "set-entry-visibility", obj: { [entId]: !visible } })
+ obj.visible = !visible;
+ if (obj.userData.type == 'mesh') {
+ obj.traverse((e) => visible ? e.layers.disable(1) : e.layers.enable(1))
+ }
+
+ sce.render()
+ forceUpdate()
+ }
+
+ const mouseHandlers = {
+ onPointerEnter: () => {
if (mouseOn) return
setMouseOn(true)
- if (obj3d.userData.type == 'sketch') {
- obj3d.visible = true
+ if (obj.userData.type == 'sketch') {
+ obj.visible = true
}
- sce.setHover(obj3d, 1)
+ sce.setHover(obj, 1)
sce.render()
- }}
- onPointerLeave={() => {
+ },
+ onPointerLeave: () => {
if (!mouseOn) return
setMouseOn(false)
- if (obj3d.userData.type == 'sketch'
- && !sce.selected.includes(obj3d)
+ if (obj.userData.type == 'sketch'
+ && !sce.selected.includes(obj)
&& !visible
) {
- obj3d.visible = false
+ obj.visible = false
}
- if (sce.selected.includes(obj3d)) return
+ if (sce.selected.includes(obj)) return
- sce.setHover(obj3d, 0)
+ sce.setHover(obj, 0)
sce.render()
- }}
- onClick={() => {
- const idx = sce.selected.indexOf(obj3d)
-
+ },
+ onClick: () => {
+ const idx = sce.selected.indexOf(obj)
if (idx == -1) {
- sce.selected.push(obj3d)
- sce.setHover(obj3d, 1)
+ sce.setHover(obj, 1)
} else {
sce.setHover(sce.selected[idx], 0)
- sce.selected.splice(idx, 1)
}
+
+ dispatch({ type: 'on-pick', obj })
+
+
sce.render()
- }}
-
- tooltip={obj3d.name[0] != '(' ? "double click to edit" : undefined}
- // tooltip= {obj3d.userData.name}
+ }
+ }
+ return
-
-
+
+
{entId}
-
- {
- dispatch({ type: 'delete-node', id: entId })
- sce.render()
- e.stopPropagation()
- }}
- />
-
{
- visible ?
- {
- e.stopPropagation()
- console.log('hide')
- dispatch({ type: "set-entry-visibility", obj: { [entId]: false } })
- obj3d.visible = false;
- if (obj3d.userData.type == 'mesh') {
- obj3d.traverse((e) => e.layers.disable(1))
- }
-
- sce.render()
- forceUpdate()
- }}
- />
- :
- {
- e.stopPropagation()
- console.log('show')
- obj3d.visible = true;
- dispatch({ type: "set-entry-visibility", obj: { [entId]: true } })
- if (obj3d.userData.type == 'mesh') {
- obj3d.traverse((e) => {
- e.layers.enable(1)
- })
- }
- sce.render()
- forceUpdate()
- }}
- />
+ mouseOn && obj.name[0] != '(' &&
+ }
+ {
+ mouseOn &&
+ }
+ {
+ (mouseOn || visible) &&
}
-
}
\ No newline at end of file
diff --git a/src/shared.js b/src/shared.js
index 540f232..8cbaca7 100644
--- a/src/shared.js
+++ b/src/shared.js
@@ -30,11 +30,11 @@ const color = {
const hoverColor = {
emissive: 0x343407,
- point: 0x00ff00,
+ point: 0x10B981,
selpoint: 0xff0000,
- line: 0x00ff00,
+ line: 0x10B981,
mesh: 0xFAB601,
- dimension: 0x00ff00,
+ dimension: 0x10B981,
plane: 0xffff00,
planeBorder: 0x919100,
@@ -105,7 +105,7 @@ async function awaitSelection(...criteria) {
const counter = {}
- let references = this.selected.slice()
+ let references = (this.selected || this.scene.selected).slice()
for (let ob of references) {
const type = ob.userData.type
@@ -149,7 +149,7 @@ async function awaitSelection(...criteria) {
window.removeEventListener('keydown', onKey)
}
- // console.log('fail')
+ console.log('fail')
return null
}
diff --git a/static/favicon.ico b/static/favicon.ico
index 30805fe..95bae8c 100644
Binary files a/static/favicon.ico and b/static/favicon.ico differ
diff --git a/static/icon-192.png b/static/icon-192.png
index 017a82d..9fc508f 100644
Binary files a/static/icon-192.png and b/static/icon-192.png differ
diff --git a/static/icon-512.png b/static/icon-512.png
index efefec7..c3d9bd6 100644
Binary files a/static/icon-512.png and b/static/icon-512.png differ