The combo's swatch takes a berth — a bar sitting in the field, not a fill

The swatch's padding goes asymmetric and user-tuned — a wider berth at the
sides than above and below, out of the swatch rather than the control's
size — so the colour reads as a bar in the field instead of wall-to-wall.
The field's fill moves to controlColor, the push-button neutral grey, whose
ring stayed legible where controlBackgroundColor's near-black dark-mode
reading drowned it; and the trigger square keeps its own two-point inset,
decoupled from the swatch's padding so the indicator stays a legible
square through any padding tweak the swatch takes.

Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
2026-08-07 11:23:54 -04:00
parent 51cf994cb9
commit 1e21d8cd60
+14 -8
View File
@@ -460,10 +460,15 @@ final class ColorComboControl: NSControl {
/// control exists to draw: "a flat swatch occupying the control, a chevron trigger at the
/// trailing edge."
private static let triggerWidth: CGFloat = 16
/// The swatch zone's padding before its rounded rect two points rather than a bare hairline,
/// so the control's own field (`drawField()`) reads as a visible ring around the colour instead
/// of being covered by it.
private static let swatchPadding: CGFloat = 2
/// The swatch's padding inside its zone, asymmetric and user-tuned: a wider berth at the sides
/// than above and below, so the colour reads as a bar sitting in the field rather than filling
/// it wall to wall. The space comes out of the swatch the control's overall size is untouched.
private static let swatchPaddingH: CGFloat = 7
private static let swatchPaddingV: CGFloat = 4
/// The trigger square's own inset from the zone's height kept at the old ring width rather
/// than the swatch's larger padding, so the indicator stays a legible ~10pt square instead of
/// shrinking with every padding tweak the swatch takes.
private static let triggerInset: CGFloat = 2
private static let cornerRadius: CGFloat = 3
/// The field's own radius a point more than the swatch's, so the two rounded rects run
/// concentric instead of pinching at the corners.
@@ -501,7 +506,8 @@ final class ColorComboControl: NSControl {
/// The control's own field: a bordered, filled rounded rect over the whole bounds, under both
/// zones what makes the swatch and the trigger read as one control rather than two shapes
/// floating beside each other. Standard control materials: `controlBackgroundColor` fill,
/// floating beside each other. `controlColor` fill the push-button neutral grey, not
/// `controlBackgroundColor`, whose near-black dark-mode reading drowned the padding ring
/// `separatorColor` hairline, the half-point inset keeping the stroke on whole pixels.
private func drawField() {
let path = NSBezierPath(
@@ -509,7 +515,7 @@ final class ColorComboControl: NSControl {
xRadius: Self.fieldRadius,
yRadius: Self.fieldRadius
)
NSColor.controlBackgroundColor.setFill()
NSColor.controlColor.setFill()
path.fill()
NSColor.separatorColor.setStroke()
path.lineWidth = 1
@@ -521,7 +527,7 @@ final class ColorComboControl: NSControl {
/// resolved colour on top, a `separatorColor` hairline stroke last. `nil`/unresolvable value
/// underlay + stroke only, the same "there is no colour, so show none" rule.
private func drawSwatch() {
let inset = swatchZone.insetBy(dx: Self.swatchPadding, dy: Self.swatchPadding)
let inset = swatchZone.insetBy(dx: Self.swatchPaddingH, dy: Self.swatchPaddingV)
let path = NSBezierPath(roundedRect: inset, xRadius: Self.cornerRadius, yRadius: Self.cornerRadius)
NSColor.textBackgroundColor.setFill()
path.fill()
@@ -538,7 +544,7 @@ final class ColorComboControl: NSControl {
/// a white `chevron.up.chevron.down` centred inside the standard `NSPopUpButton` indicator's
/// own look, redrawn here since this control has no bezel of its own to borrow one from.
private func drawTrigger() {
let side = triggerRect.height - 2 * Self.swatchPadding
let side = triggerRect.height - 2 * Self.triggerInset
let square = NSRect(
x: triggerRect.midX - side / 2,
y: triggerRect.midY - side / 2,