validatePaperInk function
The Paper & ink rules (on top of the generic ones):
- GuardrailRule.paperOutline: every key's outline (
KeyColors.edge) opaque and ≥ 3:1 against every sheet sample; width 1.25–1.75 dp. - GuardrailRule.paperOperatorCue: the recorded cue is OperatorCue.pattern; the hatch opacity is 0.60–0.75 and the hatch lines reach 3:1 against the operator face at it; operators are ≥ 200 heavier than digits as well.
- GuardrailRule.paperStamp: the
=stamp ≥ 3:1 against the digit slips (it reads as solid ink on paper). - GuardrailRule.paperWash: the wash tide line's alpha ≤ 58 and every label keeps the label floor with it laid over its face.
Implementation
List<GuardrailViolation> validatePaperInk(
ThemeSpec spec,
GuardrailLimits lim,
List<int> bgs,
) {
final p = spec.palette;
final out = <GuardrailViolation>[];
final groups = {
'digit': p.digit,
'operator': p.operator,
'equals': p.equals,
'function': p.function,
};
for (final MapEntry(key: name, value: k) in groups.entries) {
final opaque = ((k.edge >>> 24) & 0xFF) == 255;
final r = opaque ? _minContrastOn(k.edge, bgs) : 1.0;
if (r < ratioLarge) {
out.add(
GuardrailViolation(GuardrailRule.paperOutline, r, ratioLarge, name),
);
}
}
final width = spec.keyStyle.outlineWidthCdp;
if (!paperInkOutlineWidthCdp.contains(width)) {
out.add(
GuardrailViolation(
GuardrailRule.paperOutline,
width / 100,
paperInkOutlineWidthCdp.lo / 100,
'outline width (dp)',
),
);
}
if (spec.nonColourOperatorCue != OperatorCue.pattern) {
out.add(
const GuardrailViolation(GuardrailRule.paperOperatorCue, 0, 1, 'cue'),
);
}
final shade = spec.keyStyle.edgeShadePermille;
if (!paperInkHatchPermille.contains(shade)) {
out.add(
GuardrailViolation(
GuardrailRule.paperOperatorCue,
shade / 1000,
paperInkHatchPermille.lo / 1000,
'hatch opacity',
),
);
}
final hatch = paperHatchContrast(p.operator, shade);
if (hatch < paperHatchRatio) {
out.add(
GuardrailViolation(
GuardrailRule.paperOperatorCue,
hatch,
paperHatchRatio,
'hatch contrast',
),
);
}
final bonus = spec.type.operatorWeight - spec.type.keyWeight;
if (bonus < 200) {
out.add(
GuardrailViolation(
GuardrailRule.paperOperatorCue,
bonus.toDouble(),
200,
'operator weight bonus',
),
);
}
final stamp = contrastRatio(p.equals.face, p.digit.face);
if (stamp < paperStampRatio) {
out.add(GuardrailViolation(GuardrailRule.paperStamp, stamp, 3));
}
final rimAlpha = (p.highlight >>> 24) & 0xFF;
if (rimAlpha > paperWashRimMaxAlpha) {
out.add(
GuardrailViolation(
GuardrailRule.paperWash,
rimAlpha.toDouble(),
paperWashRimMaxAlpha.toDouble(),
'maximum alpha',
),
);
}
final washed = paperWashLabelContrast(p, p.highlight);
if (washed < lim.labelRatio) {
out.add(
GuardrailViolation(GuardrailRule.paperWash, washed, lim.labelRatio),
);
}
return out;
}