The combo drops its padding and turns portrait — a 4:5 field puts the symbol dead center
Owner's first review of the combo rework (2026-08-09): remove the face padding, make the field taller and narrower at about a 4:5 width:height ratio, and center the symbol glyph in its face. All three land in ComboFieldMetrics, so ColorComboControl and SymbolComboControl stay the identical shape they were built to share. - ComboFieldMetrics grows a width figure (height * widthToHeightRatio, 0.8), replacing NSView.noIntrinsicMetric — every combo now carries its own taller, narrower intrinsic size instead of stretching to whatever a caller's frame proposed. - facePaddingH/facePaddingV/glyphPadding are gone; a face fills its zone edge to edge. glyphPointSize is now whichever of the face's own width/height is smaller, with nothing subtracted for padding that no longer exists. - SymbolComboControl.drawFace centers the glyph on both axes — it only ever centered vertically before, despite its own doc comment claiming otherwise. - ComboFieldControl.drawTrigger bounds its chevron square by the smaller of the trigger strip's own width/height, not height alone, since the strip is no longer close to square once the field is much taller than it is wide. - CardSidebarSections drops the sidebar's old '* 0.55' fixed-width frame on both combo rows; each control now sizes itself, and both anchors (card sidebar, board popover) compose the narrower field with no other changes needed. - ComboFieldMetricsTests updated for the new figures, plus a ratio-holds-at-every-size test and a rewritten glyph-fit test matching the no-padding rule. Verification: xcodebuild build succeeded; xcodebuild test -only-testing:KanbanTests — 3220 tests in 559 suites, 3 failures, all PointerLatencyTests (documented locked-screen environmental mode, confirmed unrelated by isolated rerun). Pixel verification unexercised — same locked-screen constraint the first pass hit. Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
@@ -370,15 +370,6 @@ private struct SymbolComboView: NSViewRepresentable {
|
||||
return fallback
|
||||
}
|
||||
|
||||
/// The width an unconstrained measuring pass falls back to — a face wide enough for the glyph to
|
||||
/// sit in with room to read as a *field* rather than a button, plus the trigger. The normal case
|
||||
/// is a finite proposal (a sidebar row's `.frame(width:)`), which this never has to stand in for.
|
||||
@MainActor
|
||||
private var defaultFaceWidth: CGFloat {
|
||||
let metrics = ComboFieldMetrics.current
|
||||
return (metrics.height * 2 + metrics.triggerWidth).rounded()
|
||||
}
|
||||
|
||||
func makeNSView(context: Context) -> SymbolComboControl {
|
||||
SymbolComboControl(frame: .zero)
|
||||
}
|
||||
@@ -396,15 +387,15 @@ private struct SymbolComboView: NSViewRepresentable {
|
||||
control.onTriggerClick = onTrigger
|
||||
}
|
||||
|
||||
/// Obeys whatever width SwiftUI proposes, like any other control — `ColorComboView.sizeThatFits`'
|
||||
/// rule, restated so the two combos answer a proposal identically and a caller that frames them
|
||||
/// alike gets two controls the same size.
|
||||
/// Obeys an explicit finite proposal when SwiftUI hands one over, else falls back to the control's
|
||||
/// own intrinsic width — `ColorComboView.sizeThatFits`'s rule, restated so the two combos answer a
|
||||
/// proposal identically and a caller that frames them alike gets two controls the same size.
|
||||
func sizeThatFits(_ proposal: ProposedViewSize, nsView: SymbolComboControl, context: Context) -> CGSize? {
|
||||
let width: CGFloat
|
||||
if let proposed = proposal.width, proposed.isFinite {
|
||||
width = proposed
|
||||
} else {
|
||||
width = defaultFaceWidth
|
||||
width = nsView.intrinsicContentSize.width
|
||||
}
|
||||
return CGSize(width: width, height: nsView.intrinsicContentSize.height)
|
||||
}
|
||||
@@ -436,7 +427,13 @@ final class SymbolComboControl: ComboFieldControl {
|
||||
|
||||
/// The glyph, centred and tinted. A name this system cannot draw falls back to the dashed
|
||||
/// question mark the wells use — the same "show that there is nothing here" the grids draw.
|
||||
///
|
||||
/// **Centred on both axes since 2026-08-09** — the doc comment above always said "centred" but the
|
||||
/// draw only ever centred vertically and offset from the leading edge by the swatch's own
|
||||
/// horizontal padding, which read as left-aligned once the glyph was more than a sliver narrower
|
||||
/// than the face. The owner's review named this directly ("for symbol picker center the symbol").
|
||||
override func drawFace(in rect: NSRect) {
|
||||
guard rect.width > 0, rect.height > 0 else { return }
|
||||
let name = ItemSymbol.exists(glyphName) ? glyphName : "questionmark.square.dashed"
|
||||
let config = NSImage.SymbolConfiguration(pointSize: metrics.glyphPointSize, weight: .regular)
|
||||
.applying(.init(paletteColors: [glyphTint ?? .labelColor]))
|
||||
@@ -445,7 +442,7 @@ final class SymbolComboControl: ComboFieldControl {
|
||||
else { return }
|
||||
let size = image.size
|
||||
image.draw(in: NSRect(
|
||||
x: rect.minX + metrics.facePaddingH,
|
||||
x: rect.midX - size.width / 2,
|
||||
y: rect.midY - size.height / 2,
|
||||
width: size.width,
|
||||
height: size.height
|
||||
|
||||
Reference in New Issue
Block a user