feat(panel): editor keeps the values when the sim changes; one-tap RESET back to the look
This commit is contained in:
@@ -36,6 +36,9 @@ interface AdjustmentPanelProps {
|
||||
recipes: Recipe[];
|
||||
currentRecipeId: string;
|
||||
adjustments: ColorAdjustments;
|
||||
// The values the active look ships with — a saved recipe's own set, a film
|
||||
// sim's canonical set, or the neutral defaults. RESET puts them back.
|
||||
lookDefaults: ColorAdjustments;
|
||||
selectedFrame: FrameId;
|
||||
// FRAME tab CROP. Only meaningful on the library's plain frames (the camera
|
||||
// composes through its ratio band, polaroid/wall through their own window),
|
||||
@@ -163,6 +166,7 @@ export default function AdjustmentPanel({
|
||||
recipes,
|
||||
currentRecipeId,
|
||||
adjustments,
|
||||
lookDefaults,
|
||||
selectedFrame,
|
||||
cropRatio,
|
||||
onUpdateCropRatio,
|
||||
@@ -246,6 +250,17 @@ export default function AdjustmentPanel({
|
||||
|
||||
const a = adjustments;
|
||||
|
||||
// RESET (parameter tabs): every number of the active look back on the value
|
||||
// it ships with. Only the parameters count as "changed" — the groups below
|
||||
// are part of the same look, so they light it too.
|
||||
const lookDirty =
|
||||
[...PARAM_DEFS.iq, ...PARAM_DEFS.wb, ...PARAM_DEFS.filters].some(
|
||||
(d) => d.get(a) !== d.get(lookDefaults)
|
||||
) ||
|
||||
(a.colorChrome || 'none') !== (lookDefaults.colorChrome || 'none') ||
|
||||
(a.colorChromeBlue || 'none') !== (lookDefaults.colorChromeBlue || 'none') ||
|
||||
String(a.dynamicRange ?? 'auto') !== String(lookDefaults.dynamicRange ?? 'auto');
|
||||
|
||||
const renderChip = (c: ChipDef) => {
|
||||
const tone = c.active
|
||||
? 'border-amber-500/70 bg-amber-500/15'
|
||||
@@ -302,6 +317,19 @@ export default function AdjustmentPanel({
|
||||
})
|
||||
);
|
||||
|
||||
const resetChip = (): ChipDef => ({
|
||||
key: 'reset-params',
|
||||
label: 'RESET',
|
||||
active: false,
|
||||
onPress: () => onUpdateAdjustments({ ...lookDefaults }),
|
||||
});
|
||||
|
||||
// Pinned OUTSIDE the scroll row: the rows keep their scroll offset across
|
||||
// tabs, so a RESET sitting inside one can be scrolled off just when it is
|
||||
// wanted — after a tweak halfway along the strip.
|
||||
const resetChipFixed = () =>
|
||||
lookDirty ? <View className="pl-2">{renderChip(resetChip())}</View> : null;
|
||||
|
||||
const choiceChips = (
|
||||
keyPrefix: string,
|
||||
options: { v: string; d: string }[],
|
||||
@@ -521,22 +549,28 @@ export default function AdjustmentPanel({
|
||||
// opens its AUTO/DR100/DR200/DR400 strip above (same as the chrome
|
||||
// groups on WB).
|
||||
return (
|
||||
<ScrollView
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
contentContainerStyle={{ alignItems: 'center', paddingHorizontal: 8, paddingVertical: 6 }}
|
||||
>
|
||||
{paramChips(paramDefs.iq)}
|
||||
{renderChip(groupChip('dr'))}
|
||||
</ScrollView>
|
||||
<View className="flex-row items-center">
|
||||
{resetChipFixed()}
|
||||
<ScrollView
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
style={{ flex: 1 }}
|
||||
contentContainerStyle={{ alignItems: 'center', paddingHorizontal: 8, paddingVertical: 6 }}
|
||||
>
|
||||
{paramChips(paramDefs.iq)}
|
||||
{renderChip(groupChip('dr'))}
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
|
||||
case 'wb':
|
||||
return (
|
||||
<View>
|
||||
<View className="flex-row items-center">
|
||||
{resetChipFixed()}
|
||||
<ScrollView
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
style={{ flex: 1 }}
|
||||
contentContainerStyle={{ alignItems: 'center', paddingHorizontal: 8, paddingVertical: 6 }}
|
||||
>
|
||||
{choiceChips(
|
||||
@@ -561,13 +595,17 @@ export default function AdjustmentPanel({
|
||||
|
||||
case 'filters':
|
||||
return (
|
||||
<ScrollView
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
contentContainerStyle={{ alignItems: 'center', paddingHorizontal: 8, paddingVertical: 8 }}
|
||||
>
|
||||
{paramChips(paramDefs.filters)}
|
||||
</ScrollView>
|
||||
<View className="flex-row items-center">
|
||||
{resetChipFixed()}
|
||||
<ScrollView
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
style={{ flex: 1 }}
|
||||
contentContainerStyle={{ alignItems: 'center', paddingHorizontal: 8, paddingVertical: 8 }}
|
||||
>
|
||||
{paramChips(paramDefs.filters)}
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
|
||||
case 'frame':
|
||||
|
||||
@@ -228,9 +228,12 @@ export default function RecipeCreateModal({
|
||||
setIso(null);
|
||||
}, [visible, currentBase, initial]);
|
||||
|
||||
// Switching the simulation reloads its standard values into the form.
|
||||
// Switching the simulation reloads its standard values into the form — not
|
||||
// in the editor though: there the numbers on screen are the user's own, and
|
||||
// swapping the base look under them must not throw them away.
|
||||
const selectSim = (b: BaseFilter) => {
|
||||
setSim(b);
|
||||
if (initial) return;
|
||||
const v = valuesOf(b);
|
||||
setDr(v.dr);
|
||||
setGrain(v.grain);
|
||||
|
||||
Reference in New Issue
Block a user