diff --git a/src/kiri-mode/cam/animate.js b/src/kiri-mode/cam/animate.js index a184e1bd..113cc43a 100644 --- a/src/kiri-mode/cam/animate.js +++ b/src/kiri-mode/cam/animate.js @@ -52,22 +52,18 @@ kiri.load(() => { } let meshes = {}, + button = {}, + label = {}, unitScale = 1, - progress, speedValues = [ 1, 2, 4, 8, 32 ], speedPauses = [ 30, 20, 10, 5, 0 ], speedNames = [ "1x", "2x", "4x", "8x", "!!" ], speedMax = speedValues.length - 1, speedIndex = 0, - speedLabel, speed, color = 0, material, - pauseButton, - playButton, - modelButton, - shadeButton, - transButton, + origin, posOffset = { x:0, y:0, z:0 }; const { moto } = root; @@ -75,45 +71,59 @@ kiri.load(() => { const { api } = kiri; function animate_clear(api) { + let { anim } = api.ui; moto.space.platform.showGridBelow(true); kiri.client.animate_cleanup(); - $('layer-animate').innerHTML = ''; - $('layer-toolpos').innerHTML = ''; Object.keys(meshes).forEach(id => deleteMesh(id)); toggleStock(undefined,true,false); - } + api.uc.setVisible(anim.laba, false); + api.uc.setVisible(anim.vala, false); +} function animate(api, delay) { let alert = api.alerts.show("building animation"); - kiri.client.animate_setup(api.conf.get(), data => { + let settings = api.conf.get(); + kiri.client.animate_setup(settings, data => { checkMeshCommands(data); if (!(data && data.mesh_add)) { return; } - const UC = api.uc; - const layer = $('layer-animate'); - layer.innerHTML = ''; - UC.setGroup(layer); - UC.newRow([ - UC.newButton(null,replay,{icon:'',title:"restart"}), - playButton = UC.newButton(null,play,{icon:'',title:"play"}), - pauseButton = UC.newButton(null,pause,{icon:'',title:"pause"}), - UC.newButton(null,step,{icon:'',title:"single step"}), - UC.newButton(null,fast,{icon:'',title:"toggle speed"}), - speedLabel = UC.newLabel("speed", {class:"speed padleft"}), - progress = UC.newLabel('0%', {class:"progress"}), - transButton = UC.newButton(null,toggleTrans,{icon:'',title:"transparency",class:"padleft"}), - modelButton = UC.newButton(null,toggleModel,{icon:'',title:"show model"}), - shadeButton = UC.newButton(null,toggleStock,{icon:'',title:"stock box"}), - ]); + + let { anim } = api.ui; + Object.assign(button, { + replay: anim.replay, + play: anim.play, + step: anim.step, + pause: anim.pause, + speed: anim.speed, + trans: anim.trans, + model: anim.model, + shade: anim.shade + }); + Object.assign(label, { + progress: anim.progress, + speed: anim.labspd, + x: anim.valx, + y: anim.valy, + z: anim.valz, + }); + + origin = settings.origin; speedIndex = api.local.getInt('cam.anim.speed') || 0; updateSpeed(); setTimeout(step, delay || 0); - const toolpos = $('layer-toolpos'); - toolpos.innerHTML = ''; - UC.setGroup(toolpos); - playButton.style.display = ''; - pauseButton.style.display = 'none'; + + button.replay.onclick = replay; + button.play.onclick = play; + button.step.onclick = step; + button.pause.onclick = pause; + button.speed.onclick = fast; + button.trans.onclick = toggleTrans; + button.model.onclick = toggleModel; + button.shade.onclick = toggleStock; + button.play.style.display = ''; + button.pause.style.display = 'none'; + api.event.emit('animate', 'CAM'); api.alerts.hide(alert); moto.space.platform.showGridBelow(false); @@ -131,16 +141,10 @@ kiri.load(() => { animate_setup(settings, ondone) { color = settings.controller.dark ? 0x48607B : 0x607FA4; unitScale = settings.controller.units === 'in' ? 1/25.4 : 1; - let shininess = 120, - specular = 0x202020, - emissive = 0x101010, - metalness = 0.2, - roughness = 0.8, - flatShading = true, + let flatShading = true, transparent = true, opacity = 0.9, side = THREE.DoubleSide; - // material = new THREE.MeshMatcapMaterial({ material = new THREE.MeshPhongMaterial({ flatShading, transparent, @@ -236,8 +240,8 @@ kiri.load(() => { const { steps } = opts; updateSpeed(); if (steps !== 1) { - playButton.style.display = 'none'; - pauseButton.style.display = ''; + button.play.style.display = 'none'; + button.pause.style.display = ''; } kiri.client.animate({ speed, @@ -249,8 +253,8 @@ kiri.load(() => { function fast(opts) { const { steps } = opts; updateSpeed(1); - playButton.style.display = 'none'; - pauseButton.style.display = ''; + button.play.style.display = 'none'; + button.pause.style.display = ''; kiri.client.animate({ speed, steps: steps || Infinity, @@ -259,15 +263,15 @@ kiri.load(() => { } function pause() { - playButton.style.display = ''; - pauseButton.style.display = 'none'; + button.play.style.display = ''; + button.pause.style.display = 'none'; kiri.client.animate({speed: 0}, handleGridUpdate); } function handleGridUpdate(data) { checkMeshCommands(data); if (data && data.progress) { - progress.innerText = (data.progress * 100).toFixed(1) + '%' + label.progress.value = (data.progress * 100).toFixed(1); } } @@ -279,7 +283,7 @@ kiri.load(() => { } api.local.set('cam.anim.speed', speedIndex); speed = speedValues[speedIndex]; - speedLabel.innerText = speedNames[speedIndex]; + label.speed.value = speedNames[speedIndex]; } function replay() { @@ -313,6 +317,9 @@ kiri.load(() => { mesh.position.z = pos.z; space.update(); } + label.x.value = (pos.x - origin.x).toFixed(2); + label.y.value = (pos.y + origin.y).toFixed(2); + label.z.value = (pos.z - origin.z).toFixed(2); } if (data.mesh_update) { meshUpdates(data.id); @@ -341,7 +348,6 @@ kiri.load(() => { path = print.output.flat(); tools = settings.tools; stock = settings.stock; - rez = 1/Math.sqrt(density/(stock.x * stock.y)); const step = rez; diff --git a/src/kiri-mode/cam/animate2.js b/src/kiri-mode/cam/animate2.js index 75a2f820..f00452b3 100644 --- a/src/kiri-mode/cam/animate2.js +++ b/src/kiri-mode/cam/animate2.js @@ -18,61 +18,79 @@ kiri.load(() => { } let meshes = {}, - progress, + button = {}, + label = {}, + material, speedPauses = [ 0, 0, 0, 0, 0 ], speedValues = [ 1, 2, 4, 8, 32 ], speedNames = [ "1x", "2x", "4x", "8x", "!!" ], speedMax = speedValues.length - 1, speedIndex = 0, - speedLabel, speed, - color = 0, - pauseButton, - playButton; + origin, + color = 0; const { moto } = root; const { space } = moto; const { api } = kiri; function animate_clear2(api) { - // moto.space.platform.showGridBelow(true); + let { anim } = api.ui; kiri.client.animate_cleanup2(); - $('layer-animate').innerHTML = ''; - $('layer-toolpos').innerHTML = ''; Object.keys(meshes).forEach(id => deleteMesh(id)); api.widgets.setAxisIndex(0); - } + api.uc.setVisible(anim.laba, true); + api.uc.setVisible(anim.vala, true); + anim.vala.value = "0.0"; +} function animate2(api, delay) { let alert = api.alerts.show("building animation"); - kiri.client.animate_setup2(api.conf.get(), data => { + let settings = api.conf.get(); + kiri.client.animate_setup2(settings, data => { handleUpdate(data); if (data) { return; } - const UC = api.uc; - const layer = $('layer-animate'); - layer.innerHTML = ''; - UC.setGroup(layer); - UC.newRow([ - UC.newButton(null,replay,{icon:'',title:"restart"}), - playButton = UC.newButton(null,play,{icon:'',title:"play"}), - pauseButton = UC.newButton(null,pause,{icon:'',title:"pause"}), - UC.newButton(null,step,{icon:'',title:"single step"}), - UC.newButton(null,fast,{icon:'',title:"toggle speed"}), - speedLabel = UC.newLabel("speed", {class:"speed"}), - progress = UC.newLabel('0%', {class:"progress"}) - ]); - updateSpeed(); + + let { anim } = api.ui; + Object.assign(button, { + replay: anim.replay, + play: anim.play, + step: anim.step, + pause: anim.pause, + speed: anim.speed, + trans: anim.trans, + model: anim.model, + shade: anim.shade + }); + Object.assign(label, { + progress: anim.progress, + speed: anim.labspd, + x: anim.valx, + y: anim.valy, + z: anim.valz, + a: anim.vala + }); + + updateSpeed(0); setTimeout(step, delay || 0); - const toolpos = $('layer-toolpos'); - toolpos.innerHTML = ''; - UC.setGroup(toolpos); - playButton.style.display = ''; - pauseButton.style.display = 'none'; + toggleTrans(undefined, false); + origin = settings.origin; + + button.replay.onclick = replay; + button.play.onclick = play; + button.step.onclick = step; + button.pause.onclick = pause; + button.speed.onclick = fast; + button.trans.onclick = toggleTrans; + button.model.onclick = toggleModel; + button.shade.onclick = toggleStock; + button.play.style.display = ''; + button.pause.style.display = 'none'; + api.event.emit('animate', 'CAM'); api.alerts.hide(alert); - // moto.space.platform.showGridBelow(false); }); } @@ -83,6 +101,13 @@ kiri.load(() => { animate_setup2(settings, ondone) { color = settings.controller.dark ? 0x888888 : 0; + material = new THREE.MeshMatcapMaterial({ + flatShading: true, + transparent: false, + opacity: 0.9, + color: 0x888888, + side: THREE.DoubleSide + }); kiri.client.send("animate_setup2", {settings}, ondone); }, @@ -102,14 +127,7 @@ kiri.load(() => { const ia = ilen ? ind.subarray(0, ilen) : ind; geo.setAttribute('position', new THREE.BufferAttribute(pa, 3)); geo.setIndex(new THREE.BufferAttribute(ia, 1)); - const mat = new THREE.MeshMatcapMaterial({ - flatShading: true, - transparent: false, - opacity: 1, - color: 0x888888, - side: THREE.DoubleSide - }); - const mesh = new THREE.Mesh(geo, mat); + const mesh = new THREE.Mesh(geo, material); mesh.pos = pos; mesh.ind = ind; space.world.add(mesh); @@ -136,6 +154,22 @@ kiri.load(() => { delete meshes[id]; } + function toggleModel(ev,bool) { + api.local.toggle('cam.anim.model', bool); + api.widgets.all().forEach(w => w.toggleVisibility(bool)); + } + + function toggleStock(ev,bool,set) { + set !== false && api.local.toggle('cam.anim.stock', bool); + return api.event.emit('cam.stock.toggle', bool ?? undefined); + } + + function toggleTrans(ev,bool) { + bool = api.local.toggle('cam.anim.trans', bool); + material.transparent = bool; + material.needsUpdate = true; + } + function step() { updateSpeed(); kiri.client.animate2({speed, steps: 1}, handleUpdate); @@ -145,8 +179,8 @@ kiri.load(() => { const { steps } = opts; updateSpeed(); if (steps !== 1) { - playButton.style.display = 'none'; - pauseButton.style.display = ''; + button.play.style.display = 'none'; + button.pause.style.display = ''; } kiri.client.animate2({ speed, @@ -158,8 +192,8 @@ kiri.load(() => { function fast(opts) { const { steps } = opts; updateSpeed(1); - playButton.style.display = 'none'; - pauseButton.style.display = ''; + button.play.style.display = 'none'; + button.pause.style.display = ''; kiri.client.animate2({ speed, steps: steps || Infinity, @@ -168,8 +202,8 @@ kiri.load(() => { } function pause() { - playButton.style.display = ''; - pauseButton.style.display = 'none'; + button.play.style.display = ''; + button.pause.style.display = 'none'; kiri.client.animate2({speed: 0}, handleUpdate); } @@ -194,9 +228,13 @@ kiri.load(() => { mesh.position.z = pos.z; space.refresh(); } + label.x.value = (pos.x - origin.x).toFixed(2); + label.y.value = (pos.y + origin.y).toFixed(2); + label.z.value = (pos.z - origin.z).toFixed(2); } if (data.stock_index !== undefined) { api.widgets.setAxisIndex(data.stock_index); + label.a.value = -data.stock_index.toFixed(1); } if (data.mesh_index) { const { id, index } = data.mesh_index; @@ -211,7 +249,7 @@ kiri.load(() => { meshUpdate(id, ind, pos, ilen, plen); } if (data && data.progress) { - progress.innerText = (data.progress * 100).toFixed(1) + '%' + label.progress.value = (data.progress * 100).toFixed(1); } } @@ -221,8 +259,9 @@ kiri.load(() => { } else if (inc > 0) { speedIndex = (speedIndex + inc) % speedValues.length; } + api.local.set('cam.anim.speed', speedIndex); speed = speedValues[speedIndex]; - speedLabel.innerText = speedNames[speedIndex]; + label.speed.value = speedNames[speedIndex]; } function replay() { diff --git a/src/kiri-mode/cam/client.js b/src/kiri-mode/cam/client.js index 84dac0a8..c3bbfc7d 100644 --- a/src/kiri-mode/cam/client.js +++ b/src/kiri-mode/cam/client.js @@ -198,6 +198,8 @@ CAM.init = function(kiri, api) { } updateStock(); func.opRender(); + api.uc.setVisible($('layer-animate'), isAnimate && isCamMode); + // api.uc.setVisible($('layer-toolpos'), isAnimate && isCamMode); }); api.event.on("settings.saved", (settings) => { diff --git a/src/kiri/init.js b/src/kiri/init.js index 6ce1df9f..2c4e3180 100644 --- a/src/kiri/init.js +++ b/src/kiri/init.js @@ -785,7 +785,7 @@ gapp.register("kiri.init", (root, exports) => { let { event, conf, view, show } = api, { bound, toInt, toFloat } = uc, { newBlank, newButton, newBoolean, newGroup, newInput } = uc, - { newSelect, newText, newRow, newGCode, newDiv } = uc; + { newSelect, newLabel, newValue, newRow, newGCode, newDiv } = uc; event.emit('init.one'); @@ -843,6 +843,7 @@ gapp.register("kiri.init", (root, exports) => { // api augmentation with local functions api.device.export = deviceExport; + let anim = ui.anim = {}; Object.assign(ui, { tracker: tracker, @@ -978,6 +979,33 @@ gapp.register("kiri.init", (root, exports) => { stockDepth: $('stock-width'), stockHeight: $('stock-width'), + /** CAM Animation Bar */ + + _____: { + _____: newDiv({ addto: $('layer-animate'), set:true }), + row: newRow([ + anim.replay = newButton(null,"anim.replay",{icon:'',title:"restart"}), + anim.play = newButton(null,"anim.play",{icon:'',title:"play"}), + anim.pause = newButton(null,"anim.pause",{icon:'',title:"pause"}), + anim.step = newButton(null,"anim.step",{icon:'',title:"single step"}), + anim.speed = newButton(null,"anim.fast",{icon:'',title:"toggle speed"}), + anim.labspd = newValue(3, {class:"center padleft"}), + anim.labx = newLabel("X", {class:"padleft"}), + anim.valx = newValue(6, {class:"center"}), + anim.laby = newLabel("Y", {class:"padleft"}), + anim.valy = newValue(6, {class:"center"}), + anim.labz = newLabel("Z", {class:"padleft"}), + anim.valz = newValue(6, {class:"center"}), + anim.laba = newLabel("A", {class:"padleft hide"}), + anim.vala = newValue(6, {class:"center hide"}), + anim.labpro = newLabel("%", {class:"padleft"}), + anim.progress = newValue(5, {class:"center"}), + anim.trans = newButton(null,"anim.trans",{icon:'',title:"transparency",class:"padleft"}), + anim.model = newButton(null,"anim.model",{icon:'',title:"show model"}), + anim.shade = newButton(null,"anim.stock",{icon:'',title:"stock box"}), + ]) + }, + /** Device Browser / Editor */ _____: newDiv({ class: "f-col t-body t-inset", addto: $('dev-config'), set:true }), @@ -1041,7 +1069,7 @@ gapp.register("kiri.init", (root, exports) => { /** Preferences Menu */ - _____: newGroup(LANG.op_menu, $('prefs-gen1'), {inline: true}), + _____: newGroup(LANG.op_menu, $('prefs-gen1'), {inline}), antiAlias: newBoolean(LANG.op_anta_s, booleanSave, {title:LANG.op_anta_l}), reverseZoom: newBoolean(LANG.op_invr_s, booleanSave, {title:LANG.op_invr_l}), ortho: newBoolean(LANG.op_orth_s, booleanSave, {title:LANG.op_orth_l}), @@ -1049,7 +1077,7 @@ gapp.register("kiri.init", (root, exports) => { drawer: newBoolean('slide out', booleanSave, {title:'slide out settings drawer'}), scrolls: newBoolean('scrollbars', booleanSave, {title:'show scrollbars'}), devel: newBoolean(LANG.op_devl_s, booleanSave, {title:LANG.op_devl_l}), - _____: newGroup(LANG.op_disp, $('prefs-gen2'), {inline: true}), + _____: newGroup(LANG.op_disp, $('prefs-gen2'), {inline}), showOrigin: newBoolean(LANG.op_shor_s, booleanSave, {title:LANG.op_shor_l}), showRulers: newBoolean(LANG.op_shru_s, booleanSave, {title:LANG.op_shru_l}), showSpeeds: newBoolean(LANG.op_sped_s, speedSave, {title:LANG.op_sped_l}), @@ -1058,7 +1086,7 @@ gapp.register("kiri.init", (root, exports) => { animesh: newSelect(LANG.op_anim_s, {title: LANG.op_anim_l, action: aniMeshSave, modes:CAM}, "animesh"), units: newSelect(LANG.op_unit_s, {title: LANG.op_unit_l, action: unitsSave, modes:CAM}, "units"), edgeangle: newInput(LANG.op_spoa_s, {title:LANG.op_spoa_l, convert:toFloat, size:3}), - _____: newGroup(LANG.lo_menu, $('prefs-lay'), {inline: true}), + _____: newGroup(LANG.lo_menu, $('prefs-lay'), {inline}), autoSave: newBoolean(LANG.op_save_s, booleanSave, {title:LANG.op_save_l}), autoLayout: newBoolean(LANG.op_auto_s, booleanSave, {title:LANG.op_auto_l}), freeLayout: newBoolean(LANG.op_free_s, booleanSave, {title:LANG.op_free_l}), @@ -1070,7 +1098,7 @@ gapp.register("kiri.init", (root, exports) => { exportOcto: newBoolean(`OctoPrint`, booleanSave, {title:LANG.op_exop_l}), exportThumb: newBoolean(`Thumbnail`, booleanSave, {modes:FDM}), exportPreview: newBoolean(`Code Preview`, booleanSave), - _____: newGroup(LANG.pt_menu, $('prefs-prt'), {inline: true}), + _____: newGroup(LANG.pt_menu, $('prefs-prt'), {inline}), detail: newSelect(LANG.pt_qual_s, {title: LANG.pt_qual_l, action: detailSave}, "detail"), healMesh: newBoolean(LANG.pt_heal_s, booleanSave, {title: LANG.pt_heal_l}), threaded: newBoolean(LANG.pt_thrd_s, booleanSave, {title: LANG.pt_thrd_l, modes:THREED}), diff --git a/src/kiri/ui.js b/src/kiri/ui.js index d568823f..ee299411 100644 --- a/src/kiri/ui.js +++ b/src/kiri/ui.js @@ -58,6 +58,7 @@ gapp.register("kiri.ui", [], (root, exports) => { newGroup, newLabel, newInput, + newValue, newRange, newRow, newSelect, @@ -362,6 +363,17 @@ gapp.register("kiri.ui", [], (root, exports) => { return label; } + function newValue(size = 6, opt = {}) { + let value = DOC.createElement('input'); + value.setAttribute("size", size); + value.setAttribute("readonly", ''); + value.setAttribute("class", "nooutline noselect"); + if (opt.class) opt.class.split(' ').forEach(cl => { + value.classList.add(cl); + }) + return value; + } + function addId(el, opt = {}) { if (opt.id) { el.setAttribute("id", opt.id); @@ -793,9 +805,17 @@ gapp.register("kiri.ui", [], (root, exports) => { // unlike other elements, does not auto-add to a row function newButton(label, action, opt = {}) { let b = DOC.createElement('button'); + let { api } = kiri; b.onclick = function() { - if (action) action(...arguments); + switch (typeof action) { + case "string": + api.event.emit(action); + break; + case "function": + action(...arguments); + break; + } }; if (opt.class) { diff --git a/web/kiri/index.css b/web/kiri/index.css index 55e8df84..65c51cd2 100644 --- a/web/kiri/index.css +++ b/web/kiri/index.css @@ -609,6 +609,9 @@ details[open] summary::after { .hide-scroll { scrollbar-color: transparent transparent !important; } +.nooutline { + outline: none; +} .noselect { -khtml-user-select: none; -moz-user-select: none; @@ -2039,25 +2042,38 @@ details[open] summary::after { color: #335; } +.dark #layer-animate button { + border: 1px solid #555; + background-color: #444; +} +.dark #layer-animate button:hover { + background-color: var(--main-color); +} +.dark #layer-animate button svg { + color: #ddd; +} +.dark #layer-animate label { + border: 1px solid #555; + background-color: #444; +} +.dark #layer-animate input { + border: 1px solid #444; +} #layer-animate { + pointer-events: all; position: absolute; - z-index: 2; - left: 15px; - right: 15px; - bottom: 3px; + z-index: 200; + left: 0; + right: 0; + bottom: 0; + padding: 4px; } #layer-animate svg { color: #333; font-size: 30px; } -#layer-animate .speed { - width: 30px; -} -#layer-animate .progress { - width: 3.5em; -} #layer-animate .padleft { - margin-left: 5px !important; + margin-left: 8px !important; } #layer-animate button { width: 45px; @@ -2067,20 +2083,23 @@ details[open] summary::after { #layer-animate label { display: inline-flex; border-radius: 3px; - border: 1px solid #aaa; margin: 1px 2px 2px 1px; padding: 2px; justify-content: center; align-items: center; font-weight: bold; - background-color: #ddd; + border: 1px solid #ddd; + background-color: #eee; +} +#layer-animate input { + border-radius: 4px; } -#layer-toolpos { +/* #layer-toolpos { position: absolute; - display: none; right: 3px; bottom: 3px; + z-index: 201; } #layer-toolpos label, #layer-toolpos input { display: inline-flex; @@ -2102,7 +2121,7 @@ details[open] summary::after { font-family: monospace; padding: 1px 4px 1px 4px; margin: 1px 1px 2px 1px; -} +} */ #layer-slider { position: absolute; diff --git a/web/kiri/index.html b/web/kiri/index.html index 1acaa05a..7746c0c9 100644 --- a/web/kiri/index.html +++ b/web/kiri/index.html @@ -387,6 +387,9 @@