mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-15 07:42:23 +00:00
Keep Scope opacity at half or more, and ignore a value that is not a number
A fainter mask reads as Scope off while labels still fade outside the keyhole and the HUD gets no backplates. Co-authored-by: Manjunath Paparaju <[email protected]>
This commit is contained in:
1 parent
a1e7b2a394
commit
2fd8d32a5d
7 files changed
+106
-42
No files matched your search
@@ -253,7 +253,7 @@ test('detection-on-by-default is a default, not an operator override', () => {
|
|||||||
// A factory default is not that. If applying the baseline set the flag, a
|
// A factory default is not that. If applying the baseline set the flag, a
|
||||||
// fresh session would silently lose the style auto-enable behaviour — a
|
// fresh session would silently lose the style auto-enable behaviour — a
|
||||||
// separate landed feature, taken out by an unrelated change.
|
// separate landed feature, taken out by an unrelated change.
|
||||||
const applyDefaults = uiBlock(' _applyGlobalPostDefaults() {', '\n }\n');
|
const applyDefaults = uiBlock(' _applyGlobalPostDefaults({ keepHudVariant = false } = {}) {', '\n }\n');
|
||||||
assert.match(applyDefaults, /this\._setDetectionMode\(defaults\.detectionMode\)/,
|
assert.match(applyDefaults, /this\._setDetectionMode\(defaults\.detectionMode\)/,
|
||||||
'the baseline still goes through the real detection path');
|
'the baseline still goes through the real detection path');
|
||||||
assert.doesNotMatch(applyDefaults, /_detectionUserOverridden/,
|
assert.doesNotMatch(applyDefaults, /_detectionUserOverridden/,
|
||||||
|
|||||||
@@ -316,13 +316,13 @@ test('a shared scope opacity is restored and rides in the next share state', asy
|
|||||||
});
|
});
|
||||||
let shown = null;
|
let shown = null;
|
||||||
owner.store = { publish: (view) => (shown = view.scope) };
|
owner.store = { publish: (view) => (shown = view.scope) };
|
||||||
await owner.restoreShareState({ scopeOpacityPct: 40 });
|
await owner.restoreShareState({ scopeOpacityPct: 60 });
|
||||||
assert.equal(getScopeMaskOpacity(), 0.4);
|
assert.equal(getScopeMaskOpacity(), 0.6);
|
||||||
assert.equal(shown.opacityPct, 40);
|
assert.equal(shown.opacityPct, 60);
|
||||||
// A state without it leaves the opacity alone.
|
// A state without it leaves the opacity alone.
|
||||||
await owner.restoreShareState({ scopeFeatherPct: 80 });
|
await owner.restoreShareState({ scopeFeatherPct: 80 });
|
||||||
assert.equal(getScopeMaskOpacity(), 0.4);
|
assert.equal(getScopeMaskOpacity(), 0.6);
|
||||||
assert.equal(shown.opacityPct, 40);
|
assert.equal(shown.opacityPct, 60);
|
||||||
Object.assign(owner.services, {
|
Object.assign(owner.services, {
|
||||||
getDetectionTuning: () => ({ allocationStrategy: 'ELASTIC' }),
|
getDetectionTuning: () => ({ allocationStrategy: 'ELASTIC' }),
|
||||||
getDetectionMode: () => 'OFF',
|
getDetectionMode: () => 'OFF',
|
||||||
@@ -332,7 +332,11 @@ test('a shared scope opacity is restored and rides in the next share state', asy
|
|||||||
getScopeTerminusOverride: () => null,
|
getScopeTerminusOverride: () => null,
|
||||||
});
|
});
|
||||||
owner.readCelestialRing = () => null;
|
owner.readCelestialRing = () => null;
|
||||||
assert.equal(owner._readShareState().options.scopeOpacityPct, 40);
|
assert.equal(owner._readShareState().options.scopeOpacityPct, 60);
|
||||||
|
// A link asking for less than the floor opens at the floor, and says so.
|
||||||
|
await owner.restoreShareState({ scopeOpacityPct: 20 });
|
||||||
|
assert.equal(getScopeMaskOpacity(), 0.5);
|
||||||
|
assert.equal(owner._readShareState().options.scopeOpacityPct, 50);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('a scene shot saved with the retired Snow style plays on Normal', async (t) => {
|
test('a scene shot saved with the retired Snow style plays on Normal', async (t) => {
|
||||||
|
|||||||
@@ -179,7 +179,9 @@ export class DisplayBindings {
|
|||||||
resetVisual: () => {
|
resetVisual: () => {
|
||||||
this.shareLinkManager?.claimRestoreLane?.('visual');
|
this.shareLinkManager?.claimRestoreLane?.('visual');
|
||||||
this.setStyle('normal', { userInitiated: true });
|
this.setStyle('normal', { userInitiated: true });
|
||||||
this._applyGlobalPostDefaults();
|
// The HUD layout follows the Normal style, as choosing it does: the
|
||||||
|
// Cyber HUD stays Cyber.
|
||||||
|
this._applyGlobalPostDefaults({ keepHudVariant: true });
|
||||||
this._setDetectionAllocation('ELASTIC');
|
this._setDetectionAllocation('ELASTIC');
|
||||||
this._setScope({ enabled: true, featherPct: 100, opacityPct: 100 });
|
this._setScope({ enabled: true, featherPct: 100, opacityPct: 100 });
|
||||||
this._setModels3dEnabled(true);
|
this._setModels3dEnabled(true);
|
||||||
|
|||||||
@@ -108,7 +108,11 @@ test('bloom and sharpen render their state, slider and readout', async (t) => {
|
|||||||
await nextTick();
|
await nextTick();
|
||||||
assert.equal($('bloom-toggle').classList.contains('active'), false);
|
assert.equal($('bloom-toggle').classList.contains('active'), false);
|
||||||
assert.equal($('bloom-slider-row').classList.contains('visible'), false);
|
assert.equal($('bloom-slider-row').classList.contains('visible'), false);
|
||||||
assert.equal($('bloom-intensity-value').textContent, '140%', 'the amount stays');
|
assert.equal(
|
||||||
|
$('bloom-intensity-value').textContent,
|
||||||
|
'140%',
|
||||||
|
'the amount stays',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('a publish never rewrites a slider the user is dragging', async (t) => {
|
test('a publish never rewrites a slider the user is dragging', async (t) => {
|
||||||
@@ -326,36 +330,50 @@ test('scope opacity renders what VisualSettings shows and sets the mask', async
|
|||||||
assert.equal($('scope-opacity-slider').value, '100');
|
assert.equal($('scope-opacity-slider').value, '100');
|
||||||
assert.equal($('scope-opacity-value').textContent, '100%');
|
assert.equal($('scope-opacity-value').textContent, '100%');
|
||||||
|
|
||||||
owner._setScope({ opacityPct: 42.4 });
|
owner._setScope({ opacityPct: 62.4 });
|
||||||
await nextTick();
|
await nextTick();
|
||||||
assert.equal(mask.opacity, 0.42);
|
assert.equal(mask.opacity, 0.62);
|
||||||
assert.equal($('scope-opacity-slider').value, '42');
|
assert.equal($('scope-opacity-slider').value, '62');
|
||||||
assert.equal($('scope-opacity-value').textContent, '42%');
|
assert.equal($('scope-opacity-value').textContent, '62%');
|
||||||
assert.equal(store.view.scope.opacityPct, 42);
|
assert.equal(store.view.scope.opacityPct, 62);
|
||||||
|
|
||||||
|
// No fainter than the floor, where the view would read as Scope off.
|
||||||
|
owner._setScope({ opacityPct: 10 });
|
||||||
|
await nextTick();
|
||||||
|
assert.equal(mask.opacity, 0.5, 'floored');
|
||||||
|
assert.equal($('scope-opacity-value').textContent, '50%');
|
||||||
|
assert.equal($('scope-opacity-slider').min, '50');
|
||||||
|
|
||||||
|
// A value that is not a number changes nothing.
|
||||||
|
owner._setScope({ opacityPct: Number.NaN });
|
||||||
|
await nextTick();
|
||||||
|
assert.equal($('scope-opacity-value').textContent, '50%');
|
||||||
|
|
||||||
owner._setScope({ opacityPct: 180 });
|
owner._setScope({ opacityPct: 180 });
|
||||||
await nextTick();
|
await nextTick();
|
||||||
assert.equal(mask.opacity, 1, 'clamped');
|
assert.equal(mask.opacity, 1, 'clamped');
|
||||||
assert.equal($('scope-opacity-value').textContent, '100%');
|
assert.equal($('scope-opacity-value').textContent, '100%');
|
||||||
|
|
||||||
owner._setScope({ opacityPct: 30 }, { apply: false });
|
owner._setScope({ opacityPct: 70 }, { apply: false });
|
||||||
await nextTick();
|
await nextTick();
|
||||||
assert.equal(mask.opacity, 1, 'only shown');
|
assert.equal(mask.opacity, 1, 'only shown');
|
||||||
assert.equal($('scope-opacity-value').textContent, '30%');
|
assert.equal($('scope-opacity-value').textContent, '70%');
|
||||||
|
|
||||||
owner._setScope({ enabled: false });
|
owner._setScope({ enabled: false });
|
||||||
await nextTick();
|
await nextTick();
|
||||||
assert.equal($('scope-opacity-slider').disabled, true, 'off with the scope');
|
assert.equal($('scope-opacity-slider').disabled, true, 'off with the scope');
|
||||||
assert.equal(store.view.scope.opacityPct, 30, 'kept while off');
|
assert.equal(store.view.scope.opacityPct, 70, 'kept while off');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('the Visual panel groups its controls and words its on/off pills', (t) => {
|
test('the Visual panel groups its controls and words its on/off pills', (t) => {
|
||||||
const { $ } = fixture(t);
|
const { $ } = fixture(t);
|
||||||
const panel = $('pp-toggles');
|
const panel = $('pp-toggles');
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
[...panel.querySelectorAll('.pp-section-heading, .visual-presets__heading')].map(
|
[
|
||||||
(el) => el.textContent.trim(),
|
...panel.querySelectorAll(
|
||||||
),
|
'.pp-section-heading, .visual-presets__heading',
|
||||||
|
),
|
||||||
|
].map((el) => el.textContent.trim()),
|
||||||
['Look', 'MAP SOURCE 3D', 'Overlay', 'Effects'],
|
['Look', 'MAP SOURCE 3D', 'Overlay', 'Effects'],
|
||||||
);
|
);
|
||||||
assert.equal(panel.querySelector('.pp-header-label').textContent, 'VISUAL');
|
assert.equal(panel.querySelector('.pp-header-label').textContent, 'VISUAL');
|
||||||
@@ -384,7 +402,10 @@ test('the 3D aircraft group renders what AircraftDisplay shows', async (t) => {
|
|||||||
assert.equal(coreClasses(button), 'pp-toggle-btn active');
|
assert.equal(coreClasses(button), 'pp-toggle-btn active');
|
||||||
assert.equal(button.getAttribute('aria-pressed'), 'true');
|
assert.equal(button.getAttribute('aria-pressed'), 'true');
|
||||||
assert.equal(row.classList.contains('visible'), true);
|
assert.equal(row.classList.contains('visible'), true);
|
||||||
assert.equal($('models3d-mode-proximity').getAttribute('aria-checked'), 'true');
|
assert.equal(
|
||||||
|
$('models3d-mode-proximity').getAttribute('aria-checked'),
|
||||||
|
'true',
|
||||||
|
);
|
||||||
|
|
||||||
// The button leaves the row to its own sync.
|
// The button leaves the row to its own sync.
|
||||||
owner._setModels3dEnabled(false);
|
owner._setModels3dEnabled(false);
|
||||||
@@ -400,7 +421,10 @@ test('the 3D aircraft group renders what AircraftDisplay shows', async (t) => {
|
|||||||
await nextTick();
|
await nextTick();
|
||||||
assert.equal(all.classList.contains('active'), true);
|
assert.equal(all.classList.contains('active'), true);
|
||||||
assert.equal(all.getAttribute('aria-checked'), 'true');
|
assert.equal(all.getAttribute('aria-checked'), 'true');
|
||||||
assert.equal($('models3d-mode-proximity').classList.contains('active'), false);
|
assert.equal(
|
||||||
|
$('models3d-mode-proximity').classList.contains('active'),
|
||||||
|
false,
|
||||||
|
);
|
||||||
assert.deepEqual(params.at(-1), ['military', { models3dMode: 'all' }]);
|
assert.deepEqual(params.at(-1), ['military', { models3dMode: 'all' }]);
|
||||||
|
|
||||||
owner._syncModels3dFromLayerState({
|
owner._syncModels3dFromLayerState({
|
||||||
@@ -429,12 +453,18 @@ test('the Draw controls render what the draw tool publishes', async (t) => {
|
|||||||
assert.equal(segment('area').getAttribute('aria-label'), 'Area');
|
assert.equal(segment('area').getAttribute('aria-label'), 'Area');
|
||||||
assert.equal(segment('area').title, 'Area');
|
assert.equal(segment('area').title, 'Area');
|
||||||
assert.equal(segment('area').textContent, 'pentagon');
|
assert.equal(segment('area').textContent, 'pentagon');
|
||||||
const swatch = (color) => document.querySelector(`#draw-colors [data-color="${color}"]`);
|
const swatch = (color) =>
|
||||||
|
document.querySelector(`#draw-colors [data-color="${color}"]`);
|
||||||
assert.equal(swatch('primary').getAttribute('aria-checked'), 'true');
|
assert.equal(swatch('primary').getAttribute('aria-checked'), 'true');
|
||||||
assert.equal(swatch('amber').getAttribute('aria-label'), 'Amber');
|
assert.equal(swatch('amber').getAttribute('aria-label'), 'Amber');
|
||||||
assert.equal($('draw-hint').textContent, '');
|
assert.equal($('draw-hint').textContent, '');
|
||||||
|
|
||||||
store.publishDraw({ active: true, shape: 'line', color: 'amber', hint: 'Click to add points.' });
|
store.publishDraw({
|
||||||
|
active: true,
|
||||||
|
shape: 'line',
|
||||||
|
color: 'amber',
|
||||||
|
hint: 'Click to add points.',
|
||||||
|
});
|
||||||
await nextTick();
|
await nextTick();
|
||||||
assert.equal(swatch('amber').getAttribute('aria-checked'), 'true');
|
assert.equal(swatch('amber').getAttribute('aria-checked'), 'true');
|
||||||
assert.equal(swatch('primary').classList.contains('active'), false);
|
assert.equal(swatch('primary').classList.contains('active'), false);
|
||||||
@@ -530,7 +560,10 @@ test('the imported files render what the file import publishes and keep focus',
|
|||||||
assert.equal(document.activeElement === button(first, 'toggle'), true);
|
assert.equal(document.activeElement === button(first, 'toggle'), true);
|
||||||
assert.equal(button(first, 'toggle').getAttribute('aria-pressed'), 'true');
|
assert.equal(button(first, 'toggle').getAttribute('aria-pressed'), 'true');
|
||||||
assert.equal(button(first, 'fly').title, 'Fly to <b>a</b>.geojson');
|
assert.equal(button(first, 'fly').title, 'Fly to <b>a</b>.geojson');
|
||||||
assert.equal(button(first, 'remove').getAttribute('aria-label'), 'Remove <b>a</b>.geojson');
|
assert.equal(
|
||||||
|
button(first, 'remove').getAttribute('aria-label'),
|
||||||
|
'Remove <b>a</b>.geojson',
|
||||||
|
);
|
||||||
|
|
||||||
await press(button(first, 'remove'));
|
await press(button(first, 'remove'));
|
||||||
assert.equal(rowsNow().length, 1);
|
assert.equal(rowsNow().length, 1);
|
||||||
@@ -646,7 +679,11 @@ test('VisualSettings publishes a style’s parameters and writes a moved slider
|
|||||||
assert.equal(store.parameters, null, 'the sliders go with their owner');
|
assert.equal(store.parameters, null, 'the sliders go with their owner');
|
||||||
assert.equal($('param-slider-panel').classList.contains('active'), false);
|
assert.equal($('param-slider-panel').classList.contains('active'), false);
|
||||||
assert.equal(store.act('setStyleParameter', 'grainAmt', 0.2), undefined);
|
assert.equal(store.act('setStyleParameter', 'grainAmt', 0.2), undefined);
|
||||||
assert.equal(owner.stages.noir.uniforms.grainAmt, 0.3, 'a stopped owner no longer answers');
|
assert.equal(
|
||||||
|
owner.stages.noir.uniforms.grainAmt,
|
||||||
|
0.3,
|
||||||
|
'a stopped owner no longer answers',
|
||||||
|
);
|
||||||
// An older owner's stop leaves a newer owner's rows.
|
// An older owner's stop leaves a newer owner's rows.
|
||||||
const newer = { style: 'noir', rows: [] };
|
const newer = { style: 'noir', rows: [] };
|
||||||
owner._parameters = { style: 'noir', rows: [] };
|
owner._parameters = { style: 'noir', rows: [] };
|
||||||
@@ -658,10 +695,16 @@ test('VisualSettings publishes a style’s parameters and writes a moved slider
|
|||||||
test('the four Cockpit groups teleport to the published slots and back to their places', async (t) => {
|
test('the four Cockpit groups teleport to the published slots and back to their places', async (t) => {
|
||||||
const { store, $ } = fixture(t);
|
const { store, $ } = fixture(t);
|
||||||
const groupOf = (id) => $(id).closest('.pp-toggle-group') ?? $(id);
|
const groupOf = (id) => $(id).closest('.pp-toggle-group') ?? $(id);
|
||||||
const ids = ['hud-toggle', 'detection-toggle', 'param-slider-panel', 'models3d-toggle'];
|
const ids = [
|
||||||
|
'hud-toggle',
|
||||||
|
'detection-toggle',
|
||||||
|
'param-slider-panel',
|
||||||
|
'models3d-toggle',
|
||||||
|
];
|
||||||
const body = $('pp-toggles').querySelector('.pp-panel-body');
|
const body = $('pp-toggles').querySelector('.pp-panel-body');
|
||||||
const order = () =>
|
const order = () =>
|
||||||
[...body.children].filter((el) => el.matches('.pp-toggle-group, #param-slider-panel'))
|
[...body.children]
|
||||||
|
.filter((el) => el.matches('.pp-toggle-group, #param-slider-panel'))
|
||||||
.map((el) => el.id || el.querySelector('[id]')?.id);
|
.map((el) => el.id || el.querySelector('[id]')?.id);
|
||||||
const home = order();
|
const home = order();
|
||||||
const popover = document.body.appendChild(document.createElement('div'));
|
const popover = document.body.appendChild(document.createElement('div'));
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ test('the Visual panel’s scope opacity, reset and presets call their actions',
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
await nextTick();
|
await nextTick();
|
||||||
input($('scope-opacity-slider'), 40);
|
input($('scope-opacity-slider'), 60);
|
||||||
document.querySelector('#pp-toggles .pp-reset-btn').click();
|
document.querySelector('#pp-toggles .pp-reset-btn').click();
|
||||||
const presets = document.querySelector('#pp-toggles .visual-presets');
|
const presets = document.querySelector('#pp-toggles .visual-presets');
|
||||||
presets.querySelector('[data-style="noir"]').click();
|
presets.querySelector('[data-style="noir"]').click();
|
||||||
@@ -254,7 +254,7 @@ test('the Visual panel’s scope opacity, reset and presets call their actions',
|
|||||||
chips[0].click();
|
chips[0].click();
|
||||||
chips[1].click();
|
chips[1].click();
|
||||||
assert.deepEqual(calls, [
|
assert.deepEqual(calls, [
|
||||||
['setScopeOpacity', 40],
|
['setScopeOpacity', 60],
|
||||||
['resetVisual'],
|
['resetVisual'],
|
||||||
['setStyle', 'noir'],
|
['setStyle', 'noir'],
|
||||||
]);
|
]);
|
||||||
@@ -290,7 +290,8 @@ test('DisplayBindings sets the scope opacity and resets Visual to its defaults',
|
|||||||
elements: { _locationSearch: document.createElement('input') },
|
elements: { _locationSearch: document.createElement('input') },
|
||||||
operations: {
|
operations: {
|
||||||
setStyle: (style, options) => calls.push(['style', style, options]),
|
setStyle: (style, options) => calls.push(['style', style, options]),
|
||||||
_applyGlobalPostDefaults: () => calls.push(['postDefaults']),
|
_applyGlobalPostDefaults: (options) =>
|
||||||
|
calls.push(['postDefaults', options]),
|
||||||
_setDetectionAllocation: (value) => calls.push(['allocation', value]),
|
_setDetectionAllocation: (value) => calls.push(['allocation', value]),
|
||||||
_setScope: (scope) => calls.push(['scope', scope]),
|
_setScope: (scope) => calls.push(['scope', scope]),
|
||||||
_setModels3dEnabled: (on) => calls.push(['models3d', on]),
|
_setModels3dEnabled: (on) => calls.push(['models3d', on]),
|
||||||
@@ -310,10 +311,10 @@ test('DisplayBindings sets the scope opacity and resets Visual to its defaults',
|
|||||||
bindings._initUI();
|
bindings._initUI();
|
||||||
t.after(() => bindings.destroy());
|
t.after(() => bindings.destroy());
|
||||||
calls.length = 0;
|
calls.length = 0;
|
||||||
input($('scope-opacity-slider'), 35);
|
input($('scope-opacity-slider'), 65);
|
||||||
assert.deepEqual(calls, [
|
assert.deepEqual(calls, [
|
||||||
['claim', 'visual'],
|
['claim', 'visual'],
|
||||||
['scope', { opacityPct: 35 }],
|
['scope', { opacityPct: 65 }],
|
||||||
['share'],
|
['share'],
|
||||||
]);
|
]);
|
||||||
calls.length = 0;
|
calls.length = 0;
|
||||||
@@ -321,7 +322,7 @@ test('DisplayBindings sets the scope opacity and resets Visual to its defaults',
|
|||||||
assert.deepEqual(calls, [
|
assert.deepEqual(calls, [
|
||||||
['claim', 'visual'],
|
['claim', 'visual'],
|
||||||
['style', 'normal', { userInitiated: true }],
|
['style', 'normal', { userInitiated: true }],
|
||||||
['postDefaults'],
|
['postDefaults', { keepHudVariant: true }],
|
||||||
['allocation', 'ELASTIC'],
|
['allocation', 'ELASTIC'],
|
||||||
['scope', { enabled: true, featherPct: 100, opacityPct: 100 }],
|
['scope', { enabled: true, featherPct: 100, opacityPct: 100 }],
|
||||||
['models3d', true],
|
['models3d', true],
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ const allocationOptions = computed(() => [
|
|||||||
<p class="pp-section-heading">{{ t('Overlay') }}</p>
|
<p class="pp-section-heading">{{ t('Overlay') }}</p>
|
||||||
<Teleport :to="cockpitPortal?.hud ?? 'body'" :disabled="!cockpitPortal?.hud">
|
<Teleport :to="cockpitPortal?.hud ?? 'body'" :disabled="!cockpitPortal?.hud">
|
||||||
<div class="pp-toggle-group">
|
<div class="pp-toggle-group">
|
||||||
<button class="pp-toggle-btn" :class="{ active: hud?.visible }" id="hud-toggle" @click="act('toggleHud')" :title="t('Intelligence HUD (H)')">
|
<button class="pp-toggle-btn" :class="{ active: hud?.visible }" :aria-pressed="String(Boolean(hud?.visible))" id="hud-toggle" @click="act('toggleHud')" :title="t('Intelligence HUD (H)')">
|
||||||
<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>
|
||||||
@@ -182,7 +182,7 @@ const allocationOptions = computed(() => [
|
|||||||
</div>
|
</div>
|
||||||
<div class="pp-slider-row visible" id="scope-opacity-row">
|
<div class="pp-slider-row visible" id="scope-opacity-row">
|
||||||
<span class="pp-slider-mini-label">{{ t('Opacity') }}</span>
|
<span class="pp-slider-mini-label">{{ t('Opacity') }}</span>
|
||||||
<UiSlider class="pp-slider" id="scope-opacity-slider" @update:model-value="act('setScopeOpacity', $event)" min="0" max="100" :model-value="scopeOpacity" :disabled="!scopeOn" :aria-label="t('Scope opacity')" :title="t('How dark the scope shades the view outside the keyhole')" />
|
<UiSlider class="pp-slider" id="scope-opacity-slider" @update:model-value="act('setScopeOpacity', $event)" min="50" max="100" :model-value="scopeOpacity" :disabled="!scopeOn" :aria-label="t('Scope opacity')" :title="t('How dark the scope shades the view outside the keyhole')" />
|
||||||
<span class="pp-slider-value" id="scope-opacity-value">{{ pct(scopeOpacity) }}</span>
|
<span class="pp-slider-value" id="scope-opacity-value">{{ pct(scopeOpacity) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -198,7 +198,7 @@ const allocationOptions = computed(() => [
|
|||||||
</UiButton>
|
</UiButton>
|
||||||
</div>
|
</div>
|
||||||
<div class="pp-toggle-group">
|
<div class="pp-toggle-group">
|
||||||
<button class="pp-toggle-btn" :class="{ active: view?.bloom.active }" id="bloom-toggle" @click="act('toggleBloom')" :title="t('Bloom / Glow')">
|
<button class="pp-toggle-btn" :class="{ active: view?.bloom.active }" :aria-pressed="String(Boolean(view?.bloom.active))" id="bloom-toggle" @click="act('toggleBloom')" :title="t('Bloom / Glow')">
|
||||||
<span class="pp-icon">✨</span>
|
<span class="pp-icon">✨</span>
|
||||||
<span class="pp-label">{{ t('Bloom') }}</span>
|
<span class="pp-label">{{ t('Bloom') }}</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -208,7 +208,7 @@ const allocationOptions = computed(() => [
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="pp-toggle-group">
|
<div class="pp-toggle-group">
|
||||||
<button class="pp-toggle-btn" :class="{ active: view?.sharpen.active }" id="sharpen-toggle" @click="act('toggleSharpen')" :title="t('Sharpening')">
|
<button class="pp-toggle-btn" :class="{ active: view?.sharpen.active }" :aria-pressed="String(Boolean(view?.sharpen.active))" id="sharpen-toggle" @click="act('toggleSharpen')" :title="t('Sharpening')">
|
||||||
<span class="pp-icon">🔍</span>
|
<span class="pp-icon">🔍</span>
|
||||||
<span class="pp-label">{{ t('Sharpen') }}</span>
|
<span class="pp-label">{{ t('Sharpen') }}</span>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -46,6 +46,13 @@ import { cyberVisualDefaultsForHudTransition } from '../hudLayouts.js';
|
|||||||
const DETECTION_ALLOCATION_STORAGE_KEY = 'gev:detection-allocation:v1';
|
const DETECTION_ALLOCATION_STORAGE_KEY = 'gev:detection-allocation:v1';
|
||||||
|
|
||||||
/** Own visual preferences, detection overrides and display-control state. */
|
/** Own visual preferences, detection overrides and display-control state. */
|
||||||
|
/**
|
||||||
|
* The faintest the Scope mask goes. Below about half, the view reads as if
|
||||||
|
* Scope were off while labels still fade outside the keyhole and the HUD gets
|
||||||
|
* no backplates, so the slider stops here.
|
||||||
|
*/
|
||||||
|
export const SCOPE_OPACITY_MIN_PCT = 50;
|
||||||
|
|
||||||
export class VisualSettings {
|
export class VisualSettings {
|
||||||
async restoreShareState(state) {
|
async restoreShareState(state) {
|
||||||
const { setScopeTerminusOverride, clampScopeTerminusPct } = this.services;
|
const { setScopeTerminusOverride, clampScopeTerminusPct } = this.services;
|
||||||
@@ -511,8 +518,11 @@ export class VisualSettings {
|
|||||||
* given stays as it is. `apply: false` only shows the mask's state.
|
* given stays as it is. `apply: false` only shows the mask's state.
|
||||||
*/
|
*/
|
||||||
_setScope({ enabled, featherPct, opacityPct } = {}, { apply = true } = {}) {
|
_setScope({ enabled, featherPct, opacityPct } = {}, { apply = true } = {}) {
|
||||||
if (typeof opacityPct === 'number') {
|
if (Number.isFinite(opacityPct)) {
|
||||||
const pct = Math.max(0, Math.min(100, Math.round(opacityPct)));
|
const pct = Math.max(
|
||||||
|
SCOPE_OPACITY_MIN_PCT,
|
||||||
|
Math.min(100, Math.round(opacityPct)),
|
||||||
|
);
|
||||||
if (apply) this.services.setScopeMaskOpacity?.(pct / 100);
|
if (apply) this.services.setScopeMaskOpacity?.(pct / 100);
|
||||||
this._scopeOpacityShown = pct;
|
this._scopeOpacityShown = pct;
|
||||||
}
|
}
|
||||||
@@ -846,7 +856,11 @@ export class VisualSettings {
|
|||||||
if (det.mode) this._setDetectionMode(String(det.mode).toUpperCase());
|
if (det.mode) this._setDetectionMode(String(det.mode).toUpperCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
_applyGlobalPostDefaults() {
|
/**
|
||||||
|
* @param {{keepHudVariant?: boolean}} [options] `keepHudVariant` leaves the
|
||||||
|
* HUD layout to the style, as choosing a style does (Visual's reset).
|
||||||
|
*/
|
||||||
|
_applyGlobalPostDefaults({ keepHudVariant = false } = {}) {
|
||||||
const defaults = GLOBAL_POST_DEFAULTS;
|
const defaults = GLOBAL_POST_DEFAULTS;
|
||||||
if (typeof defaults.bloom?.intensity === 'number') {
|
if (typeof defaults.bloom?.intensity === 'number') {
|
||||||
this._setBloomIntensity(clampBloomIntensity(defaults.bloom.intensity), {
|
this._setBloomIntensity(clampBloomIntensity(defaults.bloom.intensity), {
|
||||||
@@ -865,7 +879,7 @@ export class VisualSettings {
|
|||||||
this._setSharpenEnabled(defaults.sharpen.enabled);
|
this._setSharpenEnabled(defaults.sharpen.enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defaults.hudVariant) {
|
if (defaults.hudVariant && !keepHudVariant) {
|
||||||
this._setHudVariant(defaults.hudVariant);
|
this._setHudVariant(defaults.hudVariant);
|
||||||
}
|
}
|
||||||
if (typeof defaults.hudVisible === 'boolean') {
|
if (typeof defaults.hudVisible === 'boolean') {
|
||||||
|
|||||||
Reference in new issue
Block a user