add selection modes to left menu

This commit is contained in:
Stewart Allen 2022-01-13 17:01:35 -05:00
commit 6ca4551fb5
4 changed files with 98 additions and 33 deletions

View file

@ -114,13 +114,15 @@ function restore_space() {
// restore preferences after models are restored
api.prefs.load().then(() => {
let { map } = api.prefs;
let { space } = map;
let { space, mode } = map;
api.grid(space.grid);
// restore selected state
let selist = space.select;
let smodel = api.model.list().filter(m => selist.contains(m.id));
let sgroup = api.group.list().filter(m => selist.contains(m.id));
api.selection.set([...smodel, ...sgroup]);
// restore edit mode
api.mode.set(mode);
});
});
// hide loading curtain
@ -264,11 +266,7 @@ function space_init(data) {
if (model) {
let group = model.group;
let { ctrlKey, metaKey, shiftKey } = event;
if (shiftKey && metaKey) {
// find faces adjacent to point/line clicked
model.find(int.point, int.face);
// console.log(int);
} else if (metaKey) {
if (metaKey) {
// set focus on intersected face
let { x, y, z } = int.point;
// y,z swap due to world rotation for orbit controls
@ -277,7 +275,18 @@ function space_init(data) {
// rotate selected face towawrd z "floor"
group.faceDown(int.face.normal);
} else {
selection.toggle(shiftKey ? model : model.group);
let modes = api.mode.modes;
switch(api.mode.get()) {
case modes.object:
selection.toggle(shiftKey ? model : model.group);
break;
case modes.face:
case modes.line:
case modes.vertex:
// find faces adjacent to point/line clicked
model.find(int.point, int.face);
break;
}
}
}
} else {

View file

@ -121,12 +121,6 @@ let selection = {
util.defer(selection.update);
},
duplicate() {
for (let m of selection.models()) {
m.duplicate();
}
},
// update selection and wireframe for all objects
update() {
for (let group of groups) {
@ -309,6 +303,12 @@ let tool = {
});
},
duplicate() {
for (let m of selection.models()) {
m.duplicate();
}
},
analyze(models) {
models = fallback(models);
api.log.emit('analyzing mesh(es)...').pin();
@ -377,10 +377,46 @@ let tool = {
}
};
let modes = { object: "object", face: "face", line: "line", vertex: "vertex" };
// edit mode
let mode = {
set(mode) {
prefs.save(prefs.map.mode = mode);
for (let key of Object.values(modes)) {
$(`mode-${key}`).classList.remove('selected');
}
$(`mode-${mode}`).classList.add('selected');
},
get() {
return prefs.map.mode;
},
object() {
mode.set(modes.object);
},
face() {
mode.set(modes.face);
},
line() {
mode.set(modes.line);
},
vertex() {
mode.set(modes.vertex);
},
modes
};
// persisted preference map
let prefs = {
map: {
info: {},
mode: modes.object,
space: {
wire: false,
grid: true,
@ -460,6 +496,8 @@ let api = mesh.api = {
prefs.save( prefs.map.space.wire = wire );
},
mode,
selection,
group,

View file

@ -210,29 +210,37 @@ function ui_build() {
// create slid in/out logging window
h.bind(logger, [ h.div({ id: 'logtext' }) ]);
// a few shortcuts to api calls
let { file, selection, mode, tool, prefs } = api;
// create hotkey/action menu (top/left)
h.bind(actions, [
h.div([
// create and bind file loading elements
h.button({ _: 'import', onclick: api.file.import }, [
h.button({ _: 'import', onclick: file.import }, [
h.input({
id: "import", type: "file", class: ["hide"], multiple: true,
onchange(evt) { broker.send.load_files(evt.target.files) }
})
]),
h.button({ _: 'export', onclick: api.file.export }),
h.button({ _: 'export', onclick: file.export }),
h.div({ class: "vsep" }),
h.button({ _: 'visible', onclick() { api.selection.visible({ toggle: true }) } }),
h.button({ _: 'bounds', onclick() { api.selection.boundsBox({ toggle: true }) } }),
h.button({ _: 'visible', onclick() { selection.visible({ toggle: true }) } }),
h.button({ _: 'bounds', onclick() { selection.boundsBox({ toggle: true }) } }),
h.button({ _: 'gridlines', onclick() { api.grid() } }),
h.button({ _: 'wireframe', onclick() { api.wireframe() } }),
h.div({ class: "vsep" }),
h.button({ _: 'duplicate', onclick: api.selection.duplicate }),
h.button({ _: 'merge', onclick: api.tool.merge }),
h.button({ _: 'duplicate', onclick: tool.duplicate }),
h.button({ _: 'merge', onclick: tool.merge }),
h.div({ class: "vsep" }),
h.button({ _: 'analyze', onclick: api.tool.analyze }),
h.button({ _: 'repair', onclick: api.tool.repair }),
h.button({ _: 'clean', onclick: api.tool.clean }),
h.button({ _: 'analyze', onclick: tool.analyze }),
h.button({ _: 'repair', onclick: tool.repair }),
h.button({ _: 'clean', onclick: tool.clean }),
h.div({ class: "vsep" }),
h.button({ _: 'object', id: "mode-object", onclick() { mode.object() } }),
h.button({ _: 'face', id: "mode-face", onclick() { mode.face() } }),
h.button({ _: 'line', id: "mode-line", onclick() { mode.line() } }),
h.button({ _: 'vertex', id: "mode-vertex", onclick() { mode.vertex() } }),
]),
]);
@ -261,14 +269,14 @@ function ui_build() {
// update model selector list (top/right)
function update_selector() {
let selHas = api.selection.contains;
let selHas = selection.contains;
// map groups to divs
let groups = api.group.list()
.map(g => h.div([
h.button({ _: g.name || `group`, title: g.id,
class: [ "group", selHas(g) ? 'selected' : undefined ],
onclick(e) {
e.shiftKey ? api.selection.toggle(g) : api.selection.set([g])
e.shiftKey ? selection.toggle(g) : selection.set([g])
}
}),
h.div({ class: "vsep" }),
@ -280,10 +288,10 @@ function ui_build() {
m.visible() ? undefined : 'hidden'
],
onclick(e) {
let sel = api.selection.list();
let sel = selection.list();
e.shiftKey || (sel.length === 1 && m === sel[0]) ?
api.selection.toggle(m) :
api.selection.set([m])
selection.toggle(m) :
selection.set([m])
}
}))
)
@ -294,8 +302,8 @@ function ui_build() {
// update model information dashboard (bottom)
function update_selection() {
let map = { fixed: 2 };
let s_grp = api.selection.groups();
let s_mdl = api.selection.models();
let s_grp = selection.groups();
let s_mdl = selection.models();
if (s_mdl.length === 0) {
return h.bind(selectlist, []);
}
@ -359,20 +367,20 @@ function ui_build() {
...h_ara,
...h_msh
]);
let prefs = api.prefs.map.info;
let pmap = prefs.map.info;
// map buttons to show/hide selection info
function toggle(label, h, s, d) {
s.onclick = () => {
s.style.display = 'none';
d.style.display = 'flex';
api.prefs.save( prefs[label] = 'show' ); // <- :)
prefs.save( pmap[label] = 'show' ); // <- :)
};
h.onclick = () => {
d.style.display = 'none';
s.style.display = 'flex';
api.prefs.save( prefs[label] = 'hide' );
prefs.save( pmap[label] = 'hide' );
};
if (prefs[label] === 'show') {
if (pmap[label] === 'show') {
s.onclick();
} else {
h.onclick();

View file

@ -280,6 +280,16 @@ button:hover {
border-bottom: 1px dashed gray;
}
/** actions menu top/left **/
#actions button.selected {
background-color: rgba(0,255,0,0.5);
}
#actions button.selected:hover {
background-color: rgba(0,255,0,1);
}
/** slide in/out logging window **/
#logger {