Skip to content

fix(ui): support macOS button and label padding - #10234

Closed
proggeramlug wants to merge 2 commits into
mainfrom
codex/10159-macos-leaf-padding
Closed

proggeramlug wants to merge 2 commits into
mainfrom
codex/10159-macos-leaf-padding

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Summary

macOS setPadding silently ignored buttons and text labels. Give Button, Text, and AttributedText real intrinsic-size and content-padding behavior, while preserving native styling and interaction. Unsupported native views now report a development-build diagnostic pointing callers to a padded stack.

Changes

  • Install the existing inset text-field cell when labels are created, preserving their text, font, and line-breaking defaults. Subsequent attributed styling remains on that cell.
  • Attach button padding to the existing native view through an instance-specific subclass, using the backend's established drag/drop pattern. Keep AppKit's original cell, factory flags, target/action, bezel, and hit target. A native associated value owns the insets; no extra thread-local registry is added.
  • Invalidate intrinsic size on updates, replace rather than accumulate insets, and honor flipped AppKit coordinates for asymmetric label/text-field/button padding.
  • Make drag/drop find its method-owning class through a padding subclass, so registration order and repeated setters preserve normal mouse-down forwarding.
  • Document the macOS support scope and unsupported-control fallback.

Related issue

Fixes #10159.

Test plan

On macOS arm64, using local development builds:

  • cargo build -p perry-ui-macos -j3 — passed, including the native backend static library.
  • RUST_TEST_THREADS=1 cargo test -p perry-ui-macos -j3 — passed the unit test, existing native_widget_order integration target, and new native_widget_padding integration target.
  • The new native target compares zero-padding controls with stock AppKit controls; checks bordered and borderless button sizing, reset/repeated updates, retained target/action, and plain/attributed labels; then renders controls into native bitmaps and verifies content displacement without clipping, both with and without layer backing. Asymmetric (top:3, left:5, bottom:7, right:11) adds exactly 16×10 points and moves the rendered content by 5×3 points.
  • The original implementation failed the new size regression for both labels and buttons. With padding enabled but the old drag/drop lookup restored, the native forwarding regression failed for padding-after-drop; the final implementation passes both orders and repeated registrations.
  • scripts/pre-tag-check.sh --quick — all checks passed except the existing public benchmark evidence-freshness failure. Its artifact, verifier, and every fingerprint input are unchanged from base 6000a00dfe.
  • git diff --check — passed.

The AppKit tests require macOS and run on the process main thread. No full workspace or non-macOS backend build was run. Other native control families still need a padded stack, as documented. Native content-inset support remains limited to the listed controls.

Checklist

  • No version bump; root Cargo.toml, Cargo.lock, CLAUDE.md, and CHANGELOG.md unchanged.
  • Added a changelog fragment, native regressions, and user-facing documentation.
  • Read the contribution instructions; commit uses the fix: prefix.

Summary by CodeRabbit

  • New Features

    • Added macOS padding support for buttons, text labels, and attributed-text labels.
    • Padding now adjusts intrinsic sizing, positions content correctly, supports asymmetric insets, and can be reset to natural sizing.
    • Native button appearance and behavior are preserved when padding is applied.
  • Bug Fixes

    • Improved padding behavior for flipped macOS views.
    • Preserved drag-and-drop interactions when styling views with padding.
  • Documentation

    • Documented macOS padding support, supported controls, reset behavior, and guidance for unsupported controls.

CI follow-up: the docs build-and-freshness job fails its gettext catalog freshness check, with repository-wide catalog diffs as well as the new styling text. The separate TLS checker and lint/check/warnings jobs are also red; remaining gap and GC jobs are still running. Local macOS validation above does not imply a green CI gate.

@coderabbitai

coderabbitai Bot commented Sep 13, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 15398bb8-efae-4824-9093-808db322f0fa

📥 Commits

Reviewing files that changed from the base of the PR and between d8bfa28 and 4807f9b.

📒 Files selected for processing (10)
  • changelog.d/10234-macos-leaf-padding.md
  • crates/perry-ui-macos/Cargo.toml
  • crates/perry-ui-macos/src/drag_drop.rs
  • crates/perry-ui-macos/src/widgets/attributed_text.rs
  • crates/perry-ui-macos/src/widgets/padding.rs
  • crates/perry-ui-macos/src/widgets/padding/button.rs
  • crates/perry-ui-macos/src/widgets/text.rs
  • crates/perry-ui-macos/tests/native_widget_padding.rs
  • crates/perry-ui-macos/tests/native_widget_padding/drag_drop.rs
  • docs/src/ui/styling.md

Included review availability: Your plan provides up to 8 included reviews per hour; 4 remain after this review.


📝 Walkthrough

Walkthrough

macOS padding now supports buttons, text labels, and attributed-text labels. The implementation handles flipped coordinates, invalidates intrinsic sizing, preserves native widget properties, avoids duplicate runtime subclasses, reports unsupported views, and adds integration coverage and documentation.

Changes

macOS native padding

Layer / File(s) Summary
Native padding implementation
crates/perry-ui-macos/src/widgets/padding.rs, crates/perry-ui-macos/src/widgets/padding/button.rs, crates/perry-ui-macos/src/widgets/text.rs, crates/perry-ui-macos/src/widgets/attributed_text.rs
Text-field cells now handle flipped coordinates. Labels and attributed-text labels install inset cells. Buttons use per-instance runtime subclasses for padded intrinsic sizing and drawing.
Padding and drag-and-drop compatibility
crates/perry-ui-macos/src/drag_drop.rs
Drag-and-drop class lookup now walks the superclass chain, including views with an inserted padding subclass.
Native regression coverage and documentation
crates/perry-ui-macos/Cargo.toml, crates/perry-ui-macos/tests/native_widget_padding.rs, crates/perry-ui-macos/tests/native_widget_padding/drag_drop.rs, docs/src/ui/styling.md, changelog.d/10234-macos-leaf-padding.md
The new native tests verify sizing, rendering, reset behavior, property preservation, and drag-and-drop ordering. Documentation and the changelog describe supported macOS padding behavior and diagnostics.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Bug fix · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant WidgetFactory
  participant set_edge_insets
  participant NSButton
  participant PerryButtonPadding
  WidgetFactory->>set_edge_insets: apply edge insets
  set_edge_insets->>NSButton: route button padding
  NSButton->>PerryButtonPadding: install or reuse subclass
  PerryButtonPadding->>NSButton: invalidate intrinsic size and redraw
Loading

Merge Risk: ⚪ Minimal · up to 4807f

MacOS padding behavior for labels and buttons is implemented with regression coverage for layout, rendering, resets, and drag/drop ordering. No merge-blocking risk is identified.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 34.78% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 23 functions across 7 files. (3 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Issue #10159 requires real macOS padding for buttons and text labels, plus a diagnostic for unsupported native views. The reviewed code routes NSButton views to a per-instance padding subclass and rou…
Out of Scope Changes check ✅ Passed The changes remain within issue #10159. The drag/drop superclass lookup change supports composition with the new per-instance button subclass and preserves drop behavior across registration orders. Th…
Title check ✅ Passed The title clearly and concisely describes the primary change: adding macOS padding support for buttons and labels.
Description check ✅ Passed The description includes the required Summary, Changes, Related issue, Test plan, and Checklist sections. It provides implementation details, validation commands, known CI failures, documentation upda…
Full details: Docstring Coverage

Explanation

Docstring coverage is 34.78% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 23 functions across 7 files. (3 skipped: 3 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/10159-macos-leaf-padding

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@proggeramlug

Copy link
Copy Markdown
Contributor Author

Landed via merge train 186r (#10247) at eb13fa1 on main.

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.

macOS setPadding is implemented for only 4 widget classes and silently no-ops on the rest (Button, labels, etc.)

1 participant