mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 19:34:01 +00:00
feat(ui): render the Display panel's HUD and Sonar controls from the store
This commit is contained in:
1 parent
c99c0e8000
commit
3aa5a3e5e3
11 files changed
+117
-93
No files matched your search
@@ -94,7 +94,7 @@ They contain no application state.
|
|||||||
renders `LayerRows` synchronously; keyed chips and list items keep focus
|
renders `LayerRows` synchronously; keyed chips and list items keep focus
|
||||||
through the refresh their own click triggers, and clicks re-read the live
|
through the refresh their own click triggers, and clicks re-read the live
|
||||||
descriptor before acting), Display (in progress: `DisplayPanel` renders
|
descriptor before acting), Display (in progress: `DisplayPanel` renders
|
||||||
bloom, sharpen and detection from the `gev-display` store, which VisualSettings
|
the HUD, Sonar, detection, bloom and sharpen from the `gev-display` store, which VisualSettings
|
||||||
publishes to; the other groups follow one owner at a time), Context and
|
publishes to; the other groups follow one owner at a time), Context and
|
||||||
Radio, the command dock,
|
Radio, the command dock,
|
||||||
the phone shell, then Cockpit. Layers that write into the right rail
|
the phone shell, then Cockpit. Layers that write into the right rail
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ export class StyleManager extends ShellFacade {
|
|||||||
this._lifetime = new UiLifetime();
|
this._lifetime = new UiLifetime();
|
||||||
this._recording = new RecordingControls({
|
this._recording = new RecordingControls({
|
||||||
syncShareState: () => this._syncShareState(),
|
syncShareState: () => this._syncShareState(),
|
||||||
|
syncHudControls: () => this._visualSettings._syncHudControls(),
|
||||||
});
|
});
|
||||||
Object.assign(this, readShellElements());
|
Object.assign(this, readShellElements());
|
||||||
this._panelChrome = new PanelChrome({
|
this._panelChrome = new PanelChrome({
|
||||||
@@ -209,20 +210,6 @@ export class StyleManager extends ShellFacade {
|
|||||||
elements: {
|
elements: {
|
||||||
_celestialBtn: this._celestialBtn,
|
_celestialBtn: this._celestialBtn,
|
||||||
_cockpitDisplayToggleBtn: this._cockpitDisplayToggleBtn,
|
_cockpitDisplayToggleBtn: this._cockpitDisplayToggleBtn,
|
||||||
_hudBtn: this._hudBtn,
|
|
||||||
_cyberSonarBtn: this._cyberSonarBtn,
|
|
||||||
_cyberSonarRings: this._cyberSonarRings,
|
|
||||||
_cyberSonarRingsValue: this._cyberSonarRingsValue,
|
|
||||||
_cyberSonarRange: this._cyberSonarRange,
|
|
||||||
_cyberSonarRangeValue: this._cyberSonarRangeValue,
|
|
||||||
_cyberSonarIntensity: this._cyberSonarIntensity,
|
|
||||||
_cyberSonarIntensityValue: this._cyberSonarIntensityValue,
|
|
||||||
_cyberSonarOpacity: this._cyberSonarOpacity,
|
|
||||||
_cyberSonarOpacityValue: this._cyberSonarOpacityValue,
|
|
||||||
_cyberSonarSector: this._cyberSonarSector,
|
|
||||||
_cyberSonarSectorValue: this._cyberSonarSectorValue,
|
|
||||||
_hudLayoutRow: this._hudLayoutRow,
|
|
||||||
_hudLayoutSelect: this._hudLayoutSelect,
|
|
||||||
_ppToggles: this._ppToggles,
|
_ppToggles: this._ppToggles,
|
||||||
_scopeBtn: this._scopeBtn,
|
_scopeBtn: this._scopeBtn,
|
||||||
_scopeFeatherSlider: this._scopeFeatherSlider,
|
_scopeFeatherSlider: this._scopeFeatherSlider,
|
||||||
@@ -1693,9 +1680,6 @@ export class StyleManager extends ShellFacade {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
_initHUDToggle() {
|
_initHUDToggle() {
|
||||||
if (this._hudLayoutSelect) {
|
|
||||||
this._hudLayoutSelect.value = 'tactical';
|
|
||||||
}
|
|
||||||
this._setHudVariant('tactical');
|
this._setHudVariant('tactical');
|
||||||
this.hud.setMode('on');
|
this.hud.setMode('on');
|
||||||
this._updateHudButtonState();
|
this._updateHudButtonState();
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ test('real runner and facade use visual settings, preserve visibility and return
|
|||||||
const renders = [];
|
const renders = [];
|
||||||
const visual = Object.create(VisualSettings.prototype);
|
const visual = Object.create(VisualSettings.prototype);
|
||||||
visual.services = { governorRequestRender: (reason) => renders.push(reason) };
|
visual.services = { governorRequestRender: (reason) => renders.push(reason) };
|
||||||
|
// No Display panel here: the controls' render is not under test.
|
||||||
|
visual._publishDisplay = () => {};
|
||||||
const owner = Object.create(StyleManager.prototype);
|
const owner = Object.create(StyleManager.prototype);
|
||||||
owner._visualSettings = visual;
|
owner._visualSettings = visual;
|
||||||
Object.defineProperty(owner, 'hud', { value: f.owner.hud });
|
Object.defineProperty(owner, 'hud', { value: f.owner.hud });
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ function styleOwner(t, initialVariant = 'cyber') {
|
|||||||
const owner = Object.create(VisualSettings.prototype);
|
const owner = Object.create(VisualSettings.prototype);
|
||||||
Object.assign(owner, {
|
Object.assign(owner, {
|
||||||
activeStyle: 'normal',
|
activeStyle: 'normal',
|
||||||
|
store: { publish() {} },
|
||||||
readHud: () => hud,
|
readHud: () => hud,
|
||||||
readShareLinks: () => ({ onStyleChange() {} }),
|
readShareLinks: () => ({ onStyleChange() {} }),
|
||||||
_visualEffects: {
|
_visualEffects: {
|
||||||
@@ -76,7 +77,6 @@ function styleOwner(t, initialVariant = 'cyber') {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
services: { governorRequestRender() {}, setDetectionStyle() {} },
|
services: { governorRequestRender() {}, setDetectionStyle() {} },
|
||||||
_hudLayoutSelect: { value: initialVariant },
|
|
||||||
_styleIndicator: {},
|
_styleIndicator: {},
|
||||||
_setBloomEnabled: (value) => calls.push(['bloom', value]),
|
_setBloomEnabled: (value) => calls.push(['bloom', value]),
|
||||||
_setSharpenEnabled: (value) => calls.push(['sharpen', value]),
|
_setSharpenEnabled: (value) => calls.push(['sharpen', value]),
|
||||||
@@ -116,7 +116,6 @@ test('visual styles retain Cyber through real preset application without droppin
|
|||||||
assert.equal(owner.activeStyle, style);
|
assert.equal(owner.activeStyle, style);
|
||||||
assert.equal(hud.getVariant(), 'cyber');
|
assert.equal(hud.getVariant(), 'cyber');
|
||||||
assert.equal(root.dataset.uiTheme, 'cyber');
|
assert.equal(root.dataset.uiTheme, 'cyber');
|
||||||
assert.equal(owner._hudLayoutSelect.value, 'cyber');
|
|
||||||
assert.deepEqual(calls.at(-1), ['share', 'cyber']);
|
assert.deepEqual(calls.at(-1), ['share', 'cyber']);
|
||||||
}
|
}
|
||||||
assert.equal(owner.stages.thermal.uniforms.sensitivity, 0.85);
|
assert.equal(owner.stages.thermal.uniforms.sensitivity, 0.85);
|
||||||
|
|||||||
@@ -205,3 +205,51 @@ test('detection renders its mode, rows, sliders and allocation', async (t) => {
|
|||||||
assert.equal(button.className, 'pp-toggle-btn');
|
assert.equal(button.className, 'pp-toggle-btn');
|
||||||
assert.equal($('detection-slider-row').classList.contains('visible'), false);
|
assert.equal($('detection-slider-row').classList.contains('visible'), false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('the HUD and Sonar controls render what VisualSettings shows', async (t) => {
|
||||||
|
const { store, $ } = fixture(t);
|
||||||
|
const { owner } = settings(store);
|
||||||
|
let visible = true;
|
||||||
|
let variant = 'minimal';
|
||||||
|
owner.readHud = () => ({
|
||||||
|
get visible() {
|
||||||
|
return visible;
|
||||||
|
},
|
||||||
|
getVariant: () => variant,
|
||||||
|
});
|
||||||
|
owner._scheduleAdaptivePanelLayout = () => {};
|
||||||
|
assert.equal($('cyber-sonar-toggle').textContent, 'ON');
|
||||||
|
assert.equal($('cyber-sonar-toggle').getAttribute('aria-pressed'), 'true');
|
||||||
|
|
||||||
|
owner._syncHudControls();
|
||||||
|
await nextTick();
|
||||||
|
assert.equal($('hud-toggle').classList.contains('active'), true);
|
||||||
|
assert.equal($('hud-layout-row').classList.contains('visible'), true);
|
||||||
|
assert.equal($('hud-layout-select').value, 'minimal');
|
||||||
|
|
||||||
|
visible = false;
|
||||||
|
owner._updateHudButtonState();
|
||||||
|
await nextTick();
|
||||||
|
assert.equal($('hud-toggle').classList.contains('active'), false);
|
||||||
|
assert.equal($('hud-layout-row').classList.contains('visible'), false);
|
||||||
|
|
||||||
|
owner._sonarShown = {
|
||||||
|
enabled: false,
|
||||||
|
rings: 5,
|
||||||
|
range: 90,
|
||||||
|
intensity: 40,
|
||||||
|
opacity: 60,
|
||||||
|
sector: 30,
|
||||||
|
};
|
||||||
|
owner._publishDisplay();
|
||||||
|
await nextTick();
|
||||||
|
const toggle = $('cyber-sonar-toggle');
|
||||||
|
assert.equal(toggle.textContent, 'OFF');
|
||||||
|
assert.equal(toggle.getAttribute('aria-pressed'), 'false');
|
||||||
|
assert.equal(toggle.classList.contains('active'), false);
|
||||||
|
assert.equal($('cyber-sonar-rings').value, '5');
|
||||||
|
assert.equal($('cyber-sonar-rings-value').textContent, '5');
|
||||||
|
assert.equal($('cyber-sonar-range-value').textContent, '90%');
|
||||||
|
assert.equal($('cyber-sonar-sector').value, '30');
|
||||||
|
assert.equal($('cyber-sonar-sector-value').textContent, '30°');
|
||||||
|
});
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* `v-range-value`: a range input's live value, written only when it differs.
|
* `v-range-value`: a range input's (or select's) live value, written only
|
||||||
|
* when it differs.
|
||||||
* A `:value` binding would also rewrite the value attribute on every patch;
|
* A `:value` binding would also rewrite the value attribute on every patch;
|
||||||
* the directive runs after the element's min, max and step are patched, so
|
* the directive runs after the element's min, max and step are patched, so
|
||||||
* the value is never clamped to a stale range.
|
* the value is never clamped to a stale range.
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
/** Own recording chrome, safe frames and the pre-recording HUD snapshot. */
|
/** Own recording chrome, safe frames and the pre-recording HUD snapshot. */
|
||||||
export class RecordingControls {
|
export class RecordingControls {
|
||||||
constructor({ syncShareState }) {
|
constructor({ syncShareState, syncHudControls }) {
|
||||||
this._syncShareState = syncShareState;
|
this._syncShareState = syncShareState;
|
||||||
|
// Shows the HUD's visibility and layout on the Display controls.
|
||||||
|
this._syncHudControls = syncHudControls;
|
||||||
this.destroyed = false;
|
this.destroyed = false;
|
||||||
this._recordingMode = false;
|
this._recordingMode = false;
|
||||||
this._recordingConfig = {
|
this._recordingConfig = {
|
||||||
@@ -12,8 +14,6 @@ export class RecordingControls {
|
|||||||
this._preRecordingHudState = null;
|
this._preRecordingHudState = null;
|
||||||
this._safeFrameOverlay = document.getElementById('safe-frame-overlay');
|
this._safeFrameOverlay = document.getElementById('safe-frame-overlay');
|
||||||
this._safeFrameBox = document.getElementById('safe-frame-box');
|
this._safeFrameBox = document.getElementById('safe-frame-box');
|
||||||
this._hudLayoutSelect = document.getElementById('hud-layout-select');
|
|
||||||
this._hudBtn = document.getElementById('hud-toggle');
|
|
||||||
this.hud = null;
|
this.hud = null;
|
||||||
}
|
}
|
||||||
_initRecordingOverlay() {
|
_initRecordingOverlay() {
|
||||||
@@ -63,8 +63,6 @@ export class RecordingControls {
|
|||||||
} else if (hudMode === 'full' || hudMode === 'minimal') {
|
} else if (hudMode === 'full' || hudMode === 'minimal') {
|
||||||
this.hud.setMode('on');
|
this.hud.setMode('on');
|
||||||
this.hud.setVariant(hudMode === 'minimal' ? 'minimal' : 'tactical');
|
this.hud.setVariant(hudMode === 'minimal' ? 'minimal' : 'tactical');
|
||||||
if (this._hudLayoutSelect)
|
|
||||||
this._hudLayoutSelect.value = this.hud.getVariant();
|
|
||||||
} else {
|
} else {
|
||||||
this.hud.setMode('auto');
|
this.hud.setMode('auto');
|
||||||
}
|
}
|
||||||
@@ -73,8 +71,6 @@ export class RecordingControls {
|
|||||||
this._preRecordingHudState = null;
|
this._preRecordingHudState = null;
|
||||||
if (saved) {
|
if (saved) {
|
||||||
this.hud.setVariant(saved.variant);
|
this.hud.setVariant(saved.variant);
|
||||||
if (this._hudLayoutSelect)
|
|
||||||
this._hudLayoutSelect.value = this.hud.getVariant();
|
|
||||||
}
|
}
|
||||||
this.hud.setMode(saved ? saved.mode : 'auto');
|
this.hud.setMode(saved ? saved.mode : 'auto');
|
||||||
if (this._safeFrameOverlay) {
|
if (this._safeFrameOverlay) {
|
||||||
@@ -85,7 +81,7 @@ export class RecordingControls {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this._hudBtn.classList.toggle('active', this.hud.visible);
|
this._syncHudControls();
|
||||||
this._syncShareState();
|
this._syncShareState();
|
||||||
}
|
}
|
||||||
destroy() {
|
destroy() {
|
||||||
|
|||||||
@@ -11,23 +11,13 @@ export function readShellElements(document = globalThis.document) {
|
|||||||
_sharpenBtn: document.getElementById('sharpen-toggle'),
|
_sharpenBtn: document.getElementById('sharpen-toggle'),
|
||||||
_sharpenSlider: document.getElementById('sharpen-intensity-slider'),
|
_sharpenSlider: document.getElementById('sharpen-intensity-slider'),
|
||||||
_hudBtn: document.getElementById('hud-toggle'),
|
_hudBtn: document.getElementById('hud-toggle'),
|
||||||
_hudLayoutRow: document.getElementById('hud-layout-row'),
|
|
||||||
_hudLayoutSelect: document.getElementById('hud-layout-select'),
|
_hudLayoutSelect: document.getElementById('hud-layout-select'),
|
||||||
_cyberSonarBtn: document.getElementById('cyber-sonar-toggle'),
|
_cyberSonarBtn: document.getElementById('cyber-sonar-toggle'),
|
||||||
_cyberSonarRings: document.getElementById('cyber-sonar-rings'),
|
_cyberSonarRings: document.getElementById('cyber-sonar-rings'),
|
||||||
_cyberSonarRingsValue: document.getElementById('cyber-sonar-rings-value'),
|
|
||||||
_cyberSonarRange: document.getElementById('cyber-sonar-range'),
|
_cyberSonarRange: document.getElementById('cyber-sonar-range'),
|
||||||
_cyberSonarRangeValue: document.getElementById('cyber-sonar-range-value'),
|
|
||||||
_cyberSonarIntensity: document.getElementById('cyber-sonar-intensity'),
|
_cyberSonarIntensity: document.getElementById('cyber-sonar-intensity'),
|
||||||
_cyberSonarIntensityValue: document.getElementById(
|
|
||||||
'cyber-sonar-intensity-value',
|
|
||||||
),
|
|
||||||
_cyberSonarOpacity: document.getElementById('cyber-sonar-opacity'),
|
_cyberSonarOpacity: document.getElementById('cyber-sonar-opacity'),
|
||||||
_cyberSonarOpacityValue: document.getElementById(
|
|
||||||
'cyber-sonar-opacity-value',
|
|
||||||
),
|
|
||||||
_cyberSonarSector: document.getElementById('cyber-sonar-sector'),
|
_cyberSonarSector: document.getElementById('cyber-sonar-sector'),
|
||||||
_cyberSonarSectorValue: document.getElementById('cyber-sonar-sector-value'),
|
|
||||||
_detectionDensitySlider: document.getElementById(
|
_detectionDensitySlider: document.getElementById(
|
||||||
'detection-density-slider',
|
'detection-density-slider',
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -200,7 +200,11 @@ test('recording restores the original HUD after repeated entry and revokes retai
|
|||||||
try {
|
try {
|
||||||
let mode = 'auto',
|
let mode = 'auto',
|
||||||
variant = 'tactical';
|
variant = 'tactical';
|
||||||
const owner = new RecordingControls({ syncShareState() {} });
|
const hudSyncs = [];
|
||||||
|
const owner = new RecordingControls({
|
||||||
|
syncShareState() {},
|
||||||
|
syncHudControls: () => hudSyncs.push(variant),
|
||||||
|
});
|
||||||
owner.hud = {
|
owner.hud = {
|
||||||
getMode: () => mode,
|
getMode: () => mode,
|
||||||
getVariant: () => variant,
|
getVariant: () => variant,
|
||||||
@@ -218,6 +222,11 @@ test('recording restores the original HUD after repeated entry and revokes retai
|
|||||||
owner.setRecordingMode(true);
|
owner.setRecordingMode(true);
|
||||||
assert.equal(mode, 'auto');
|
assert.equal(mode, 'auto');
|
||||||
assert.equal(variant, 'tactical');
|
assert.equal(variant, 'tactical');
|
||||||
|
assert.deepEqual(
|
||||||
|
hudSyncs,
|
||||||
|
['minimal', 'minimal', 'tactical'],
|
||||||
|
'each change shows the HUD layout it leaves',
|
||||||
|
);
|
||||||
assert.equal(document.body.classList.contains('recording-mode'), false);
|
assert.equal(document.body.classList.contains('recording-mode'), false);
|
||||||
assert.equal(
|
assert.equal(
|
||||||
f.nodes.get('safe-frame-overlay').classList.contains('active'),
|
f.nodes.get('safe-frame-overlay').classList.contains('active'),
|
||||||
|
|||||||
@@ -5,11 +5,14 @@ import { t } from '../../../i18n/index.js';
|
|||||||
import { vRangeValue } from '../../rail/rangeValue.js';
|
import { vRangeValue } from '../../rail/rangeValue.js';
|
||||||
import { useDisplayStore } from '../../stores/display.js';
|
import { useDisplayStore } from '../../stores/display.js';
|
||||||
|
|
||||||
// The Display panel. VisualSettings presents bloom, sharpen and detection
|
// The Display panel. VisualSettings presents the HUD, Sonar, detection,
|
||||||
// and publishes them; until it does, the panel shows its initial markup.
|
// bloom and sharpen and publishes them; until it does, the panel shows its
|
||||||
// The other groups keep their owners' element bindings.
|
// initial markup. The other groups keep their owners' element bindings.
|
||||||
const { view } = storeToRefs(useDisplayStore());
|
const { view } = storeToRefs(useDisplayStore());
|
||||||
const pct = (value) => `${value}%`;
|
const pct = (value) => `${value}%`;
|
||||||
|
const hud = computed(() => view.value?.hud ?? null);
|
||||||
|
const sonar = computed(() => view.value?.sonar ?? null);
|
||||||
|
const sonarOn = computed(() => sonar.value?.enabled ?? true);
|
||||||
const detection = computed(() => view.value?.detection ?? null);
|
const detection = computed(() => view.value?.detection ?? null);
|
||||||
const detectButton = computed(() => detection.value?.button ?? null);
|
const detectButton = computed(() => detection.value?.button ?? null);
|
||||||
const allocation = computed(() => detection.value?.allocation ?? 'ELASTIC');
|
const allocation = computed(() => detection.value?.allocation ?? 'ELASTIC');
|
||||||
@@ -29,13 +32,13 @@ const allocationSegment = (value) => ({
|
|||||||
</div>
|
</div>
|
||||||
<div class="pp-panel-body" data-rail-scroller>
|
<div class="pp-panel-body" data-rail-scroller>
|
||||||
<div class="pp-toggle-group">
|
<div class="pp-toggle-group">
|
||||||
<button class="pp-toggle-btn" id="hud-toggle" title="Intelligence HUD (H)" data-i18n-title>
|
<button class="pp-toggle-btn" :class="{ active: hud?.visible }" id="hud-toggle" title="Intelligence HUD (H)" data-i18n-title>
|
||||||
<span class="pp-icon">◎</span>
|
<span class="pp-icon">◎</span>
|
||||||
<span class="pp-label" translate="no">HUD</span>
|
<span class="pp-label" translate="no">HUD</span>
|
||||||
</button>
|
</button>
|
||||||
<div class="pp-slider-row" id="hud-layout-row">
|
<div class="pp-slider-row" :class="{ visible: hud?.visible }" id="hud-layout-row">
|
||||||
<span class="pp-slider-mini-label" data-i18n>Layout</span>
|
<span class="pp-slider-mini-label" data-i18n>Layout</span>
|
||||||
<select id="hud-layout-select" class="pp-select gev-field gev-field--compact" aria-label="HUD layout" data-i18n-aria-label>
|
<select id="hud-layout-select" class="pp-select gev-field gev-field--compact" v-range-value="hud?.variant ?? 'tactical'" aria-label="HUD layout" data-i18n-aria-label>
|
||||||
<option value="tactical" data-i18n>Tactical</option>
|
<option value="tactical" data-i18n>Tactical</option>
|
||||||
<option value="minimal" data-i18n>Minimal</option>
|
<option value="minimal" data-i18n>Minimal</option>
|
||||||
<option value="cyber" data-i18n>Cyber</option>
|
<option value="cyber" data-i18n>Cyber</option>
|
||||||
@@ -43,33 +46,33 @@ const allocationSegment = (value) => ({
|
|||||||
</div>
|
</div>
|
||||||
<div class="pp-slider-row cyber-sonar-control cyber-sonar-toggle-row" id="cyber-sonar-row">
|
<div class="pp-slider-row cyber-sonar-control cyber-sonar-toggle-row" id="cyber-sonar-row">
|
||||||
<span class="pp-slider-mini-label" data-i18n>Sonar</span>
|
<span class="pp-slider-mini-label" data-i18n>Sonar</span>
|
||||||
<button class="pp-mode-btn active" id="cyber-sonar-toggle" title="Cyber sonar contact scanner" aria-label="Cyber sonar contact scanner" aria-pressed="true" data-i18n-title data-i18n-aria-label data-i18n>ON</button>
|
<button class="pp-mode-btn" :class="{ active: sonarOn }" id="cyber-sonar-toggle" title="Cyber sonar contact scanner" aria-label="Cyber sonar contact scanner" :aria-pressed="String(sonarOn)" data-i18n-title data-i18n-aria-label>{{ sonarOn ? t('ON') : t('OFF') }}</button>
|
||||||
</div>
|
</div>
|
||||||
<output id="cyber-sonar-status" class="cyber-sonar-control" role="status"></output>
|
<output id="cyber-sonar-status" class="cyber-sonar-control" role="status"></output>
|
||||||
<div class="pp-slider-row cyber-sonar-control cyber-sonar-setting" id="cyber-sonar-rings-row">
|
<div class="pp-slider-row cyber-sonar-control cyber-sonar-setting" id="cyber-sonar-rings-row">
|
||||||
<label class="pp-slider-mini-label" for="cyber-sonar-rings" data-i18n>Rings</label>
|
<label class="pp-slider-mini-label" for="cyber-sonar-rings" data-i18n>Rings</label>
|
||||||
<input type="range" class="gev-quantitative-slider pp-slider" id="cyber-sonar-rings" min="3" max="12" step="1" value="8" aria-label="Sonar ring count" data-i18n-aria-label />
|
<input type="range" class="gev-quantitative-slider pp-slider" id="cyber-sonar-rings" min="3" max="12" step="1" value="8" v-range-value="sonar?.rings ?? 8" aria-label="Sonar ring count" data-i18n-aria-label />
|
||||||
<span class="pp-slider-value" id="cyber-sonar-rings-value">8</span>
|
<span class="pp-slider-value" id="cyber-sonar-rings-value">{{ sonar?.rings ?? 8 }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="pp-slider-row cyber-sonar-control cyber-sonar-setting" id="cyber-sonar-range-row">
|
<div class="pp-slider-row cyber-sonar-control cyber-sonar-setting" id="cyber-sonar-range-row">
|
||||||
<label class="pp-slider-mini-label" for="cyber-sonar-range" data-i18n>Range</label>
|
<label class="pp-slider-mini-label" for="cyber-sonar-range" data-i18n>Range</label>
|
||||||
<input type="range" class="gev-quantitative-slider pp-slider" id="cyber-sonar-range" min="60" max="120" step="1" value="100" aria-label="Sonar ring range" data-i18n-aria-label />
|
<input type="range" class="gev-quantitative-slider pp-slider" id="cyber-sonar-range" min="60" max="120" step="1" value="100" v-range-value="sonar?.range ?? 100" aria-label="Sonar ring range" data-i18n-aria-label />
|
||||||
<span class="pp-slider-value" id="cyber-sonar-range-value">100%</span>
|
<span class="pp-slider-value" id="cyber-sonar-range-value">{{ pct(sonar?.range ?? 100) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="pp-slider-row cyber-sonar-control cyber-sonar-setting" id="cyber-sonar-intensity-row">
|
<div class="pp-slider-row cyber-sonar-control cyber-sonar-setting" id="cyber-sonar-intensity-row">
|
||||||
<label class="pp-slider-mini-label" for="cyber-sonar-intensity" data-i18n>Power</label>
|
<label class="pp-slider-mini-label" for="cyber-sonar-intensity" data-i18n>Power</label>
|
||||||
<input type="range" class="gev-quantitative-slider pp-slider" id="cyber-sonar-intensity" min="0" max="100" step="1" value="70" aria-label="Sonar intensity" data-i18n-aria-label />
|
<input type="range" class="gev-quantitative-slider pp-slider" id="cyber-sonar-intensity" min="0" max="100" step="1" value="70" v-range-value="sonar?.intensity ?? 70" aria-label="Sonar intensity" data-i18n-aria-label />
|
||||||
<span class="pp-slider-value" id="cyber-sonar-intensity-value">70%</span>
|
<span class="pp-slider-value" id="cyber-sonar-intensity-value">{{ pct(sonar?.intensity ?? 70) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="pp-slider-row cyber-sonar-control cyber-sonar-setting" id="cyber-sonar-opacity-row">
|
<div class="pp-slider-row cyber-sonar-control cyber-sonar-setting" id="cyber-sonar-opacity-row">
|
||||||
<label class="pp-slider-mini-label" for="cyber-sonar-opacity" data-i18n>Opacity</label>
|
<label class="pp-slider-mini-label" for="cyber-sonar-opacity" data-i18n>Opacity</label>
|
||||||
<input type="range" class="gev-quantitative-slider pp-slider" id="cyber-sonar-opacity" min="35" max="100" step="1" value="84" aria-label="Cyber contact and label opacity" title="Minimum opacity for map dots, icons, models, brackets, and labels between sonar passes" data-i18n-aria-label data-i18n-title />
|
<input type="range" class="gev-quantitative-slider pp-slider" id="cyber-sonar-opacity" min="35" max="100" step="1" value="84" v-range-value="sonar?.opacity ?? 84" aria-label="Cyber contact and label opacity" title="Minimum opacity for map dots, icons, models, brackets, and labels between sonar passes" data-i18n-aria-label data-i18n-title />
|
||||||
<span class="pp-slider-value" id="cyber-sonar-opacity-value">84%</span>
|
<span class="pp-slider-value" id="cyber-sonar-opacity-value">{{ pct(sonar?.opacity ?? 84) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="pp-slider-row cyber-sonar-control cyber-sonar-setting" id="cyber-sonar-sector-row">
|
<div class="pp-slider-row cyber-sonar-control cyber-sonar-setting" id="cyber-sonar-sector-row">
|
||||||
<label class="pp-slider-mini-label" for="cyber-sonar-sector" data-i18n>Sector</label>
|
<label class="pp-slider-mini-label" for="cyber-sonar-sector" data-i18n>Sector</label>
|
||||||
<input type="range" class="gev-quantitative-slider pp-slider" id="cyber-sonar-sector" min="8" max="60" step="1" value="24" aria-label="Sonar sector width" data-i18n-aria-label />
|
<input type="range" class="gev-quantitative-slider pp-slider" id="cyber-sonar-sector" min="8" max="60" step="1" value="24" v-range-value="sonar?.sector ?? 24" aria-label="Sonar sector width" data-i18n-aria-label />
|
||||||
<span class="pp-slider-value" id="cyber-sonar-sector-value">24°</span>
|
<span class="pp-slider-value" id="cyber-sonar-sector-value">{{ `${sonar?.sector ?? 24}°` }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="pp-toggle-group">
|
<div class="pp-toggle-group">
|
||||||
|
|||||||
+28
-36
@@ -213,6 +213,11 @@ export class VisualSettings {
|
|||||||
this._detectionOutsidePct = 1;
|
this._detectionOutsidePct = 1;
|
||||||
this._detectionModeLabel = null;
|
this._detectionModeLabel = null;
|
||||||
this._detectionAllocationShown = null;
|
this._detectionAllocationShown = null;
|
||||||
|
// What the HUD and Sonar controls show; null until first synced, so the
|
||||||
|
// initial markup stands.
|
||||||
|
this._hudVisibleShown = null;
|
||||||
|
this._hudVariantShown = null;
|
||||||
|
this._sonarShown = null;
|
||||||
this.activeStyle = 'normal';
|
this.activeStyle = 'normal';
|
||||||
this._preCyberStyle = null;
|
this._preCyberStyle = null;
|
||||||
this._cyberStyleUserSelected = false;
|
this._cyberStyleUserSelected = false;
|
||||||
@@ -476,6 +481,8 @@ export class VisualSettings {
|
|||||||
bloom: { active: this.bloomEnabled, intensity: this.bloomIntensityPct },
|
bloom: { active: this.bloomEnabled, intensity: this.bloomIntensityPct },
|
||||||
sharpen: { active: this.sharpenEnabled, intensity: this._sharpenPct },
|
sharpen: { active: this.sharpenEnabled, intensity: this._sharpenPct },
|
||||||
detection: this._presentDetection(),
|
detection: this._presentDetection(),
|
||||||
|
hud: { visible: this._hudVisibleShown, variant: this._hudVariantShown },
|
||||||
|
sonar: this._sonarShown,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -666,9 +673,8 @@ export class VisualSettings {
|
|||||||
this._preCyberStyle = this.activeStyle;
|
this._preCyberStyle = this.activeStyle;
|
||||||
this._cyberStyleUserSelected = false;
|
this._cyberStyleUserSelected = false;
|
||||||
}
|
}
|
||||||
if (this._hudLayoutSelect && this._hudLayoutSelect.value !== nextVariant) {
|
this._hudVariantShown = nextVariant;
|
||||||
this._hudLayoutSelect.value = nextVariant;
|
this._publishDisplay();
|
||||||
}
|
|
||||||
const visualDefaults = cyberVisualDefaultsForHudTransition(
|
const visualDefaults = cyberVisualDefaultsForHudTransition(
|
||||||
previousVariant,
|
previousVariant,
|
||||||
nextVariant,
|
nextVariant,
|
||||||
@@ -709,37 +715,16 @@ export class VisualSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_syncCyberSonarControl() {
|
_syncCyberSonarControl() {
|
||||||
if (!this._cyberSonarBtn) return;
|
|
||||||
const enabled = isCyberSonarEnabled();
|
|
||||||
const settings = applyCyberSonarSettings(readCyberSonarSettings());
|
const settings = applyCyberSonarSettings(readCyberSonarSettings());
|
||||||
this._cyberSonarBtn.classList.toggle('active', enabled);
|
this._sonarShown = {
|
||||||
this._cyberSonarBtn.setAttribute('aria-pressed', String(enabled));
|
enabled: isCyberSonarEnabled(),
|
||||||
this._cyberSonarBtn.textContent = enabled ? t('ON') : t('OFF');
|
rings: settings.rings,
|
||||||
for (const [input, output, value, suffix] of [
|
range: settings.range,
|
||||||
[this._cyberSonarRings, this._cyberSonarRingsValue, settings.rings, ''],
|
intensity: settings.intensity,
|
||||||
[this._cyberSonarRange, this._cyberSonarRangeValue, settings.range, '%'],
|
opacity: settings.opacity,
|
||||||
[
|
sector: settings.sector,
|
||||||
this._cyberSonarIntensity,
|
};
|
||||||
this._cyberSonarIntensityValue,
|
this._publishDisplay();
|
||||||
settings.intensity,
|
|
||||||
'%',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
this._cyberSonarOpacity,
|
|
||||||
this._cyberSonarOpacityValue,
|
|
||||||
settings.opacity,
|
|
||||||
'%',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
this._cyberSonarSector,
|
|
||||||
this._cyberSonarSectorValue,
|
|
||||||
settings.sector,
|
|
||||||
'°',
|
|
||||||
],
|
|
||||||
]) {
|
|
||||||
if (input) input.value = String(value);
|
|
||||||
if (output) output.textContent = `${value}${suffix}`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_setCyberSonarEnabled(enabled = !isCyberSonarEnabled()) {
|
_setCyberSonarEnabled(enabled = !isCyberSonarEnabled()) {
|
||||||
@@ -1587,10 +1572,17 @@ export class VisualSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_updateHudButtonState() {
|
_updateHudButtonState() {
|
||||||
this._hudBtn.classList.toggle('active', this.hud.visible);
|
this._syncHudControls();
|
||||||
if (this._hudLayoutRow) {
|
|
||||||
this._hudLayoutRow.classList.toggle('visible', this.hud.visible);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the HUD's current visibility and layout on its controls; the layout
|
||||||
|
* row's visibility changes the panel's height, so the rails settle again.
|
||||||
|
*/
|
||||||
|
_syncHudControls() {
|
||||||
|
this._hudVisibleShown = Boolean(this.hud.visible);
|
||||||
|
this._hudVariantShown = this.hud.getVariant();
|
||||||
|
this._publishDisplay();
|
||||||
this._scheduleAdaptivePanelLayout({ settle: true });
|
this._scheduleAdaptivePanelLayout({ settle: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user