@preference-sl/pref-viewer 2.16.0-beta.1 → 2.16.0-beta.11
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/LICENSE.md +13 -0
- package/README.md +486 -0
- package/package.json +7 -7
- package/src/babylonjs-animation-opening.js +11 -5
- package/src/babylonjs-controller.js +455 -903
- package/src/file-storage.js +5 -126
- package/src/gltf-resolver.js +24 -58
- package/src/localization/translations.js +5 -17
- package/src/material-utils.js +72 -0
- package/src/pref-viewer-2d.js +14 -21
- package/src/pref-viewer-3d.js +160 -193
- package/src/pref-viewer-menu-3d.js +185 -268
- package/src/pref-viewer-task.js +7 -2
- package/src/pref-viewer.js +549 -333
- package/src/render-math.js +127 -0
- package/src/styles.js +163 -179
- package/Readme.md +0 -8
|
@@ -3,34 +3,32 @@ import BabylonJSController from "./babylonjs-controller.js";
|
|
|
3
3
|
import { DEFAULT_LOCALE, resolveLocale, translate } from "./localization/i18n.js";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* PrefViewerMenu3D - Localized floating control
|
|
6
|
+
* PrefViewerMenu3D - Localized floating control panel for Babylon.js render settings.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
* -
|
|
10
|
-
* -
|
|
11
|
-
* -
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
8
|
+
* Renders a gear-icon toggle button that appears on viewer hover and opens a panel with:
|
|
9
|
+
* - Boolean switches for every boolean render setting (AA, SSAO, IBL, shadows, highlight, etc.).
|
|
10
|
+
* - A hue slider for the highlight color.
|
|
11
|
+
* - A time-of-day slider with play/pause continuous lighting-cycle animation.
|
|
12
|
+
*
|
|
13
|
+
* Every interaction emits `pref-viewer-3d-render-settings-change-requested` immediately; there is no Apply button or
|
|
14
|
+
* draft/pending state. Switch changes emit the full settings snapshot, while highlight color and
|
|
15
|
+
* lighting changes emit partial payloads to avoid unnecessary scene reloads.
|
|
15
16
|
*
|
|
16
17
|
* Public API:
|
|
17
|
-
* - `setSettings(settings)`:
|
|
18
|
-
* - `setApplying(isApplying
|
|
19
|
-
* - `setViewerHover(isHovering)`:
|
|
20
|
-
* - `setEnabled(isEnabled)`: hides the menu
|
|
21
|
-
* - `
|
|
22
|
-
* - `
|
|
18
|
+
* - `setSettings(settings)`: syncs the UI with the latest render settings snapshot.
|
|
19
|
+
* - `setApplying(isApplying)`: locks interactions while an async apply operation is running.
|
|
20
|
+
* - `setViewerHover(isHovering)`: drives panel visibility from the 3D viewport hover state.
|
|
21
|
+
* - `setEnabled(isEnabled)`: hides the menu when 3D mode is unavailable.
|
|
22
|
+
* - `setElementEnabled(settingKey, isEnabled)`: enables/disables a specific switch or slider at runtime.
|
|
23
|
+
* - `setElementVisible(settingKey, isVisible)`: shows/hides a specific switch or slider at runtime.
|
|
24
|
+
* - `setCulture(cultureId)`: switches the display locale.
|
|
23
25
|
*
|
|
24
|
-
*
|
|
25
|
-
* - Automatically creates shadow DOM/UI in `connectedCallback`, wiring hover/focus listeners and ARIA labels.
|
|
26
|
-
* - Exposes a single `culture` observed attribute so hosts can drive localization declaratively.
|
|
26
|
+
* Observed attributes: `culture`. Runtime render values are synchronized through `setSettings()`.
|
|
27
27
|
*
|
|
28
|
-
*
|
|
29
|
-
* - Uses ARIA labels/live regions for the toggle button, dialog panel, pending indicator, and status slot.
|
|
28
|
+
* Events emitted: `pref-viewer-3d-render-settings-change-requested` - `{ detail: { settings: object } }`.
|
|
30
29
|
*/
|
|
31
30
|
export default class PrefViewerMenu3D extends HTMLElement {
|
|
32
31
|
#elements = {
|
|
33
|
-
applyButton: null,
|
|
34
32
|
colorPicker: null,
|
|
35
33
|
colorSlider: null,
|
|
36
34
|
colorPickerPreview: null,
|
|
@@ -43,8 +41,8 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
43
41
|
lightingSlider: null,
|
|
44
42
|
lightingValue: null,
|
|
45
43
|
panel: null,
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
sliders: {},
|
|
45
|
+
sliderWrappers: {},
|
|
48
46
|
subtitle: null,
|
|
49
47
|
switches: {},
|
|
50
48
|
switchCopyNodes: {},
|
|
@@ -54,7 +52,6 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
54
52
|
};
|
|
55
53
|
|
|
56
54
|
#handles = {
|
|
57
|
-
onApplyClick: null,
|
|
58
55
|
onColorSliderInput: null,
|
|
59
56
|
onLightingSliderInput: null,
|
|
60
57
|
onLightingPlayClick: null,
|
|
@@ -65,25 +62,29 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
65
62
|
};
|
|
66
63
|
|
|
67
64
|
#DEFAULT_RENDER_SETTINGS = { ...BabylonJSController.DEFAULT_RENDER_SETTINGS };
|
|
68
|
-
// Only include boolean settings as switches
|
|
65
|
+
// Only include boolean settings as switches; scalar settings are handled by sliders.
|
|
69
66
|
#MENU_SWITCHES = Object.keys(this.#DEFAULT_RENDER_SETTINGS).filter(key =>
|
|
70
67
|
typeof this.#DEFAULT_RENDER_SETTINGS[key] === "boolean"
|
|
71
68
|
);
|
|
72
|
-
#
|
|
73
|
-
#
|
|
74
|
-
#
|
|
75
|
-
#statusTimeout = null;
|
|
69
|
+
#settings = { ...this.#DEFAULT_RENDER_SETTINGS };
|
|
70
|
+
#elementAvailability = {};
|
|
71
|
+
#elementVisibility = {};
|
|
76
72
|
#isApplying = false;
|
|
77
73
|
#isEnabled = true;
|
|
78
74
|
#isLightingPlaying = false;
|
|
79
75
|
#lightingAnimationFrame = null;
|
|
80
76
|
#lightingPlaybackStart = 0;
|
|
81
77
|
#lightingPlaybackBase = 0.5;
|
|
82
|
-
#lightingPlaybackDurationMs =
|
|
78
|
+
#lightingPlaybackDurationMs = 15000;
|
|
83
79
|
|
|
84
80
|
#culture = DEFAULT_LOCALE;
|
|
85
81
|
#texts = {};
|
|
86
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Creates the menu custom element.
|
|
85
|
+
* Rendering is deferred until connectedCallback() so attributes can be set before the UI is built.
|
|
86
|
+
* @public
|
|
87
|
+
*/
|
|
87
88
|
constructor() {
|
|
88
89
|
super();
|
|
89
90
|
}
|
|
@@ -94,40 +95,22 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
94
95
|
* @returns {string[]} Array of attribute names to observe.
|
|
95
96
|
*/
|
|
96
97
|
static get observedAttributes() {
|
|
97
|
-
return ["culture"
|
|
98
|
+
return ["culture"];
|
|
98
99
|
}
|
|
99
100
|
|
|
100
101
|
/**
|
|
101
|
-
* Reacts to observed attribute mutations
|
|
102
|
+
* Reacts to observed attribute mutations and mirrors them into the internal settings/UI state.
|
|
102
103
|
* @public
|
|
103
|
-
* @param {
|
|
104
|
-
* @param {
|
|
105
|
-
* @param {
|
|
104
|
+
* @param {"culture"} name - Attribute name that changed.
|
|
105
|
+
* @param {string|null} _old - Previous attribute value (unused).
|
|
106
|
+
* @param {string|null} value - New attribute value.
|
|
106
107
|
* @returns {void}
|
|
107
108
|
*/
|
|
108
109
|
attributeChangedCallback(name, _old, value) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if (name === "show-illumination") {
|
|
114
|
-
this.#draftSettings.illuminationEnabled = value === "true" || value === true;
|
|
115
|
-
// Update the corresponding switch if it exists
|
|
116
|
-
const switchEl = this.#elements.switches?.illuminationEnabled;
|
|
117
|
-
if (switchEl) {
|
|
118
|
-
switchEl.checked = this.#draftSettings.illuminationEnabled;
|
|
119
|
-
}
|
|
120
|
-
} else if (name === "illumination-color") {
|
|
121
|
-
this.#draftSettings.illuminationColor = value;
|
|
122
|
-
// Update color picker preview if exists
|
|
123
|
-
this.#updateColorPickerPreview(value);
|
|
124
|
-
}
|
|
125
|
-
} else if (name === "lighting-time-of-day") {
|
|
126
|
-
const parsed = Number(value);
|
|
127
|
-
if (Number.isFinite(parsed)) {
|
|
128
|
-
this.#draftSettings.lightingTimeOfDay = this.#clampLightingTime(parsed);
|
|
129
|
-
this.#updateLightingSliderUI(this.#draftSettings.lightingTimeOfDay);
|
|
130
|
-
}
|
|
110
|
+
switch (name) {
|
|
111
|
+
case "culture":
|
|
112
|
+
this.#setCultureInternal(value || DEFAULT_LOCALE);
|
|
113
|
+
break;
|
|
131
114
|
}
|
|
132
115
|
}
|
|
133
116
|
|
|
@@ -143,27 +126,23 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
143
126
|
this.#createDOMElements();
|
|
144
127
|
this.#cacheElements();
|
|
145
128
|
this.#attachEvents();
|
|
146
|
-
this.setSettings(this.#
|
|
129
|
+
this.setSettings(this.#settings);
|
|
147
130
|
}
|
|
148
131
|
}
|
|
149
132
|
|
|
150
133
|
/**
|
|
151
134
|
* Lifecycle hook invoked when the element is removed from the DOM.
|
|
152
|
-
* Cleans up listeners and
|
|
135
|
+
* Cleans up listeners and stops lighting playback to avoid leaks.
|
|
153
136
|
* @public
|
|
154
137
|
* @returns {void}
|
|
155
138
|
*/
|
|
156
139
|
disconnectedCallback() {
|
|
157
140
|
this.#detachEvents();
|
|
158
141
|
this.#stopLightingPlayback();
|
|
159
|
-
if (this.#statusTimeout) {
|
|
160
|
-
clearTimeout(this.#statusTimeout);
|
|
161
|
-
this.#statusTimeout = null;
|
|
162
|
-
}
|
|
163
142
|
}
|
|
164
143
|
|
|
165
144
|
/**
|
|
166
|
-
* Builds the
|
|
145
|
+
* Builds the internal DOM structure for the toggle button, panel, switches, color slider, and lighting controls.
|
|
167
146
|
* @private
|
|
168
147
|
* @returns {void}
|
|
169
148
|
*/
|
|
@@ -180,34 +159,31 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
180
159
|
<p class="menu-subtitle">${this.#texts.subtitle}</p>
|
|
181
160
|
</div>
|
|
182
161
|
<div class="menu-switches">
|
|
183
|
-
${this.#MENU_SWITCHES.map((key) => this.#renderSwitchRow(key, this.#texts)).join("")}
|
|
162
|
+
${this.#MENU_SWITCHES.map((key) => this.#renderSwitchRow(key, this.#texts.features)).join("")}
|
|
184
163
|
</div>
|
|
185
|
-
<div class="menu-color-picker" data-setting="highlightColor">
|
|
164
|
+
<div class="menu-color-picker menu-slider" data-setting="highlightColor">
|
|
186
165
|
<div class="color-slider-row">
|
|
187
|
-
<span class="color-picker-label">${this.#texts.
|
|
188
|
-
<span class="color-preview" style="background-color: ${this.#
|
|
166
|
+
<span class="color-picker-label">${this.#texts.features?.highlightColor?.label || "Highlight Color"}</span>
|
|
167
|
+
<span class="color-preview" style="background-color: ${this.#settings.highlightColor || '#ff6700'}"></span>
|
|
189
168
|
</div>
|
|
190
|
-
<input type="range" class="color-slider" min="0" max="359" value="${PrefViewerMenu3D.#hexToHue(this.#
|
|
169
|
+
<input type="range" data-setting="highlightColor" class="color-slider" min="0" max="359" value="${PrefViewerMenu3D.#hexToHue(this.#settings.highlightColor || '#ff6700')}">
|
|
191
170
|
</div>
|
|
192
|
-
<div class="menu-lighting-slider" data-setting="lightingTimeOfDay">
|
|
171
|
+
<div class="menu-lighting-slider menu-slider" data-setting="lightingTimeOfDay">
|
|
193
172
|
<div class="lighting-slider-row">
|
|
194
|
-
<span class="lighting-slider-label">${this.#texts.
|
|
195
|
-
<span class="lighting-slider-value">${PrefViewerMenu3D.#formatLightingTime(this.#
|
|
173
|
+
<span class="lighting-slider-label menu-slider-label">${this.#texts.features?.lightingTimeOfDay?.label || "Time of day"}</span>
|
|
174
|
+
<span class="lighting-slider-value">${PrefViewerMenu3D.#formatLightingTime(this.#settings.lightingTimeOfDay ?? 0.5)}</span>
|
|
196
175
|
</div>
|
|
197
|
-
<input type="range" class="lighting-slider" min="0" max="1000" step="1" value="${Math.round((this.#
|
|
176
|
+
<input type="range" data-setting="lightingTimeOfDay" class="lighting-slider" min="0" max="1000" step="1" value="${Math.round((this.#settings.lightingTimeOfDay ?? 0.5) * 1000)}">
|
|
198
177
|
<div class="lighting-slider-markers" aria-hidden="true">
|
|
199
|
-
<span class="lighting-slider-start">${this.#texts.
|
|
200
|
-
<span class="lighting-slider-mid">${this.#texts.
|
|
201
|
-
<span class="lighting-slider-end">${this.#texts.
|
|
178
|
+
<span class="lighting-slider-start">${this.#texts.features?.lightingTimeOfDay?.startLabel || "Night"}</span>
|
|
179
|
+
<span class="lighting-slider-mid">${this.#texts.features?.lightingTimeOfDay?.midLabel || "Day"}</span>
|
|
180
|
+
<span class="lighting-slider-end">${this.#texts.features?.lightingTimeOfDay?.endLabel || "Night"}</span>
|
|
202
181
|
</div>
|
|
203
182
|
<div class="lighting-slider-actions">
|
|
204
183
|
<button type="button" class="lighting-play-button">${this.#texts.actions?.play || "Play"}</button>
|
|
205
184
|
</div>
|
|
206
185
|
</div>
|
|
207
|
-
<div class="menu-footer">
|
|
208
|
-
<span class="menu-pending" aria-live="polite">${this.#texts.pendingLabel}</span>
|
|
209
|
-
<span class="menu-status" aria-live="assertive"></span>
|
|
210
|
-
</div>
|
|
186
|
+
<div class="menu-footer"></div>
|
|
211
187
|
</div>
|
|
212
188
|
`;
|
|
213
189
|
const style = document.createElement("style");
|
|
@@ -216,14 +192,14 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
216
192
|
}
|
|
217
193
|
|
|
218
194
|
/**
|
|
219
|
-
* Generates the HTML fragment for a single render-setting switch.
|
|
195
|
+
* Generates the HTML fragment for a single boolean render-setting switch.
|
|
220
196
|
* @private
|
|
221
|
-
* @param {string} key - Render setting
|
|
222
|
-
* @param {
|
|
197
|
+
* @param {string} key - Render setting key from BabylonJSController.DEFAULT_RENDER_SETTINGS.
|
|
198
|
+
* @param {Record<string, {label?: string, helper?: string}>} copy - Locale-aware feature copy used for labels.
|
|
223
199
|
* @returns {string} HTML string representing the switch row.
|
|
224
200
|
*/
|
|
225
201
|
#renderSwitchRow(key, copy) {
|
|
226
|
-
const switchCopy = copy
|
|
202
|
+
const switchCopy = copy?.[key] ?? {};
|
|
227
203
|
const label = switchCopy.label ?? key;
|
|
228
204
|
const helper = switchCopy.helper ?? "";
|
|
229
205
|
return `
|
|
@@ -243,7 +219,7 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
243
219
|
/**
|
|
244
220
|
* Pulls the full translation namespace for the menu using the active culture.
|
|
245
221
|
* @private
|
|
246
|
-
* @returns {object} Resolved translation object or an empty fallback.
|
|
222
|
+
* @returns {object} Resolved `prefViewer.menu3d` translation object or an empty fallback.
|
|
247
223
|
*/
|
|
248
224
|
#getMenuNamespace() {
|
|
249
225
|
const namespace = translate("prefViewer.menu3d", { locale: this.#culture });
|
|
@@ -253,24 +229,18 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
253
229
|
/**
|
|
254
230
|
* Normalizes locale data into a predictable shape consumed by the UI helpers.
|
|
255
231
|
* @private
|
|
256
|
-
* @returns {object} Structured copy bundle for titles, actions,
|
|
232
|
+
* @returns {{title: string, subtitle: string, actions: {play: string, pause: string}, features: object}} Structured copy bundle for titles, actions, and feature labels.
|
|
257
233
|
*/
|
|
258
234
|
#getMenuTexts() {
|
|
259
235
|
const data = this.#getMenuNamespace();
|
|
260
236
|
return {
|
|
261
237
|
title: data.title || "",
|
|
262
238
|
subtitle: data.subtitle || "",
|
|
263
|
-
pendingLabel: data.pendingLabel || "",
|
|
264
239
|
actions: {
|
|
265
|
-
apply: data.actions?.apply || "",
|
|
266
|
-
applying: data.actions?.applying || "",
|
|
267
240
|
play: data.actions?.play || "",
|
|
268
241
|
pause: data.actions?.pause || "",
|
|
269
242
|
},
|
|
270
|
-
|
|
271
|
-
error: data.status?.error || "",
|
|
272
|
-
},
|
|
273
|
-
switches: data.switches || {},
|
|
243
|
+
features: data.features || {},
|
|
274
244
|
};
|
|
275
245
|
}
|
|
276
246
|
|
|
@@ -291,34 +261,28 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
291
261
|
if (this.#elements.subtitle) {
|
|
292
262
|
this.#elements.subtitle.textContent = this.#texts.subtitle;
|
|
293
263
|
}
|
|
294
|
-
if (this.#elements.pendingLabel) {
|
|
295
|
-
this.#elements.pendingLabel.textContent = this.#texts.pendingLabel;
|
|
296
|
-
}
|
|
297
|
-
if (this.#elements.applyButton) {
|
|
298
|
-
this.#elements.applyButton.textContent = this.#isApplying ? this.#texts.actions.applying : this.#texts.actions.apply;
|
|
299
|
-
}
|
|
300
264
|
if (this.#elements.lightingPlayButton) {
|
|
301
265
|
this.#elements.lightingPlayButton.textContent = this.#isLightingPlaying ? (this.#texts.actions.pause || "Pause") : (this.#texts.actions.play || "Play");
|
|
302
266
|
this.#elements.lightingPlayButton.setAttribute("aria-pressed", this.#isLightingPlaying ? "true" : "false");
|
|
303
267
|
}
|
|
304
268
|
if (this.#elements.lightingSliderLabel) {
|
|
305
|
-
this.#elements.lightingSliderLabel.textContent = this.#texts.
|
|
269
|
+
this.#elements.lightingSliderLabel.textContent = this.#texts.features?.lightingTimeOfDay?.label || "Time of day";
|
|
306
270
|
}
|
|
307
271
|
if (this.#elements.lightingSliderStart) {
|
|
308
|
-
this.#elements.lightingSliderStart.textContent = this.#texts.
|
|
272
|
+
this.#elements.lightingSliderStart.textContent = this.#texts.features?.lightingTimeOfDay?.startLabel || "Night";
|
|
309
273
|
}
|
|
310
274
|
if (this.#elements.lightingSliderMid) {
|
|
311
|
-
this.#elements.lightingSliderMid.textContent = this.#texts.
|
|
275
|
+
this.#elements.lightingSliderMid.textContent = this.#texts.features?.lightingTimeOfDay?.midLabel || "Day";
|
|
312
276
|
}
|
|
313
277
|
if (this.#elements.lightingSliderEnd) {
|
|
314
|
-
this.#elements.lightingSliderEnd.textContent = this.#texts.
|
|
278
|
+
this.#elements.lightingSliderEnd.textContent = this.#texts.features?.lightingTimeOfDay?.endLabel || "Night";
|
|
315
279
|
}
|
|
316
280
|
this.#updateLightingPlayButtonUI();
|
|
317
281
|
Object.entries(this.#elements.switchCopyNodes).forEach(([key, nodes]) => {
|
|
318
282
|
if (!nodes) {
|
|
319
283
|
return;
|
|
320
284
|
}
|
|
321
|
-
const switchCopy = this.#texts.
|
|
285
|
+
const switchCopy = this.#texts.features?.[key] ?? {};
|
|
322
286
|
nodes.title && (nodes.title.textContent = switchCopy.label ?? key);
|
|
323
287
|
nodes.helper && (nodes.helper.textContent = switchCopy.helper ?? "");
|
|
324
288
|
});
|
|
@@ -342,7 +306,7 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
342
306
|
}
|
|
343
307
|
|
|
344
308
|
/**
|
|
345
|
-
* Caches references to frequently used DOM nodes for
|
|
309
|
+
* Caches references to frequently used DOM nodes for event binding and UI synchronization.
|
|
346
310
|
* @private
|
|
347
311
|
* @returns {void}
|
|
348
312
|
*/
|
|
@@ -351,11 +315,8 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
351
315
|
this.#elements.panel = this.querySelector(".menu-panel");
|
|
352
316
|
this.#elements.title = this.querySelector(".menu-title");
|
|
353
317
|
this.#elements.subtitle = this.querySelector(".menu-subtitle");
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
this.#elements.status = this.querySelector(".menu-status");
|
|
357
|
-
|
|
358
|
-
// Cache color picker elements
|
|
318
|
+
|
|
319
|
+
// Cache slider elements
|
|
359
320
|
this.#elements.colorPicker = this.querySelector(".menu-color-picker");
|
|
360
321
|
this.#elements.colorSlider = this.querySelector(".color-slider");
|
|
361
322
|
this.#elements.colorPickerPreview = this.querySelector(".color-preview");
|
|
@@ -367,6 +328,11 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
367
328
|
this.#elements.lightingSliderEnd = this.querySelector(".lighting-slider-end");
|
|
368
329
|
this.#elements.lightingSlider = this.querySelector(".lighting-slider");
|
|
369
330
|
this.#elements.lightingValue = this.querySelector(".lighting-slider-value");
|
|
331
|
+
|
|
332
|
+
this.#elements.sliders["highlightColor"] = this.querySelector("input[data-setting='highlightColor']");
|
|
333
|
+
this.#elements.sliderWrappers["highlightColor"] = this.querySelector(".menu-slider[data-setting='highlightColor']");
|
|
334
|
+
this.#elements.sliders["lightingTimeOfDay"] = this.querySelector("input[data-setting='lightingTimeOfDay']");
|
|
335
|
+
this.#elements.sliderWrappers["lightingTimeOfDay"] = this.querySelector(".menu-slider[data-setting='lightingTimeOfDay']");
|
|
370
336
|
|
|
371
337
|
this.#MENU_SWITCHES.forEach((key) => {
|
|
372
338
|
this.#elements.switches[key] = this.querySelector(`input[data-setting="${key}"]`);
|
|
@@ -380,7 +346,7 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
380
346
|
}
|
|
381
347
|
|
|
382
348
|
/**
|
|
383
|
-
* Attaches all interactive event listeners for hover, focus, switch
|
|
349
|
+
* Attaches all interactive event listeners for hover, focus, switch, color, and lighting controls.
|
|
384
350
|
* @private
|
|
385
351
|
* @returns {void}
|
|
386
352
|
*/
|
|
@@ -397,7 +363,6 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
397
363
|
this.#closeMenu();
|
|
398
364
|
};
|
|
399
365
|
this.#handles.onSwitchChange = (event) => this.#handleSwitchChange(event);
|
|
400
|
-
this.#handles.onApplyClick = () => this.#emitApply();
|
|
401
366
|
this.#handles.onColorSliderInput = (event) => this.#handleColorSliderInput(event);
|
|
402
367
|
this.#handles.onLightingSliderInput = (event) => this.#handleLightingSliderInput(event);
|
|
403
368
|
this.#handles.onLightingPlayClick = () => this.#toggleLightingPlayback();
|
|
@@ -407,7 +372,6 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
407
372
|
this.#elements.panel.addEventListener("mouseenter", this.#handles.onPanelEnter);
|
|
408
373
|
this.addEventListener("mouseleave", this.#handles.onHostLeave);
|
|
409
374
|
Object.values(this.#elements.switches).forEach((input) => input?.addEventListener("change", this.#handles.onSwitchChange));
|
|
410
|
-
this.#elements.applyButton?.addEventListener("click", this.#handles.onApplyClick);
|
|
411
375
|
this.#elements.colorSlider?.addEventListener("input", this.#handles.onColorSliderInput);
|
|
412
376
|
this.#elements.lightingSlider?.addEventListener("input", this.#handles.onLightingSliderInput);
|
|
413
377
|
this.#elements.lightingPlayButton?.addEventListener("click", this.#handles.onLightingPlayClick);
|
|
@@ -427,8 +391,6 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
427
391
|
this.#elements.panel?.removeEventListener("mouseenter", this.#handles.onPanelEnter);
|
|
428
392
|
this.removeEventListener("mouseleave", this.#handles.onHostLeave);
|
|
429
393
|
Object.values(this.#elements.switches).forEach((input) => input?.removeEventListener("change", this.#handles.onSwitchChange));
|
|
430
|
-
this.#elements.applyButton?.removeEventListener("click", this.#handles.onApplyClick);
|
|
431
|
-
|
|
432
394
|
this.#elements.colorSlider?.removeEventListener("input", this.#handles.onColorSliderInput);
|
|
433
395
|
this.#elements.lightingSlider?.removeEventListener("input", this.#handles.onLightingSliderInput);
|
|
434
396
|
this.#elements.lightingPlayButton?.removeEventListener("click", this.#handles.onLightingPlayClick);
|
|
@@ -456,7 +418,7 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
456
418
|
}
|
|
457
419
|
|
|
458
420
|
/**
|
|
459
|
-
* Handles switch changes by updating
|
|
421
|
+
* Handles switch changes by updating settings and emitting a full settings snapshot.
|
|
460
422
|
* @private
|
|
461
423
|
* @param {Event} event - Change event triggered by a switch input.
|
|
462
424
|
* @returns {void}
|
|
@@ -469,32 +431,28 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
469
431
|
if (!key) {
|
|
470
432
|
return;
|
|
471
433
|
}
|
|
472
|
-
this.#
|
|
473
|
-
this.#
|
|
474
|
-
|
|
475
|
-
// For highlight toggle, apply immediately without waiting for user to click Apply
|
|
476
|
-
if (key === "highlightEnabled") {
|
|
477
|
-
this.#emitApply(true);
|
|
478
|
-
}
|
|
434
|
+
this.#settings[key] = event.currentTarget.checked;
|
|
435
|
+
this.#emitApply();
|
|
479
436
|
}
|
|
480
437
|
|
|
481
438
|
/**
|
|
482
|
-
* Handles
|
|
439
|
+
* Handles hue slider input by converting the selected hue to a highlight color.
|
|
440
|
+
* Emits a partial payload so highlight color changes apply without scheduling a render-settings reload.
|
|
483
441
|
* @private
|
|
484
|
-
* @param {Event} event -
|
|
442
|
+
* @param {Event} event - Input event from the hue slider.
|
|
485
443
|
* @returns {void}
|
|
486
444
|
*/
|
|
487
445
|
#handleColorSliderInput(event) {
|
|
488
446
|
const hue = parseInt(event.target.value, 10);
|
|
489
447
|
const color = PrefViewerMenu3D.#hueToHex(hue);
|
|
490
|
-
this.#
|
|
448
|
+
this.#settings.highlightColor = color;
|
|
491
449
|
this.#updateColorPickerPreview(color);
|
|
492
|
-
this.#
|
|
493
|
-
this.#emitApply(true);
|
|
450
|
+
this.#emitApply({ highlightColor: color }, { partial: true });
|
|
494
451
|
}
|
|
495
452
|
|
|
496
453
|
/**
|
|
497
|
-
* Handles lighting cycle slider input by updating the
|
|
454
|
+
* Handles lighting cycle slider input by updating the normalized time-of-day value.
|
|
455
|
+
* Emits a partial payload so lighting changes apply immediately without scheduling a render-settings reload.
|
|
498
456
|
* @private
|
|
499
457
|
* @param {Event} event - Input event from the time-of-day slider.
|
|
500
458
|
* @returns {void}
|
|
@@ -505,14 +463,13 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
505
463
|
return;
|
|
506
464
|
}
|
|
507
465
|
const normalized = this.#clampLightingTime(rawValue / 1000);
|
|
508
|
-
this.#
|
|
466
|
+
this.#settings.lightingTimeOfDay = normalized;
|
|
509
467
|
if (this.#isLightingPlaying) {
|
|
510
468
|
this.#lightingPlaybackBase = normalized;
|
|
511
469
|
this.#lightingPlaybackStart = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
|
|
512
470
|
}
|
|
513
471
|
this.#updateLightingSliderUI(normalized);
|
|
514
|
-
this.#
|
|
515
|
-
this.#emitApply(true);
|
|
472
|
+
this.#emitApply({ lightingTimeOfDay: normalized }, { partial: true });
|
|
516
473
|
}
|
|
517
474
|
|
|
518
475
|
/**
|
|
@@ -530,6 +487,7 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
530
487
|
|
|
531
488
|
/**
|
|
532
489
|
* Starts the continuous day/night playback loop.
|
|
490
|
+
* The playback speed is controlled by `#lightingPlaybackDurationMs`, which represents one full 0..1 cycle.
|
|
533
491
|
* @private
|
|
534
492
|
* @returns {void}
|
|
535
493
|
*/
|
|
@@ -538,7 +496,7 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
538
496
|
return;
|
|
539
497
|
}
|
|
540
498
|
this.#isLightingPlaying = true;
|
|
541
|
-
this.#lightingPlaybackBase = this.#
|
|
499
|
+
this.#lightingPlaybackBase = this.#settings.lightingTimeOfDay ?? 0.5;
|
|
542
500
|
this.#lightingPlaybackStart = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
|
|
543
501
|
this.#updateLightingPlayButtonUI();
|
|
544
502
|
const tick = () => {
|
|
@@ -548,9 +506,9 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
548
506
|
const now = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
|
|
549
507
|
const elapsed = now - this.#lightingPlaybackStart;
|
|
550
508
|
const cycle = (this.#lightingPlaybackBase + (elapsed / this.#lightingPlaybackDurationMs)) % 1;
|
|
551
|
-
this.#
|
|
509
|
+
this.#settings.lightingTimeOfDay = cycle;
|
|
552
510
|
this.#updateLightingSliderUI(cycle);
|
|
553
|
-
this.#emitApply(
|
|
511
|
+
this.#emitApply({ lightingTimeOfDay: cycle, persist: false }, { partial: true });
|
|
554
512
|
this.#lightingAnimationFrame = requestAnimationFrame(tick);
|
|
555
513
|
};
|
|
556
514
|
this.#lightingAnimationFrame = requestAnimationFrame(tick);
|
|
@@ -559,6 +517,7 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
559
517
|
/**
|
|
560
518
|
* Stops the continuous day/night playback loop.
|
|
561
519
|
* @private
|
|
520
|
+
* @param {boolean} [persist=false] - True to emit a final apply event that should be persisted by the host.
|
|
562
521
|
* @returns {void}
|
|
563
522
|
*/
|
|
564
523
|
#stopLightingPlayback(persist = false) {
|
|
@@ -568,7 +527,7 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
568
527
|
this.#lightingAnimationFrame = null;
|
|
569
528
|
}
|
|
570
529
|
if (persist) {
|
|
571
|
-
this.#emitApply(true, {
|
|
530
|
+
this.#emitApply({ lightingTimeOfDay: this.#settings.lightingTimeOfDay, persist: true }, { partial: true });
|
|
572
531
|
}
|
|
573
532
|
this.#updateLightingPlayButtonUI();
|
|
574
533
|
}
|
|
@@ -587,6 +546,12 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
587
546
|
this.#elements.lightingPlayButton.setAttribute("aria-pressed", this.#isLightingPlaying ? "true" : "false");
|
|
588
547
|
}
|
|
589
548
|
|
|
549
|
+
/**
|
|
550
|
+
* Converts a hue angle into a saturated hex color.
|
|
551
|
+
* @private
|
|
552
|
+
* @param {number} hue - Hue angle in degrees. Values outside 0..359 wrap around.
|
|
553
|
+
* @returns {string} Hex color string in "#rrggbb" format.
|
|
554
|
+
*/
|
|
590
555
|
static #hueToHex(hue) {
|
|
591
556
|
const h = ((hue % 360) + 360) % 360;
|
|
592
557
|
const a = Math.min(0.5, 1 - 0.5);
|
|
@@ -597,6 +562,12 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
597
562
|
return '#' + [f(0), f(8), f(4)].map((v) => Math.round(v * 255).toString(16).padStart(2, '0')).join('');
|
|
598
563
|
}
|
|
599
564
|
|
|
565
|
+
/**
|
|
566
|
+
* Extracts the hue angle from a hex color string.
|
|
567
|
+
* @private
|
|
568
|
+
* @param {string} hex - Hex color string in "#rrggbb" format.
|
|
569
|
+
* @returns {number} Hue angle in degrees, or the default orange hue when the value is invalid.
|
|
570
|
+
*/
|
|
600
571
|
static #hexToHue(hex) {
|
|
601
572
|
if (!hex || hex.length < 7) return 24;
|
|
602
573
|
const r = parseInt(hex.slice(1, 3), 16) / 255;
|
|
@@ -609,6 +580,12 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
609
580
|
return Math.round(h * 60);
|
|
610
581
|
}
|
|
611
582
|
|
|
583
|
+
/**
|
|
584
|
+
* Formats a normalized lighting-cycle value as a 24-hour clock label.
|
|
585
|
+
* @private
|
|
586
|
+
* @param {number} value - Normalized time-of-day value between 0 and 1.
|
|
587
|
+
* @returns {string} Time label formatted as "HH:mm".
|
|
588
|
+
*/
|
|
612
589
|
static #formatLightingTime(value) {
|
|
613
590
|
const normalized = Math.min(1, Math.max(0, Number(value) || 0));
|
|
614
591
|
const minutes = Math.round(normalized * 24 * 60) % (24 * 60);
|
|
@@ -617,6 +594,12 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
617
594
|
return `${String(hours).padStart(2, "0")}:${String(mins).padStart(2, "0")}`;
|
|
618
595
|
}
|
|
619
596
|
|
|
597
|
+
/**
|
|
598
|
+
* Clamps a lighting-cycle value to the supported normalized range.
|
|
599
|
+
* @private
|
|
600
|
+
* @param {number} value - Value to clamp.
|
|
601
|
+
* @returns {number} Clamped value between 0 and 1, or 0.5 when the input is invalid.
|
|
602
|
+
*/
|
|
620
603
|
#clampLightingTime(value) {
|
|
621
604
|
if (!Number.isFinite(value)) {
|
|
622
605
|
return 0.5;
|
|
@@ -625,7 +608,7 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
625
608
|
}
|
|
626
609
|
|
|
627
610
|
/**
|
|
628
|
-
* Updates the color picker UI
|
|
611
|
+
* Updates the color picker UI, including the hue slider and color preview.
|
|
629
612
|
* @private
|
|
630
613
|
* @param {string} color - Selected color.
|
|
631
614
|
* @returns {void}
|
|
@@ -669,129 +652,60 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
669
652
|
}
|
|
670
653
|
|
|
671
654
|
/**
|
|
672
|
-
* Emits the apply event with the current
|
|
655
|
+
* Emits the apply event with the current settings immediately unless the menu is locked.
|
|
673
656
|
* @private
|
|
657
|
+
* @param {object} [extraSettings={}] - Additional fields merged into the emitted settings payload, or the complete payload when `options.partial` is true.
|
|
658
|
+
* @param {object} [options={}] - Event payload options.
|
|
659
|
+
* @param {boolean} [options.partial=false] - True to emit only `extraSettings` instead of the full settings snapshot.
|
|
674
660
|
* @returns {void}
|
|
675
661
|
*/
|
|
676
|
-
#emitApply(
|
|
677
|
-
|
|
678
|
-
if (!force && this.#isApplying) {
|
|
662
|
+
#emitApply(extraSettings = {}, options = {}) {
|
|
663
|
+
if (this.#isApplying) {
|
|
679
664
|
return;
|
|
680
665
|
}
|
|
681
|
-
|
|
682
|
-
const
|
|
683
|
-
const customEventOptions = {
|
|
666
|
+
const detail = { settings: options.partial ? { ...extraSettings } : { ...this.#settings, ...extraSettings } };
|
|
667
|
+
const eventOptions = {
|
|
684
668
|
bubbles: true,
|
|
685
669
|
cancelable: true,
|
|
686
670
|
composed: true,
|
|
687
|
-
detail
|
|
671
|
+
detail,
|
|
688
672
|
};
|
|
689
|
-
this.dispatchEvent(new CustomEvent("pref-viewer-
|
|
673
|
+
this.dispatchEvent(new CustomEvent("pref-viewer-3d-render-settings-change-requested", eventOptions));
|
|
690
674
|
}
|
|
691
675
|
|
|
692
676
|
/**
|
|
693
|
-
* Synchronizes checkbox states with the
|
|
677
|
+
* Synchronizes checkbox states with the current settings snapshot.
|
|
694
678
|
* @private
|
|
695
679
|
* @returns {void}
|
|
696
680
|
*/
|
|
697
681
|
#updateSwitches() {
|
|
698
682
|
Object.entries(this.#elements.switches).forEach(([key, input]) => {
|
|
699
683
|
if (input) {
|
|
700
|
-
const isEnabled = this.#
|
|
701
|
-
|
|
684
|
+
const isEnabled = this.#elementAvailability[key] !== false;
|
|
685
|
+
const isVisible = this.#elementVisibility[key] !== false;
|
|
686
|
+
input.checked = Boolean(this.#settings[key]);
|
|
702
687
|
input.disabled = !isEnabled;
|
|
703
688
|
this.#elements.switchWrappers[key]?.toggleAttribute("data-disabled", !isEnabled);
|
|
689
|
+
this.#elements.switchWrappers[key]?.toggleAttribute("data-hidden", !isVisible);
|
|
704
690
|
}
|
|
705
691
|
});
|
|
706
692
|
}
|
|
707
693
|
|
|
708
694
|
/**
|
|
709
|
-
*
|
|
695
|
+
* Synchronizes slider states with the current settings snapshot.
|
|
710
696
|
* @private
|
|
711
697
|
* @returns {void}
|
|
712
698
|
*/
|
|
713
|
-
#
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
}
|
|
722
|
-
this.#updateSwitchPendingIndicators(pendingKeys);
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
/**
|
|
726
|
-
* Calculates which render keys differ between draft and applied snapshots.
|
|
727
|
-
* @private
|
|
728
|
-
* @returns {string[]} Keys currently pending application.
|
|
729
|
-
*/
|
|
730
|
-
#getPendingKeys() {
|
|
731
|
-
return Object.keys(this.#DEFAULT_RENDER_SETTINGS).filter((key) => {
|
|
732
|
-
if (key === "lightingTimeOfDay") {
|
|
733
|
-
return false;
|
|
734
|
-
}
|
|
735
|
-
if (this.#elements.switches[key]?.disabled) {
|
|
736
|
-
return false;
|
|
737
|
-
}
|
|
738
|
-
return this.#draftSettings[key] !== this.#appliedSettings[key];
|
|
739
|
-
});
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
/**
|
|
743
|
-
* Convenience helper to check if any pending changes exist.
|
|
744
|
-
* @private
|
|
745
|
-
* @returns {boolean}
|
|
746
|
-
*/
|
|
747
|
-
#hasPendingChanges() {
|
|
748
|
-
return this.#getPendingKeys().length > 0;
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
/**
|
|
752
|
-
* Adds or removes the `data-pending` attribute on switch wrappers to visually flag unsaved toggles.
|
|
753
|
-
* @private
|
|
754
|
-
* @param {string[]} pendingKeys - Keys currently pending.
|
|
755
|
-
* @returns {void}
|
|
756
|
-
*/
|
|
757
|
-
#updateSwitchPendingIndicators(pendingKeys = []) {
|
|
758
|
-
Object.entries(this.#elements.switchWrappers).forEach(([key, wrapper]) => {
|
|
759
|
-
if (!wrapper) {
|
|
760
|
-
return;
|
|
699
|
+
#updateSliders() {
|
|
700
|
+
Object.entries(this.#elements.sliders).forEach(([key, input]) => {
|
|
701
|
+
if (input) {
|
|
702
|
+
const isEnabled = this.#elementAvailability[key] !== false;
|
|
703
|
+
const isVisible = this.#elementVisibility[key] !== false;
|
|
704
|
+
input.disabled = !isEnabled;
|
|
705
|
+
this.#elements.sliderWrappers[key]?.toggleAttribute("data-disabled", !isEnabled);
|
|
706
|
+
this.#elements.sliderWrappers[key]?.toggleAttribute("data-hidden", !isVisible);
|
|
761
707
|
}
|
|
762
|
-
wrapper.toggleAttribute("data-pending", pendingKeys.includes(key));
|
|
763
708
|
});
|
|
764
|
-
this.#elements.lightingSliderWrapper?.toggleAttribute("data-pending", pendingKeys.includes("lightingTimeOfDay"));
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
/**
|
|
768
|
-
* Shows a transient status message in the footer and schedules it to auto-clear.
|
|
769
|
-
* @private
|
|
770
|
-
* @param {string} message - The status text to display.
|
|
771
|
-
* @returns {void}
|
|
772
|
-
*/
|
|
773
|
-
#setStatusMessage(message) {
|
|
774
|
-
if (!this.#elements.status) {
|
|
775
|
-
return;
|
|
776
|
-
}
|
|
777
|
-
this.#elements.status.textContent = message;
|
|
778
|
-
if (message) {
|
|
779
|
-
this.setAttribute("data-status", "visible");
|
|
780
|
-
} else {
|
|
781
|
-
this.removeAttribute("data-status");
|
|
782
|
-
}
|
|
783
|
-
if (this.#statusTimeout) {
|
|
784
|
-
clearTimeout(this.#statusTimeout);
|
|
785
|
-
this.#statusTimeout = null;
|
|
786
|
-
}
|
|
787
|
-
if (message) {
|
|
788
|
-
const schedule = typeof window !== "undefined" ? window.setTimeout : setTimeout;
|
|
789
|
-
this.#statusTimeout = schedule(() => {
|
|
790
|
-
this.#elements.status.textContent = "";
|
|
791
|
-
this.removeAttribute("data-status");
|
|
792
|
-
this.#statusTimeout = null;
|
|
793
|
-
}, 4000);
|
|
794
|
-
}
|
|
795
709
|
}
|
|
796
710
|
|
|
797
711
|
/**
|
|
@@ -801,24 +715,14 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
801
715
|
*/
|
|
802
716
|
|
|
803
717
|
/**
|
|
804
|
-
* Locks or unlocks the menu while changes are applied
|
|
718
|
+
* Locks or unlocks the menu while changes are applied.
|
|
805
719
|
* @public
|
|
806
720
|
* @param {boolean} isApplying - Whether an apply operation is currently running.
|
|
807
|
-
* @param {boolean} [hasError=false] - Optional flag to show an error message.
|
|
808
721
|
* @returns {void}
|
|
809
722
|
*/
|
|
810
|
-
setApplying(isApplying
|
|
723
|
+
setApplying(isApplying) {
|
|
811
724
|
this.#isApplying = isApplying;
|
|
812
725
|
this.toggleAttribute("data-applying", isApplying);
|
|
813
|
-
if (this.#elements.applyButton) {
|
|
814
|
-
this.#elements.applyButton.textContent = isApplying ? this.#texts.actions.applying : this.#texts.actions.apply;
|
|
815
|
-
this.#elements.applyButton.disabled = isApplying || !this.#hasPendingChanges();
|
|
816
|
-
}
|
|
817
|
-
if (hasError) {
|
|
818
|
-
this.#setStatusMessage(this.#texts.status.error);
|
|
819
|
-
} else if (!isApplying) {
|
|
820
|
-
this.#setStatusMessage("");
|
|
821
|
-
}
|
|
822
726
|
}
|
|
823
727
|
|
|
824
728
|
/**
|
|
@@ -852,32 +756,23 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
852
756
|
}
|
|
853
757
|
|
|
854
758
|
/**
|
|
855
|
-
* Applies a new
|
|
759
|
+
* Applies a new render settings snapshot to the UI and clears the applying state.
|
|
856
760
|
* @public
|
|
857
|
-
* @param {object} settings - Render settings snapshot from PrefViewer.
|
|
761
|
+
* @param {object} settings - Render settings snapshot from PrefViewer or BabylonJSController.
|
|
858
762
|
* @returns {void}
|
|
859
763
|
*/
|
|
860
764
|
setSettings(settings = {}) {
|
|
861
|
-
this.#
|
|
862
|
-
this.#draftSettings = { ...this.#appliedSettings };
|
|
765
|
+
this.#settings = { ...this.#DEFAULT_RENDER_SETTINGS, ...settings };
|
|
863
766
|
this.#updateSwitches();
|
|
864
|
-
this.#
|
|
865
|
-
|
|
866
|
-
// Sync color slider with current highlightColor
|
|
867
|
-
if (this.#draftSettings.highlightColor) {
|
|
868
|
-
this.#updateColorPickerUI(this.#draftSettings.highlightColor);
|
|
869
|
-
}
|
|
870
|
-
if (this.#draftSettings.lightingTimeOfDay !== undefined) {
|
|
871
|
-
this.#updateLightingSliderUI(this.#draftSettings.lightingTimeOfDay);
|
|
767
|
+
if (this.#settings.highlightColor) {
|
|
768
|
+
this.#updateColorPickerUI(this.#settings.highlightColor);
|
|
872
769
|
}
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
this.#updateColorPickerUI(this.#draftSettings.illuminationColor);
|
|
770
|
+
if (this.#settings.lightingTimeOfDay !== undefined) {
|
|
771
|
+
this.#updateLightingSliderUI(this.#settings.lightingTimeOfDay);
|
|
876
772
|
}
|
|
773
|
+
this.#updateSliders();
|
|
877
774
|
this.#updateLightingPlayButtonUI();
|
|
878
|
-
|
|
879
775
|
this.setApplying(false);
|
|
880
|
-
this.#setStatusMessage("");
|
|
881
776
|
}
|
|
882
777
|
|
|
883
778
|
/**
|
|
@@ -899,22 +794,44 @@ export default class PrefViewerMenu3D extends HTMLElement {
|
|
|
899
794
|
}
|
|
900
795
|
|
|
901
796
|
/**
|
|
902
|
-
* Enables or disables a specific render-setting switch in the menu.
|
|
797
|
+
* Enables or disables a specific render-setting switch or slider in the menu.
|
|
903
798
|
* @public
|
|
904
|
-
* @param {string} settingKey -
|
|
799
|
+
* @param {string} settingKey - Setting key (e.g. "iblEnabled", "highlightColor", or "lightingTimeOfDay").
|
|
905
800
|
* @param {boolean} [isEnabled=true] - True to allow interaction, false to disable it.
|
|
906
801
|
* @returns {void}
|
|
907
802
|
*/
|
|
908
|
-
|
|
909
|
-
if (!settingKey
|
|
803
|
+
setElementEnabled(settingKey, isEnabled = true) {
|
|
804
|
+
if (!settingKey) {
|
|
910
805
|
return;
|
|
911
806
|
}
|
|
912
|
-
|
|
913
|
-
this.#
|
|
914
|
-
|
|
915
|
-
this.#
|
|
807
|
+
|
|
808
|
+
if (this.#MENU_SWITCHES.includes(settingKey)) {
|
|
809
|
+
this.#elementAvailability[settingKey] = Boolean(isEnabled);
|
|
810
|
+
this.#updateSwitches();
|
|
811
|
+
} else if (this.#elements.sliders[settingKey]) {
|
|
812
|
+
this.#elementAvailability[settingKey] = Boolean(isEnabled);
|
|
813
|
+
this.#updateSliders();
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
/**
|
|
818
|
+
* Shows or hides a specific render-setting switch or slider in the menu.
|
|
819
|
+
* @public
|
|
820
|
+
* @param {string} settingKey - Setting key (e.g. "iblEnabled", "highlightColor", or "lightingTimeOfDay").
|
|
821
|
+
* @param {boolean} [isVisible=true] - True to show the switch, false to hide it.
|
|
822
|
+
* @returns {void}
|
|
823
|
+
*/
|
|
824
|
+
setElementVisible(settingKey, isVisible = true) {
|
|
825
|
+
if (!settingKey) {
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
if (this.#MENU_SWITCHES.includes(settingKey)) {
|
|
830
|
+
this.#elementVisibility[settingKey] = Boolean(isVisible);
|
|
831
|
+
this.#updateSwitches();
|
|
832
|
+
} else if (this.#elements.sliders[settingKey]) {
|
|
833
|
+
this.#elementVisibility[settingKey] = Boolean(isVisible);
|
|
834
|
+
this.#updateSliders();
|
|
916
835
|
}
|
|
917
|
-
this.#updateSwitches();
|
|
918
|
-
this.#updatePendingState();
|
|
919
836
|
}
|
|
920
837
|
}
|