mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
customization and flexible doPaint
This commit is contained in:
@@ -43,6 +43,7 @@ import java.util.Map;
|
||||
*
|
||||
* @author Vladimir Kondratyev
|
||||
*/
|
||||
@SuppressWarnings({"NonPrivateFieldAccessedInSynchronizedContext", "FieldAccessedSynchronizedAndUnsynchronized", "UnusedDeclaration"})
|
||||
public class SimpleColoredComponent extends JComponent implements Accessible {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.ui.SimpleColoredComponent");
|
||||
public static final Color STYLE_SEARCH_MATCH_BACKGROUND = new Color(250, 250, 250, 140);
|
||||
@@ -78,7 +79,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible {
|
||||
* if the component represents a selected item in a focused JList.
|
||||
* Border can be <code>null</code>.
|
||||
*/
|
||||
private MyBorder myBorder;
|
||||
private Border myBorder;
|
||||
|
||||
private int myMainTextLastIndex = -1;
|
||||
|
||||
@@ -107,6 +108,8 @@ public class SimpleColoredComponent extends JComponent implements Accessible {
|
||||
/**
|
||||
* Appends string fragments to existing ones. Appended string
|
||||
* will have specified <code>attributes</code>.
|
||||
* @param fragment text fragment
|
||||
* @param attributes text attributes
|
||||
*/
|
||||
public final void append(@NotNull final String fragment, @NotNull final SimpleTextAttributes attributes) {
|
||||
append(fragment, attributes, myMainTextLastIndex < 0);
|
||||
@@ -115,17 +118,22 @@ public class SimpleColoredComponent extends JComponent implements Accessible {
|
||||
/**
|
||||
* Appends string fragments to existing ones. Appended string
|
||||
* will have specified <code>attributes</code>.
|
||||
* @param fragment text fragment
|
||||
* @param attributes text attributes
|
||||
* @param isMainText main text of not
|
||||
*/
|
||||
public void append(@NotNull final String fragment, @NotNull final SimpleTextAttributes attributes, boolean isMainText) {
|
||||
synchronized (this) {
|
||||
myFragments.add(fragment);
|
||||
myAttributes.add(attributes);
|
||||
if (isMainText) {
|
||||
myMainTextLastIndex = myFragments.size() - 1;
|
||||
}
|
||||
}
|
||||
_append(fragment, attributes, isMainText);
|
||||
revalidateAndRepaint();
|
||||
}
|
||||
|
||||
private synchronized void _append(@NotNull final String fragment, @NotNull final SimpleTextAttributes attributes, boolean isMainText) {
|
||||
myFragments.add(fragment);
|
||||
myAttributes.add(attributes);
|
||||
if (isMainText) {
|
||||
myMainTextLastIndex = myFragments.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
private void revalidateAndRepaint() {
|
||||
if (myAutoInvalidate) {
|
||||
@@ -136,19 +144,21 @@ public class SimpleColoredComponent extends JComponent implements Accessible {
|
||||
}
|
||||
|
||||
public void append(@NotNull final String fragment, @NotNull final SimpleTextAttributes attributes, Object tag) {
|
||||
synchronized (this) {
|
||||
append(fragment, attributes);
|
||||
if (myFragmentTags == null) {
|
||||
myFragmentTags = new ArrayList<Object>();
|
||||
}
|
||||
while(myFragmentTags.size() < myFragments.size()-1) {
|
||||
myFragmentTags.add(null);
|
||||
}
|
||||
myFragmentTags.add(tag);
|
||||
}
|
||||
_append(fragment, attributes, tag);
|
||||
revalidateAndRepaint();
|
||||
}
|
||||
|
||||
private synchronized void _append(String fragment, SimpleTextAttributes attributes, Object tag) {
|
||||
append(fragment, attributes);
|
||||
if (myFragmentTags == null) {
|
||||
myFragmentTags = new ArrayList<Object>();
|
||||
}
|
||||
while(myFragmentTags.size() < myFragments.size()-1) {
|
||||
myFragmentTags.add(null);
|
||||
}
|
||||
myFragmentTags.add(tag);
|
||||
}
|
||||
|
||||
public synchronized void appendAlign(int alignWidth) {
|
||||
final int alignIndex = myFragments.size()-1;
|
||||
myAligns.put(alignIndex, alignWidth);
|
||||
@@ -159,18 +169,20 @@ public class SimpleColoredComponent extends JComponent implements Accessible {
|
||||
* They are icon, text fragments and their attributes, "paint focus border".
|
||||
*/
|
||||
public void clear() {
|
||||
synchronized (this) {
|
||||
myIcon = null;
|
||||
myPaintFocusBorder = false;
|
||||
myFragments.clear();
|
||||
myAttributes.clear();
|
||||
myFragmentTags = null;
|
||||
myMainTextLastIndex = -1;
|
||||
myAligns.clear();
|
||||
}
|
||||
_clear();
|
||||
revalidateAndRepaint();
|
||||
}
|
||||
|
||||
private synchronized void _clear() {
|
||||
myIcon = null;
|
||||
myPaintFocusBorder = false;
|
||||
myFragments.clear();
|
||||
myAttributes.clear();
|
||||
myFragmentTags = null;
|
||||
myMainTextLastIndex = -1;
|
||||
myAligns.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return component's icon. This method returns <code>null</code>
|
||||
* if there is no icon.
|
||||
@@ -181,6 +193,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible {
|
||||
|
||||
/**
|
||||
* Sets a new component icon
|
||||
* @param icon icon
|
||||
*/
|
||||
public final void setIcon(final @Nullable Icon icon) {
|
||||
myIcon = icon;
|
||||
@@ -196,6 +209,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible {
|
||||
|
||||
/**
|
||||
* Sets specified internal paddings
|
||||
* @param ipad insets
|
||||
*/
|
||||
public void setIpad(final Insets ipad) {
|
||||
myIpad = ipad;
|
||||
@@ -213,6 +227,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible {
|
||||
/**
|
||||
* Sets a new gap between icon and text
|
||||
*
|
||||
* @param iconTextGap the gap between text and icon
|
||||
* @throws java.lang.IllegalArgumentException
|
||||
* if the <code>iconTextGap</code>
|
||||
* has a negative value
|
||||
@@ -226,16 +241,17 @@ public class SimpleColoredComponent extends JComponent implements Accessible {
|
||||
revalidateAndRepaint();
|
||||
}
|
||||
|
||||
public MyBorder getMyBorder() {
|
||||
public Border getMyBorder() {
|
||||
return myBorder;
|
||||
}
|
||||
|
||||
public void setMyBorder(@Nullable MyBorder border) {
|
||||
public void setMyBorder(@Nullable Border border) {
|
||||
myBorder = border;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether focus border is painted or not
|
||||
* @param paintFocusBorder <code>true</code> or <code>false</code>
|
||||
*/
|
||||
protected final void setPaintFocusBorder(final boolean paintFocusBorder) {
|
||||
myPaintFocusBorder = paintFocusBorder;
|
||||
@@ -246,6 +262,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible {
|
||||
/**
|
||||
* Sets whether focus border extends to icon or not. If so then
|
||||
* component also extends the selection.
|
||||
* @param focusBorderAroundIcon <code>true</code> or <code>false</code>
|
||||
*/
|
||||
protected final void setFocusBorderAroundIcon(final boolean focusBorderAroundIcon) {
|
||||
myFocusBorderAroundIcon = focusBorderAroundIcon;
|
||||
@@ -274,6 +291,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible {
|
||||
return computePreferredSize(false);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public synchronized Object getFragmentTag(int index) {
|
||||
if (myFragmentTags != null && index < myFragmentTags.size()) {
|
||||
return myFragmentTags.get(index);
|
||||
@@ -368,7 +386,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible {
|
||||
|
||||
protected void paintComponent(final Graphics g) {
|
||||
try {
|
||||
doPaint(g);
|
||||
_doPaint(g);
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
LOG.error(logSwingPath(), e);
|
||||
@@ -376,55 +394,67 @@ public class SimpleColoredComponent extends JComponent implements Accessible {
|
||||
}
|
||||
}
|
||||
|
||||
protected synchronized void doPaint(final Graphics g) {
|
||||
private synchronized void _doPaint(final Graphics g) {
|
||||
checkCanPaint(g);
|
||||
int xOffset = 0;
|
||||
|
||||
// Paint icon and its background
|
||||
final Icon icon = myIcon; // guard against concurrent modification (IDEADEV-12635)
|
||||
doPaint((Graphics2D)g);
|
||||
}
|
||||
|
||||
protected void doPaint(final Graphics2D g) {
|
||||
int offset = 0;
|
||||
final Icon icon = myIcon; // guard against concurrent modification (IDEADEV-12635)
|
||||
if (icon != null) {
|
||||
final Container parent = getParent();
|
||||
Color iconBackgroundColor = null;
|
||||
if (isOpaque() || isIconOpaque()) {
|
||||
if (parent != null && !myFocusBorderAroundIcon && !UIUtil.isFullRowSelectionLAF()) {
|
||||
iconBackgroundColor = parent.getBackground();
|
||||
}
|
||||
else {
|
||||
iconBackgroundColor = getBackground();
|
||||
}
|
||||
}
|
||||
|
||||
if (iconBackgroundColor != null) {
|
||||
g.setColor(iconBackgroundColor);
|
||||
g.fillRect(0, 0, icon.getIconWidth() + myIpad.left + myIconTextGap, getHeight());
|
||||
}
|
||||
|
||||
paintIcon(g, icon);
|
||||
|
||||
xOffset += myIpad.left + icon.getIconWidth() + myIconTextGap;
|
||||
doPaintIcon(g, icon);
|
||||
offset += myIpad.left + icon.getIconWidth() + myIconTextGap;
|
||||
}
|
||||
|
||||
doPaintTextBackground(g, offset);
|
||||
doPaintText(g, offset, myFocusBorderAroundIcon || icon == null);
|
||||
}
|
||||
|
||||
|
||||
protected void doPaintTextBackground(Graphics2D g, int offset) {
|
||||
if (isOpaque() || shouldDrawBackground()) {
|
||||
// Paint text background
|
||||
g.setColor(getBackground());
|
||||
g.fillRect(xOffset, 0, getWidth() - xOffset, getHeight());
|
||||
g.fillRect(offset, 0, getWidth() - offset, getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
protected void doPaintIcon(Graphics2D g, Icon icon) {
|
||||
final Container parent = getParent();
|
||||
Color iconBackgroundColor = null;
|
||||
if (isOpaque() || isIconOpaque()) {
|
||||
if (parent != null && !myFocusBorderAroundIcon && !UIUtil.isFullRowSelectionLAF()) {
|
||||
iconBackgroundColor = parent.getBackground();
|
||||
}
|
||||
else {
|
||||
iconBackgroundColor = getBackground();
|
||||
}
|
||||
}
|
||||
|
||||
if (iconBackgroundColor != null) {
|
||||
g.setColor(iconBackgroundColor);
|
||||
g.fillRect(0, 0, icon.getIconWidth() + myIpad.left + myIconTextGap, getHeight());
|
||||
}
|
||||
|
||||
paintIcon(g, icon);
|
||||
}
|
||||
|
||||
protected int doPaintText(Graphics2D g, int offset, boolean focusAroundIcon) {
|
||||
// If there is no icon, then we have to add left internal padding
|
||||
if (xOffset == 0) {
|
||||
xOffset = myIpad.left;
|
||||
if (offset == 0) {
|
||||
offset = myIpad.left;
|
||||
}
|
||||
|
||||
int textStart = xOffset;
|
||||
int textStart = offset;
|
||||
if (myBorder != null) {
|
||||
xOffset += myBorder.getBorderInsets(this).left;
|
||||
offset += myBorder.getBorderInsets(this).left;
|
||||
}
|
||||
|
||||
final List<Object[]> searchMatches = new ArrayList<Object[]>();
|
||||
|
||||
// Paint text
|
||||
|
||||
UIUtil.applyRenderingHints(g);
|
||||
applyAdditionalHints(g);
|
||||
|
||||
for (int i = 0; i < myFragments.size(); i++) {
|
||||
final SimpleTextAttributes attributes = myAttributes.get(i);
|
||||
Font font = g.getFont();
|
||||
@@ -440,7 +470,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible {
|
||||
final Color bgColor = attributes.getBgColor();
|
||||
if (isOpaque() && bgColor != null) {
|
||||
g.setColor(bgColor);
|
||||
g.fillRect(xOffset, 0, fragmentWidth, getHeight());
|
||||
g.fillRect(offset, 0, fragmentWidth, getHeight());
|
||||
}
|
||||
|
||||
Color color = attributes.getFgColor();
|
||||
@@ -457,17 +487,17 @@ public class SimpleColoredComponent extends JComponent implements Accessible {
|
||||
if (!attributes.isSearchMatch()) {
|
||||
if (shouldDrawMacShadow()) {
|
||||
g.setColor(STYLE_SEARCH_MATCH_BACKGROUND);
|
||||
g.drawString(fragment, xOffset, textBaseline + 1);
|
||||
g.drawString(fragment, offset, textBaseline + 1);
|
||||
}
|
||||
|
||||
|
||||
g.setColor(color);
|
||||
g.drawString(fragment, xOffset, textBaseline);
|
||||
g.drawString(fragment, offset, textBaseline);
|
||||
}
|
||||
|
||||
// 1. Strikeout effect
|
||||
if (attributes.isStrikeout()) {
|
||||
final int strikeOutAt = textBaseline + (metrics.getDescent() - metrics.getAscent()) / 2;
|
||||
UIUtil.drawLine(g, xOffset, strikeOutAt, xOffset + fragmentWidth, strikeOutAt);
|
||||
UIUtil.drawLine(g, offset, strikeOutAt, offset + fragmentWidth, strikeOutAt);
|
||||
}
|
||||
// 2. Waved effect
|
||||
if (attributes.isWaved()) {
|
||||
@@ -475,7 +505,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible {
|
||||
g.setColor(attributes.getWaveColor());
|
||||
}
|
||||
final int wavedAt = textBaseline + 1;
|
||||
for (int x = xOffset; x <= xOffset + fragmentWidth; x += 4) {
|
||||
for (int x = offset; x <= offset + fragmentWidth; x += 4) {
|
||||
UIUtil.drawLine(g, x, wavedAt, x + 2, wavedAt + 2);
|
||||
UIUtil.drawLine(g, x + 3, wavedAt + 1, x + 4, wavedAt);
|
||||
}
|
||||
@@ -483,41 +513,40 @@ public class SimpleColoredComponent extends JComponent implements Accessible {
|
||||
// 3. Underline
|
||||
if (attributes.isUnderline()) {
|
||||
final int underlineAt = textBaseline + 1;
|
||||
UIUtil.drawLine(g, xOffset, underlineAt, xOffset + fragmentWidth, underlineAt);
|
||||
UIUtil.drawLine(g, offset, underlineAt, offset + fragmentWidth, underlineAt);
|
||||
}
|
||||
// 4. Bold Dotted Line
|
||||
if (attributes.isBoldDottedLine()) {
|
||||
final int dottedAt = SystemInfo.isMac ? textBaseline : textBaseline + 1;
|
||||
final Color lineColor = attributes.getWaveColor();
|
||||
UIUtil.drawBoldDottedLine((Graphics2D)g, xOffset, xOffset + fragmentWidth, dottedAt, bgColor, lineColor, isOpaque());
|
||||
UIUtil.drawBoldDottedLine(g, offset, offset + fragmentWidth, dottedAt, bgColor, lineColor, isOpaque());
|
||||
}
|
||||
|
||||
if (attributes.isSearchMatch()) {
|
||||
searchMatches.add(new Object[] {xOffset, xOffset + fragmentWidth, textBaseline, fragment, g.getFont()});
|
||||
searchMatches.add(new Object[] {offset, offset + fragmentWidth, textBaseline, fragment, g.getFont()});
|
||||
}
|
||||
|
||||
final Integer fixedWidth = myAligns.get(i);
|
||||
if (fixedWidth != null && fragmentWidth < fixedWidth.intValue()) {
|
||||
//if (fixedWidth != null) {
|
||||
xOffset += fixedWidth.intValue();
|
||||
//if (fixedWidth != null) {
|
||||
offset += fixedWidth.intValue();
|
||||
} else {
|
||||
xOffset += fragmentWidth;
|
||||
offset += fragmentWidth;
|
||||
}
|
||||
}
|
||||
|
||||
// Paint focus border around the text and icon (if necessary)
|
||||
if (myPaintFocusBorder && myBorder != null) {
|
||||
if (myFocusBorderAroundIcon || icon == null) {
|
||||
if (focusAroundIcon) {
|
||||
myBorder.paintBorder(this, g, 0, 0, getWidth(), getHeight());
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
myBorder.paintBorder(this, g, textStart, 0, getWidth() - textStart, getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
// draw search matches after all
|
||||
for (final Object[] info: searchMatches) {
|
||||
UIUtil.drawSearchMatch((Graphics2D)g, (Integer) info[0], (Integer) info[1], getHeight());
|
||||
UIUtil.drawSearchMatch(g, (Integer) info[0], (Integer) info[1], getHeight());
|
||||
g.setFont((Font) info[4]);
|
||||
|
||||
if (shouldDrawMacShadow()) {
|
||||
@@ -528,8 +557,9 @@ public class SimpleColoredComponent extends JComponent implements Accessible {
|
||||
g.setColor(new Color(50, 50, 50));
|
||||
g.drawString((String) info[3], (Integer) info[0], (Integer) info[2]);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
protected boolean shouldDrawMacShadow() {
|
||||
return false;
|
||||
}
|
||||
@@ -583,8 +613,8 @@ public class SimpleColoredComponent extends JComponent implements Accessible {
|
||||
}
|
||||
|
||||
protected void setBorderInsets(Insets insets) {
|
||||
if (myBorder != null) {
|
||||
myBorder.setInsets(insets);
|
||||
if (myBorder instanceof MyBorder) {
|
||||
((MyBorder)myBorder).setInsets(insets);
|
||||
}
|
||||
|
||||
revalidateAndRepaint();
|
||||
@@ -617,7 +647,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer result = new StringBuffer();
|
||||
final StringBuilder result = new StringBuilder();
|
||||
for (String each : myFragments) {
|
||||
result.append(each);
|
||||
}
|
||||
@@ -662,6 +692,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Accessible getAccessibleChild(int i) {
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user