diff --git a/src/kiri/app/inputs.js b/src/kiri/app/inputs.js index cb876b1f..2a3a05a1 100644 --- a/src/kiri/app/inputs.js +++ b/src/kiri/app/inputs.js @@ -1034,7 +1034,11 @@ function newButton(label, action, opt = {}) { */ function newRow(children, options) { let row = addCollapsableElement((options && options.noadd) ? null : addTo); - if (children) children.forEach(function (c) { row.appendChild(c) }); + if (children) { + children.forEach((c) => { + row.appendChild(c); + }); + }; addModeControls(row, options); if (options && options.class) { options.class.split(' ').forEach(ce => { diff --git a/src/kiri/mode/cam/cl-ops.js b/src/kiri/mode/cam/cl-ops.js index b141323b..713b5b00 100644 --- a/src/kiri/mode/cam/cl-ops.js +++ b/src/kiri/mode/cam/cl-ops.js @@ -8,7 +8,7 @@ import { opFlip } from './cl-flip.js'; import { selectHoles } from './cl-hole.js'; import { selectHelical } from './cl-helical.js'; import { surfaceAdd } from './cl-surface.js'; -import { traceAdd } from './cl-trace.js'; +import { traceAdd, traceClear, traceLoad } from './cl-trace.js'; import { startFaceUp } from '../../app/face-tool.js'; import { showZBottom, showZTop, updateStock } from './cl-stock.js'; @@ -137,14 +137,21 @@ export function createPopOp(type, map) { return rec; }, hideshow: () => { + let conf = api.conf.get(); for (let inp of Object.values(op.inputs)) { let parent = inp.parentElement; if (parent && parent.setVisible && parent.__opt.show) { // for normal inputs - parent.setVisible(parent.__opt.show(op, api.conf.get())); + parent.setVisible(parent.__opt.show(op, conf)); } else if (inp.__opt?.show) { // for blanks - inp.setVisible(inp.__opt.show(op, api.conf.get())); + inp.setVisible(inp.__opt.show(op, conf)); + } else if (inp.children) { + for (let c of inp.children) { + if (c.__opt?.show) { + c.setVisible(c.__opt.show(op, conf)); + } + } } } }, @@ -322,10 +329,6 @@ export function createPopOps() { tool: UC.newSelect(LANG.cc_tool, {}, "tools"), direction: UC.newSelect(LANG.ou_dire_s, { title: LANG.ou_dire_l }, "direction"), sep: UC.newBlank({ class: "pop-sep" }), - spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: toInt, show: hasSpindle }), - rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: toInt, units }), - plunge: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: toInt, units }), - sep: UC.newBlank({ class: "pop-sep" }), step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: toFloat, bound: UC.bound(0.01, 1.0) }), down: UC.newInput(LANG.cc_sdwn_s, { title: LANG.cc_sdwn_l, convert: toFloat, units }), leave: UC.newInput(LANG.cr_lsto_s, { title: LANG.cr_lsto_l, convert: toFloat, units }), @@ -336,7 +339,12 @@ export function createPopOps() { inside: UC.newBoolean(LANG.cr_olin_s, undefined, { title: LANG.cr_olin_l, show: () => !env.poppedRec.all || env.poppedRec.inside }), omitthru: UC.newBoolean(LANG.co_omit_s, undefined, { title: LANG.co_omit_l }), sep: UC.newBlank({ class: "pop-sep" }), - exp: UC.newExpand("overrides", ov_hover), + exp: UC.newExpand("feeds & speeds", { }), + spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: toInt, show: hasSpindle }), + rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: toInt, units }), + plunge: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: toInt, units }), + exp_end: UC.endExpand(), + exp: UC.newExpand("top & bottom", ov_hover), ov_topz: UC.newInput(LANG.ou_ztop_s, ov_topz), ov_botz: UC.newInput(LANG.ou_zbot_s, ov_botz), exp_end: UC.endExpand(), @@ -364,9 +372,6 @@ export function createPopOps() { tool: UC.newSelect(LANG.cc_tool, {}, "tools"), direction: UC.newSelect(LANG.ou_dire_s, { title: LANG.ou_dire_l }, "direction"), sep: UC.newBlank({ class: "pop-sep" }), - spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: toInt, show: hasSpindle }), - rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: toInt, units }), - plunge: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: toInt, units }), down: UC.newInput(LANG.cc_sdwn_s, { title: LANG.cc_sdwn_l, convert: toFloat, units }), step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: toFloat, bound: UC.bound(0.01, 1.0), show: () => env.popOp.outline.rec.wide }), steps: UC.newInput(LANG.cc_sovc_s, { title: LANG.cc_sovc_l, convert: toInt, bound: UC.bound(1, 500), show: () => env.popOp.outline.rec.wide }), @@ -380,7 +385,12 @@ export function createPopOps() { dogbones: UC.newBoolean(LANG.co_dogb_s, undefined, { title: LANG.co_dogb_l, show: (op) => { return !op.inputs.wide.checked } }), revbones: UC.newBoolean(LANG.co_dogr_s, undefined, { title: LANG.co_dogr_l, show: () => env.poppedRec.dogbones }), sep: UC.newBlank({ class: "pop-sep" }), - exp: UC.newExpand("overrides", ov_hover), + exp: UC.newExpand("feeds & speeds", { }), + spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: toInt, show: hasSpindle }), + rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: toInt, units }), + plunge: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: toInt, units }), + exp_end: UC.endExpand(), + exp: UC.newExpand("top & bottom", ov_hover), ov_topz: UC.newInput(LANG.ou_ztop_s, ov_topz), ov_botz: UC.newInput(LANG.ou_zbot_s, ov_botz), exp_end: UC.endExpand(), @@ -487,10 +497,6 @@ export function createPopOps() { offset: UC.newSelect(LANG.cc_offs_s, { title: LANG.cc_offs_l, show: () => (env.poppedRec.mode === 'follow') }, "traceoff"), direction: UC.newSelect(LANG.ou_dire_s, { title: LANG.ou_dire_l }, "direction"), sep: UC.newBlank({ class: "pop-sep" }), - spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: toInt, show: hasSpindle }), - rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: toInt, units }), - plunge: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: toInt, units }), - sep: UC.newBlank({ class: "pop-sep" }), step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: toFloat, bound: UC.bound(0.01, 1.0), show: (op) => env.popOp.trace.rec.mode === "clear" }), down: UC.newInput(LANG.cc_sdwn_s, { title: LANG.cc_sdwn_l, convert: toFloat, units }), offover: UC.newInput(LANG.cc_offd_s, { title: LANG.cc_offd_l, convert: toFloat, units, show: () => env.poppedRec.offset !== "none" || env.poppedRec.mode === "clear" }), @@ -499,13 +505,22 @@ export function createPopOps() { merge: UC.newBoolean(LANG.co_merg_s, undefined, { title: LANG.co_merg_l, show: () => !env.popOp.trace.rec.down }), dogbone: UC.newBoolean(LANG.co_dogb_s, undefined, { title: LANG.co_dogb_l, show: canDogBones }), revbone: UC.newBoolean(LANG.co_dogr_s, undefined, { title: LANG.co_dogr_l, show: canDogBonesRev }), - exp: UC.newExpand("overrides", ov_hover), + exp: UC.newExpand("feeds & speeds", { }), + spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: toInt, show: hasSpindle }), + rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: toInt, units }), + plunge: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: toInt, units }), + exp_end: UC.endExpand(), + exp: UC.newExpand("top & bottom", ov_hover), sep: UC.newBlank({ class: "pop-sep" }), ov_topz: UC.newInput(LANG.ou_ztop_s, ov_topz), ov_botz: UC.newInput(LANG.ou_zbot_s, ov_botz), exp_end: UC.endExpand(), sep: UC.newBlank({ class: "pop-sep" }), - menu: UC.newRow([UC.newButton("select", traceAdd)], { class: "ext-buttons f-row" }), + menu: UC.newRow([ + UC.newButton("select", traceAdd), + // UC.newButton("load", traceLoad, { show: () => env.poppedRec.mode === "follow" }), + // UC.newButton("", traceClear, { icon: '' }), + ], { class: "ext-buttons f-row", row: true }), }; createPopOp('pocket', { @@ -530,10 +545,6 @@ export function createPopOps() { tool: UC.newSelect(LANG.cc_tool, {}, "tools"), direction: UC.newSelect(LANG.ou_dire_s, { title: LANG.ou_dire_l }, "direction"), sep: UC.newBlank({ class: "pop-sep" }), - spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: toInt, show: hasSpindle }), - rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: toInt, units }), - plunge: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: toInt, units }), - sep: UC.newBlank({ class: "pop-sep" }), step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: toFloat, bound: UC.bound(0.01, 1.0) }), down: UC.newInput(LANG.cc_sdwn_s, { title: LANG.cc_sdwn_l, convert: toFloat, units, show: () => !env.poppedRec.contour }), sep: UC.newBlank({ class: "pop-sep" }), @@ -545,7 +556,12 @@ export function createPopOps() { sep: UC.newBlank({ class: "pop-sep" }), contour: UC.newBoolean(LANG.cp_cont_s, undefined, { title: LANG.cp_cont_s }), outline: UC.newBoolean(LANG.cp_outl_s, undefined, { title: LANG.cp_outl_l }), - exp: UC.newExpand("overrides", ov_hover), + exp: UC.newExpand("feeds & speeds", { }), + spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: toInt, show: hasSpindle }), + rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: toInt, units }), + plunge: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: toInt, units }), + exp_end: UC.endExpand(), + exp: UC.newExpand("top & bottom", ov_hover), sep: UC.newBlank({ class: "pop-sep" }), ov_topz: UC.newInput(LANG.ou_ztop_s, ov_topz), ov_botz: UC.newInput(LANG.ou_zbot_s, ov_botz), diff --git a/src/kiri/mode/cam/cl-trace.js b/src/kiri/mode/cam/cl-trace.js index 3fd4666b..31203c63 100644 --- a/src/kiri/mode/cam/cl-trace.js +++ b/src/kiri/mode/cam/cl-trace.js @@ -2,9 +2,11 @@ import { api } from '../../app/api.js'; import { env, clearPops, isDark } from './init-ui.js'; +import { parse } from '../../../load/svg.js'; import { CAM } from './driver-fe.js'; import { Layers } from '../../app/layers.js'; import { Stack } from '../../app/stack.js'; +import { newPolygon } from '../../../geo/polygon.js'; export let traceOn = false; export let lastTrace; @@ -13,6 +15,95 @@ export function setLastTrace(trace) { lastTrace = trace; } +export function traceLoad(ev) { + let widget = api.widgets.all()[0]; + if (!widget) return; + window.showOpenFilePicker({ + types: [{ + description: 'SVG Files', + accept: { 'text/svg': ['.svg'] } + }], + multiple: false + }).then(async fileHandle => { + const file = await fileHandle[0].getFile() + const text = await file.text(); // string + // const buf = await file.arrayBuffer(); // binary + // const blob = await file.slice(); + const polys = parse(text, { flat: true, soup: true }); + const rec = env.poppedRec; + rec.areas[widget.id] = polys.map(p => p.toArray()); + rec.svg = true; + traceAdd(); + }).catch(error => { + console.log('no file load', error); + }); +} + +export function traceClear(ev) { + return; + api.widgets.for(widget => { + unselectTraces(widget, true); + widget.traces = []; + widget.adds = []; + }); + env.poppedRec.areas = []; + env.poppedRec.svg = false; + traceDone(); +} + +function startTraceAdd(ids) { + api.hide.alert(alert); + alert = api.show.alert("[esc] cancels trace editing"); + api.widgets.for(widget => { + if (ids.indexOf(widget.id) >= 0) { + unselectTraces(widget, true); + widget.trace_stack = null; + } + if (widget.trace_stack) { + widget.adds.appendAll(widget.trace_stack.meshes); + widget.trace_stack.show(); + return; + } + let areas = (env.poppedRec.areas[widget.id] || []); + let stack = new Stack(widget.mesh); + widget.trace_stack = stack; + widget.traces?.forEach(poly => { + let match = areas.filter(arr => poly.matches(arr)); + let layers = new Layers(); + layers.setLayer("trace", { line: 0xaaaa55, fat: 4, order: -10 }, false).addPoly(poly); + stack.addLayers(layers); + stack.new_meshes.forEach(mesh => { + mesh.trace = { widget, poly }; + // ensure trace poly singleton from matches + if (match.length > 0) { + poly._trace = match[0]; + } else { + poly._trace = poly.toArray(); + } + }); + widget.adds.appendAll(stack.new_meshes); + // console.log(widget) + }); + }); + // ensure appropriate traces are toggled matching current record + api.widgets.for(widget => { + widget.setVisualState({ opacity: 0.25 }); + let areas = (env.poppedRec.areas[widget.id] || []); + let stack = widget.trace_stack; + stack.meshes.forEach(mesh => { + let { poly } = mesh.trace; + let match = areas.filter(arr => poly.matches(arr)); + if (match.length > 0) { + if (!mesh.selected) { + traceToggle(mesh, true); + } + } else if (mesh.selected) { + traceToggle(mesh, true); + } + }); + }); +} + export function traceAdd(ev) { if (traceOn) { return traceDone(); @@ -25,58 +116,16 @@ export function traceAdd(ev) { api.feature.hoverAdds = true; env.hover = traceHover; env.hoverUp = traceHoverUp; - CAM.traces((ids) => { - api.hide.alert(alert); - alert = api.show.alert("[esc] cancels trace editing"); - api.widgets.for(widget => { - if (ids.indexOf(widget.id) >= 0) { - unselectTraces(widget, true); - widget.trace_stack = null; - } - if (widget.trace_stack) { - widget.adds.appendAll(widget.trace_stack.meshes); - widget.trace_stack.show(); - return; - } - let areas = (env.poppedRec.areas[widget.id] || []); - let stack = new Stack(widget.mesh); - widget.trace_stack = stack; - widget.traces?.forEach(poly => { - let match = areas.filter(arr => poly.matches(arr)); - let layers = new Layers(); - layers.setLayer("trace", { line: 0xaaaa55, fat: 4, order: -10 }, false).addPoly(poly); - stack.addLayers(layers); - stack.new_meshes.forEach(mesh => { - mesh.trace = { widget, poly }; - // ensure trace poly singleton from matches - if (match.length > 0) { - poly._trace = match[0]; - } else { - poly._trace = poly.toArray(); - } - }); - widget.adds.appendAll(stack.new_meshes); - // console.log(widget) - }); - }); - // ensure appropriate traces are toggled matching current record - api.widgets.for(widget => { - widget.setVisualState({ opacity: 0.25 }); - let areas = (env.poppedRec.areas[widget.id] || []); - let stack = widget.trace_stack; - stack.meshes.forEach(mesh => { - let { poly } = mesh.trace; - let match = areas.filter(arr => poly.matches(arr)); - if (match.length > 0) { - if (!mesh.selected) { - traceToggle(mesh, true); - } - } else if (mesh.selected) { - traceToggle(mesh, true); - } - }); - }); - }, env.poppedRec.select === 'lines'); + if (env.poppedRec.svg === true) { + let widgets = api.widgets.all(); + for (let [ id, areas ] of Object.entries(env.poppedRec.areas)) { + let widget = widgets.filter(w => w.id === id)[0]; + widget.traces = areas.map(arr => newPolygon().fromArray(arr)); + } + startTraceAdd(Object.keys(env.poppedRec.areas)); + } else { + CAM.traces(startTraceAdd, env.poppedRec.select === 'lines'); + } } export function traceDone() { diff --git a/web/kiri/index.css b/web/kiri/index.css index 6dc1e276..6150a59a 100644 --- a/web/kiri/index.css +++ b/web/kiri/index.css @@ -1346,10 +1346,12 @@ details[open] summary::after { cursor: pointer; } .ext-buttons button { + display: inline-flex; + line-height: 1; justify-content: center; align-items: center; text-align: center; - flex-grow: 1; + flex: 1 1 0; /* equal width */ margin-top: 3px; height: 75%; } diff --git a/web/kiri/index.html b/web/kiri/index.html index 7afcc4a5..c90fac76 100644 --- a/web/kiri/index.html +++ b/web/kiri/index.html @@ -110,8 +110,8 @@
- - + +