From 7e05b65791533f9572b3275ecac48330da6e7aef Mon Sep 17 00:00:00 2001 From: Heiko Klare Date: Thu, 9 Apr 2026 16:50:19 +0200 Subject: [PATCH] [Cocoa] Use NSBezelStyleFlexiblePush for buttons with custom font size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NSRoundedBezelStyle (the default rounded push button style on macOS) has a fixed height optimised for the system default font size of 13 pt. When a larger custom font is set on a push or toggle button, the text overflows the fixed rendering bounds and is visually clipped. Apple provides NSBezelStyleFlexiblePush (previously known as the now- deprecated NSRegularSquareBezelStyle) specifically for this situation: it allows the button cell to grow vertically and adapt its appearance to whatever content height is required. The fix has two parts: 1. setFont() – when the internal Cocoa font hook fires, check whether a custom font has been explicitly set on the widget (Control.font != null). If so, immediately switch the bezel style to NSBezelStyleFlexiblePush so that a subsequent computeSize() / layout pass sees the correct style and the cell reports the right preferred height. When the custom font is cleared (setFont(null)), the style is restored to NSRoundedBezelStyle. 2. setBounds() – the existing height-threshold guard that switches bezel styles during layout is extended with "|| font != null" so that a layout pass following a font change never inadvertently reverts the button back to NSRoundedBezelStyle. Both guards apply only to PUSH and TOGGLE buttons without the FLAT or WRAP style bits, mirroring the existing bezel-style selection logic. The constant NSBezelStyleFlexiblePush is added to OS.java (value 2, sourced from NSButtonCell.h in the macOS 15.4 SDK) in alphabetical order alongside the other NSBezelStyle constants, making the intention explicit and avoiding reliance on the deprecated NSRegularSquareBezelStyle alias. A regression test is added to Test_org_eclipse_swt_widgets_Button that verifies a push button reports a greater preferred height after its font size is increased to 50 pt. This ensures that layout managers allocate sufficient space and the button text is not clipped. Fixes https://github.com/eclipse-platform/eclipse.platform.swt/issues/3085 --- .../org/eclipse/swt/internal/cocoa/OS.java | 1 + .../cocoa/org/eclipse/swt/widgets/Button.java | 14 +++++++-- .../Test_org_eclipse_swt_widgets_Button.java | 31 +++++++++++++++++++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/OS.java b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/OS.java index fffa4837ed..284026717b 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/OS.java +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/cocoa/org/eclipse/swt/internal/cocoa/OS.java @@ -2179,6 +2179,7 @@ public static Selector getSelector (long value) { public static final int NSBackspaceCharacter = 8; public static final int NSBevelLineJoinStyle = 2; public static final int NSBezelBorder = 2; +public static final int NSBezelStyleFlexiblePush = 2; public static final int NSBoldFontMask = 2; public static final int NSBorderlessWindowMask = 0; public static final int NSBottomTabsBezelBorder = 2; diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Button.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Button.java index 571b793a07..c71f7da62a 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Button.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Button.java @@ -829,8 +829,11 @@ void setBounds (int x, int y, int width, int height, boolean move, boolean resiz } NSButton button = (NSButton)view; - if (height > heightThreshold) { - button.setBezelStyle(OS.NSRegularSquareBezelStyle); + // Use NSBezelStyleFlexiblePush when a custom font is set or when the height + // exceeds the standard button height. NSRoundedBezelStyle assumes the macOS + // default font size (13pt) and clips text at larger sizes. + if (height > heightThreshold || font != null) { + button.setBezelStyle(OS.NSBezelStyleFlexiblePush); } else { button.setBezelStyle(OS.NSRoundedBezelStyle); } @@ -845,10 +848,15 @@ void setBounds (int x, int y, int width, int height, boolean move, boolean resiz } @Override -void setFont (NSFont font) { +void setFont (NSFont nsFont) { if (text != null) { ((NSButton)view).setAttributedTitle(createString()); } + if ((style & (SWT.PUSH | SWT.TOGGLE)) != 0 && (style & (SWT.FLAT | SWT.WRAP)) == 0) { + // Use NSBezelStyleFlexiblePush when a custom font is set. NSRoundedBezelStyle + // assumes the macOS default font size (13pt) and clips text at larger sizes. + ((NSButton)view).setBezelStyle(font != null ? OS.NSBezelStyleFlexiblePush : OS.NSRoundedBezelStyle); + } } @Override diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Button.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Button.java index d406cedb87..df252704b5 100644 --- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Button.java +++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Button.java @@ -28,8 +28,11 @@ import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageGcDrawer; +import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; @@ -584,6 +587,34 @@ public void test_consistency_DragDetect () { consistencyEvent(5, 5, 15, 15, ConsistencyUtility.MOUSE_DRAG); } +/** + * Test that a push button reports a greater preferred height after its font + * size is increased. A button whose font grows larger must compute a + * proportionally taller preferred size so that layout managers allocate + * sufficient space and the text is not clipped. + * + * @see issue #3085 + */ +@Test +public void test_computeSize_largerWithLargeCustomFont() { + button.setText("OK"); + shell.open(); + + Point defaultSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT); + + FontData[] fontData = button.getFont().getFontData(); + Font largeFont = new Font(button.getDisplay(), fontData[0].getName(), 50, fontData[0].getStyle()); + try { + button.setFont(largeFont); + SwtTestUtil.processEvents(); + Point largeSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT); + assertTrue(largeSize.y > defaultSize.y, + "Button with 50 pt font should be taller than button with default font"); + } finally { + largeFont.dispose(); + } +} + /** Test for Bug 381668 - NPE when disposing radio buttons right before they should gain focus */ @Disabled(value = "Test works fine locally but fails to get correct focus on automated builds.") @Test