refactor: isolate camera panel controls and presentation

This commit is contained in:
Sameh Khamis committed 2026-09-13 00:38:01 -07:00
1 parent bd14d6c301
commit f45f399c31
17 files changed
+932 -657

No files matched your search

+130
View File
@@ -0,0 +1,130 @@
export function _initCctvPanel() {
if (!this._cctvPanel) return;
this.listen(this._cctvEnableBtn, 'click', async () => {
this._actionGeneration++;
await this.actions.toggleEnabled();
});
this.listen(this._cctvNearestBtn, 'click', async () => {
const generation = ++this._actionGeneration;
const activeId = this._cctvState?.activeCameraId;
if (!await this.actions.toggleEnabled(true)) return;
if (this.destroyed || generation !== this._actionGeneration
|| !this.actions.isEnabled()
|| (activeId && activeId !== this._cctvState?.activeCameraId)) return;
this.actions.runExplicitFocus(
() => this.cctv.focusNearest({ focus: false }),
(cameraId) => this.cctv.focusCamera(cameraId, 1.8),
);
});
this.listen(this._cctvPrevBtn, 'click', async () => {
const generation = ++this._actionGeneration;
const activeId = this._cctvState?.activeCameraId;
if (!await this.actions.toggleEnabled(true)) return;
if (this.destroyed || generation !== this._actionGeneration
|| !this.actions.isEnabled()
|| (activeId && activeId !== this._cctvState?.activeCameraId)) return;
this.actions.runExplicitFocus(
() => this.cctv.cycleCamera(-1),
(cameraId) => this.cctv.focusCamera(cameraId, 1.4),
);
});
this.listen(this._cctvNextBtn, 'click', async () => {
const generation = ++this._actionGeneration;
const activeId = this._cctvState?.activeCameraId;
if (!await this.actions.toggleEnabled(true)) return;
if (this.destroyed || generation !== this._actionGeneration
|| !this.actions.isEnabled()
|| (activeId && activeId !== this._cctvState?.activeCameraId)) return;
this.actions.runExplicitFocus(
() => this.cctv.cycleCamera(1),
(cameraId) => this.cctv.focusCamera(cameraId, 1.4),
);
});
this.listen(this._cctvSelect, 'change', async () => {
const generation = ++this._actionGeneration;
const activeId = this._cctvState?.activeCameraId;
const cameraId = this._cctvSelect.value;
if (!cameraId) return;
if (!await this.actions.toggleEnabled(true)) return;
if (this.destroyed || generation !== this._actionGeneration
|| !this.actions.isEnabled()
|| (activeId && activeId !== this._cctvState?.activeCameraId)) return;
// Picking a camera from the dropdown flies to it. The catalog spans
// three metros, so a bare selection used to leave the view in the old
// city with a camera active thousands of km away.
this.actions.runExplicitFocus(
() => (this.cctv.selectCamera(cameraId) ? cameraId : null),
(selectedId) => this.cctv.focusCamera(selectedId, 2.2),
);
this.actions.setParams({ selectedCameraId: cameraId }, { origin: 'user' });
});
this.listen(this._cctvFocusBtn, 'click', async () => {
const generation = ++this._actionGeneration;
const activeId = this._cctvState?.activeCameraId;
const selected = this._cctvState?.activeCameraId || this._cctvSelect?.value;
if (!selected) return;
if (!await this.actions.toggleEnabled(true)) return;
if (this.destroyed || generation !== this._actionGeneration
|| !this.actions.isEnabled()
|| (activeId && activeId !== this._cctvState?.activeCameraId)) return;
this.actions.runExplicitFocus(
() => selected,
(cameraId) => this.cctv.focusCamera(cameraId, 1.9),
);
this.actions.setParams({ selectedCameraId: selected }, { origin: 'user' });
});
this.listen(this._cctvCoverageBtn, 'click', () => {
const current = this._cctvState?.coverageMode
|| (this._cctvState?.showCoverage ? 'on' : 'off');
const next = current === 'off' ? 'on' : current === 'on' ? 'viewshed' : 'off';
this.actions.setParams({ coverageMode: next }, { origin: 'user' });
});
this.listen(this._cctvAutoHopBtn, 'click', () => {
const current = !!this._cctvState?.autoHop;
this.actions.setParams({ autoHop: !current }, { origin: 'user' });
});
this.listen(this._cctvProjectionBtn, 'click', () => {
const current = this._cctvState?.showProjection !== false;
this.actions.setParams({ showProjection: !current }, { origin: 'user' });
});
this.listen(this._cctvAdjustBtn, 'click', () => {
const current = !!this._cctvState?.calibrationMode;
this.actions.setParams({ calibrationMode: !current }, { origin: 'user' });
});
// Click-to-edit pose readout: each chip swaps to a number input; Enter or
// blur commits (converted to a calibration offset against basePose),
// Escape cancels. Delegated so re-renders never re-bind.
this.listen(this._cctvCalReadout, 'click', (event) => {
const chip = event.target.closest?.('.cctv-cal-value');
if (!chip || chip.disabled || chip.querySelector('input')) return;
this._beginCctvCalValueEdit(chip);
});
this.listen(this._cctvCalibSaveBtn, 'click', () => {
const cameraId = this._activeCctvCameraId();
if (!cameraId || !this.actions.setParams) return;
this.actions.setParams({
selectedCameraId: cameraId,
calibration: { cameraId, save: true },
}, { origin: 'user' });
this.actions.showToast('CCTV calibration saved');
});
this.listen(this._cctvCalibResetBtn, 'click', () => {
this._resetCctvCalibration();
});
this._renderCctvState(null);
this.actions.syncViewport();
}