JDK-6489585 : GTK L&F: buttons, checkboxes, and radiobuttons are sized incorrectly
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 6
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: generic,solaris_9
  • CPU: generic
  • Submitted: 2006-11-02
  • Updated: 2011-03-09
  • Resolved: 2011-03-08
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6 JDK 7
6u1Fixed 7 b07Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Description
While investigating 6479305 (involving toolbars and their buttons under Swing's
GTK L&F), I began to question the current approach to calculating button insets.
It is clear from running any Swing app with the GTK L&F that JButtons (as well as
JCheckBoxes and JRadioButtons) are sized differently than their native equivalents,
specifically they appear to be much wider (esp. for JButtons) and their height is
sometimes a couple pixels off.

I'm attaching the usual JavaWidgetFactory and native "The Widget Factory" testcases
where you can see these differences.  It is apparent under any theme, but it's easier
to see (esp. for JCheckBox and JRadioButton) if you use a theme like Simple, where
the background of the checkbox/radiobutton is filled with a different color on mouse
over events.

The specific problems include:
1) JButtons have extra padding on the left/sides, which makes them look much wider
than native.  They are also a couple pixels taller than native in most cases.

2) JCheckBoxes and JRadioButtons have lots of padding around all sides, which makes
them layout with much more spacing than in native apps.

3) JCheckBoxes and JRadioButtons do not have the correct amount of spacing between
the indicator icon and the text.

Fixing these issues at the source will make it much easier to resolve the toolbar
issues described in 6479305.

Comments
EVALUATION Here's the evaluation for each of the issues listed above: 1) First a quick background on how the preferred size of JButtons are calculated under the Synth/GTK L&Fs. Take for example a simple JButton containing only the text "Test". There are a few things that are typically taken into account when SynthButtonUI is calculating the preferred size of a button: a) the insets b) the margins c) the icon rect d) the text rect The total preferred size of the button will be the union of the icon and text rects, plus the margins, plus the insets. In this example, we can forget about the icon rect. The text rect is being calculated properly (in this case, we get a nice tight bounding box of 27x17, which is consistent with native). The problem areas are in (a) and (b). In the case of (b), we are erroneously taking into account the default Button.margin value, defined in BasicLookAndFeel as (2,14,2,14). This helps explain why buttons are so much wider than expected by default. In the case of (a), our calculations in GTKStyle.getButtonInsets() are nearly correct, except that we're not taking into account the CHILD_SPACING constant value that is used in the native gtk_button_size_allocate() method. The fix here is to override the Button.margin value in GTKLookAndFeel to use a zero insets value instead. This takes the margin value out of the equation. Now the only other thing we need to do is to fix GTKStyle.getButtonInsets() to add in the CHILD_SPACING constant, and voila, our buttons are now pixel-for-pixel accurate with native GtkButtons. It is worth noting that fixing this issue resolves a number of the problems we were seeing in 6479305 w.r.t. toolbar buttons being rectangular by default. It was really this bogus margins value that was causing those toolbar buttons to be non-square. With this fix in place, toolbar buttons (especially those that contain only a square icon) will now be laid out correctly. So that resolves the first part of 6479305, although there is still more work to be done under that bugid to get toolbars looking perfect. 2,3) These issues are closely related to what I've described above for (1). The extra padding is again caused by the fact that we're picking up the margins defined in BasicLookAndFeel for CheckBox.margin and RadioButton.margin, both of which are defined as (2,2,2,2). The first fix here is to override CheckBox.margin and RadioButton.margin with zero insets in GTKLookAndFeel. The remaining padding issue is caused by the fact that we use GTKStyle.getButtonInsets() to calculate the insets for JCheckBox and JRadioButton. There are subtle differences between how GtkButtons and GtkCheckButtons are laid out, so we really should have a separate method, GTKStyle.getRadioInsets(), that is tuned to laying out JCheckBoxes and JRadioButtons. These two widgets are made up of the same four regions as I described above, but with some minor variation: a) the insets b) the margins c) the icon rect (for the indicator) d) the text rect e) the icon-text spacing (the padding between the indicator and the text) The difficulty here is that native GtkCheckButtons (this includes GtkRadioButtons, which are a subclass) paint their focus around only the text, not the indicator. This means we can't just use the same calculation that is used in GTKStyle.getButtonInsets(), since that will figure the focus around both the icon and the text (also, GtkCheckButtons do not have that CHILD_SPACING constant that I described earlier, which is another difference). So, the top/bottom insets are easy: that's just "focus-line-width" plus "focus-padding" (call it "totalFocus"). The left/right insets are more tricky, and depend on the LTR/RTL orientation of the component. In the LTR case, there should be no padding on the left side of the component (where the indicator lies; any padding is provided by the indicator icon itself); on the right side of the component, we need to include "totalFocus". For the RTL case, we simply reverse these values. Finally, we need to be smarter about how we handle CheckBox/RadioButton.iconTextGap values. Currently, we use GtkCheckButton's "indicator-spacing" value, but that isn't enough. It might help to visualize the horizontal layout of the contents of a JCheckBox; from left to right, the important elements are: a) the left inset b) the width of the indicator icon c) the iconTextGap d) the left part of the focus indicator e) the width of the text f) the right part of the focus indicator g) the right inset It's also worth describing how those parts map to the way GtkCheckButton lays its elements out horizontally. In gtkcheckbutton.c (gtk_check_button_size_allocate() method), it appears to lay out horizontally like this: a) indicator-spacing b) indicator-size c) indicator-spacing d) indicator-spacing e) focus-padding + focus-line-width f) the width of the text g) focus-padding + focus-line-width Note that GTKIconFactory.DelegateIcon actually adds "indicator-spacing" as a padding to each side of the icon, so if "indicator-size" is 13 and "indicator-spacing" is 2, the actual SynthIcon will end up being 17x17 (2+13+2). To bridge these two worlds, we need to do the following for JCheckBox and JRadioButton: - the left inset should be zero - the DelegateIcon already includes "indicator-spacing" PLUS "indicator-size" PLUS "indicator-spacing" (so nothing needs to change in DelegateIcon) - the value of iconTextGap needs to include another "indicator-spacing" PLUS "focus-padding" PLUS "focus-line-width" (this needs to be calculated in GTKStyle.get()) - the width of the text is okay, no changes needed - the right inset should be "focus-padding" PLUS "focus-line-width" With those changes in place, Swing's JCheckBox and JRadioButton are now pixel-for-pixel identical to their native counterparts.
02-11-2006