Skip to content

8348760: RadioButton is not shown if JRadioButtonMenuItem is rendered with ImageIcon in WindowsLookAndFeel #23324

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 36 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
06c1d44
8348760: RadioButton is not shown if JRadioButtonMenuItem is rendered…
prsadhuk Jan 28, 2025
bc5580f
jecheck
prsadhuk Jan 28, 2025
befbdf5
formatting
prsadhuk Jan 29, 2025
2bb0869
image path correction
prsadhuk Jan 30, 2025
9aeda88
optimise
prsadhuk Jan 30, 2025
4a5a779
RadioButton not drawn. ImageIcon on the fly
prsadhuk Jan 30, 2025
6a8faec
Remove duke
prsadhuk Jan 30, 2025
9482b26
Draw checkmark skin at same location with/without icon
prsadhuk Jan 30, 2025
6a9f914
Move icon w.r.t bullet skin width
prsadhuk Feb 4, 2025
f9cb299
Move icon w.r.t bullet skin width
prsadhuk Feb 4, 2025
d5a252b
remove debug
prsadhuk Feb 4, 2025
31cdc70
retain diff of OFFSET between skin background start coord and skin co…
prsadhuk Feb 4, 2025
cdcd7d0
Move text position w.r.t menuItem icon
prsadhuk Feb 7, 2025
5742db5
remove test file
prsadhuk Feb 7, 2025
46a1cb5
Restore Windows 10 behavior
prsadhuk Feb 10, 2025
7fac9e0
Extend to Windows11 and later
prsadhuk Feb 13, 2025
7cb51be
comment
prsadhuk Feb 13, 2025
7f0849f
Merge branch 'master' of https://git.openjdk.java.net/jdk into JDK-83…
prsadhuk Feb 24, 2025
de139e5
Move windows specific change to windows folder
prsadhuk Feb 25, 2025
9a45719
Revert to non-CSR needed fix
prsadhuk Feb 28, 2025
a3475a9
Test rename
prsadhuk Feb 28, 2025
3887606
Review comment fix
prsadhuk Mar 5, 2025
00daa8f
Remove Windows L&F check from BasicMenuItemUI
prsadhuk Mar 7, 2025
b5a91f5
Code duplication removed
prsadhuk Mar 10, 2025
03a0872
Merge branch 'master' of https://git.openjdk.java.net/jdk into JDK-83…
prsadhuk Mar 12, 2025
381cdf5
Remove unneeded methods
prsadhuk Mar 12, 2025
2ff5f03
Expand wildcard imports
prsadhuk Mar 12, 2025
e20cfc0
Review comments fix
prsadhuk Mar 12, 2025
ba7ecae
Merge branch 'master' of https://git.openjdk.java.net/jdk into JDK-83…
prsadhuk May 28, 2025
bfc108e
Text alignment fix
prsadhuk May 28, 2025
898996a
Fix issue for presence of gap between buller and text only if atleast…
prsadhuk Jun 24, 2025
f019f63
Windows 10 offset correction without icon
prsadhuk Jun 26, 2025
ea1016f
Merge branch 'master' of https://git.openjdk.java.net/jdk into JDK-83…
prsadhuk Jun 26, 2025
2348548
MenuItem with icon fix
prsadhuk Jun 26, 2025
24fb819
Alignment fix
prsadhuk Jun 30, 2025
fcaeb2d
squish fix
prsadhuk Jul 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -26,22 +26,30 @@
package com.sun.java.swing;

import java.applet.Applet;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.Window;
import java.awt.geom.AffineTransform;
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;

import javax.swing.ButtonModel;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.RepaintManager;

import sun.awt.AppContext;
import sun.awt.SunToolkit;
import sun.swing.MenuItemLayoutHelper;
import sun.swing.SwingUtilities2;

import static sun.java2d.pipe.Region.clipRound;

Expand All @@ -64,6 +72,10 @@ public class SwingUtilities3 {
private static final Object DELEGATE_REPAINT_MANAGER_KEY =
new StringBuilder("DelegateRepaintManagerKey");

private static Color disabledForeground;
private static Color acceleratorSelectionForeground;
private static Color acceleratorForeground;

/**
* Registers delegate RepaintManager for {@code JComponent}.
*/
Expand Down Expand Up @@ -143,6 +155,128 @@ public static RepaintManager getDelegateRepaintManager(Component
return delegate;
}

public static void applyInsets(Rectangle rect, Insets insets) {
if (insets != null) {
rect.x += insets.left;
rect.y += insets.top;
rect.width -= (insets.right + rect.x);
rect.height -= (insets.bottom + rect.y);
Comment on lines +162 to +163
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
rect.width -= (insets.right + rect.x);
rect.height -= (insets.bottom + rect.y);
rect.width -= (insets.right + insets.left);
rect.height -= (insets.bottom + insets.top);

The formula doesn't look right. Why do you subtract rect.x and rect.y instead of insets.left and insets.top?

This would work correctly if both rect.x and rect.y are zero, but it would give wrong results in other cases.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was the same calculation used in BasicMenuItemUI which is now moved to SwingUtilities3 so that it can be called from Basic and WindowsMenuItemUI to avoid code duplication....you can compare the contents before the fix.....in this specific case, rect.x is inclusive of insets.left..

Similarly other SwingUtilities3 changes are also as it was in BasicMenuItemUI, it was just moved verbatim from BasicMenuItemUI to it so that it can be called from both Basic and WindowsMenuItemUI class with no changes..nothing more and nothing less...probably it can be optimized but I wanted to keep the call and the content in each method in SwingUtilities3 same as it was in BasicMenuItemUI

}
}

public static void paintCheckIcon(Graphics g, MenuItemLayoutHelper lh,
MenuItemLayoutHelper.LayoutResult lr,
Color holdc, Color foreground) {
if (lh.getCheckIcon() != null) {
ButtonModel model = lh.getMenuItem().getModel();
if (model.isArmed() || (lh.getMenuItem() instanceof JMenu
&& model.isSelected())) {
g.setColor(foreground);
} else {
g.setColor(holdc);
}
if (lh.useCheckAndArrow()) {
lh.getCheckIcon().paintIcon(lh.getMenuItem(), g,
lr.getCheckRect().x, lr.getCheckRect().y);
}
g.setColor(holdc);
}
}

public static void paintIcon(Graphics g, MenuItemLayoutHelper lh,
MenuItemLayoutHelper.LayoutResult lr, Color holdc) {
if (lh.getIcon() != null) {
Icon icon;
ButtonModel model = lh.getMenuItem().getModel();
if (!model.isEnabled()) {
icon = lh.getMenuItem().getDisabledIcon();
} else if (model.isPressed() && model.isArmed()) {
icon = lh.getMenuItem().getPressedIcon();
if (icon == null) {
// Use default icon
icon = lh.getMenuItem().getIcon();
}
} else {
icon = lh.getMenuItem().getIcon();
}

if (icon != null) {
icon.paintIcon(lh.getMenuItem(), g, lr.getIconRect().x,
lr.getIconRect().y);
g.setColor(holdc);
}
}
}


public static void paintAccText(Graphics g, MenuItemLayoutHelper lh,
MenuItemLayoutHelper.LayoutResult lr) {
if (!lh.getAccText().isEmpty()) {
ButtonModel model = lh.getMenuItem().getModel();
g.setFont(lh.getAccFontMetrics().getFont());
if (!model.isEnabled()) {

// paint the accText disabled
if (disabledForeground != null) {
g.setColor(disabledForeground);
SwingUtilities2.drawString(lh.getMenuItem(), g,
lh.getAccText(), lr.getAccRect().x,
lr.getAccRect().y + lh.getAccFontMetrics().getAscent());
} else {
g.setColor(lh.getMenuItem().getBackground().brighter());
SwingUtilities2.drawString(lh.getMenuItem(), g,
lh.getAccText(), lr.getAccRect().x,
lr.getAccRect().y + lh.getAccFontMetrics().getAscent());
g.setColor(lh.getMenuItem().getBackground().darker());
SwingUtilities2.drawString(lh.getMenuItem(), g,
lh.getAccText(), lr.getAccRect().x - 1,
lr.getAccRect().y + lh.getFontMetrics().getAscent() - 1);
}
} else {

// paint the accText normally
if (model.isArmed()
|| (lh.getMenuItem() instanceof JMenu
&& model.isSelected())) {
g.setColor(acceleratorSelectionForeground);
} else {
g.setColor(acceleratorForeground);
}
SwingUtilities2.drawString(lh.getMenuItem(), g, lh.getAccText(),
lr.getAccRect().x, lr.getAccRect().y +
lh.getAccFontMetrics().getAscent());
}
}
}

public static void setDisabledForeground(Color disabledFg) {
disabledForeground = disabledFg;
}

public static void setAcceleratorSelectionForeground(Color acceleratorSelectionFg) {
acceleratorForeground = acceleratorSelectionFg;
}

public static void setAcceleratorForeground(Color acceleratorFg) {
acceleratorForeground = acceleratorFg;
}

public static void paintArrowIcon(Graphics g, MenuItemLayoutHelper lh,
MenuItemLayoutHelper.LayoutResult lr,
Color foreground) {
if (lh.getArrowIcon() != null) {
ButtonModel model = lh.getMenuItem().getModel();
if (model.isArmed() || (lh.getMenuItem() instanceof JMenu
&& model.isSelected())) {
g.setColor(foreground);
}
if (lh.useCheckAndArrow()) {
lh.getArrowIcon().paintIcon(lh.getMenuItem(), g,
lr.getArrowRect().x, lr.getArrowRect().y);
}
}
}

/**
* A task which paints an <i>unscaled</i> border after {@code Graphics}
* transforms are removed. It's used with the
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -25,17 +25,52 @@

package javax.swing.plaf.basic;

import java.awt.*;
import java.awt.event.*;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.plaf.*;
import javax.swing.ButtonModel;
import javax.swing.Icon;
import javax.swing.InputMap;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.KeyStroke;
import javax.swing.LookAndFeel;
import javax.swing.MenuElement;
import javax.swing.MenuSelectionManager;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.MenuDragMouseEvent;
import javax.swing.event.MenuDragMouseListener;
import javax.swing.event.MenuKeyListener;

import javax.swing.event.MouseInputListener;
import javax.swing.plaf.ComponentInputMapUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.MenuItemUI;
import javax.swing.plaf.UIResource;
import javax.swing.text.View;

import sun.swing.*;
import com.sun.java.swing.SwingUtilities3;
import sun.swing.MenuItemCheckIconFactory;
import sun.swing.MenuItemLayoutHelper;
import sun.swing.SwingUtilities2;
import sun.swing.UIAction;


/**
* BasicMenuItem implementation
Expand Down Expand Up @@ -670,84 +705,22 @@ protected void paintMenuItem(Graphics g, JComponent c,

private void paintIcon(Graphics g, MenuItemLayoutHelper lh,
MenuItemLayoutHelper.LayoutResult lr, Color holdc) {
if (lh.getIcon() != null) {
Icon icon;
ButtonModel model = lh.getMenuItem().getModel();
if (!model.isEnabled()) {
icon = lh.getMenuItem().getDisabledIcon();
} else if (model.isPressed() && model.isArmed()) {
icon = lh.getMenuItem().getPressedIcon();
if (icon == null) {
// Use default icon
icon = lh.getMenuItem().getIcon();
}
} else {
icon = lh.getMenuItem().getIcon();
}

if (icon != null) {
icon.paintIcon(lh.getMenuItem(), g, lr.getIconRect().x,
lr.getIconRect().y);
g.setColor(holdc);
}
}
SwingUtilities3.paintIcon(g, lh, lr, holdc);
}

private void paintCheckIcon(Graphics g, MenuItemLayoutHelper lh,
MenuItemLayoutHelper.LayoutResult lr,
Color holdc, Color foreground) {
if (lh.getCheckIcon() != null) {
ButtonModel model = lh.getMenuItem().getModel();
if (model.isArmed() || (lh.getMenuItem() instanceof JMenu
&& model.isSelected())) {
g.setColor(foreground);
} else {
g.setColor(holdc);
}
if (lh.useCheckAndArrow()) {
lh.getCheckIcon().paintIcon(lh.getMenuItem(), g,
lr.getCheckRect().x, lr.getCheckRect().y);
}
g.setColor(holdc);
}
SwingUtilities3.paintCheckIcon(g, lh, lr, holdc, foreground);
}

private void paintAccText(Graphics g, MenuItemLayoutHelper lh,
MenuItemLayoutHelper.LayoutResult lr) {
if (!lh.getAccText().isEmpty()) {
ButtonModel model = lh.getMenuItem().getModel();
g.setFont(lh.getAccFontMetrics().getFont());
if (!model.isEnabled()) {
// *** paint the accText disabled
if (disabledForeground != null) {
g.setColor(disabledForeground);
SwingUtilities2.drawString(lh.getMenuItem(), g,
lh.getAccText(), lr.getAccRect().x,
lr.getAccRect().y + lh.getAccFontMetrics().getAscent());
} else {
g.setColor(lh.getMenuItem().getBackground().brighter());
SwingUtilities2.drawString(lh.getMenuItem(), g,
lh.getAccText(), lr.getAccRect().x,
lr.getAccRect().y + lh.getAccFontMetrics().getAscent());
g.setColor(lh.getMenuItem().getBackground().darker());
SwingUtilities2.drawString(lh.getMenuItem(), g,
lh.getAccText(), lr.getAccRect().x - 1,
lr.getAccRect().y + lh.getFontMetrics().getAscent() - 1);
}
} else {
// *** paint the accText normally
if (model.isArmed()
|| (lh.getMenuItem() instanceof JMenu
&& model.isSelected())) {
g.setColor(acceleratorSelectionForeground);
} else {
g.setColor(acceleratorForeground);
}
SwingUtilities2.drawString(lh.getMenuItem(), g, lh.getAccText(),
lr.getAccRect().x, lr.getAccRect().y +
lh.getAccFontMetrics().getAscent());
}
}
SwingUtilities3.setDisabledForeground(disabledForeground);
SwingUtilities3.setAcceleratorSelectionForeground(
acceleratorSelectionForeground);
SwingUtilities3.setAcceleratorForeground(acceleratorForeground);
SwingUtilities3.paintAccText(g, lh, lr);
}

private void paintText(Graphics g, MenuItemLayoutHelper lh,
Expand All @@ -766,26 +739,11 @@ private void paintText(Graphics g, MenuItemLayoutHelper lh,
private void paintArrowIcon(Graphics g, MenuItemLayoutHelper lh,
MenuItemLayoutHelper.LayoutResult lr,
Color foreground) {
if (lh.getArrowIcon() != null) {
ButtonModel model = lh.getMenuItem().getModel();
if (model.isArmed() || (lh.getMenuItem() instanceof JMenu
&& model.isSelected())) {
g.setColor(foreground);
}
if (lh.useCheckAndArrow()) {
lh.getArrowIcon().paintIcon(lh.getMenuItem(), g,
lr.getArrowRect().x, lr.getArrowRect().y);
}
}
SwingUtilities3.paintArrowIcon(g, lh, lr, foreground);
}

private void applyInsets(Rectangle rect, Insets insets) {
if(insets != null) {
rect.x += insets.left;
rect.y += insets.top;
rect.width -= (insets.right + rect.x);
rect.height -= (insets.bottom + rect.y);
}
SwingUtilities3.applyInsets(rect, insets);
}

/**
Expand Down
Loading