ui: Remove model -- a button in the stats card takes the part off the plate and brings back the start page, so the next model needs no reload; the drawn walls, removed fins, load arrow, Suggest list, section cut, scale, import note and undo go with it, the fin settings stay

This commit is contained in:
matthewtrahan authored and Matthew Trahan committed 2026-10-18 09:23:30 -05:00
1 parent 9ccef01aee
commit b2bdb0149a
11 files changed
+79 -10

No files matched your search

+2
View File
@@ -311,6 +311,8 @@ export default {
"Restore all": "استعادة الكل",
"Highlight small overhangs": "إبراز البروزات المعلّقة الصغيرة",
"Clear all": "مسح الكل",
"Remove model": "إزالة النموذج",
"Take this model off the plate, to import another without reloading the page.": "إزالة هذا النموذج من اللوحة لاستيراد نموذج آخر دون إعادة تحميل الصفحة.",
"Remove selected": "إزالة المحدد",
// Manual Draw hint
+2
View File
@@ -324,6 +324,8 @@ export default {
"Restore all": "Alle wiederherstellen",
"Highlight small overhangs": "Kleine Überhänge hervorheben",
"Clear all": "Alle löschen",
"Remove model": "Modell entfernen",
"Take this model off the plate, to import another without reloading the page.": "Dieses Modell von der Platte nehmen, um ein anderes ohne Neuladen der Seite zu importieren.",
"Remove selected": "Ausgewählte entfernen",
// Manual Draw hint
+2
View File
@@ -312,6 +312,8 @@ export default {
"Restore all": "Alles herstellen",
"Highlight small overhangs": "Kleine overhangen markeren",
"Clear all": "Alles wissen",
"Remove model": "Model verwijderen",
"Take this model off the plate, to import another without reloading the page.": "Haal dit model van de plaat om een ander te importeren zonder de pagina te herladen.",
"Remove selected": "Selectie verwijderen",
// Manual Draw hint
+2
View File
@@ -296,6 +296,8 @@ export default {
"Restore all": "Restaurar todas",
"Highlight small overhangs": "Destacar balanços pequenos",
"Clear all": "Limpar tudo",
"Remove model": "Remover modelo",
"Take this model off the plate, to import another without reloading the page.": "Tirar este modelo da mesa, para importar outro sem recarregar a página.",
"Remove selected": "Remover selecionado",
"Click two points across an overhang — straight onto the red faces — to lay a breakaway wall along that line. Click an upright side once to stand a sway brace against it. Esc or right-click cancels.": "Clique em dois pontos atravessando um balanço — direto nas faces vermelhas — para criar uma parede destacável ao longo dessa linha. Clique uma vez num lado vertical para apoiar uma escora lateral nele. Esc ou botão direito cancela.",
"off": "desligado",
+2
View File
@@ -327,6 +327,8 @@ export default {
"Restore all": "全部恢复",
"Highlight small overhangs": "高亮细小悬垂",
"Clear all": "全部清除",
"Remove model": "移除模型",
"Take this model off the plate, to import another without reloading the page.": "将此模型从打印板上移除,无需重新加载页面即可导入另一个模型。",
"Remove selected": "移除所选",
// Manual Draw hint
+2
View File
@@ -204,6 +204,8 @@
<dt><i class="sw sw-pad"></i><span data-i18n="Bed pad">Bed&nbsp;pad</span></dt> <dd id="s-pad">—</dd>
<dt data-i18n="Analysis">Analysis</dt> <dd id="s-time">—</dd>
</dl>
<button type="button" class="btn sm" id="remove-part" data-i18n-title
title="Take this model off the plate, to import another without reloading the page."><span data-i18n="Remove model">Remove model</span></button>
</aside>
</div><!-- /left-rail -->
+1
View File
@@ -347,6 +347,7 @@ html, body {
fin/pad time is appended, and that one-line growth used to nudge everything below
the panel down when fins were added. Always two lines high = no shift. */
#stats #s-time { display: block; min-height: 2.6em; line-height: 1.3; }
#stats #remove-part { margin-top: 10px; }
#stats hr {
border: 0;
border-top: 1px solid var(--line);
+8
View File
@@ -63,6 +63,14 @@ export function renderImportNote() {
/** The part was rescaled (ui/scale.js): the supports a saved session brought back
* are gone with it, so the note no longer says they were restored. */
/** The part was taken off the plate (part.js clearPart): its import note goes too. */
export function forgetImport() {
importNote = '';
lastImportMeta = null;
pendingSession = null;
el('s-import-note').textContent = '';
}
export function forgetSessionNote() {
if (!lastImportMeta?.session) return;
lastImportMeta.session = null;
+50 -8
View File
@@ -7,14 +7,14 @@ import { t, tn } from './i18n.js';
import * as THREE from 'three';
import { buildTopology, analyze, DEFAULT_THRESHOLD, MIN_REGION_AREA } from '../overhangs.js';
import { el } from './dom.js';
import { scene, controls, frame, clip, MODEL } from './scene.js';
import { scene, controls, frame, clip, MODEL, requestRender } from './scene.js';
import { setSection, followPart } from './section.js';
import { showToolbar } from './toolbar.js';
import { removeMode, cancelRemove, resetRemovals } from './remove.js';
import { resetHistory } from './history.js';
import { importNote, renderImportNote } from './io.js';
import { importNote, renderImportNote, forgetImport } from './io.js';
import { currentVolume } from './volume.js';
import { resetLoad, updateLayerView, updateLoadReadout, syncLoadUI } from './strength.js';
import { resetLoad, updateLayerView, hideLayerView, updateLoadReadout, syncLoadUI } from './strength.js';
import { hideSuggestions } from './suggest.js';
import {
setDrawnWalls, setDrawMsg, markPrintTrisDirty, clearPreview, syncDrawControls,
@@ -109,7 +109,21 @@ export function setPart(geometry, filename, { quat } = {}) {
gizmo.attach(part);
showToolbar(true);
// A new part starts with no hand-drawn walls and a fresh print-space cache.
resetPartState();
const size = shade();
frame(size);
resetScale();
return size;
}
/**
* What a part's tools hold that means nothing on another part (or on none): the
* drawn walls, removed fins, armed modes, load arrow, Suggest list, section cut and
* undo history. Shared by setPart and clearPart.
*/
function resetPartState() {
// A new part (or none) starts with no hand-drawn walls and a fresh print-space cache.
setDrawnWalls([]);
// Per-fin removals are keyed by a content signature that can coincidentally
// match a different model's fins, so they must NOT carry across parts -- clear
@@ -124,7 +138,7 @@ export function setPart(geometry, filename, { quat } = {}) {
clearPreview();
syncAugmentUI(); // "+ Add" is off now: the button and the Draw hint say so
syncDrawControls();
// A new part starts with no load direction either, and no Suggest ranking: the
// A new part (or none) starts with no load direction either, and no Suggest ranking: the
// list and verdict were the OLD part's poses.
resetLoad();
hideSuggestions();
@@ -136,11 +150,37 @@ export function setPart(geometry, filename, { quat } = {}) {
// Undo history does not carry across parts.
resetHistory();
}
const size = shade();
frame(size);
/**
* Take the part off the plate (the stats card's Remove model): back to the empty
* page a fresh tab shows, so the next model needs no reload. The fin settings stay,
* as they do across a load.
*/
export function clearPart() {
if (!part) return;
gizmo.detach();
part.remove(hoverFace);
hoverFace.visible = false;
scene.remove(part);
part.geometry.dispose();
part = null;
topology = null;
lastResult = lastShadeRes = null;
flatRegions = null;
painted = paintedAttr = null;
lastSize = null;
partName = '';
resetPartState();
refreshFins(); // no lastResult now: drops the fins, pad and readout
resetScale();
return size;
forgetImport();
hideLayerView();
showToolbar(false);
el('stats').hidden = true;
el('status').hidden = true;
el('drop').classList.remove('hidden');
requestRender();
}
/**
@@ -431,4 +471,6 @@ export function syncPartLanguage() {
renderIslandText();
}
el('remove-part').addEventListener('click', clearPart);
window.addEventListener('languagechange', syncPartLanguage);
+5
View File
@@ -108,6 +108,11 @@ export function updateLayerView(size) {
layerViz.visible = layersOn && !!part;
}
/** No part on the plate: no layer frames either. */
export function hideLayerView() {
layerViz.visible = false;
}
// ---------------------------------------------------------------- load arrow UI
/**
+3 -2
View File
@@ -18,8 +18,8 @@
* 3D view leaves it open (Lay a face flat and Section are used there); Esc folds it
* and hands focus back to its badge. `onFold` runs when a popover folds, for a mode
* armed from inside it that must not stay armed out of sight (Lay a face flat).
* The bar shows once a part is loaded (showToolbar, from part.js); nothing unloads
* a part, so it is never hidden again.
* The bar shows while a part is loaded (showToolbar, from part.js) and hides again
* when Remove model takes it off, folding any open popover.
*
* It sits bottom-left, at the window's edge -- or just right of the stats card when
* a short window has scrolled the card down beside it.
@@ -112,5 +112,6 @@ addEventListener('keydown', (e) => {
/** Show the bar (a part is loaded) or hide it. */
export function showToolbar(v) {
el('viewbar').hidden = !v;
if (!v && openId) { openId = null; render(); }
place();
}