Skip to content

refactor: make SortableHeaderCell.titleRect AX-correct and share data grid horizontal inset#1042

Merged
datlechin merged 1 commit intomainfrom
refactor/sortable-header-layout
May 6, 2026
Merged

refactor: make SortableHeaderCell.titleRect AX-correct and share data grid horizontal inset#1042
datlechin merged 1 commit intomainfrom
refactor/sortable-header-layout

Conversation

@datlechin
Copy link
Copy Markdown
Member

Summary

Follow-up refactor to #1040. Two correctness wins and one cleanup.

1. titleRect(forBounds:) now returns the same rect AppKit and AX see

After #1040, drawInterior was passing an indicator-subtracted sub-rect into titleRect(forBounds:). AppKit and AX call cell.titleRect(forBounds: cellFrame) with full cell bounds, so external callers were getting back a frame that overlapped the sort indicator and priority badge.

Moved the indicator/priority width math into a private reservedTrailingWidth() helper that titleRect(forBounds:) consults. drawInterior now calls titleRect(forBounds: cellFrame) exactly once on the full bounds, and AX hit-testing lines up with what is actually drawn.

2. Row-number column header right-alignment is now testable

Extracted DataGridView.makeRowNumberColumn() as a static @MainActor factory so the row-number column setup can be exercised from tests. Added DataGridRowNumberColumnTests.rowNumberHeaderIsRightAlignedSortableCell so a future drive-by edit cannot silently drop .alignment = .right on the # header.

3. Shared DataGridMetrics.cellHorizontalInset

The 4pt inset that ties data cells and column headers together was duplicated as literals across 5 files. Pulled into a single DataGridMetrics.cellHorizontalInset constant (new Cells/DataGridMetrics.swift). SortableHeaderCell, DataGridBaseCellView, DataGridCellRegistry, DataGridChevronCellView, DataGridForeignKeyCellView all read from it. The two values can no longer drift.

Tests

  • SortableHeaderCellTests.sortedTitleRectReservesTrailingSpaceForIndicator — sorted rect is narrower than unsorted at the same bounds, and its maxX does not run past the trailing inset.
  • SortableHeaderCellTests.priorityBadgeShrinksSortedTitleRectFurther — priority >= 2 shrinks the rect further, matching what is reserved for the badge.
  • DataGridRowNumberColumnTests.rowNumberHeaderIsRightAlignedSortableCell# header is a SortableHeaderCell with .right alignment.
  • Existing titleRectUsesDataCellHorizontalPadding and narrowTitleRectDoesNotProduceNegativeWidth still pass against the new titleRect.

Validation

  • swiftlint lint --strict --config .swiftlint.yml clean across all eight changed files.
  • xcodebuild ... test -only-testing:TableProTests/SortableHeaderCellTests and -only-testing:TableProTests/DataGridRowNumberColumnTests to verify (run locally).

CHANGELOG

No entry. The AX semantic issue this fixes was introduced in #1040, which has not shipped, and project rules say not to add a Fixed entry for fixing something that is itself still unreleased.

Related

@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@datlechin datlechin merged commit 671862a into main May 6, 2026
2 checks passed
@datlechin datlechin deleted the refactor/sortable-header-layout branch May 6, 2026 11:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant