@things-factory/figure-ui 10.1.125 → 10.1.127
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/modeller/align.ts +6 -4
- package/client/modeller/canvas.ts +6 -1
- package/client/modeller/editor.ts +149 -34
- package/client/modeller/evaluated.ts +47 -0
- package/client/modeller/figure-facts.ts +8 -0
- package/client/modeller/figure-preview.ts +38 -16
- package/client/modeller/figure-properties.ts +32 -0
- package/client/modeller/figure-verdict.ts +10 -1
- package/client/modeller/joint-fan.ts +4 -7
- package/client/modeller/links.ts +2 -1
- package/dist-client/modeller/align.d.ts +2 -1
- package/dist-client/modeller/align.js +6 -4
- package/dist-client/modeller/align.js.map +1 -1
- package/dist-client/modeller/canvas.js +8 -1
- package/dist-client/modeller/canvas.js.map +1 -1
- package/dist-client/modeller/editor.d.ts +35 -1
- package/dist-client/modeller/editor.js +138 -37
- package/dist-client/modeller/editor.js.map +1 -1
- package/dist-client/modeller/evaluated.d.ts +12 -0
- package/dist-client/modeller/evaluated.js +42 -0
- package/dist-client/modeller/evaluated.js.map +1 -0
- package/dist-client/modeller/figure-facts.d.ts +0 -7
- package/dist-client/modeller/figure-facts.js +9 -0
- package/dist-client/modeller/figure-facts.js.map +1 -1
- package/dist-client/modeller/figure-preview.js +38 -16
- package/dist-client/modeller/figure-preview.js.map +1 -1
- package/dist-client/modeller/figure-properties.d.ts +8 -2
- package/dist-client/modeller/figure-properties.js +26 -0
- package/dist-client/modeller/figure-properties.js.map +1 -1
- package/dist-client/modeller/figure-verdict.d.ts +2 -0
- package/dist-client/modeller/figure-verdict.js +10 -2
- package/dist-client/modeller/figure-verdict.js.map +1 -1
- package/dist-client/modeller/joint-fan.js +4 -7
- package/dist-client/modeller/joint-fan.js.map +1 -1
- package/dist-client/modeller/links.js +3 -2
- package/dist-client/modeller/links.js.map +1 -1
- package/dist-client/modeller/product-session.d.ts +68 -112
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/test/evaluated.test.ts +40 -0
- package/test/gizmo.test.ts +1 -1
- package/test/mode-switch.test.ts +41 -0
|
@@ -7,7 +7,7 @@ import { notify } from '@operato/layout';
|
|
|
7
7
|
import { OxPrompt } from '@operato/popup';
|
|
8
8
|
import { customElement, property, state } from 'lit/decorators.js';
|
|
9
9
|
import { live } from 'lit/directives/live.js';
|
|
10
|
-
import { PART_LIMIT, parseFigureRecipe, resolveFigureRecipe, figurePartCountOf, figureRecipeIdFor, parseFigureAsset, figureSizeEditChanges, figureScaleAnchorOf, figureSectionMeasuresOf, figurePlaneAlignChanges, figurePartFaceOf, figureRowOf, figureFaceOverhangOf, figureRoomOnlyInputsOf, figureRoomRefitOf } from '@hatiolab/figure-model';
|
|
10
|
+
import { PART_LIMIT, parseFigureRecipe, resolveFigureRecipe, figurePartCountOf, figureRecipeIdFor, parseFigureAsset, figureSizeEditChanges, figureScaleAnchorOf, figureSectionMeasuresOf, figurePlaneAlignChanges, figurePartFaceOf, figureRowOf, figureFaceOverhangOf, figureRoomOnlyInputsOf, figureRoomRefitOf, seedFigureEvaluation, upgradeFigurePlacement } from '@hatiolab/figure-model';
|
|
11
11
|
import './figure-recipe-catalog.js';
|
|
12
12
|
import { captureFigureThumbnail } from './thumbnail.js';
|
|
13
13
|
import { drawableFigureParts } from './renderer.js';
|
|
@@ -39,6 +39,7 @@ import { roomRefitRowsOf } from './occupancy.js';
|
|
|
39
39
|
import { editRefusalOf, inDeclaredRoom, inputRangeRefusalOf, narrowingRetryOf, partRefusalOf, placementRefusalOf, recipeRefusalOf, removalNoticeOf, sizeRangeRefusalOf } from './refusals.js';
|
|
40
40
|
import { endPlaceKeyOf, fieldWordsOf, followOf, measureNow, partSummaryOf, instanceRangeOf, instanceRangeToDeclare, proportionToFollow, rangeDiffers, rangeWith, turnsAboutAJoint, valueNow } from './links.js';
|
|
41
41
|
import { jointFanOf } from './joint-fan.js';
|
|
42
|
+
import { seedEvaluatedGeometry } from './evaluated.js';
|
|
42
43
|
import { jointDragOf } from './joint-drag.js';
|
|
43
44
|
import { liveOverSession, NOTHING_LIVE, scrubbed, scrubStep } from './live.js';
|
|
44
45
|
import { startingShapeKindOfBody } from './starting-shape.js';
|
|
@@ -55,6 +56,18 @@ function foldSaid() {
|
|
|
55
56
|
return false;
|
|
56
57
|
}
|
|
57
58
|
/** Product editor surface. The injected session is shared by page persistence and AI commands. */
|
|
59
|
+
/** The words a panel is given when there are none: one array, so it does not read as a change. */
|
|
60
|
+
const NO_WORDS = [];
|
|
61
|
+
/** How long a command's candidate rests before its preview is worked out. */
|
|
62
|
+
const PREVIEW_SETTLE_MS = 150;
|
|
63
|
+
function deepFreeze(value) {
|
|
64
|
+
if (value && typeof value === 'object' && !Object.isFrozen(value)) {
|
|
65
|
+
Object.freeze(value);
|
|
66
|
+
for (const inner of Object.values(value))
|
|
67
|
+
deepFreeze(inner);
|
|
68
|
+
}
|
|
69
|
+
return value;
|
|
70
|
+
}
|
|
58
71
|
let FigureEditor = class FigureEditor extends LitElement {
|
|
59
72
|
constructor() {
|
|
60
73
|
super(...arguments);
|
|
@@ -219,6 +232,10 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
219
232
|
min-width: 0;
|
|
220
233
|
min-height: 0;
|
|
221
234
|
}
|
|
235
|
+
/* The edit canvas stays standing while the preview is in front (a 3D scene costs a third of a second to make), out of sight. */
|
|
236
|
+
div[middle][hidden] {
|
|
237
|
+
display: none;
|
|
238
|
+
}
|
|
222
239
|
ox-canvas-bar .status {
|
|
223
240
|
padding: 0 8px;
|
|
224
241
|
color: var(--md-sys-color-on-surface-variant);
|
|
@@ -497,6 +514,8 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
497
514
|
disconnectedCallback() {
|
|
498
515
|
window.removeEventListener('keydown', this.onKey, true);
|
|
499
516
|
this.widthWatch.disconnect();
|
|
517
|
+
clearTimeout(this.previewTimer);
|
|
518
|
+
clearTimeout(this.detachTimer);
|
|
500
519
|
super.disconnectedCallback();
|
|
501
520
|
}
|
|
502
521
|
/*
|
|
@@ -837,7 +856,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
837
856
|
*/
|
|
838
857
|
insertRecipe(recipe, values) {
|
|
839
858
|
try {
|
|
840
|
-
const asset =
|
|
859
|
+
const asset = this.plainAsset();
|
|
841
860
|
const checked = parseFigureRecipe(recipe);
|
|
842
861
|
const id = figureRecipeIdFor(asset, checked);
|
|
843
862
|
const steps = resolveFigureRecipe(checked, { id, ...(checked.target === 'part' ? { target: this.selected } : {}), values });
|
|
@@ -854,7 +873,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
854
873
|
/** The design values of the asset being edited. */
|
|
855
874
|
designValues() {
|
|
856
875
|
try {
|
|
857
|
-
return this.session ? (
|
|
876
|
+
return this.session ? (this.plainAsset().designInputs ?? {}) : {};
|
|
858
877
|
}
|
|
859
878
|
catch {
|
|
860
879
|
return {};
|
|
@@ -867,7 +886,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
867
886
|
if (!id || !this.session || !this.session.read().geometry.some(g => g.id === id))
|
|
868
887
|
return none;
|
|
869
888
|
try {
|
|
870
|
-
const asset =
|
|
889
|
+
const asset = this.plainAsset();
|
|
871
890
|
const reach = gizmoReachOf(asset, id);
|
|
872
891
|
/*
|
|
873
892
|
A size drag shows the face it keeps and the commit keeps the same (figureScaleAnchorOf). Where figure-model cannot
|
|
@@ -895,7 +914,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
895
914
|
transformed(id, result) {
|
|
896
915
|
const view = this.session.read();
|
|
897
916
|
/* A part hanging from a joint: the drag edits the joint -- its value, or where it sits (ADR-0093). */
|
|
898
|
-
const asset =
|
|
917
|
+
const asset = this.plainAsset();
|
|
899
918
|
const drawn = view.geometry.find(g => g.id === id);
|
|
900
919
|
const drag = drawn ? jointDragOf(asset, ownerOf(id), drawn, result, this.currentInputs()) : null;
|
|
901
920
|
if (drag) {
|
|
@@ -978,7 +997,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
978
997
|
/** 맞추기 — one tool, one step of the history, through the same inputs as the gizmo. */
|
|
979
998
|
align(tool) {
|
|
980
999
|
this.run(() => {
|
|
981
|
-
const asset =
|
|
1000
|
+
const asset = this.plainAsset();
|
|
982
1001
|
const changes = alignChanges(asset, this.selected, this.reachOf(this.selected), tool);
|
|
983
1002
|
if (changes.length)
|
|
984
1003
|
this.session.apply(changes);
|
|
@@ -993,7 +1012,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
993
1012
|
const copy = this.session.read().geometry.find(g => !before.has(g.id))?.id;
|
|
994
1013
|
if (!copy)
|
|
995
1014
|
return;
|
|
996
|
-
this.session.apply(mirrorChanges(
|
|
1015
|
+
this.session.apply(mirrorChanges(this.plainAsset(), id, copy, axis));
|
|
997
1016
|
this.selected = copy;
|
|
998
1017
|
});
|
|
999
1018
|
}
|
|
@@ -1030,7 +1049,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1030
1049
|
@click=${() => this.alignToPlane()}>${i18next.t(`figure.button.align-to-${placement}`)}</button>`;
|
|
1031
1050
|
}
|
|
1032
1051
|
alignToPlane() {
|
|
1033
|
-
const asset =
|
|
1052
|
+
const asset = this.parsedAsset();
|
|
1034
1053
|
const { changes, contact, refusal } = figurePlaneAlignChanges(asset, this.selected);
|
|
1035
1054
|
if (refusal) {
|
|
1036
1055
|
this.error = i18next.t(`figure.text.align-refused-${refusal.toLowerCase().replace(/_/g, '-')}`, { part: partLabelOf(this.selected) });
|
|
@@ -1047,7 +1066,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1047
1066
|
return null;
|
|
1048
1067
|
let asset;
|
|
1049
1068
|
try {
|
|
1050
|
-
asset =
|
|
1069
|
+
asset = this.plainAsset();
|
|
1051
1070
|
}
|
|
1052
1071
|
catch {
|
|
1053
1072
|
return null;
|
|
@@ -1113,22 +1132,39 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1113
1132
|
: String(error);
|
|
1114
1133
|
}
|
|
1115
1134
|
}
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1135
|
+
dimsOf(asset) {
|
|
1136
|
+
const view = this.session?.read();
|
|
1137
|
+
const key = `${view?.context}|${view?.revision}|${this.selected}`;
|
|
1138
|
+
if (this.dimsSaid?.key === key)
|
|
1139
|
+
return this.dimsSaid.dims;
|
|
1140
|
+
let dims;
|
|
1119
1141
|
try {
|
|
1120
|
-
|
|
1142
|
+
dims = boxOf(asset, this.selected, this.currentInputs())?.dims;
|
|
1121
1143
|
}
|
|
1122
1144
|
catch {
|
|
1123
|
-
|
|
1145
|
+
dims = undefined;
|
|
1124
1146
|
}
|
|
1125
|
-
|
|
1147
|
+
this.dimsSaid = { key, dims };
|
|
1148
|
+
return dims;
|
|
1149
|
+
}
|
|
1150
|
+
previewWordsNow() {
|
|
1151
|
+
const preview = this.currentPreview();
|
|
1152
|
+
const language = i18next.language;
|
|
1153
|
+
if (this.previewWordsSaid && this.previewWordsSaid.preview === preview && this.previewWordsSaid.part === this.selected && this.previewWordsSaid.language === language)
|
|
1154
|
+
return this.previewWordsSaid.words;
|
|
1155
|
+
const words = previewWordsOf(preview, this.selected, (key, params) => i18next.t(key, params));
|
|
1156
|
+
this.previewWordsSaid = { preview, part: this.selected, language, words };
|
|
1157
|
+
return words;
|
|
1158
|
+
}
|
|
1159
|
+
renderLinks(unavailable, section) {
|
|
1160
|
+
let asset;
|
|
1126
1161
|
try {
|
|
1127
|
-
|
|
1162
|
+
asset = this.plainAsset();
|
|
1128
1163
|
}
|
|
1129
1164
|
catch {
|
|
1130
|
-
|
|
1165
|
+
return null;
|
|
1131
1166
|
}
|
|
1167
|
+
const dims = this.dimsOf(asset);
|
|
1132
1168
|
return html `<figure-links
|
|
1133
1169
|
.asset=${asset}
|
|
1134
1170
|
.section=${section}
|
|
@@ -1136,10 +1172,10 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1136
1172
|
.dims=${dims}
|
|
1137
1173
|
?locked=${unavailable}
|
|
1138
1174
|
@command=${(e) => this.linkCommand(e.detail.action)}
|
|
1139
|
-
.previewWords=${
|
|
1175
|
+
.previewWords=${this.previewWordsNow()}
|
|
1140
1176
|
.detachWords=${this.detachWords(asset)}
|
|
1141
|
-
.overhangWords=${section === 'shape' ? this.overhangWords(asset) :
|
|
1142
|
-
.overhangNote=${section === 'shape' ? this.overhangNote(asset) :
|
|
1177
|
+
.overhangWords=${section === 'shape' ? this.overhangWords(asset) : NO_WORDS}
|
|
1178
|
+
.overhangNote=${section === 'shape' ? this.overhangNote(asset) : NO_WORDS}
|
|
1143
1179
|
.motionEnds=${section === 'motion' ? this.motionEnds() : null}
|
|
1144
1180
|
@go-fasten=${() => this.goFasten()}
|
|
1145
1181
|
@preview-command=${(e) => this.previewCommand(e.detail)}
|
|
@@ -1170,7 +1206,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1170
1206
|
renderControls(view, unavailable) {
|
|
1171
1207
|
let asset;
|
|
1172
1208
|
try {
|
|
1173
|
-
asset =
|
|
1209
|
+
asset = this.plainAsset();
|
|
1174
1210
|
}
|
|
1175
1211
|
catch {
|
|
1176
1212
|
return null;
|
|
@@ -1259,7 +1295,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1259
1295
|
/* A size typed in keeps the face the figure's placement keeps -- figure-model's one rule, as the gizmo and "follow the size" do. */
|
|
1260
1296
|
const part = this.selected;
|
|
1261
1297
|
const change = { kind: field.role === 'state' ? 'set-state' : 'set-design', input: field.id, unit: field.unit, value };
|
|
1262
|
-
this.run(() => this.session.apply(field.role !== 'state' && part ? figureSizeEditChanges(
|
|
1298
|
+
this.run(() => this.session.apply(field.role !== 'state' && part ? figureSizeEditChanges(this.parsedAsset(), part, [change]) : [change]));
|
|
1263
1299
|
// Rejected edits must also restore the displayed numeric value.
|
|
1264
1300
|
input.value = String(this.session.read().fields.find(i => i.id === field.id).value);
|
|
1265
1301
|
}
|
|
@@ -1597,7 +1633,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1597
1633
|
if (!Number.isFinite(pitch) || pitch === field.value)
|
|
1598
1634
|
return;
|
|
1599
1635
|
/* Read from a design input the board may set: the input's value changes, the row keeps reading it (ADR-0096). */
|
|
1600
|
-
const from = this.pitchInputOf(
|
|
1636
|
+
const from = this.pitchInputOf(this.plainAsset(), this.selected);
|
|
1601
1637
|
if (from) {
|
|
1602
1638
|
this.run(() => this.session.apply([{ kind: 'set-design', input: from, unit: 'mm', value: pitch }]));
|
|
1603
1639
|
input.value = String(this.session.read().fields.find(i => i.id === from)?.value ?? field.value);
|
|
@@ -1633,20 +1669,29 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1633
1669
|
return i18next.t('figure.text.release-state-released', { version: String(version) });
|
|
1634
1670
|
return version > 0 ? i18next.t('figure.text.release-state-draft-over', { version: String(version) }) : i18next.t('figure.text.release-state-draft-new');
|
|
1635
1671
|
}
|
|
1636
|
-
/** The fastening form's command, seen before it is done; null clears what was shown. */
|
|
1637
1672
|
previewCommand(candidate) {
|
|
1673
|
+
clearTimeout(this.previewTimer);
|
|
1638
1674
|
if (!candidate || !this.session || !this.selected) {
|
|
1639
1675
|
this.preview = undefined;
|
|
1640
1676
|
return;
|
|
1641
1677
|
}
|
|
1642
1678
|
const view = this.session.read();
|
|
1679
|
+
const same = this.preview && this.preview.key === JSON.stringify(candidate) && this.preview.context === view.context && this.preview.part === this.selected && 'revision' in this.preview && this.preview.revision === view.revision;
|
|
1680
|
+
if (same)
|
|
1681
|
+
return;
|
|
1682
|
+
this.previewTimer = setTimeout(() => this.computePreview(candidate), PREVIEW_SETTLE_MS);
|
|
1683
|
+
}
|
|
1684
|
+
computePreview(candidate) {
|
|
1685
|
+
if (!this.session || !this.selected)
|
|
1686
|
+
return;
|
|
1687
|
+
const view = this.session.read();
|
|
1643
1688
|
const held = { context: view.context, revision: view.revision, key: JSON.stringify(candidate), part: this.selected };
|
|
1644
1689
|
try {
|
|
1645
1690
|
const seen = this.session.previewCommand(candidate.action);
|
|
1646
1691
|
let face;
|
|
1647
1692
|
if (candidate.face) {
|
|
1648
1693
|
try {
|
|
1649
|
-
face = figurePartFaceOf(
|
|
1694
|
+
face = figurePartFaceOf(this.parsedAsset(), candidate.face.part, candidate.face.face, this.currentInputs());
|
|
1650
1695
|
}
|
|
1651
1696
|
catch {
|
|
1652
1697
|
face = undefined;
|
|
@@ -1681,14 +1726,32 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1681
1726
|
return undefined;
|
|
1682
1727
|
return p;
|
|
1683
1728
|
}
|
|
1729
|
+
/**
|
|
1730
|
+
* Said once the figure has rested: working it out is a preview of the command on a copy (tens of milliseconds), and the
|
|
1731
|
+
* edit that made this version should be on screen before it. Until then nothing is said, as for a part with no joint.
|
|
1732
|
+
*/
|
|
1684
1733
|
detachWords(asset) {
|
|
1685
1734
|
const view = this.session?.read();
|
|
1686
1735
|
const joint = asset?.joints?.find(j => j.body1.part === this.selected);
|
|
1687
1736
|
if (!asset || !view || !joint || !this.session)
|
|
1688
|
-
return
|
|
1737
|
+
return NO_WORDS;
|
|
1689
1738
|
const key = `${view.context}|${view.revision}|${this.selected}`;
|
|
1690
1739
|
if (this.detachSaid?.key === key)
|
|
1691
1740
|
return this.detachSaid.words;
|
|
1741
|
+
if (this.detachAsked !== key) {
|
|
1742
|
+
this.detachAsked = key;
|
|
1743
|
+
clearTimeout(this.detachTimer);
|
|
1744
|
+
this.detachTimer = setTimeout(() => {
|
|
1745
|
+
const now = this.session?.read();
|
|
1746
|
+
if (!now || `${now.context}|${now.revision}|${this.selected}` !== key)
|
|
1747
|
+
return;
|
|
1748
|
+
this.computeDetachWords(asset, key);
|
|
1749
|
+
this.requestUpdate();
|
|
1750
|
+
}, PREVIEW_SETTLE_MS);
|
|
1751
|
+
}
|
|
1752
|
+
return NO_WORDS;
|
|
1753
|
+
}
|
|
1754
|
+
computeDetachWords(asset, key) {
|
|
1692
1755
|
const say = (k, params) => i18next.t(k, params);
|
|
1693
1756
|
let words;
|
|
1694
1757
|
try {
|
|
@@ -1717,7 +1780,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1717
1780
|
overhangWords(asset) {
|
|
1718
1781
|
const view = this.session?.read();
|
|
1719
1782
|
if (!asset || !view || !this.selected)
|
|
1720
|
-
return
|
|
1783
|
+
return NO_WORDS;
|
|
1721
1784
|
const key = `${view.context}|${view.revision}|${this.selected}`;
|
|
1722
1785
|
if (this.overhangSaid?.key === key)
|
|
1723
1786
|
return this.overhangSaid.words;
|
|
@@ -1759,7 +1822,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1759
1822
|
if (this.motionEndsSaid?.key !== key) {
|
|
1760
1823
|
let ends = null;
|
|
1761
1824
|
try {
|
|
1762
|
-
ends = motionEndsOf(
|
|
1825
|
+
ends = motionEndsOf(this.parsedAsset(), this.selected, this.currentInputs());
|
|
1763
1826
|
}
|
|
1764
1827
|
catch {
|
|
1765
1828
|
ends = null;
|
|
@@ -1803,9 +1866,46 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1803
1866
|
if (id && (this.tab === 'verdict' || this.tab === 'view' || this.tab === 'history'))
|
|
1804
1867
|
this.tab = 'properties';
|
|
1805
1868
|
}
|
|
1869
|
+
/**
|
|
1870
|
+
* The figure as the session holds it now, parsed once per text: a render asks for it a dozen times, and parsing the whole
|
|
1871
|
+
* figure is most of what a selection costs. Read, never changed -- what changes a figure goes through the session.
|
|
1872
|
+
*/
|
|
1873
|
+
/**
|
|
1874
|
+
* The session has evaluated this figure at this version, with these inputs: the screen's questions of the text it just
|
|
1875
|
+
* parsed are answered from that, not by evaluating the figure again (each is tens of milliseconds on a real figure).
|
|
1876
|
+
*/
|
|
1877
|
+
seeded(asset) {
|
|
1878
|
+
const view = this.session?.read();
|
|
1879
|
+
if (view?.geometry.length) {
|
|
1880
|
+
const values = this.currentInputs();
|
|
1881
|
+
seedEvaluatedGeometry(asset, values, view.geometry);
|
|
1882
|
+
seedFigureEvaluation(asset, values, view.geometry);
|
|
1883
|
+
}
|
|
1884
|
+
return asset;
|
|
1885
|
+
}
|
|
1886
|
+
parsedAsset() {
|
|
1887
|
+
const text = this.session.source();
|
|
1888
|
+
if (this.parsed?.text !== text) {
|
|
1889
|
+
/* The session's text is what its workspace exported, compiled then: it is read here, not compiled again. */
|
|
1890
|
+
const plain = this.plainAsset();
|
|
1891
|
+
const upgraded = upgradeFigurePlacement(plain);
|
|
1892
|
+
this.parsed = { text, asset: upgraded === plain ? plain : this.seeded(deepFreeze(upgraded)) };
|
|
1893
|
+
}
|
|
1894
|
+
return this.parsed.asset;
|
|
1895
|
+
}
|
|
1896
|
+
/**
|
|
1897
|
+
* The figure as plain data, parsed once per text and frozen: the render, the gizmo's reach and every tool read it, and
|
|
1898
|
+
* a copy for each of them cost more than the selection they serve. A change goes through the session, never through this.
|
|
1899
|
+
*/
|
|
1900
|
+
plainAsset() {
|
|
1901
|
+
const text = this.session.source();
|
|
1902
|
+
if (this.plain?.text !== text)
|
|
1903
|
+
this.plain = { text, asset: this.seeded(deepFreeze(JSON.parse(text))) };
|
|
1904
|
+
return this.plain.asset;
|
|
1905
|
+
}
|
|
1806
1906
|
asset() {
|
|
1807
1907
|
try {
|
|
1808
|
-
return
|
|
1908
|
+
return this.plainAsset();
|
|
1809
1909
|
}
|
|
1810
1910
|
catch {
|
|
1811
1911
|
return undefined;
|
|
@@ -1939,7 +2039,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1939
2039
|
let summary;
|
|
1940
2040
|
try {
|
|
1941
2041
|
summary = this.selected
|
|
1942
|
-
? partSummaryOf(
|
|
2042
|
+
? partSummaryOf(this.parsedAsset(), ownerOf(this.selected), (key, params) => i18next.t(key, params), i18next.language || 'ko')
|
|
1943
2043
|
: undefined;
|
|
1944
2044
|
}
|
|
1945
2045
|
catch {
|
|
@@ -1979,7 +2079,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1979
2079
|
*/
|
|
1980
2080
|
let roomOnly = [];
|
|
1981
2081
|
try {
|
|
1982
|
-
roomOnly = this.selected ? figureRoomOnlyInputsOf(
|
|
2082
|
+
roomOnly = this.selected ? figureRoomOnlyInputsOf(this.parsedAsset(), this.selected) : [];
|
|
1983
2083
|
}
|
|
1984
2084
|
catch {
|
|
1985
2085
|
roomOnly = [];
|
|
@@ -1990,7 +2090,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1990
2090
|
try {
|
|
1991
2091
|
const body = view.geometry.find(g => g.id === this.selected);
|
|
1992
2092
|
const placed = body ? placementOf(body) : undefined;
|
|
1993
|
-
const parsed = this.selected ?
|
|
2093
|
+
const parsed = this.selected ? this.parsedAsset() : undefined;
|
|
1994
2094
|
if (placed && parsed)
|
|
1995
2095
|
held = {
|
|
1996
2096
|
position: placed.position,
|
|
@@ -2084,7 +2184,8 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
2084
2184
|
}}
|
|
2085
2185
|
@part-edit=${(e) => this.run(() => this.session.edit(e.detail.edit))}
|
|
2086
2186
|
></figure-preview>`
|
|
2087
|
-
:
|
|
2187
|
+
: nothing}
|
|
2188
|
+
<div middle ?hidden=${this.middle === 'preview'}>
|
|
2088
2189
|
${view.geometry.length === 0 && !unavailable ? this.renderStart() : nothing}
|
|
2089
2190
|
${this.sectionEditing && this.sectionEditing === this.selected && !unavailable ? this.renderSectionEditor(view.geometry) : nothing}
|
|
2090
2191
|
<figure-canvas
|
|
@@ -2101,9 +2202,9 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
2101
2202
|
@part-transformed=${(e) => this.transformed(e.detail.id, e.detail.result)}
|
|
2102
2203
|
@part-selected=${(e) => this.choose(e.detail)}
|
|
2103
2204
|
@render-error=${(e) => {
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
></figure-canvas></div
|
|
2205
|
+
this.error = e.detail.message;
|
|
2206
|
+
}}
|
|
2207
|
+
></figure-canvas></div>
|
|
2107
2208
|
<aside slot="end">
|
|
2108
2209
|
<div tabs>
|
|
2109
2210
|
${this.renderTab('properties', 'tune', i18next.t('figure.label.properties'))}
|
|
@@ -2285,7 +2386,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
2285
2386
|
async askRoomRefit() {
|
|
2286
2387
|
let refit;
|
|
2287
2388
|
try {
|
|
2288
|
-
refit = figureRoomRefitOf(
|
|
2389
|
+
refit = figureRoomRefitOf(this.parsedAsset());
|
|
2289
2390
|
}
|
|
2290
2391
|
catch (error) {
|
|
2291
2392
|
this.error = this.said(error);
|