refactor animation control bar, re-add axis positions

This commit is contained in:
Stewart Allen 2025-02-27 11:11:31 -05:00
commit 5f69f353bf
7 changed files with 233 additions and 120 deletions

View file

@ -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:'<i class="fas fa-fast-backward"></i>',title:"restart"}),
playButton = UC.newButton(null,play,{icon:'<i class="fas fa-play"></i>',title:"play"}),
pauseButton = UC.newButton(null,pause,{icon:'<i class="fas fa-pause"></i>',title:"pause"}),
UC.newButton(null,step,{icon:'<i class="fas fa-step-forward"></i>',title:"single step"}),
UC.newButton(null,fast,{icon:'<i class="fas fa-forward"></i>',title:"toggle speed"}),
speedLabel = UC.newLabel("speed", {class:"speed padleft"}),
progress = UC.newLabel('0%', {class:"progress"}),
transButton = UC.newButton(null,toggleTrans,{icon:'<i class="fa-solid fa-border-none"></i>',title:"transparency",class:"padleft"}),
modelButton = UC.newButton(null,toggleModel,{icon:'<i class="fa-solid fa-eye"></i>',title:"show model"}),
shadeButton = UC.newButton(null,toggleStock,{icon:'<i class="fa-solid fa-cube"></i>',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;

View file

@ -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:'<i class="fas fa-fast-backward"></i>',title:"restart"}),
playButton = UC.newButton(null,play,{icon:'<i class="fas fa-play"></i>',title:"play"}),
pauseButton = UC.newButton(null,pause,{icon:'<i class="fas fa-pause"></i>',title:"pause"}),
UC.newButton(null,step,{icon:'<i class="fas fa-step-forward"></i>',title:"single step"}),
UC.newButton(null,fast,{icon:'<i class="fas fa-forward"></i>',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() {

View file

@ -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) => {

View file

@ -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:'<i class="fas fa-fast-backward"></i>',title:"restart"}),
anim.play = newButton(null,"anim.play",{icon:'<i class="fas fa-play"></i>',title:"play"}),
anim.pause = newButton(null,"anim.pause",{icon:'<i class="fas fa-pause"></i>',title:"pause"}),
anim.step = newButton(null,"anim.step",{icon:'<i class="fas fa-step-forward"></i>',title:"single step"}),
anim.speed = newButton(null,"anim.fast",{icon:'<i class="fas fa-forward"></i>',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:'<i class="fa-solid fa-border-none"></i>',title:"transparency",class:"padleft"}),
anim.model = newButton(null,"anim.model",{icon:'<i class="fa-solid fa-eye"></i>',title:"show model"}),
anim.shade = newButton(null,"anim.stock",{icon:'<i class="fa-solid fa-cube"></i>',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}),

View file

@ -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) {

View file

@ -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;

View file

@ -387,6 +387,9 @@
<div id="top-slider" class="f-col grow">
<input id="anim-slider" type="range" min="0" max="1000" value="0"></input>
</div>
<!-- CAM animation controls and readout -->
<div id="layer-animate" class="f-col a-center set2-group hide"></div>
<!-- <div id="layer-toolpos" class="f-row a-center hide"></div> -->
</div>
<!-- allows right tray to slide/hide but still show speeds menu -->
@ -733,10 +736,6 @@
<div id="rnfo"></div>
</div>
<!-- CAM animation controls and readout -->
<div id="layer-animate" class="f-col a-center"></div>
<div id="layer-toolpos" class="f-row a-center"></div>
<!-- ephemeral non-modal alerts -->
<div id="alert-area">
<div id="alert-border">