import { ColorAdjustments } from '../types'; // Static metadata for the continuous (slider) adjustments of the IQ/WB/FILTERS // tabs — shared between AdjustmentPanel (chips + slider rows) and App (which // needs the open row's bounds to drive drag-on-the-image adjustment). The get // /set accessors are stateless so one table serves every render. export interface ContinuousParamDef { key: string; label: string; min: number; max: number; step: number; defaultValue: number; display: (v: number) => string; get: (a: ColorAdjustments) => number; set: (v: number) => Partial; // PRO-only knob: the LITE build greys the chip out (PRO corner tag) and // cannot open its row, so the value stays at its default there. pro?: boolean; } const sign = (v: number) => (v > 0 ? `+${v}` : String(v)); const oneEv = (v: number) => `${v > 0 ? '+' : ''}${v.toFixed(1)} EV`; export const PARAM_DEFS: { iq: ContinuousParamDef[]; wb: ContinuousParamDef[]; filters: ContinuousParamDef[]; } = { iq: [ { key: 'exposure', label: 'EXPOSURE', min: -10, max: 10, step: 1, defaultValue: 0, display: sign, get: (a) => a.exposure, set: (v) => ({ exposure: v }), }, { key: 'ev', label: 'EV', min: -3, max: 3, step: 0.5, defaultValue: 0, display: oneEv, get: (a) => a.exposureCompensation ?? 0, set: (v) => ({ exposureCompensation: v }), }, { key: 'contrast', label: 'CONTRAST', min: -10, max: 10, step: 1, defaultValue: 0, display: sign, get: (a) => a.contrast, set: (v) => ({ contrast: v }), }, { key: 'color', label: 'COLOR', min: -10, max: 10, step: 1, defaultValue: 0, display: sign, get: (a) => a.saturation, set: (v) => ({ saturation: v }), }, { key: 'vibrance', label: 'VIBRANCE', min: -10, max: 10, step: 1, defaultValue: 0, display: sign, get: (a) => a.vibrance ?? 0, set: (v) => ({ vibrance: v }), }, { key: 'highlight', label: 'HIGHLIGHT', min: -10, max: 10, step: 1, defaultValue: 0, display: sign, get: (a) => a.highlight ?? 0, set: (v) => ({ highlight: v }), }, { key: 'shadow', label: 'SHADOW', min: -10, max: 10, step: 1, defaultValue: 0, display: sign, get: (a) => a.shadow ?? 0, set: (v) => ({ shadow: v }), }, ], wb: [ { key: 'temperature', label: 'COLOR TEMP', min: 2500, max: 10000, step: 100, defaultValue: 5500, display: (v) => `${v}K`, get: (a) => a.temperature, set: (v) => ({ temperature: v }), }, { key: 'tint', label: 'TINT', min: -10, max: 10, step: 1, defaultValue: 0, display: sign, get: (a) => a.tint ?? 0, set: (v) => ({ tint: v }), }, { // The two points live on WB, not on LIGHT: they shift each channel's own // end of the ramp, which balances a cast at the toe and the shoulder // rather than adding another tone knob. Same range as the CREATE form's // rows, so a look round-trips. key: 'whites', label: 'WHITE', min: -10, max: 10, step: 1, defaultValue: 0, display: sign, get: (a) => a.whites ?? 0, set: (v) => ({ whites: v }), }, { key: 'blacks', label: 'BLACK', min: -10, max: 10, step: 1, defaultValue: 0, display: sign, get: (a) => a.blacks ?? 0, set: (v) => ({ blacks: v }), }, ], filters: [ { key: 'denoise', label: 'NOISE REDUCTION', min: -10, max: 10, step: 1, defaultValue: 0, display: String, get: (a) => a.denoise, set: (v) => ({ denoise: v }), }, { key: 'clarity', label: 'CLARITY', min: -10, max: 10, step: 1, defaultValue: 0, display: sign, get: (a) => a.clarity, set: (v) => ({ clarity: v }), }, { key: 'sharpening', label: 'SHARPENING', min: -10, max: 10, step: 1, defaultValue: 0, display: String, get: (a) => a.sharpening ?? 0, set: (v) => ({ sharpening: v }), }, { key: 'grain', label: 'MONOCHROME GRAIN', min: 0, max: 10, step: 1, defaultValue: 0, display: String, get: (a) => a.grain, set: (v) => ({ grain: v }), }, { key: 'hdf', label: 'HDF EFFECT', pro: true, min: 0, max: 10, step: 1, defaultValue: 0, display: String, get: (a) => a.hdf ?? 0, set: (v) => ({ hdf: v }), }, { key: 'vignette', label: 'VIGNETTING', min: 0, max: 10, step: 1, defaultValue: 0, display: String, get: (a) => a.vignette ?? 0, set: (v) => ({ vignette: v }), }, ], };