Say which blue a colour mismatch is about (issue #2941)

A print was refused a colour match between two filaments the dialog itself
labelled "Blue". The comparison was right: the slicer profile asked for a
near-pure #0028FF and the slot held Bambu's navy #0A2989, 118 apart in the
blue channel alone and a CIEDE2000 distance of 15, where 1 is a
just-noticeable difference. Nothing on screen said so. A hex that misses the
colour catalogue is named by a coarse family bucket, so both sides resolved
to the same word, and the warning sat between two identical labels with
nothing to reconcile it against. Read as a broken matcher, which is what the
report said, and a fair reading of what was shown.

Where both sides of a mismatch carry the same name they are now qualified by
their hex, and the tooltip names them together: "Same type, different color:
needs Blue (#0028FF), slot has Blue (#0A2989)". Names that already differ are
left alone -- the hex is noise once the words separate them -- and a side with
no name falls back to its hex rather than growing an empty bracket.

The comparison is untouched. It was correct, and its tolerance is not
something to widen on one report: a difference that size would start matching
navy to cyan, and eligibility is the same rule the queue scheduler dispatches
on, so loosening it would change which spool gets printed rather than only
which warning gets shown. This issue was about being able to see why the
warning fired, and a test pins that it still fires.

The strings around it were hardcoded English: the panel's status line, the
required-filament tooltip, the auto-matched marker, the slot placeholder, the
mismatch detail and the type-not-found message. All nine now go through
translation, in all thirteen locales. Two of them -- "Same type, different
color" and "Filament type not loaded" -- turned out to have had translations
sitting in every locale file the whole time, unused, while the component
rendered the English literal beside them. The parity gate could not have
caught any of this: keys that were never added have nothing to compare
against.
This commit is contained in:
maziggy
2026-08-24 10:14:31 +02:00
parent 6988a30eae
commit cbbdab86f9
20 changed files with 500 additions and 146 deletions
+40
View File
@@ -251,6 +251,46 @@ export function getColorName(hexColor: string, material?: string | null): string
return hexToColorName(hexColor);
}
/**
* Label two colours so a reader can tell which is which.
*
* `getColorName` resolves a hex against the catalogue and falls back to a
* coarse family bucket, so a slicer profile's near-pure `#0028FF` and Bambu's
* navy `#0A2989` are both called "Blue". A mismatch warning between those two
* then reads as a contradiction of the two identical names printed either side
* of it, which is the whole of #2941: the comparison was right, the labels gave
* the user no way to see what it was comparing.
*
* When the names collide the hex is appended to both, because that is what
* actually differs. Distinct names are returned untouched -- once the words
* separate them the hex is noise. A side with no name falls back to its hex, and
* a pair with no usable hex at all keeps the bare names rather than growing an
* empty "()".
*/
export function disambiguateColorNames(
first: { name?: string | null; hex?: string | null },
second: { name?: string | null; hex?: string | null },
): [string, string] {
const hexLabel = (hex?: string | null): string => {
const clean = (hex ?? '').replace('#', '').trim().slice(0, 6).toUpperCase();
return /^[0-9A-F]{6}$/.test(clean) ? `#${clean}` : '';
};
const firstName = (first.name ?? '').trim();
const secondName = (second.name ?? '').trim();
const firstHex = hexLabel(first.hex);
const secondHex = hexLabel(second.hex);
if (!firstName || !secondName) return [firstName || firstHex, secondName || secondHex];
if (firstName.toLowerCase() !== secondName.toLowerCase()) return [firstName, secondName];
if (!firstHex && !secondHex) return [firstName, secondName];
return [
firstHex ? `${firstName} (${firstHex})` : firstName,
secondHex ? `${secondName} (${secondHex})` : secondName,
];
}
/**
* Resolve a spool's display color name.
* Tries: stored color_name (if it's a readable name) → runtime catalog via rgba → null.