Skip to content

Commit

Permalink
7124282: [macosx] Can't see table cell highlighter when the highlight…
Browse files Browse the repository at this point in the history
… border is the same color as the cell.

Reviewed-by: psadhukhan, prr
  • Loading branch information
honkar-jdk authored and prsadhuk committed May 10, 2022
1 parent 9a3cb93 commit bd6026c
Show file tree
Hide file tree
Showing 6 changed files with 263 additions and 14 deletions.
45 changes: 35 additions & 10 deletions src/java.desktop/macosx/classes/com/apple/laf/AquaFocusHandler.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2022, 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,11 +25,21 @@

package com.apple.laf;

import java.awt.*;
import java.awt.event.*;
import java.beans.*;

import javax.swing.*;
import java.awt.Color;
import java.awt.Window;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.JComponent;
import javax.swing.JTree;
import javax.swing.JTable;
import javax.swing.JList;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

import javax.swing.plaf.BorderUIResource;
import javax.swing.plaf.UIResource;

/**
Expand Down Expand Up @@ -113,22 +123,35 @@ static void swapSelectionColors(final String prefix, final JTable c, final Objec

final Color bg = c.getSelectionBackground();
final Color fg = c.getSelectionForeground();

if (!(bg instanceof UIResource) || !(fg instanceof UIResource)) return;

if (Boolean.FALSE.equals(value)) {
setSelectionColors(c, "Table.selectionInactiveForeground", "Table.selectionInactiveBackground");
setSelectionColors(c, "Table.selectionInactiveForeground",
"Table.selectionInactiveBackground");
return;
}

if (Boolean.TRUE.equals(value)) {
setSelectionColors(c, "Table.selectionForeground", "Table.selectionBackground");
setSelectionColors(c, "Table.selectionForeground",
"Table.selectionBackground");
return;
}
}

static void setSelectionColors(final JTable c, final String fgName, final String bgName) {

c.setSelectionForeground(UIManager.getColor(fgName));
c.setSelectionBackground(UIManager.getColor(bgName));

// focus ring changes for on-the-fly accent color changes
Color prominentFocusRing = AquaLookAndFeel.deriveProminentFocusRing(
UIManager.getColor("Table.cellFocusRing"));
BorderUIResource.LineBorderUIResource focusCellHighlightBorder =
new BorderUIResource.LineBorderUIResource(prominentFocusRing, 2);
UIManager.getDefaults().put("Table.focusCellHighlightBorder",
focusCellHighlightBorder);

}

static void swapSelectionColors(final String prefix, final JList<?> c, final Object value) {
Expand All @@ -139,12 +162,14 @@ static void swapSelectionColors(final String prefix, final JList<?> c, final Obj
if (!(bg instanceof UIResource) || !(fg instanceof UIResource)) return;

if (Boolean.FALSE.equals(value)) {
setSelectionColors(c, "List.selectionInactiveForeground", "List.selectionInactiveBackground");
setSelectionColors(c, "List.selectionInactiveForeground",
"List.selectionInactiveBackground");
return;
}

if (Boolean.TRUE.equals(value)) {
setSelectionColors(c, "List.selectionForeground", "List.selectionBackground");
setSelectionColors(c, "List.selectionForeground",
"List.selectionBackground");
return;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2022, 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 Down Expand Up @@ -506,6 +506,10 @@ public static Color getFocusRingColorUIResource() {
return new SystemColorProxy(LWCToolkit.getAppleColor(LWCToolkit.KEYBOARD_FOCUS_COLOR));
}

public static Color getCellHighlightColorUIResource() {
return new SystemColorProxy(LWCToolkit.getAppleColor(LWCToolkit.CELL_HIGHLIGHT_COLOR));
}

public static Color getSelectionInactiveBackgroundColorUIResource() {
return new SystemColorProxy(LWCToolkit.getAppleColor(LWCToolkit.INACTIVE_SELECTION_BACKGROUND_COLOR));
}
Expand Down
66 changes: 64 additions & 2 deletions src/java.desktop/macosx/classes/com/apple/laf/AquaLookAndFeel.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2022, 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 Down Expand Up @@ -388,6 +388,9 @@ public Object createValue(UIDefaults defaultsTable) {
final Color focusRingColor = AquaImageFactory.getFocusRingColorUIResource();
final Border focusCellHighlightBorder = new BorderUIResource.LineBorderUIResource(focusRingColor);

// for table cell highlighter
final Color cellFocusRingColor = AquaImageFactory.getCellHighlightColorUIResource();

final Color windowBackgroundColor = AquaImageFactory.getWindowBackgroundColorUIResource();
final Color panelBackgroundColor = windowBackgroundColor;
final Color tabBackgroundColor = windowBackgroundColor;
Expand Down Expand Up @@ -889,7 +892,9 @@ public Object createValue(UIDefaults defaultsTable) {
"Table.gridColor", white, // grid line color
"Table.focusCellBackground", textHighlightText,
"Table.focusCellForeground", textHighlight,
"Table.focusCellHighlightBorder", focusCellHighlightBorder,
"Table.cellFocusRing", cellFocusRingColor,
"Table.focusCellHighlightBorder", new BorderUIResource.LineBorderUIResource(
deriveProminentFocusRing(cellFocusRingColor), 2),
"Table.scrollPaneBorder", scollListBorder,

"Table.ancestorInputMap", aquaKeyBindings.getTableInputMap(),
Expand Down Expand Up @@ -1122,4 +1127,61 @@ protected void initClassDefaults(final UIDefaults table) {
};
table.putDefaults(uiDefaults);
}

/**
* Returns a new cell focus ring color by changing saturation
* and setting the brightness to 100% for incoming cellFocusRing.
*
* If the incoming cellFocusRingColor is equal to white/black/grayish,
* the returned cellFocusRingColor is Light Gray. For all other colors,
* new cellFocusRingColor (in the latter case), is obtained by adjusting
* the saturation levels and setting the brightness to 100% of the
* incoming cellFocusRingColor.
*
* @param cellFocusRingColor - the {@code Color} object
* @return the {@code Color} object corresponding to new HSB values
*/
static Color deriveProminentFocusRing(Color cellFocusRingColor) {

// define constants
float satLowerValue = 0.30f;
float satUpperValue = 1.0f;

// saturation threshold for grayish colors
float satGrayScale = 0.10f;

// used to compare with saturation value of original focus ring and
// set it to either lower or upper saturation value
float saturationThreshold = 0.5f;

// brightness always set to 100%
float brightnessValue = 1.0f;

float[] hsbValues = new float[3];

int redValue = cellFocusRingColor.getRed();
int greenValue = cellFocusRingColor.getGreen();
int blueValue = cellFocusRingColor.getBlue();

Color.RGBtoHSB(redValue, greenValue, blueValue, hsbValues);

// if cellFocusRing is White/Black/Grayish
if ((hsbValues[0] == 0 && hsbValues[1] == 0)
|| hsbValues[1] <= satGrayScale) {
return Color.LIGHT_GRAY;
}

// if cellFocusRing color NOT White/Black/Grayish
// saturation adjustment - saturation set to either lower or
// upper saturation value based on current saturation level
hsbValues[1] = hsbValues[1] >= saturationThreshold ?
satLowerValue : satUpperValue;

// brightness adjustment - brightness set to 100%, always return the
// brightest color for the new color
hsbValues[2] = brightnessValue;

//create and return color corresponding to new hsbValues
return Color.getHSBColor(hsbValues[0], hsbValues[1], hsbValues[2]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -209,16 +209,19 @@ public LWCToolkit() {
/*
* System colors with default initial values, overwritten by toolkit if system values differ and are available.
*/
private static final int NUM_APPLE_COLORS = 4;
private static final int NUM_APPLE_COLORS = 5;
public static final int KEYBOARD_FOCUS_COLOR = 0;
public static final int INACTIVE_SELECTION_BACKGROUND_COLOR = 1;
public static final int INACTIVE_SELECTION_FOREGROUND_COLOR = 2;
public static final int SELECTED_CONTROL_TEXT_COLOR = 3;
public static final int CELL_HIGHLIGHT_COLOR = 4;

private static int[] appleColors = {
0xFF808080, // keyboardFocusColor = Color.gray;
0xFFC0C0C0, // secondarySelectedControlColor
0xFF303030, // controlDarkShadowColor
0xFFFFFFFF, // controlTextColor
0xFF808080, // cellHighlightColor = Color.gray;
};

private native void loadNativeColors(final int[] systemColors, final int[] appleColors);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ + (void)reloadColors {
}
}

// added for JTable Focus Ring
if (@available(macOS 10.14, *)) {
appleColors[sun_lwawt_macosx_LWCToolkit_CELL_HIGHLIGHT_COLOR] = [NSColor controlAccentColor];
} else {
appleColors[sun_lwawt_macosx_LWCToolkit_CELL_HIGHLIGHT_COLOR] = [NSColor keyboardFocusIndicatorColor];
}
appleColors[sun_lwawt_macosx_LWCToolkit_KEYBOARD_FOCUS_COLOR] = [NSColor keyboardFocusIndicatorColor];
appleColors[sun_lwawt_macosx_LWCToolkit_INACTIVE_SELECTION_BACKGROUND_COLOR] = [NSColor secondarySelectedControlColor];
appleColors[sun_lwawt_macosx_LWCToolkit_INACTIVE_SELECTION_FOREGROUND_COLOR] = [NSColor controlDarkShadowColor];
Expand Down
149 changes: 149 additions & 0 deletions test/jdk/javax/swing/JTable/7124282/JTableFocusRingTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*
* Copyright (c) 2022, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/


/*
* @test
* @bug 7124282
* @key headful
* @requires (os.family == "mac")
* @summary Checks whether the JTable's focus ring color's RGB color
* diff with selectionBackground is greater in comparison to original
* focus ring (represented by 'Table.cellFocusRing' property in Aqua LAF
* UIDefaults).
* @run main JTableFocusRingTest
*/

import java.awt.Color;
import java.util.Arrays;
import javax.swing.plaf.BorderUIResource.LineBorderUIResource;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class JTableFocusRingTest {

public static void main(String[] args) throws Exception{

try {
UIManager.setLookAndFeel("com.apple.laf.AquaLookAndFeel");
} catch (ClassNotFoundException | InstantiationException |
IllegalAccessException | UnsupportedLookAndFeelException e) {
throw new RuntimeException("Unsupported Look&Feel Class");
}
SwingUtilities.invokeAndWait(() -> {

float[] bckRGB = new float[3];
float[] oldCellRingRGB = new float[3];
float[] newCellRingRGB = new float[3];

Color selectionBck = null;
Color originalRingColor = null;
Color newRingColor = null;

// saturation threshold for grayish colors
float satGrayScale = 0.10f;

if (UIManager.getDefaults().get("Table.selectionBackground") != null
&& UIManager.getDefaults().get("Table.selectionBackground")
instanceof Color) {
selectionBck = (Color) UIManager.getDefaults()
.get("Table.selectionBackground");
}
if (UIManager.getDefaults().get("Table.cellFocusRing") != null
&& UIManager.getDefaults().get("Table.cellFocusRing")
instanceof Color) {
originalRingColor = (Color) UIManager.getDefaults().get("Table.cellFocusRing");
}

if (UIManager.getDefaults()
.get("Table.focusCellHighlightBorder") != null &&
UIManager.getDefaults().get("Table.focusCellHighlightBorder")
instanceof LineBorderUIResource) {
LineBorderUIResource cellFocusBorderObj = (LineBorderUIResource)
UIManager.getDefaults().get("Table.focusCellHighlightBorder");
newRingColor = cellFocusBorderObj.getLineColor();
}

if (selectionBck == null || originalRingColor == null ||
newRingColor == null) {
throw new RuntimeException("One or more color values are null");
}
System.out.println(UIManager.getLookAndFeel().toString());
System.out.println("Selection Background Color: "
+ selectionBck.toString());

System.out.println("Original FocusRing Color: "
+ originalRingColor.toString());

System.out.println("Brighter FocusRing Color: "
+ newRingColor.toString());

int redValue = originalRingColor.getRed();
int greenValue = originalRingColor.getGreen();
int blueValue = originalRingColor.getBlue();

float[] hsbValues = new float[3];
Color.RGBtoHSB(redValue, greenValue, blueValue, hsbValues);

System.out.println("Original Focus Ring Hue, Saturation and" +
" Brightness: "+ Arrays.toString(hsbValues));

// Edge case - Original Focus ring color: WHITE/BLACK/GRAY
if (((hsbValues[0] == 0 && hsbValues[1] == 0)
|| hsbValues[1] <= satGrayScale) &&
newRingColor.equals(Color.LIGHT_GRAY)) {
System.out.println("Original Focus ring color:" +
"WHITE/BLACK/GRAYISH, Cell Focus Ring Color: LIGHT GRAY");
System.out.println("Test case passed");
return;
}
selectionBck.getRGBColorComponents(bckRGB);
originalRingColor.getRGBColorComponents(oldCellRingRGB);
newRingColor.getRGBColorComponents(newCellRingRGB);

float originalRGBDiff = calculateRGBDiff(oldCellRingRGB, bckRGB);
float brighterRGBDiff = calculateRGBDiff(newCellRingRGB, bckRGB);

System.out.println("Original RGB Diff: "+ originalRGBDiff);
System.out.println("Brighter RGB Diff: "+ brighterRGBDiff);

if (brighterRGBDiff <= originalRGBDiff) {
throw new RuntimeException("Cell Focus Ring Not Visible");
}
});
}

/* calculates the difference between individual RGB components of 2 colors
and returns the total difference. A higher RGB difference is preferred
for a prominent cell highlighter */

private static float calculateRGBDiff(float[] focusRingRGB, float[] bckRGB) {

float totalRGBDiff = 0;
for (int i=0; i< focusRingRGB.length; i++) {
totalRGBDiff += Math.abs(focusRingRGB[i] - bckRGB[i]);
}
return totalRGBDiff;
}
}

1 comment on commit bd6026c

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

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

Please sign in to comment.