-
Notifications
You must be signed in to change notification settings - Fork 866
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
[NETBEANS-3592] Workarounds for JDK Windows LAF bugs on HiDPI screens #1777
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,6 +25,7 @@ | |
import java.awt.Insets; | ||
import java.awt.geom.AffineTransform; | ||
import javax.swing.border.Border; | ||
import javax.swing.border.LineBorder; | ||
import javax.swing.border.MatteBorder; | ||
|
||
/** | ||
|
@@ -34,8 +35,7 @@ | |
* @author Eirik Bakke ([email protected]) | ||
*/ | ||
final class DPISafeBorder implements Border { | ||
private final Insets insets; | ||
private final Color color; | ||
private final Border delegate; | ||
|
||
/** | ||
* Create a new instance with the same semantics as that produced by | ||
|
@@ -44,16 +44,26 @@ final class DPISafeBorder implements Border { | |
* @param color may not be null | ||
*/ | ||
public static Border matte(int top, int left, int bottom, int right, Color color) { | ||
return new DPISafeBorder(new Insets(top, left, bottom, right), color); | ||
return fromDelegate(new MatteBorder(new Insets(top, left, bottom, right), color)); | ||
} | ||
|
||
private DPISafeBorder(Insets insets, Color color) { | ||
if (insets == null) | ||
public static Border fromDelegate(Border delegate) { | ||
if (delegate == null) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should use curly braces( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, my humble opinion is that we shall avoid throwing NullPointerExceptions directly from the code. It would be better to do an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will add curly braces... I keep forgetting the code style. (The previous code was mine, too.) Assertions can be disabled, which make them more or less useless for enforcing invariants--no way to know down the line whether they were enabled or not (e.g. when reading a log file while trying to debug an intermittent problem down the road). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree - I tried to run netbeans with The Code can be made better readable by using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe, we can also use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the annotations we'd need a dependency on |
||
throw new NullPointerException(); | ||
if (color == null) | ||
if (delegate instanceof MatteBorder) { | ||
return new DPISafeBorder(delegate); | ||
} else if (delegate instanceof LineBorder && !((LineBorder) delegate).getRoundedCorners()) { | ||
return new DPISafeBorder(delegate); | ||
} else { | ||
return delegate; | ||
} | ||
} | ||
|
||
private DPISafeBorder(Border delegate) { | ||
if (delegate == null) { | ||
throw new NullPointerException(); | ||
this.insets = new Insets(insets.top, insets.left, insets.bottom, insets.right); | ||
this.color = color; | ||
} | ||
this.delegate = delegate; | ||
} | ||
|
||
@Override | ||
|
@@ -78,11 +88,15 @@ are identical, and always integral (whole number) values. */ | |
{ | ||
// HiDPI scaling is active. | ||
scale = tx.getScaleX(); | ||
/* Round the starting (top-left) position up and the end (bottom-right) position down, | ||
to ensure we are painting the border in an area that will not be painted over by an | ||
adjacent component. */ | ||
int deviceX = (int) Math.ceil(tx.getTranslateX()); | ||
int deviceY = (int) Math.ceil(tx.getTranslateY()); | ||
/* To be completely safe from overpainting the previous adjacent component, we would | ||
probably need to round up here. But for borders to work properly on JTextField, we | ||
must round down. And it seems to work fine in the | ||
EDITOR_TAB_CONTENT_BORDER/VIEW_TAB_CONTENT_BORDER cases as well. */ | ||
int deviceX = (int) tx.getTranslateX(); | ||
int deviceY = (int) tx.getTranslateY(); | ||
/* Rounding down here should guarantee that we do not paint in an area that will be | ||
painted over by the next adjacent component. Rounding up, or to the nearest integer, | ||
is confirmed to cause problems. */ | ||
int deviceXend = (int) (tx.getTranslateX() + width * scale); | ||
int deviceYend = (int) (tx.getTranslateY() + height * scale); | ||
deviceWidth = deviceXend - deviceX; | ||
|
@@ -95,21 +109,38 @@ are identical, and always integral (whole number) values. */ | |
deviceWidth = width; | ||
deviceHeight = height; | ||
} | ||
final int deviceLeft = deviceBorderWidth(scale, insets.left); | ||
final int deviceRight = deviceBorderWidth(scale, insets.right); | ||
final int deviceTop = deviceBorderWidth(scale, insets.top); | ||
final int deviceBottom = deviceBorderWidth(scale, insets.bottom); | ||
final Insets insets = getBorderInsets(c); | ||
// Thicknesses of respective borders, in device pixels. | ||
final int dtLeft, dtRight, dtTop, dtBottom; | ||
|
||
final Color color; | ||
if (delegate instanceof MatteBorder) { | ||
color = ((MatteBorder) delegate).getMatteColor(); | ||
dtLeft = deviceBorderWidth(scale, insets.left); | ||
dtRight = deviceBorderWidth(scale, insets.right); | ||
dtTop = deviceBorderWidth(scale, insets.top); | ||
dtBottom = deviceBorderWidth(scale, insets.bottom); | ||
} else if (delegate instanceof LineBorder) { | ||
LineBorder lineBorder = (LineBorder) delegate; | ||
color = lineBorder.getLineColor(); | ||
final int dt = deviceBorderWidth(scale, lineBorder.getThickness()); | ||
dtLeft = dt; | ||
dtRight = dt; | ||
dtTop = dt; | ||
dtBottom = dt; | ||
} else { | ||
throw new RuntimeException("Expected either a MatteBorder or LineBorder delegate"); | ||
} | ||
g.setColor(color); | ||
|
||
// Top border. | ||
g.fillRect(0, 0, deviceWidth - deviceRight, deviceTop); | ||
g.fillRect(0, 0, deviceWidth - dtRight, dtTop); | ||
// Left border. | ||
g.fillRect(0, deviceTop, deviceLeft, deviceHeight - deviceTop); | ||
g.fillRect(0, dtTop, dtLeft, deviceHeight - dtTop); | ||
// Bottom border. | ||
g.fillRect(deviceLeft, deviceHeight - deviceBottom, deviceWidth - deviceLeft, deviceBottom); | ||
g.fillRect(dtLeft, deviceHeight - dtBottom, deviceWidth - dtLeft, dtBottom); | ||
// Right border. | ||
g.fillRect(deviceWidth - deviceRight, 0, deviceRight, deviceHeight - deviceBottom); | ||
g.fillRect(deviceWidth - dtRight, 0, dtRight, deviceHeight - dtBottom); | ||
|
||
g.setTransform(oldTransform); | ||
g.setColor(oldColor); | ||
|
@@ -123,7 +154,7 @@ private int deviceBorderWidth(double scale, int logical) { | |
|
||
@Override | ||
public Insets getBorderInsets(Component c) { | ||
return new Insets(insets.top, insets.left, insets.bottom, insets.right); | ||
return delegate.getBorderInsets(c); | ||
} | ||
|
||
@Override | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Should add
// NOI18N
s to strings of the other files that are not expected translation as well.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do.