Name the frame's category for the decision, not the maths
`Attribute::Geometry` becomes `Attribute::Compose`, and `film_sim` moves from `[tone, colour]` to `[effect]`. Two categories were doing the wrong job. "Geometry" describes what crop, straighten and the quarter turns do to coordinates — but it describes lens distortion correction exactly as well, and that is not a compositional choice at all. Naming the attribute for the photographer's decision is what separates it from `Optics`: one is what the lens did, the other is what they chose. The maths the two have in common is not the thing worth filing them under. A film stock declared both `tone` and `colour`, so "Kodachrome" appeared in the Light group beside exposure and again in Colour beside white balance — two places, neither of which is where anyone looks for it. It is neither: `Effect` is defined in this same file as "applied rather than corrected — a look, not a fix", which is what a stock is. That it moves tone and colour is true of every look, and is not what the attribute is for. `from_name` still accepts "geometry" on the way in. That string is persisted in `develop.copy_attributes`, and an entry it fails to parse is not an error — `presets::scope_for` logs it and drops it — so without the alias an existing settings file would have quietly narrowed what a paste carries. `name` writes the current spelling, so the file migrates itself the first time it is saved. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1021,15 +1021,15 @@ impl DevelopSession {
|
||||
/// (FR-DEV-3a). An attribute nothing carries is left out rather than
|
||||
/// offered as a tab that opens onto nothing.
|
||||
///
|
||||
/// Geometry is excluded: its one operation prefers an on-canvas widget and
|
||||
/// is skipped by the row builder, so a Geometry tab would be empty of rows
|
||||
/// while `GeometryPanel` holds the real controls.
|
||||
/// Compose is excluded: its one operation prefers an on-canvas widget and
|
||||
/// is skipped by the row builder, so a Compose tab would be empty of rows
|
||||
/// while `ComposePanel` holds the real controls.
|
||||
pub fn tabs(&self) -> Vec<(dr_pipeline::Attribute, String)> {
|
||||
use dr_pipeline::Attribute;
|
||||
let caps = self.scoped_capabilities();
|
||||
Attribute::ALL
|
||||
.into_iter()
|
||||
.filter(|a| *a != Attribute::Geometry)
|
||||
.filter(|a| *a != Attribute::Compose)
|
||||
.filter(|a| {
|
||||
caps.iter().any(|c| {
|
||||
c.attributes.contains(a)
|
||||
@@ -1171,7 +1171,7 @@ pub(crate) fn supported(widget: WidgetKind) -> bool {
|
||||
// Drawn in the panel.
|
||||
WidgetKind::ToneCurve => true,
|
||||
// Hosted on the canvas: the overlay is drawn over the photograph and
|
||||
// the panel contributes `GeometryPanel`, the affordance that turns it
|
||||
// the panel contributes `ComposePanel`, the affordance that turns it
|
||||
// on.
|
||||
WidgetKind::CropOverlay => true,
|
||||
// Not implemented. Listed rather than caught by a wildcard so the next
|
||||
@@ -1254,7 +1254,7 @@ pub(crate) fn rows_filtered(
|
||||
// terms, with nothing named.
|
||||
//
|
||||
// Skipped rather than rendered as an affordance row, because
|
||||
// the affordance is `GeometryPanel` — a bespoke control for a
|
||||
// the affordance is `ComposePanel` — a bespoke control for a
|
||||
// known stage, which is a thing the interface is entitled to
|
||||
// build (ARCH §4.3a draws the line at the *generated* panel
|
||||
// naming stages, not at the interface having hand-made
|
||||
@@ -5748,7 +5748,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn framing_is_not_generated_as_sliders() {
|
||||
// `GeometryPanel` presents crop, rotation, flips and straightening as
|
||||
// `ComposePanel` presents crop, rotation, flips and straightening as
|
||||
// the gestures they are. If the generic path emitted them too the
|
||||
// sidebar would carry both — including four "Crop Left/Top/Width/
|
||||
// Height" sliders no one can compose a photograph with.
|
||||
|
||||
@@ -127,7 +127,7 @@ fn catalogued(key: &str) -> Option<&'static str> {
|
||||
"attr.colour" => "Colour",
|
||||
"attr.detail" => "Detail",
|
||||
"attr.optics" => "Optics",
|
||||
"attr.geometry" => "Geometry",
|
||||
"attr.compose" => "Compose",
|
||||
"attr.effect" => "Effects",
|
||||
|
||||
"op.white_balance" => "White Balance",
|
||||
|
||||
@@ -210,7 +210,7 @@ fn label_for(attribute: dr_pipeline::Attribute) -> &'static str {
|
||||
Attribute::Colour => "Colour",
|
||||
Attribute::Detail => "Detail",
|
||||
Attribute::Optics => "Optics",
|
||||
Attribute::Geometry => "Geometry",
|
||||
Attribute::Compose => "Compose",
|
||||
Attribute::Effect => "Effect",
|
||||
}
|
||||
}
|
||||
@@ -548,7 +548,7 @@ pub fn render(
|
||||
// holding no crop loses nothing to the setting, and saying so anyway would
|
||||
// train the user to ignore the line.
|
||||
window.set_settings_framing_withheld(
|
||||
clipboard.holds_framing() && !scope.has(dr_pipeline::Attribute::Geometry),
|
||||
clipboard.holds_framing() && !scope.has(dr_pipeline::Attribute::Compose),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user