Files
gods-eye-view/src/ui/displayBindings.js
T

231 lines
8.3 KiB
JavaScript

import { createFrameRateMonitor } from './frameRateMonitor.js';
import { bindApplicationShortcuts } from './visualInput.js';
import { bindDisplayControls } from './displayControls.js';
import { canonicalizeDensity } from '../data/detectionPolicy.js';
/** Own keyboard/display event subscriptions; settings remain with their state owners. */
export class DisplayBindings {
constructor({
viewer,
services,
elements,
operations,
readState,
claimDetection,
}) {
Object.assign(
this,
{ viewer, services, readState, claimDetection },
elements,
operations,
);
}
get shareLinkManager() {
return this.readState().shareLinkManager;
}
get hud() {
return this.readState().hud;
}
get bloomEnabled() {
return this.readState().bloomEnabled;
}
get sharpenEnabled() {
return this.readState().sharpenEnabled;
}
get celestialRing() {
return this.readState().celestialRing;
}
get celestialRingEnabled() {
return this.readState().celestialRingEnabled;
}
get _models3dEnabled() {
return this.readState()._models3dEnabled;
}
get _models3dModeBtns() {
return this.readState()._models3dModeBtns;
}
get _detectionAllocationBtns() {
return this.readState()._detectionAllocationBtns;
}
_initUI() {
const {
cycleDetectionMode,
setScopeMaskEnabled,
isScopeMaskEnabled,
setScopeMaskFeather,
} = this.services;
this._applicationShortcuts?.destroy();
this._frameRateMonitor?.destroy();
this._frameRateMonitor = createFrameRateMonitor({
viewer: this.viewer,
documentRef: document,
});
this._applicationShortcuts = bindApplicationShortcuts({
documentRef: document,
searchInput: this._locationSearch,
actions: {
setStyle: (style) => this.setStyle(style, { userInitiated: true }),
dismissSearch: () => {
if (this._locationSearch.classList.contains('expanded')) {
this._locationSearch.classList.remove('expanded');
this._locationSearch.value = '';
this._locationSearch.blur();
}
},
toggleHud: () => {
this.shareLinkManager?.claimRestoreLane?.('visual');
this.hud.toggle();
this._updateHudButtonState();
this._syncShareState();
},
toggleOrbit: () => this._toggleOrbit(),
toggleCleanView: () => this.toggleCleanView(),
toggleLayers: () =>
document.getElementById('data-panel').classList.toggle('active'),
cycleDetection: () => {
this.shareLinkManager?.claimRestoreLane?.('visual');
this.claimDetection();
cycleDetectionMode();
this._syncShareState();
},
toggleCctv: () => this._toggleCctvEnabled(),
},
});
this._displayControls?.destroy();
this._displayControls = bindDisplayControls({
elements: {
styleButtons: document.querySelectorAll('.style-btn'),
bloomButton: this._bloomBtn,
bloomSlider: this._bloomSlider,
sharpenButton: this._sharpenBtn,
sharpenSlider: this._sharpenSlider,
scopeButton: this._scopeBtn,
scopeFeatherSlider: this._scopeFeatherSlider,
hudLayout: this._hudLayoutSelect,
hudButton: this._hudBtn,
sonarButton: this._cyberSonarBtn,
sonarRingsSlider: this._cyberSonarRings,
sonarRangeSlider: this._cyberSonarRange,
sonarIntensitySlider: this._cyberSonarIntensity,
sonarOpacitySlider: this._cyberSonarOpacity,
sonarSectorSlider: this._cyberSonarSector,
cleanViewButton: this._cleanViewBtn,
cleanViewExitButton: this._cleanViewExitBtn,
densitySlider: this._detectionDensitySlider,
detectionButton: this._detectionBtn,
allocationButtons: this._detectionAllocationBtns,
fadeSliders: [this._detectionFadeSlider, this._detectionOpacitySlider],
celestialButton: this._celestialBtn,
modelsButton: this._models3dBtn,
modelModeButtons: this._models3dBtn ? this._models3dModeBtns : [],
},
actions: {
setStyle: (style) => this.setStyle(style, { userInitiated: true }),
toggleBloom: () => {
this.shareLinkManager?.claimRestoreLane?.('visual');
this._setBloomEnabled(!this.bloomEnabled);
},
setBloomIntensity: (value) => {
this.shareLinkManager?.claimRestoreLane?.('visual');
this._setBloomIntensity(value);
},
toggleSharpen: () => {
this.shareLinkManager?.claimRestoreLane?.('visual');
this._setSharpenEnabled(!this.sharpenEnabled);
},
toggleScope: () => {
this.shareLinkManager?.claimRestoreLane?.('visual');
const next = !isScopeMaskEnabled();
setScopeMaskEnabled(next);
this._scopeBtn.classList.toggle('active', next);
this._scopeBtn.setAttribute('aria-pressed', String(next));
this._syncShareState();
},
setScopeFeather: (value) => {
this.shareLinkManager?.claimRestoreLane?.('visual');
const pct = Math.max(0, Math.min(100, value || 0));
if (this._scopeFeatherValue)
this._scopeFeatherValue.textContent = `${pct}%`;
setScopeMaskFeather(pct / 100);
this._syncShareState();
},
setSharpenIntensity: (pct) => {
this.shareLinkManager?.claimRestoreLane?.('visual');
if (this._sharpenSliderValue)
this._sharpenSliderValue.textContent = `${pct}%`;
this._applySharpenIntensity(pct / 100);
this._syncShareState();
},
setHudLayout: (value) => {
this.shareLinkManager?.claimRestoreLane?.('visual');
this._setHudVariant(value, { applyVisualDefaults: true });
},
toggleCleanView: () => this.toggleCleanView(),
exitCleanView: () => this.toggleCleanView(false),
setDensity: (value) => {
this.shareLinkManager?.claimRestoreLane?.('visual');
this.claimDetection();
const pct = canonicalizeDensity(value);
this._detectionDensitySlider.value = String(pct);
if (this._detectionDensityValue)
this._detectionDensityValue.textContent = `${pct}%`;
this._applyDetectionDensityFromUi();
this._syncShareState();
},
setAllocation: (value) => {
this.shareLinkManager?.claimRestoreLane?.('visual');
this.claimDetection();
this._setDetectionAllocation(value);
},
setFade: () => {
this.shareLinkManager?.claimRestoreLane?.('visual');
this._applyDetectionFadeFromUi();
this._syncShareState();
},
toggleCelestial: () => {
const ringIsVisible = !!this.celestialRing?.visible;
if (!this.celestialRingEnabled || !ringIsVisible) {
this.setCelestialRingEnabled(true, { focus: true });
} else {
this.setCelestialRingEnabled(false);
}
},
toggleHud: () => {
this.shareLinkManager?.claimRestoreLane?.('visual');
this.hud.toggle();
this._updateHudButtonState();
this._syncShareState();
},
toggleSonar: () => this._setCyberSonarEnabled(),
setSonarRings: (value) => this._setCyberSonarSetting('rings', value),
setSonarRange: (value) => this._setCyberSonarSetting('range', value),
setSonarIntensity: (value) =>
this._setCyberSonarSetting('intensity', value),
setSonarOpacity: (value) =>
this._setCyberSonarSetting('opacity', value),
setSonarSector: (value) => this._setCyberSonarSetting('sector', value),
cycleDetection: () => {
this.shareLinkManager?.claimRestoreLane?.('visual');
this.claimDetection();
cycleDetectionMode();
this._syncShareState();
},
toggleModels: () => {
this._setModels3dEnabled(!this._models3dEnabled);
this._syncModels3dModeRow();
},
setModelsMode: (mode) => this._setModels3dMode(mode),
},
});
}
destroy() {
this._applicationShortcuts?.destroy();
this._applicationShortcuts = null;
this._frameRateMonitor?.destroy();
this._frameRateMonitor = null;
this._displayControls?.destroy();
this._displayControls = null;
}
}