+2003-06-19 Michael Koch <konqueror@gmx.de>
+
+ * java/awt/Font.java
+ javax/swing/UIManager.java
+ javax/swing/border/AbstractBorder.java
+ javax/swing/border/BevelBorder.java
+ javax/swing/border/Border.java
+ javax/swing/border/CompoundBorder.java
+ javax/swing/border/EmptyBorder.java
+ javax/swing/border/EtchedBorder.java
+ javax/swing/border/LineBorder.java
+ javax/swing/border/MatteBorder.java
+ javax/swing/border/TitledBorder.java
+ javax/swing/plaf/BorderUIResource.java
+ javax/swing/plaf/basic/BasicBorders.java
+ javax/swing/plaf/basic/BasicButtonUI.java
+ javax/swing/plaf/basic/BasicCheckBoxUI.java
+ javax/swing/plaf/basic/BasicGraphicsUtils.java
+ javax/swing/plaf/basic/BasicLabelUI.java
+ javax/swing/plaf/basic/BasicRadioButtonUI.java
+ javax/swing/plaf/basic/BasicToggleButtonUI.java:
+ New versions from classpath.
+ * javax/swing/border/SoftBevelBorder.java:
+ New file from classpath.
+ * javax/swing/border/doc-files/LineBorder-1.png,
+ javax/swing/border/doc-files/BevelBorder-1.png,
+ javax/swing/border/doc-files/BevelBorder-2.png,
+ javax/swing/border/doc-files/BevelBorder-3.png,
+ javax/swing/border/doc-files/EmptyBorder-1.png,
+ javax/swing/border/doc-files/EtchedBorder-1.png,
+ javax/swing/border/doc-files/EtchedBorder-2.png,
+ javax/swing/border/doc-files/MatteBorder-1.png,
+ javax/swing/border/doc-files/MatteBorder-2.png,
+ javax/swing/border/doc-files/MatteBorder-3.png,
+ javax/swing/border/doc-files/MatteBorder-4.png,
+ javax/swing/border/doc-files/MatteBorder-5.png,
+ javax/swing/border/doc-files/MatteBorder-6.png,
+ javax/swing/border/doc-files/SoftBevelBorder-1.png,
+ javax/swing/border/doc-files/SoftBevelBorder-2.png,
+ javax/swing/border/doc-files/SoftBevelBorder-3.png,
+ javax/swing/plaf/basic/doc-files/BasicBorders.MarginBorder-1.png,
+ javax/swing/plaf/basic/doc-files/BasicBorders.ButtonBorder-1.png,
+ javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-1.png,
+ javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-2.png,
+ javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-3.png,
+ javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-4.png,
+ javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-5.png,
+ javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-6.png,
+ javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-7.png:
+ New binary files from classpath.
+ * Makefile.am
+ (awt_java_source_files): Added
+ javax/swing/border/SoftBevelBorder.java.
+ * Makefile.in: Regenerated.
+
2003-06-19 Michael Koch <konqueror@gmx.de>
* gnu/java/security/x509/X509Certificate.java
javax/swing/border/EtchedBorder.java \
javax/swing/border/LineBorder.java \
javax/swing/border/MatteBorder.java \
+javax/swing/border/SoftBevelBorder.java \
javax/swing/border/TitledBorder.java \
javax/swing/GrayFilter.java \
javax/swing/AbstractAction.java \
javax/swing/border/EtchedBorder.java \
javax/swing/border/LineBorder.java \
javax/swing/border/MatteBorder.java \
+javax/swing/border/SoftBevelBorder.java \
javax/swing/border/TitledBorder.java \
javax/swing/GrayFilter.java \
javax/swing/AbstractAction.java \
.deps/javax/swing/border/EtchedBorder.P \
.deps/javax/swing/border/LineBorder.P \
.deps/javax/swing/border/MatteBorder.P \
+.deps/javax/swing/border/SoftBevelBorder.P \
.deps/javax/swing/border/TitledBorder.P \
.deps/javax/swing/colorchooser/AbstractColorChooserPanel.P \
.deps/javax/swing/colorchooser/ColorChooserComponentFactory.P \
package java.awt;
import java.awt.peer.FontPeer;
+import java.awt.font.FontRenderContext;
+import java.awt.font.LineMetrics;
import java.io.Serializable;
import java.util.StringTokenizer;
",size=" + size + ")");
}
+
+ /**
+ * Determines the line metrics for a run of text.
+ *
+ * @param str the text run to be measured.
+ *
+ * @param frc the font rendering parameters that are used for the
+ * measurement. The exact placement and size of text slightly
+ * depends on device-specific characteristics, for instance
+ * the device resolution or anti-aliasing. For this reason,
+ * the returned measurement will only be accurate if the
+ * passed <code>FontRenderContext</code> correctly reflects
+ * the relevant parameters. Hence, <code>frc</code> should be
+ * obtained from the same <code>Graphics2D</code> that will
+ * be used for drawing, and any rendering hints should be set
+ * to the desired values before obtaining <code>frc</code>.
+ *
+ * @see java.awt.Graphics2D#getFontRenderContext()
+ */
+ public LineMetrics getLineMetrics(String str, FontRenderContext frc)
+ {
+ throw new UnsupportedOperationException(); // FIXME
+ }
} // class Font
System.out.println("UIManager.getDim");
return new Dimension(200,100);
}
- static Font getFont(Object key)
- // Returns a drawing font from the defaults table.
- {
- return (Font) getLookAndFeel().getDefaults().get(key);
- }
+
+
+ /**
+ * Retrieves a font from the defaults table of the current
+ * LookAndFeel.
+ *
+ * @param key an Object that specifies the font. Typically,
+ * this is a String such as
+ * <code>"TitledBorder.font"</code>.
+ */
+ public static Font getFont(Object key)
+ {
+ return (Font) getLookAndFeel().getDefaults().get(key);
+ }
+
static Icon getIcon(Object key)
// Returns an Icon from the defaults table.
{
return look_and_feel;
}
- static UIDefaults getLookAndFeelDefaults()
- // Returns the default values for this look and feel.
- {
- return getLookAndFeel().getDefaults();
- }
+
+ /**
+ * Returns the <code>UIDefaults</code> table of the currently active
+ * look and feel.
+ */
+ public static UIDefaults getLookAndFeelDefaults()
+ {
+ return getLookAndFeel().getDefaults();
+ }
+
+
static String getString(Object key)
// Returns a string from the defaults table.
{
/**
- * Determines the insets of this border. The implementation provided
- * by AbstractButton returns Insets for a zero-width border, whose
- * <code>left</code>, <code>right</code>, <code>top</code> and
- * <code>bottom</code> fields are all zero.
+ * Measures the width of this border.
*
* @param c the component whose border is to be measured.
*
- * @return a newly created Insets object, indicating a zero-width
- * border.
+ * @return an Insets object whose <code>left</code>, <code>right</code>,
+ * <code>top</code> and <code>bottom</code> fields indicate the
+ * width of the border at the respective edge, which is zero
+ * for the default implementation provided by AbstractButton.
+ *
+ * @see #getBorderInsets(java.awt.Component, java.awt.Insets)
*/
public Insets getBorderInsets (Component c)
{
* <code>top</code> and <code>bottom</code> fields of the passed
* <code>insets</code> parameter to zero.
*
- * @param c the component in the center of this border.
+ * @param c the component whose border is to be measured.
*
- * @param insets an Insets object for holding the insets of this
- * border.
+ * @return the same object that was passed for <code>insets</code>.
*
- * @return the <code>insets</code> object.
+ * @see #getBorderInsets()
*/
public Insets getBorderInsets (Component c, Insets insets)
{
/* BevelBorder.java --
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of GNU Classpath.
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
+import java.awt.Insets;
-public class BevelBorder extends AbstractBorder
+
+/**
+ * A rectangular, two pixel thick border that causes the enclosed area
+ * to appear as if it was raising out of or lowered into the screen. Some
+ * LookAndFeels use this kind of border for rectangular buttons.
+ *
+ * <p>A BevelBorder has a highlight and a shadow color. In the raised
+ * variant, the highlight color is used for the top and left edges,
+ * and the shadow color is used for the bottom and right edge. For an
+ * image, see the documentation of the individual constructors.
+ *
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
+public class BevelBorder
+ extends AbstractBorder
{
- public static final int LOWERED = 1;
+ /**
+ * Determined using the <code>serialver</code> tool
+ * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5.
+ */
+ static final long serialVersionUID = -1034942243356299676L;
+
+
+ /**
+ * Indicates that the BevelBorder looks like if the enclosed area was
+ * raising out of the screen.
+ */
public static final int RAISED = 0;
-
+
+
+ /**
+ * Indicates that the BevelBorder looks like if the enclosed area was
+ * pressed into the screen.
+ */
+ public static final int LOWERED = 1;
+
+
+ /**
+ * The type of this BevelBorder, which is either {@link #RAISED}
+ * or {@link #LOWERED}.
+ */
protected int bevelType;
+
+
+ /**
+ * The outer highlight color, or <code>null</code> to indicate that
+ * the color shall be derived from the background of the component
+ * whose border is being painted.
+ */
protected Color highlightOuter;
+
+
+ /**
+ * The inner highlight color, or <code>null</code> to indicate that
+ * the color shall be derived from the background of the component
+ * whose border is being painted.
+ */
protected Color highlightInner;
+
+
+ /**
+ * The outer shadow color, or <code>null</code> to indicate that the
+ * color shall be derived from the background of the component whose
+ * border is being painted.
+ */
protected Color shadowOuter;
+
+
+ /**
+ * The inner shadow color, or <code>null</code> to indicate that the
+ * color shall be derived from the background of the component whose
+ * border is being painted.
+ */
protected Color shadowInner;
- public BevelBorder (int bevelType)
+
+ /**
+ * Constructs a BevelBorder whose colors will be derived from the
+ * background of the enclosed component. The background color is
+ * retrieved each time the border is painted, so a BevelBorder
+ * constructed by this method will automatically reflect a change
+ * to the component’s background color.
+ *
+ * <p><img src="BevelBorder-1.png" width="500" height="150"
+ * alt="[An illustration showing raised and lowered BevelBorders]" />
+ *
+ * @param bevelType the desired appearance of the border. The value
+ * must be either {@link #RAISED} or {@link #LOWERED}.
+ *
+ * @throws IllegalArgumentException if <code>bevelType</code> has
+ * an unsupported value.
+ */
+ public BevelBorder(int bevelType)
{
- this (bevelType, null, null, null, null);
+ if ((bevelType != RAISED) && (bevelType != LOWERED))
+ throw new IllegalArgumentException();
+
+ this.bevelType = bevelType;
}
+
+ /**
+ * Constructs a BevelBorder given its appearance type and two colors
+ * for its highlight and shadow.
+ *
+ * <p><img src="BevelBorder-2.png" width="500" height="150"
+ * alt="[An illustration showing BevelBorders that were constructed
+ * with this method]" />
+ *
+ * @param bevelType the desired appearance of the border. The value
+ * must be either {@link #RAISED} or {@link #LOWERED}.
+ *
+ * @param highlight the color that will be used for the inner
+ * side of the highlighted edges (top and left if
+ * if <code>bevelType</code> is {@link #RAISED}; bottom
+ * and right otherwise). The color for the outer side
+ * is a brightened version of this color.
+ *
+ * @param shadow the color that will be used for the outer
+ * side of the shadowed edges (bottom and right
+ * if <code>bevelType</code> is {@link #RAISED}; top
+ * and left otherwise). The color for the inner side
+ * is a brightened version of this color.
+ *
+ * @throws IllegalArgumentException if <code>bevelType</code> has
+ * an unsupported value.
+ *
+ * @throws NullPointerException if <code>highlight</code> or
+ * <code>shadow</code> is <code>null</code>.
+ *
+ * @see java.awt.Color.brighter()
+ */
public BevelBorder(int bevelType, Color highlight, Color shadow)
{
- this (bevelType, highlight, highlight, shadow, shadow);
+ this(bevelType,
+ /* highlightOuter */ highlight.brighter(),
+ /* highlightInner */ highlight,
+ /* shadowOuter */ shadow,
+ /* shadowInner */ shadow.brighter());
}
- public BevelBorder (int bevelType, Color highlightOuter,
- Color highlightInner, Color shadowOuter,
- Color shadowInner)
+
+ /**
+ * Constructs a BevelBorder given its appearance type and all
+ * colors.
+ *
+ * <p><img src="BevelBorder-3.png" width="500" height="150"
+ * alt="[An illustration showing BevelBorders that were constructed
+ * with this method]" />
+ *
+ * @param bevelType the desired appearance of the border. The value
+ * must be either {@link #RAISED} or {@link #LOWERED}.
+ *
+ * @param highlightOuter the color that will be used for the outer
+ * side of the highlighted edges (top and left if
+ * <code>bevelType</code> is {@link #RAISED}; bottom and
+ * right otherwise).
+ *
+ * @param highlightInner the color that will be used for the inner
+ * side of the highlighted edges.
+ *
+ * @param shadowOuter the color that will be used for the outer
+ * side of the shadowed edges (bottom and right
+ * if <code>bevelType</code> is {@link #RAISED}; top
+ * and left otherwise).
+ *
+ * @param shadowInner the color that will be used for the inner
+ * side of the shadowed edges.
+ *
+ * @throws IllegalArgumentException if <code>bevelType</code> has
+ * an unsupported value.
+ *
+ * @throws NullPointerException if one of the passed colors
+ * is <code>null</code>.
+ */
+ public BevelBorder(int bevelType,
+ Color highlightOuter, Color highlightInner,
+ Color shadowOuter, Color shadowInner)
{
- this.bevelType = bevelType;
+ this(bevelType); // checks the validity of bevelType
+
+ if ((highlightOuter == null) || (highlightInner == null)
+ || (shadowOuter == null) || (shadowInner == null))
+ throw new NullPointerException();
+
this.highlightOuter = highlightOuter;
this.highlightInner = highlightInner;
this.shadowOuter = shadowOuter;
this.shadowInner = shadowInner;
}
- public boolean isBorderOpaque()
+
+ /**
+ * Paints the border for a given component.
+ *
+ * @param c the component whose border is to be painted.
+ * @param g the graphics for painting.
+ * @param x the horizontal position for painting the border.
+ * @param y the vertical position for painting the border.
+ * @param width the width of the available area for painting the border.
+ * @param height the height of the available area for painting the border.
+ */
+ public void paintBorder(Component c, Graphics g,
+ int x, int y, int width, int height)
+ {
+ switch (bevelType)
+ {
+ case RAISED:
+ paintRaisedBevel(c, g, x, y, width, height);
+ break;
+
+ case LOWERED:
+ paintLoweredBevel(c, g, x, y, width, height);
+ break;
+ }
+ }
+
+
+ /**
+ * Measures the width of this border.
+ *
+ * @param c the component whose border is to be measured.
+ *
+ * @return an Insets object whose <code>left</code>, <code>right</code>,
+ * <code>top</code> and <code>bottom</code> fields indicate the
+ * width of the border at the respective edge.
+ *
+ * @see #getBorderInsets(java.awt.Component, java.awt.Insets)
+ */
+ public Insets getBorderInsets(Component c)
+ {
+ return new Insets(2, 2, 2, 2);
+ }
+
+
+ /**
+ * Measures the width of this border, storing the results into a
+ * pre-existing Insets object.
+ *
+ * @param insets an Insets object for holding the result values.
+ * After invoking this method, the <code>left</code>,
+ * <code>right</code>, <code>top</code> and
+ * <code>bottom</code> fields indicate the width of the
+ * border at the respective edge.
+ *
+ * @return the same object that was passed for <code>insets</code>.
+ *
+ * @see #getBorderInsets()
+ */
+ public Insets getBorderInsets(Component c, Insets insets)
+ {
+ insets.left = insets.right = insets.top = insets.bottom = 2;
+ return insets;
+ }
+
+
+ /**
+ * Determines the color that will be used for the outer side of
+ * highlighted edges when painting the border. If a highlight color
+ * has been specified upon constructing the border, that color is
+ * returned. Otherwise, the inner highlight color is brightened.
+ *
+ * @param c the component enclosed by this border.
+ *
+ * @see #getHighlightInnerColor(java.awt.Component)
+ * @see java.awt.Color#brighter()
+ */
+ public Color getHighlightOuterColor(Component c)
+ {
+ if (highlightOuter != null)
+ return highlightOuter;
+ else
+ return getHighlightInnerColor(c).brighter();
+ }
+
+
+ /**
+ * Determines the color that will be used for the inner side of
+ * highlighted edges when painting the border. If a highlight color
+ * has been specified upon constructing the border, that color is
+ * returned. Otherwise, the background color of the enclosed
+ * component is brightened.
+ *
+ * @param c the component enclosed by this border.
+ *
+ * @see java.awt.Component#getBackground()
+ * @see java.awt.Color#brighter()
+ */
+ public Color getHighlightInnerColor(Component c)
+ {
+ if (highlightInner != null)
+ return highlightInner;
+ else
+ return c.getBackground().brighter();
+ }
+
+
+ /**
+ * Determines the color that will be used for the inner side of
+ * shadowed edges when painting the border. If a shadow color has
+ * been specified upon constructing the border, that color is
+ * returned. Otherwise, the background color of the enclosed
+ * component is darkened.
+ *
+ * @param c the component enclosed by this border.
+ *
+ * @see java.awt.Component#getBackground()
+ * @see java.awt.Color#darker()
+ */
+ public Color getShadowInnerColor(Component c)
+ {
+ if (shadowInner != null)
+ return shadowInner;
+ else
+ return c.getBackground().darker();
+ }
+
+
+ /**
+ * Determines the color that will be used for the outer side of
+ * shadowed edges when painting the border. If a shadow color
+ * has been specified upon constructing the border, that color is
+ * returned. Otherwise, the inner shadow color is darkened.
+ *
+ * @param c the component enclosed by this border.
+ *
+ * @see #getShadowInnerColor(java.awt.Component)
+ * @see java.awt.Color#darker()
+ */
+ public Color getShadowOuterColor(Component c)
+ {
+ if (shadowOuter != null)
+ return shadowOuter;
+ else
+ return getShadowInnerColor(c).darker();
+ }
+
+
+ /**
+ * Returns the color that will be used for the outer side of
+ * highlighted edges when painting the border, or <code>null</code>
+ * if that color will be derived from the background of the enclosed
+ * Component.
+ */
+ public Color getHighlightOuterColor()
+ {
+ return highlightOuter;
+ }
+
+
+ /**
+ * Returns the color that will be used for the inner side of
+ * highlighted edges when painting the border, or <code>null</code>
+ * if that color will be derived from the background of the enclosed
+ * Component.
+ */
+ public Color getHighlightInnerColor()
+ {
+ return highlightInner;
+ }
+
+
+ /**
+ * Returns the color that will be used for the inner side of
+ * shadowed edges when painting the border, or <code>null</code> if
+ * that color will be derived from the background of the enclosed
+ * Component.
+ */
+ public Color getShadowInnerColor()
+ {
+ return shadowInner;
+ }
+
+
+ /**
+ * Returns the color that will be used for the outer side of
+ * shadowed edges when painting the border, or <code>null</code> if
+ * that color will be derived from the background of the enclosed
+ * Component.
+ */
+ public Color getShadowOuterColor()
+ {
+ return shadowOuter;
+ }
+
+
+ /**
+ * Returns the appearance of this border, which is either {@link
+ * #RAISED} or {@link #LOWERED}.
+ */
+ public int getBevelType()
+ {
+ return bevelType;
+ }
+
+
+ /**
+ * Determines whether this border fills every pixel in its area
+ * when painting.
+ *
+ * <p>If the border colors are derived from the background color of
+ * the enclosed component, the result is <code>true</code> because
+ * the derivation method always returns opaque colors. Otherwise,
+ * the result depends on the opacity of the individual colors.
+ *
+ * @return <code>true</code> if the border is fully opaque, or
+ * <code>false</code> if some pixels of the background
+ * can shine through the border.
+ */
+ public boolean isBorderOpaque()
+ {
+ /* If the colors are to be drived from the enclosed Component's
+ * background color, the border is guaranteed to be fully opaque
+ * because Color.brighten() and Color.darken() always return an
+ * opaque color.
+ */
+ return
+ ((highlightOuter == null) || (highlightOuter.getAlpha() == 255))
+ && ((highlightInner == null) || (highlightInner.getAlpha() == 255))
+ && ((shadowInner == null) || (shadowInner.getAlpha() == 255))
+ && ((shadowOuter == null) ||(shadowOuter.getAlpha() == 255));
+ }
+
+
+ /**
+ * Paints a raised bevel border around a component.
+ *
+ * @param c the component whose border is to be painted.
+ * @param g the graphics for painting.
+ * @param x the horizontal position for painting the border.
+ * @param y the vertical position for painting the border.
+ * @param width the width of the available area for painting the border.
+ * @param height the height of the available area for painting the border.
+ */
+ protected void paintRaisedBevel(Component c, Graphics g,
+ int x, int y, int width, int height)
+ {
+ paintBevel(g, x, y, width, height,
+ getHighlightOuterColor(c), getHighlightInnerColor(c),
+ getShadowInnerColor(c), getShadowOuterColor(c));
+ }
+
+
+ /**
+ * Paints a lowered bevel border around a component.
+ *
+ * @param c the component whose border is to be painted.
+ * @param g the graphics for painting.
+ * @param x the horizontal position for painting the border.
+ * @param y the vertical position for painting the border.
+ * @param width the width of the available area for painting the border.
+ * @param height the height of the available area for painting the border.
+ */
+ protected void paintLoweredBevel(Component c, Graphics g,
+ int x, int y, int width, int height)
+ {
+ paintBevel(g, x, y, width, height,
+ getShadowInnerColor(c), getShadowOuterColor(c),
+ getHighlightInnerColor(c), getHighlightOuterColor(c));
+ }
+
+
+ /**
+ * Paints a two-pixel bevel in four colors.
+ *
+ * <pre>
+ * @@@@@@@@@@@@
+ * @..........# @ = color a
+ * @. X# . = color b
+ * @. X# X = color c
+ * @.XXXXXXXXX# # = color d
+ * ############</pre>
+ *
+ * @param g the graphics for painting.
+ * @param x the horizontal position for painting the border.
+ * @param y the vertical position for painting the border.
+ * @param width the width of the available area for painting the border.
+ * @param height the height of the available area for painting the border.
+ * @param a the color for the outer side of the top and left edges.
+ * @param b the color for the inner side of the top and left edges.
+ * @param c the color for the inner side of the bottom and right edges.
+ * @param d the color for the outer side of the bottom and right edges.
+ */
+ private static void paintBevel(Graphics g,
+ int x, int y, int width, int height,
+ Color a, Color b, Color c, Color d)
+ {
+ Color oldColor;
+
+ oldColor = g.getColor();
+ g.translate(x, y);
+ width = width - 1;
+ height = height - 1;
+
+ try
{
- return false;
+ /* To understand this code, it might be helpful to look at the
+ * images that are included with the JavaDoc. They are located
+ * in the "doc-files" subdirectory.
+ */
+ g.setColor(a);
+ g.drawLine(0, 0, width, 0); // a, horizontal
+ g.drawLine(0, 1, 0, height); // a, vertical
+
+ g.setColor(b);
+ g.drawLine(1, 1, width - 1, 1); // b, horizontal
+ g.drawLine(1, 2, 1, height - 1); // b, vertical
+
+ g.setColor(c);
+ g.drawLine(2, height - 1, width - 1, height - 1); // c, horizontal
+ g.drawLine(width - 1, 2, width - 1, height - 2); // c, vertical
+
+ g.setColor(d);
+ g.drawLine(1, height, width, height); // d, horizontal
+ g.drawLine(width, 1, width, height - 1); // d, vertical
}
-
- public void paintBorder(Component c,
- Graphics g,
- int x,
- int y,
- int width,
- int height)
+ finally
{
+ g.translate(-x, -y);
+ g.setColor(oldColor);
}
+ }
}
/* Border.java --
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of GNU Classpath.
import java.awt.Graphics;
import java.awt.Insets;
+
+/**
+ * An interface for decorative or spacing borders around a Component.
+ *
+ * <p>To reduce memory consumption, several Components may share a
+ * single Border instance. {@link javax.swing.BorderFactory} is a
+ * factory class for producing commonly used shared borders.
+ *
+ * @see javax.swing.BorderFactory
+ * @see EmptyBorder
+ * @see CompoundBorder
+ * @see BevelBorder
+ * @see EtchedBorder
+ * @see LineBorder
+ * @see MatteBorder
+ * @see SoftBevelBorder
+ * @see TitledBorder
+ * @see AbstractBorder
+ *
+ * @author Ronald Veldema (rveldema@cs.vu.nl)
+ * @author Michael Koch (konqueror@gmx.de)
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
public interface Border
{
- public Insets getBorderInsets (Component c);
- public boolean isBorderOpaque ();
- public void paintBorder (Component c, Graphics g, int x, int y,
- int width, int height);
+ /**
+ * Paints the border for a given component.
+ *
+ * @param c the component whose border is to be painted.
+ * @param g the graphics for painting.
+ * @param x the horizontal position for painting the border.
+ * @param y the vertical position for painting the border.
+ * @param width the width of the available area for painting the border.
+ * @param height the height of the available area for painting the border.
+ */
+ public void paintBorder(Component c, Graphics g,
+ int x, int y, int width, int height);
+
+
+ /**
+ * Measures the width of this border.
+ *
+ * @param c the component whose border is to be measured.
+ *
+ * @return an Insets object whose <code>left</code>, <code>right</code>,
+ * <code>top</code> and <code>bottom</code> fields indicate the
+ * width of the border at the respective edge.
+ */
+ public Insets getBorderInsets(Component c);
+
+
+ /**
+ * Determines whether this border fills every pixel in its area
+ * when painting.
+ *
+ * @return <code>true</code> if the border is fully opaque, or
+ * <code>false</code> if some pixels of the background
+ * can shine through the border.
+ */
+ public boolean isBorderOpaque();
}
public class CompoundBorder
extends AbstractBorder
{
+ /**
+ * Determined using the <code>serialver</code> tool
+ * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5.
+ */
static final long serialVersionUID = 9054540377030555103L;
* outside borders.
*
* @param outsideBorder the outside border, which is painted to the
- * outside of both <code>insideBorder</code> and the bordered
- * compoonent. It is acceptable to pass <code>null</code>, in
- * which no outside border is painted.
+ * outside of both <code>insideBorder</code> and the enclosed
+ * component. It is acceptable to pass <code>null</code>, in
+ * which case no outside border is painted.
*
* @param insideBorder the inside border, which is painted to
- * between <code>outsideBorder</code> and the bordered
+ * between <code>outsideBorder</code> and the enclosed
* component. It is acceptable to pass <code>null</code>, in
- * which no intside border is painted.
+ * which case no inside border is painted.
*/
public CompoundBorder (Border outsideBorder, Border insideBorder)
{
/* EmptyBorder.java --
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of GNU Classpath.
import java.awt.Graphics;
import java.awt.Insets;
-public class EmptyBorder extends AbstractBorder
+
+/**
+ * A border for leaving a specifiable number of pixels empty around
+ * the enclosed component. An EmptyBorder requires some space on each
+ * edge, but does not perform any drawing.
+ *
+ * <p><img src="EmptyBorder-1.png" width="290" height="200"
+ * alt="[An illustration of EmptyBorder]" />
+ *
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
+public class EmptyBorder
+ extends AbstractBorder
{
+ /**
+ * Determined using the <code>serialver</code> tool
+ * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5.
+ */
+ static final long serialVersionUID = -8116076291731988694L;
+
+
+ /**
+ * The number of pixels required at the left edge.
+ */
protected int left;
+
+
+ /**
+ * The number of pixels required at the right edge.
+ */
protected int right;
- protected int bottom;
+
+
+ /**
+ * The number of pixels required at the top edge.
+ */
protected int top;
- public EmptyBorder (Insets borderInsets)
- {
- this (borderInsets.left, borderInsets.right,
- borderInsets.top, borderInsets.bottom);
- }
- public EmptyBorder (int left, int right, int top, int bottom)
+ /**
+ * The number of pixels required at the bottom edge.
+ */
+ protected int bottom;
+
+
+ /**
+ * Constructs an empty border given the number of pixels required
+ * on each side.
+ *
+ * @param top the number of pixels that the border will need
+ * for its top edge.
+ *
+ * @param left the number of pixels that the border will need
+ * for its left edge.
+ *
+ * @param bottom the number of pixels that the border will need
+ * for its bottom edge.
+ *
+ * @param right the number of pixels that the border will need
+ * for its right edge.
+ */
+ public EmptyBorder(int top, int left, int bottom, int right)
{
- this.left = left;
- this.right = right;
this.top = top;
+ this.left = left;
this.bottom = bottom;
+ this.right = right;
}
- public Insets getBorderInsets (Component c, Insets s)
+
+ /**
+ * Constructs an empty border given the number of pixels required
+ * on each side, passed in an Insets object.
+ *
+ * @param borderInsets the Insets for the new border.
+ */
+ public EmptyBorder(Insets borderInsets)
{
- if (s == null)
- s = new Insets (0,0,0,0);
-
- s.left = left;
- s.right = right;
- s.top = top;
- s.bottom = bottom;
- return s;
+ this(borderInsets.top, borderInsets.left,
+ borderInsets.bottom, borderInsets.right);
}
-
- public boolean isBorderOpaque ()
+
+
+ /**
+ * Performs nothing because an EmptyBorder does not paint any
+ * pixels. While the inherited implementation provided by
+ * {@link AbstractBorder#paintBorder} is a no-op as well,
+ * it is overwritten in order to match the API of the Sun
+ * reference implementation.
+ *
+ * @param c the component whose border is to be painted.
+ * @param g the graphics for painting.
+ * @param x the horizontal position for painting the border.
+ * @param y the vertical position for painting the border.
+ * @param width the width of the available area for painting the border.
+ * @param height the height of the available area for painting the border.
+ */
+ public void paintBorder(Component c, Graphics g,
+ int x, int y, int width, int height)
{
- return false;
}
- public void paintBorder (Component c, Graphics g, int x, int y,
- int width, int height)
+
+ /**
+ * Measures the width of this border.
+ *
+ * @param c the component whose border is to be measured.
+ *
+ * @return an Insets object whose <code>left</code>, <code>right</code>,
+ * <code>top</code> and <code>bottom</code> fields indicate the
+ * width of the border at the respective edge.
+ *
+ * @see #getBorderInsets(java.awt.Component, java.awt.Insets)
+ */
+ public Insets getBorderInsets(Component c)
{
+ return getBorderInsets(c, null);
}
-}
+
+ /**
+ * Measures the width of this border, storing the results into a
+ * pre-existing Insets object.
+ *
+ * @param insets an Insets object for holding the result values.
+ * After invoking this method, the <code>left</code>,
+ * <code>right</code>, <code>top</code> and
+ * <code>bottom</code> fields indicate the width of the
+ * border at the respective edge.
+ *
+ * @return the same object that was passed for <code>insets</code>.
+ *
+ * @see #getBorderInsets()
+ */
+ public Insets getBorderInsets(Component c, Insets insets)
+ {
+ if (insets == null)
+ insets = new Insets(0, 0, 0, 0);
+
+ insets.left = left;
+ insets.right = right;
+ insets.top = top;
+ insets.bottom = bottom;
+ return insets;
+ }
+
+
+ /**
+ * Measures the width of this border.
+ *
+ * @return an Insets object whose <code>left</code>, <code>right</code>,
+ * <code>top</code> and <code>bottom</code> fields indicate the
+ * width of the border at the respective edge.
+ *
+ * @see #getBorderInsets(java.awt.Component, java.awt.Insets)
+ */
+ public Insets getBorderInsets()
+ {
+ return getBorderInsets(null, null);
+ }
+
+
+ /**
+ * Determines whether this border fills every pixel in its area
+ * when painting. Since an empty border does not paint any pixels
+ * whatsoever, the result is <code>false</code>.
+ *
+ * @return <code>false</code>.
+ */
+ public boolean isBorderOpaque()
+ {
+ /* The inherited implementation of AbstractBorder.isBorderOpaque()
+ * would also return false. It is not clear why this is overriden
+ * in the Sun implementation, at least not from just reading the
+ * JavaDoc.
+ */
+ return false;
+ }
+}
/* EtchedBorder.java --
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of GNU Classpath.
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
+import java.awt.Insets;
-public class EtchedBorder extends AbstractBorder
+
+/**
+ * A border that looks like an engraving etched into the background
+ * surface, or (in its raised variant) coming out of the surface
+ * plane. Using different constructors, it is possible to either
+ * explicitly specify the border colors, or to let the colors derive
+ * from the background color of the enclosed Component.
+ *
+ * <p><img src="EtchedBorder-1.png" width="500" height="200"
+ * alt="[An illustration of the two EtchedBorder variants]" />
+ *
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
+public class EtchedBorder
+ extends AbstractBorder
{
- public static final int LOWERED = 1;
+ /**
+ * Determined using the <code>serialver</code> tool
+ * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5.
+ */
+ static final long serialVersionUID = 4001244046866360638L;
+
+
+ /**
+ * Indicates that the border appears as coming out of the
+ * background.
+ */
public static final int RAISED = 0;
-
+
+
+ /**
+ * Indicates that the border appears as engraved into the
+ * background.
+ */
+ public static final int LOWERED = 1;
+
+
+ /**
+ * The type of this EtchedBorder, which is either {@link #RAISED}
+ * or {@link #LOWERED}.
+ */
protected int etchType;
+
+
+ /**
+ * The highlight color, or <code>null</code> to indicate that the
+ * color shall be derived from the background of the enclosed
+ * component.
+ */
protected Color highlight;
+
+
+ /**
+ * The shadow color, or <code>null</code> to indicate that the
+ * color shall be derived from the background of the enclosed
+ * component.
+ */
protected Color shadow;
- public EtchedBorder ()
+
+ /**
+ * Constructs a lowered EtchedBorder. The colors will be derived
+ * from the background color of the enclosed Component when the
+ * border gets painted.
+ */
+ public EtchedBorder()
{
- this (LOWERED, null, null);
+ this(LOWERED);
}
- public EtchedBorder (Color highlight, Color shadow)
+
+ /**
+ * Constructs an EtchedBorder with the specified appearance. The
+ * colors will be derived from the background color of the enclosed
+ * Component when the border gets painted.
+ *
+ * <p><img src="EtchedBorder-1.png" width="500" height="200"
+ * alt="[An illustration of the two EtchedBorder variants]" />
+ *
+ * @param etchType the desired appearance of the border. The value
+ * must be either {@link #RAISED} or {@link #LOWERED}.
+ *
+ * @throws IllegalArgumentException if <code>etchType</code> has
+ * an unsupported value.
+ */
+ public EtchedBorder(int etchType)
{
- this (LOWERED, highlight, shadow);
- }
+ if ((etchType != RAISED) && (etchType != LOWERED))
+ throw new IllegalArgumentException();
+
+ this.etchType = etchType;
- public EtchedBorder (int etchType)
+ /* The highlight and shadow fields already have a null value
+ * when the constructor gets called, so there is no need to
+ * assign a value here.
+ */
+ }
+
+
+ /**
+ * Constructs a lowered EtchedBorder, explicitly selecting the
+ * colors that will be used for highlight and shadow.
+ *
+ * @param highlight the color that will be used for painting
+ * the highlight part of the border.
+ *
+ * @param shadow the color that will be used for painting
+ * the shadow part of the border.
+ *
+ * @see #EtchedBorder(int, Color, Color)
+ */
+ public EtchedBorder(Color highlight, Color shadow)
{
- this (etchType, null, null);
+ this(LOWERED, highlight, shadow);
}
-
- public EtchedBorder (int etchType, Color highlight, Color shadow)
+
+
+ /**
+ * Constructs an EtchedBorder with the specified appearance,
+ * explicitly selecting the colors that will be used for
+ * highlight and shadow.
+ *
+ * <p><img src="EtchedBorder-2.png" width="500" height="200"
+ * alt="[An illustration that shows which pixels get painted
+ * in what color]" />
+ *
+ * @param etchType the desired appearance of the border. The value
+ * must be either {@link #RAISED} or {@link #LOWERED}.
+ *
+ * @param highlight the color that will be used for painting
+ * the highlight part of the border.
+ *
+ * @param shadow the color that will be used for painting
+ * the shadow part of the border.
+ *
+ * @throws IllegalArgumentException if <code>etchType</code> has
+ * an unsupported value.
+ */
+ public EtchedBorder(int etchType, Color highlight, Color shadow)
{
- this.etchType = etchType;
+ this(etchType); // Checks the validity of the value.
this.highlight = highlight;
this.shadow = shadow;
}
-
- public boolean isBorderOpaque()
+
+
+ /**
+ * Paints the border for a given component.
+ *
+ * @param c the component whose border is to be painted.
+ * @param g the graphics for painting.
+ * @param x the horizontal position for painting the border.
+ * @param y the vertical position for painting the border.
+ * @param width the width of the available area for painting the border.
+ * @param height the height of the available area for painting the border.
+ */
+ public void paintBorder(Component c, Graphics g,
+ int x, int y, int width, int height)
+ {
+ switch (etchType)
+ {
+ case RAISED:
+ paintEtchedBorder(g, x, y, width, height,
+ getHighlightColor(c), getShadowColor(c));
+ break;
+
+ case LOWERED:
+ paintEtchedBorder(g, x, y, width, height,
+ getShadowColor(c), getHighlightColor(c));
+ break;
+ }
+ }
+
+
+ /**
+ * Measures the width of this border.
+ *
+ * @param c the component whose border is to be measured.
+ *
+ * @return an Insets object whose <code>left</code>, <code>right</code>,
+ * <code>top</code> and <code>bottom</code> fields indicate the
+ * width of the border at the respective edge.
+ *
+ * @see #getBorderInsets(java.awt.Component, java.awt.Insets)
+ */
+ public Insets getBorderInsets(Component c)
+ {
+ return new Insets(2, 2, 2, 2);
+ }
+
+
+ /**
+ * Measures the width of this border, storing the results into a
+ * pre-existing Insets object.
+ *
+ * @param insets an Insets object for holding the result values.
+ * After invoking this method, the <code>left</code>,
+ * <code>right</code>, <code>top</code> and
+ * <code>bottom</code> fields indicate the width of the
+ * border at the respective edge.
+ *
+ * @return the same object that was passed for <code>insets</code>.
+ *
+ * @see #getBorderInsets()
+ */
+ public Insets getBorderInsets(Component c, Insets insets)
+ {
+ insets.left = insets.right = insets.top = insets.bottom = 2;
+ return insets;
+ }
+
+
+ /**
+ * Determines whether this border fills every pixel in its area
+ * when painting.
+ *
+ * <p>If the border colors are derived from the background color of
+ * the enclosed component, the result is <code>true</code> because
+ * the derivation method always returns opaque colors. Otherwise,
+ * the result depends on the opacity of the individual colors.
+ *
+ * @return <code>true</code> if the border is fully opaque, or
+ * <code>false</code> if some pixels of the background
+ * can shine through the border.
+ */
+ public boolean isBorderOpaque()
+ {
+ /* If the colors are to be drived from the enclosed Component's
+ * background color, the border is guaranteed to be fully opaque
+ * because Color.brighten() and Color.darken() always return an
+ * opaque color.
+ */
+ return
+ ((highlight == null) || (highlight.getAlpha() == 255))
+ && ((shadow == null) || (shadow.getAlpha() == 255));
+ }
+
+
+ /**
+ * Returns the appearance of this EtchedBorder, which is either
+ * {@link #RAISED} or {@link #LOWERED}.
+ */
+ public int getEtchType()
+ {
+ return etchType;
+ }
+
+
+ /**
+ * Determines the color that will be used for highlighted parts when
+ * painting the border around a given component. If a highlight
+ * color has been specified upon constructing the border, that color
+ * is returned. Otherwise, the background color of the enclosed
+ * component is brightened.
+ *
+ * @param c the component enclosed by this border.
+ *
+ * @see java.awt.Component#getBackground()
+ * @see java.awt.Color#brighter()
+ */
+ public Color getHighlightColor(Component c)
+ {
+ if (highlight != null)
+ return highlight;
+ else
+ return c.getBackground().brighter();
+ }
+
+
+ /**
+ * Returns the color that will be used for highlighted parts when
+ * painting the border, or <code>null</code> if that color will be
+ * derived from the background of the enclosed Component.
+ */
+ public Color getHighlightColor()
+ {
+ return highlight;
+ }
+
+
+ /**
+ * Determines the color that will be used for shadowed parts when
+ * painting the border around a given component. If a shadow color
+ * has been specified upon constructing the border, that color is
+ * returned. Otherwise, the background color of the enclosed
+ * component is darkened.
+ *
+ * @param c the component enclosed by this border.
+ *
+ * @see java.awt.Component#getBackground()
+ * @see java.awt.Color#darker()
+ */
+ public Color getShadowColor(Component c)
+ {
+ if (shadow != null)
+ return shadow;
+ else
+ return c.getBackground().darker();
+ }
+
+
+ /**
+ * Returns the color that will be used for shadowed parts when
+ * painting the border, or <code>null</code> if that color will be
+ * derived from the background of the enclosed Component.
+ */
+ public Color getShadowColor()
+ {
+ return shadow;
+ }
+
+
+ /**
+ * Paints a two-pixel etching in two colors.
+ *
+ * <pre>
+ * @@@@@@@@@@@.
+ * @.........@. @ = color a
+ * @. @. . = color b
+ * @. @.
+ * @@@@@@@@@@@.
+ * ............</pre>
+ *
+ * @param g the graphics for painting.
+ * @param x the horizontal position for painting the border.
+ * @param y the vertical position for painting the border.
+ * @param width the width of the available area for painting the border.
+ * @param height the height of the available area for painting the border.
+ * @param a one of the two colors.
+ * @param b the second of the two colors.
+ */
+ private static void paintEtchedBorder(Graphics g,
+ int x, int y, int width, int height,
+ Color a, Color b)
+ {
+ Color oldColor;
+
+ oldColor = g.getColor();
+ g.translate(x, y);
+ width = width - 1;
+ height = height - 1;
+
+ try
{
- return false;
+ /* To understand this code, it might be helpful to look at the
+ * images that are included with the JavaDoc. They are located
+ * in the "doc-files" subdirectory. EtchedBorder-2.png might
+ * be especially informative.
+ */
+ g.setColor(a);
+ g.drawRect(0, 0, width - 1, height - 1);
+
+ g.setColor(b);
+ g.drawLine(1, 1, width - 2, 1); // top edge
+ g.drawLine(1, 2, 1, height - 2); // left edge
+ g.drawLine(0, height, width, height); // bottom edge
+ g.drawLine(width, 0, width, height - 1); // right edge
}
-
- public void paintBorder(Component c,
- Graphics g,
- int x,
- int y,
- int width,
- int height)
+ finally
{
+ g.translate(-x, -y);
+ g.setColor(oldColor);
}
+ }
}
/* LineBorder.java --
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of GNU Classpath.
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
+import java.awt.Insets;
-public class LineBorder extends AbstractBorder
+
+/**
+ * A border that consists of a line whose thickness and color can be
+ * specified. There also is a variant with rounded corners.
+ *
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
+public class LineBorder
+ extends AbstractBorder
{
+ /**
+ * Determined using the <code>serialver</code> tool
+ * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5.
+ */
+ static final long serialVersionUID = -787563427772288970L;
+
+
+ /**
+ * A shared instance of a black, one pixel thick, plain LineBorder.
+ * The singleton object is lazily created by {@link
+ * #createBlackLineBorder()} upon its first invocation.
+ */
+ private static LineBorder blackLineBorder;
+
+
+ /**
+ * A shared instance of a gray, one pixel thick, plain LineBorder.
+ * The singleton object is lazily created by {@link
+ * #createBlackGrayBorder()} upon its first invocation.
+ */
+ private static LineBorder grayLineBorder;
+
+
+ /**
+ * The width of the line in pixels.
+ */
+ protected int thickness;
+
+
+ /**
+ * The color of the line.
+ */
protected Color lineColor;
+
+
+ /**
+ * Indicates whether the line is drawn with rounded corners
+ * (<code>true</code>) or not ((<code>false</code>).
+ */
protected boolean roundedCorners;
- protected int thickness;
- public LineBorder (Color color)
+
+ /**
+ * Constructs a LineBorder given its color. The border will be one
+ * pixel thick and have plain corners.
+ *
+ * @param color the color for drawing the border.
+ *
+ * @see #LineBorder(java.awt.Color, int, boolean)
+ */
+ public LineBorder(Color color)
{
- this (color, 1);
+ this(color, /* thickness */ 1, /* roundedCorners */ false);
}
- public LineBorder (Color color, int thickness)
+
+ /**
+ * Constructs a LineBorder given its color and thickness. The
+ * border will have plain corners.
+ *
+ * @param color the color for drawing the border.
+ * @param thickness the width of the line in pixels.
+ *
+ * @see #LineBorder(java.awt.Color, int, boolean)
+ */
+ public LineBorder(Color color, int thickness)
{
- this (color, thickness, false); // FIXME: check roundedCorners argument
+ this (color, thickness, /* roundedCorners */ false);
}
-
+
+
/**
+ * Constructs a LineBorder given its color, thickness, and whether
+ * it has rounded corners.
+ *
+ * <p><img src="LineBorder-1.png" width="500" height="200"
+ * alt="[An illustration of two LineBorders] />
+ *
+ * <p>Note that the enlarged view in the right-hand picture shows
+ * that the implementation draws one more pixel than specified,
+ * provided that <code>roundedCorders</code> is <code>true</code>
+ * and anti-aliasing is turned on while painting. While this might
+ * be considered a bug, the Sun reference implementation (at least
+ * JDK 1.3.1 on Apple MacOS X 10.1.5) can be observed to fill
+ * exactly the same pixels as shown above. The GNU Classpath
+ * LineBorder replicates the observed behavior of the Sun
+ * implementation.
+ *
+ * @param color the color for drawing the border.
+ * @param thickness the width of the line in pixels.
+ * @param roundedCorners <code>true</code> for rounded corners,
+ * <code>false</code> for plain corners.
+ *
* @since 1.3
*/
- public LineBorder (Color color, int thickness, boolean roundedCorners)
+ // For the bug mentioned in the JavaDoc, please see also the comment
+ // in the paintBorder method below.
+ //
+ public LineBorder(Color color, int thickness, boolean roundedCorners)
{
+ if ((color == null) || (thickness < 0))
+ throw new IllegalArgumentException();
+
this.lineColor = color;
this.thickness = thickness;
this.roundedCorners = roundedCorners;
}
+
+
+ /**
+ * Returns a black, one pixel thick, plain LineBorder. The method
+ * may always return the same (singleton) LineBorder instance.
+ */
+ public static Border createBlackLineBorder()
+ {
+ /* Swing is not designed to be thread-safe, so there is no
+ * need to synchronize the access to the global variable.
+ */
+ if (blackLineBorder == null)
+ blackLineBorder = new LineBorder(Color.black);
- public boolean isBorderOpaque()
+ return blackLineBorder;
+ }
+
+
+ /**
+ * Returns a gray, one pixel thick, plain LineBorder. The method
+ * may always return the same (singleton) LineBorder instance.
+ */
+ public static Border createGrayLineBorder()
+ {
+ /* Swing is not designed to be thread-safe, so there is no
+ * need to synchronize the access to the global variable.
+ */
+ if (grayLineBorder == null)
+ grayLineBorder = new LineBorder(Color.gray);
+
+ return grayLineBorder;
+ }
+
+
+ /**
+ * Paints the line border around a given Component.
+ *
+ * @param c the component whose border is to be painted.
+ * @param g the graphics for painting.
+ * @param x the horizontal position for painting the border.
+ * @param y the vertical position for painting the border.
+ * @param width the width of the available area for painting the border.
+ * @param height the height of the available area for painting the border.
+ */
+ public void paintBorder(Component c, Graphics g,
+ int x, int y, int width, int height)
+ {
+ Color oldColor = g.getColor();
+
+ try
{
- return false;
+ g.setColor(lineColor);
+
+ /* If width and height were not adjusted, the border would
+ * appear one pixel too large in both directions.
+ */
+ width -= 1;
+ height -= 1;
+
+ /* Blurred, too large appearance
+ * -----------------------------
+ * While Java 2D has introduced line strokes of arbitrary width,
+ * it seems desirable to keep this code independent of Java 2D.
+ * Therefore, multiple nested rectangles (or rounded rectangles)
+ * are drawn in order to simulate a line whose thickness is
+ * greater than one pixel.
+ *
+ * This hack causes a blurred appearance when anti-aliasing is
+ * on. Interestingly enough, though, the Sun JDK 1.3.1 (at least
+ * on MacOS X 10.1.5) shows exactly the same appearance under
+ * this condition. It thus seems likely that Sun does the same
+ * hack for simulating thick lines. For this reason, the
+ * blurred appearance seems acceptable -- especially since GNU
+ * Classpath tries to be compatible with the Sun reference
+ * implementation.
+ */
+ for (int i = 0; i < thickness; i++)
+ {
+ if (roundedCorners)
+ g.drawRoundRect(x, y, width, height, thickness, thickness);
+ else
+ g.drawRect(x, y, width, height);
+
+ x += 1;
+ y += 1;
+ width -= 2;
+ height -= 2;
+ }
}
-
- public void paintBorder(Component c,
- Graphics g,
- int x,
- int y,
- int width,
- int height)
+ finally
{
+ g.setColor(oldColor);
}
+ }
+
+
+ /**
+ * Measures the width of this border.
+ *
+ * @param c the component whose border is to be measured.
+ *
+ * @return an Insets object whose <code>left</code>, <code>right</code>,
+ * <code>top</code> and <code>bottom</code> fields indicate the
+ * width of the border at the respective edge, which is the
+ * thickness of the line.
+ *
+ * @see #getBorderInsets(java.awt.Component, java.awt.Insets)
+ */
+ public Insets getBorderInsets(Component c)
+ {
+ return new Insets(thickness, thickness, thickness, thickness);
+ }
+
+
+ /**
+ * Measures the width of this border, storing the results into a
+ * pre-existing Insets object.
+ *
+ * @param insets an Insets object for holding the result values.
+ * After invoking this method, the <code>left</code>,
+ * <code>right</code>, <code>top</code> and
+ * <code>bottom</code> fields indicate the width of the
+ * border at the respective edge, which is the thickness
+ * of the line.
+ *
+ * @return the same object that was passed for <code>insets</code>.
+ *
+ * @see #getBorderInsets()
+ */
+ public Insets getBorderInsets(Component c, Insets insets)
+ {
+ insets.left = insets.right = insets.top = insets.bottom = thickness;
+ return insets;
+ }
+
+
+ /**
+ * Returns the thickness of the line in pixels.
+ */
+ public int getThickness()
+ {
+ return thickness;
+ }
+
+
+ /**
+ * Returns whether this LineBorder os drawm with rounded
+ * or with plain corners.
+ *
+ * @return <code>true</code> if the corners are rounded,
+ * <code>false</code> if the corners are plain.
+ */
+ public boolean getRoundedCorners()
+ {
+ return roundedCorners;
+ }
+
+
+ /**
+ * Determines whether this border fills every pixel in its area
+ * when painting.
+ *
+ * @return <code>true</code> if the corners are plain and the line
+ * color is fully opaque; <code>false</code> if the corners
+ * are rounded or the line color is partially transparent.
+ */
+ public boolean isBorderOpaque()
+ {
+ return (!roundedCorners) && (lineColor.getAlpha() == 255);
+ }
}
/* MatteBorder.java --
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of GNU Classpath.
import java.awt.Insets;
import javax.swing.Icon;
-public class MatteBorder extends EmptyBorder
+
+/**
+ * A border that is filled with either a solid color or with repeated
+ * icon tiles.
+ *
+ * <p><img src="MatteBorder-1.png" width="500" height="150"
+ * alt="[Two MatteBorders]" />
+ *
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
+public class MatteBorder
+ extends EmptyBorder
{
+ /**
+ * Determined using the <code>serialver</code> tool
+ * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5.
+ */
+ static final long serialVersionUID = 4422248989617298224L;
+
+
+ /**
+ * The color that is used for filling the border, or
+ * <code>null</code> if the border is filled with repetitions of a
+ * tile icon.
+ *
+ * @see #tileIcon
+ */
protected Color color;
+
+
+ /**
+ * The icon is used for filling the border with a tile, or
+ * <code>null</code> if the border is filled with a solid
+ * color.
+ *
+ * @see #color
+ */
protected Icon tileIcon;
-
- public MatteBorder (Icon tileIcon)
+
+
+ /**
+ * Constructs a MatteBorder given the width on each side
+ * and a fill color.
+ *
+ * <p><img src="MatteBorder-2.png" width="500" height="150"
+ * alt="[A picture of a MatteBorder made by this constructor]" />
+ *
+ * @param top the width of the border at its top edge.
+ * @param left the width of the border at its left edge.
+ * @param bottom the width of the border at its bottom edge.
+ * @param right the width of the border at its right edge.
+ * @param matteColor the color for filling the border.
+ */
+ public MatteBorder(int top, int left, int bottom, int right,
+ Color matteColor)
{
- // FIXME: implement this
- this (null, tileIcon);
+ super(top, left, bottom, right);
+
+ if (matteColor == null)
+ throw new IllegalArgumentException();
+
+ this.color = matteColor;
}
- public MatteBorder (Insets borderInsets, Color color)
+
+ /**
+ * Constructs a MatteBorder given its insets and fill color.
+ *
+ * <p><img src="MatteBorder-3.png" width="500" height="150"
+ * alt="[A picture of a MatteBorder made by this constructor]" />
+ *
+ * @param borderInsets an Insets object whose <code>top</code>,
+ * <code>left</code>, <code>bottom</code> and <code>right</code>
+ * fields indicate the with of the border at the respective
+ * edge.
+ *
+ * @param matteColor the color for filling the border.
+ */
+ public MatteBorder(Insets borderInsets, Color matteColor)
{
- this (borderInsets.top, borderInsets.left, borderInsets.bottom,
- borderInsets.right, color);
+ this(borderInsets.top, borderInsets.left,
+ borderInsets.bottom, borderInsets.right,
+ matteColor);
}
- public MatteBorder (Insets borderInsets, Icon tileIcon)
+
+ /**
+ * Constructs a MatteBorder given the width on each side
+ * and an icon for tiling the border area.
+ *
+ * <p><img src="MatteBorder-4.png" width="500" height="150"
+ * alt="[A picture of a MatteBorder made by this constructor]" />
+ *
+ * @param top the width of the border at its top edge.
+ * @param left the width of the border at its left edge.
+ * @param bottom the width of the border at its bottom edge.
+ * @param right the width of the border at its right edge.
+ * @param tileIcon an icon for tiling the border area.
+ */
+ public MatteBorder(int top, int left, int bottom, int right,
+ Icon tileIcon)
{
- this (borderInsets.top, borderInsets.left, borderInsets.bottom,
- borderInsets.right, tileIcon);
+ super(top, left, bottom, right);
+
+ if (tileIcon == null)
+ throw new IllegalArgumentException();
+
+ this.tileIcon = tileIcon;
}
- public MatteBorder (int top, int left, int bottom, int right, Icon tileIcon)
+
+ /**
+ * Constructs a MatteBorder given its insets and an icon
+ * for tiling the border area.
+ *
+ * <p><img src="MatteBorder-5.png" width="500" height="150"
+ * alt="[A picture of a MatteBorder made by this constructor]" />
+ *
+ * @param borderInsets an Insets object whose <code>top</code>,
+ * <code>left</code>, <code>bottom</code> and <code>right</code>
+ * fields indicate the with of the border at the respective
+ * edge.
+ *
+ * @param tileIcon an icon for tiling the border area.
+ */
+ public MatteBorder(Insets borderInsets, Icon tileIcon)
{
- super (top, left, bottom, right);
- this.tileIcon = tileIcon;
+ this(borderInsets.top, borderInsets.left,
+ borderInsets.bottom, borderInsets.right,
+ tileIcon);
+ }
+
+
+ /**
+ * Constructs a MatteBorder given an icon for tiling the
+ * border area. The icon width is used for the border insets
+ * at the left and right edge, the icon height for the top and
+ * bottom edge.
+ *
+ * <p><img src="MatteBorder-6.png" width="500" height="150"
+ * alt="[A picture of a MatteBorder made by this constructor]" />
+ *
+ * @param tileIcon an icon for tiling the border area.
+ */
+ public MatteBorder(Icon tileIcon)
+ {
+ this(-1, -1, -1, -1, tileIcon);
+ }
+
+
+ /**
+ * Paints the border for a given component.
+ *
+ * @param c the component whose border is to be painted.
+ * @param g the graphics for painting.
+ * @param x the horizontal position for painting the border.
+ * @param y the vertical position for painting the border.
+ * @param width the width of the available area for painting the border.
+ * @param height the height of the available area for painting the border.
+ */
+ public void paintBorder(Component c, Graphics g,
+ int x, int y, int width, int height)
+ {
+ Insets i = getBorderInsets();
+ paintEdge(c, g, x, y, width, i.top, 0, 0); // top edge
+ paintEdge(c, g, x, y + height - i.bottom, // bottom edge
+ width, i.bottom,
+ 0, height - i.bottom);
+ paintEdge(c, g, x, y + i.top, // left edge
+ i.left, height - i.top,
+ 0, i.top);
+ paintEdge(c, g, x + width - i.right, y + i.top, // right edge
+ i.right, height - i.bottom,
+ width - i.right, i.top);
}
+
+
+ /**
+ * Measures the width of this border.
+ *
+ * @param c the component whose border is to be measured.
+ *
+ * @return an Insets object whose <code>left</code>, <code>right</code>,
+ * <code>top</code> and <code>bottom</code> fields indicate the
+ * width of the border at the respective edge.
+ *
+ * @see #getBorderInsets(java.awt.Component, java.awt.Insets)
+ */
+ public Insets getBorderInsets(Component c)
+ {
+ /* There is no obvious reason for overriding this method, but we
+ * try to have exactly the same API as the Sun reference
+ * implementation.
+ */
+ return this.getBorderInsets(c, null);
+ }
+
+
+ /**
+ * Measures the width of this border, storing the results into a
+ * pre-existing Insets object.
+ *
+ * @param insets an Insets object for holding the result values.
+ * After invoking this method, the <code>left</code>,
+ * <code>right</code>, <code>top</code> and
+ * <code>bottom</code> fields indicate the width of the
+ * border at the respective edge.
+ *
+ * @return the same object that was passed for <code>insets</code>.
+ *
+ * @see #getBorderInsets()
+ */
+ public Insets getBorderInsets(Component c, Insets insets)
+ {
+ if (insets == null)
+ insets = new Insets(0, 0, 0, 0);
+
+ if ((tileIcon != null)
+ && (top < 0) && (left < 0)
+ && (right < 0) && (bottom < 0))
+ {
+ insets.left = insets.right = tileIcon.getIconWidth();
+ insets.top = insets.bottom = tileIcon.getIconHeight();
+ return insets;
+ }
- public MatteBorder (int top, int left, int bottom, int right, Color color)
+ /* Copy top, left, bottom and right into the respective
+ * field of insets.
+ */
+ return super.getBorderInsets(c, insets);
+ }
+
+
+ /**
+ * Measures the width of this border.
+ *
+ * @return an Insets object whose <code>left</code>, <code>right</code>,
+ * <code>top</code> and <code>bottom</code> fields indicate the
+ * width of the border at the respective edge.
+ *
+ * @see #getBorderInsets(java.awt.Component, java.awt.Insets)
+ */
+ public Insets getBorderInsets()
+ {
+ /* The inherited implementation of EmptyBorder.isBorderOpaque()
+ * would do the same. It is not clear why this is overriden in the
+ * Sun implementation, at least not from just reading the JavaDoc.
+ */
+ return this.getBorderInsets(null, null);
+ }
+
+
+ /**
+ * Returns the color that is used for filling the border, or
+ * <code>null</code> if the border is filled with repetitions of a
+ * tile icon.
+ */
+ public Color getMatteColor()
{
- super (top, left, bottom, right);
- this.color = color;
+ return color;
}
-
- public boolean isBorderOpaque()
+
+
+ /**
+ * Returns the icon is used for tiling the border, or
+ * <code>null</code> if the border is filled with a color instead of
+ * an icon.
+ */
+ public Icon getTileIcon()
+ {
+ return tileIcon;
+ }
+
+
+ /**
+ * Determines whether this border fills every pixel in its area
+ * when painting.
+ *
+ * @return <code>true</code> if the border is filled with an
+ * opaque color; <code>false</code> if it is filled with
+ * a semi-transparent color or with an icon.
+ */
+ public boolean isBorderOpaque()
+ {
+ return (color != null) && (color.getAlpha() == 255);
+ }
+
+
+ /**
+ * Paints a rectangular area of the border. This private helper
+ * method is called once for each of the border edges
+ * by {@link #paintBorder}.
+ *
+ * @param c the component whose border is being painted.
+ * @param g the graphics for painting.
+ * @param x the horizontal position of the rectangular area.
+ * @param y the vertical position of the rectangular area.
+ * @param width the width of the rectangular area.
+ * @param height the height of the rectangular area.
+ * @param dx the x displacement for repeating the tile.
+ * @param dy the y displacement for repeating the tile.
+ */
+ private void paintEdge(Component c, Graphics g,
+ int x, int y, int width, int height,
+ int dx, int dy)
+ {
+ Color oldColor;
+ int iconWidth, iconHeight;
+ Graphics clipped;
+
+ if ((width <= 0) || (height <= 0))
+ return;
+
+ /* Paint a colored rectangle if desired. */
+ if (color != null)
{
- return false;
+ oldColor = g.getColor();
+ try
+ {
+ g.setColor(color);
+ g.fillRect(x, y, width, height);
+ }
+ finally
+ {
+ g.setColor(oldColor);
+ }
+ return;
}
-
- public void paintBorder(Component c,
- Graphics g,
- int x,
- int y,
- int width,
- int height)
+
+ /* Determine the width and height of the icon. Some icons return
+ * -1 if it is an image whose dimensions have not yet been
+ * retrieved. There is not much we can do about this, but we
+ * should at least avoid entering the paint loop below
+ * with negative increments.
+ */
+ iconWidth = tileIcon.getIconWidth();
+ iconHeight = tileIcon.getIconHeight();
+ if ((iconWidth <= 0) || (iconHeight <= 0))
+ return;
+
+ dx = dx % iconWidth;
+ dy = dy % iconHeight;
+
+ clipped = g.create();
+ try
+ {
+ clipped.setClip(x, y, width, height);
+ for (int ty = y - dy; ty < y + height; ty += iconHeight)
+ for (int tx = x - dx; tx < x + width; tx += iconWidth)
+ tileIcon.paintIcon(c, clipped, tx, ty);
+ }
+ finally
{
+ clipped.dispose();
}
+ }
}
--- /dev/null
+/* SoftBevelBorder.java --
+ Copyright (C) 2003 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.swing.border;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Insets;
+
+
+/**
+ * A rectangular, three pixel thick border that looks like a BevelBorder
+ * with slightly softened corners.
+ *
+ * <p>Like BevelBorder, SoftBevelBorder has a highlight and a shadow
+ * color. In the raised variant, the highlight color is used for the
+ * top and left edges, and the shadow color is used for the bottom and
+ * right edge. In the lowered variant, color usage is reversed. For
+ * an image, see the documentation of the individual constructors.
+ *
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
+public class SoftBevelBorder
+ extends BevelBorder
+{
+ /**
+ * Determined using the <code>serialver</code> tool
+ * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5.
+ */
+ static final long serialVersionUID = -6658357140774549493L;
+
+
+ /**
+ * Constructs a SoftBevelBorder whose colors will be derived from the
+ * background of the enclosed component. The background color is
+ * retrieved each time the border is painted, so a SoftBevelBorder
+ * constructed by this method will automatically reflect a change
+ * to the component’s background color.
+ *
+ * <p><img src="SoftBevelBorder-1.png" width="500" height="200"
+ * alt="[An illustration showing raised and lowered SoftBevelBorders]" />
+ *
+ * @param bevelType the desired appearance of the border. The value
+ * must be either {@link BevelBorder#RAISED}
+ * or {@link BevelBorder#LOWERED}.
+ *
+ * @throws IllegalArgumentException if <code>bevelType</code> has
+ * an unsupported value.
+ */
+ public SoftBevelBorder(int bevelType)
+ {
+ super(bevelType);
+ }
+
+
+ /**
+ * Constructs a SoftBevelBorder given its appearance type and two
+ * colors for its highlight and shadow.
+ *
+ * <p><img src="SoftBevelBorder-2.png" width="500" height="150"
+ * alt="[An illustration showing SoftBevelBorders that were
+ * constructed with this method]" />
+ *
+ * @param bevelType the desired appearance of the border. The value
+ * must be either {@link BevelBorder#RAISED} or {@link
+ * BevelBorder#LOWERED}.
+ *
+ * @param highlight the color that will be used for the inner side
+ * of the highlighted edges (top and left if if
+ * <code>bevelType</code> is {@link BevelBorder#RAISED};
+ * bottom and right otherwise). The color for the outer side
+ * is a brightened version of this color.
+ *
+ * @param shadow the color that will be used for the outer side of
+ * the shadowed edges (bottom and right if
+ * <code>bevelType</code> is {@link BevelBorder#RAISED}; top
+ * and left otherwise). The color for the inner side is a
+ * brightened version of this color.
+ *
+ * @throws IllegalArgumentException if <code>bevelType</code> has an
+ * unsupported value.
+ *
+ * @throws NullPointerException if <code>highlight</code> or
+ * <code>shadow</code> is <code>null</code>.
+ *
+ * @see java.awt.Color.brighter()
+ */
+ public SoftBevelBorder(int bevelType, Color highlight, Color shadow)
+ {
+ this(bevelType,
+ /* highlightOuter */ highlight.brighter(),
+ /* highlightInner */ highlight,
+ /* shadowOuter */ shadow,
+ /* shadowInner */ shadow.brighter());
+ }
+
+
+ /**
+ * Constructs a SoftBevelBorder given its appearance type and all
+ * colors.
+ *
+ * <p><img src="SoftBevelBorder-3.png" width="500" height="150"
+ * alt="[An illustration showing SoftBevelBorders that were
+ * constructed with this method]" />
+ *
+ * @param bevelType the desired appearance of the border. The value
+ * must be either {@link BevelBorder#RAISED} or {@link
+ * BevelBorder#LOWERED}.
+ *
+ * @param highlightOuter the color that will be used for the outer
+ * side of the highlighted edges (top and left if
+ * <code>bevelType</code> is {@link BevelBorder#RAISED};
+ * bottom and right otherwise).
+ *
+ * @param highlightInner the color that will be used for the inner
+ * side of the highlighted edges.
+ *
+ * @param shadowOuter the color that will be used for the outer side
+ * of the shadowed edges (bottom and right if
+ * <code>bevelType</code> is {@link BevelBorder#RAISED}; top
+ * and left otherwise).
+ *
+ * @param shadowInner the color that will be used for the inner
+ * side of the shadowed edges.
+ *
+ * @throws IllegalArgumentException if <code>bevelType</code> has
+ * an unsupported value.
+ *
+ * @throws NullPointerException if one of the passed colors
+ * is <code>null</code>.
+ */
+ public SoftBevelBorder(int bevelType,
+ Color highlightOuter, Color highlightInner,
+ Color shadowOuter, Color shadowInner)
+ {
+ super(bevelType,
+ highlightOuter, highlightInner,
+ shadowOuter, shadowInner);
+ }
+
+
+ /**
+ * Paints the border for a given component.
+ *
+ * @param c the component whose border is to be painted.
+ * @param g the graphics for painting.
+ * @param x the horizontal position for painting the border.
+ * @param y the vertical position for painting the border.
+ * @param width the width of the available area for painting the border.
+ * @param height the height of the available area for painting the border.
+ */
+ public void paintBorder(Component c, Graphics g,
+ int x, int y, int width, int height)
+ {
+ switch (bevelType)
+ {
+ case RAISED:
+ paintSoftBevel(g, x, y, width, height,
+ getHighlightOuterColor(c), getHighlightInnerColor(c),
+ getShadowInnerColor(c), getShadowOuterColor(c));
+ break;
+
+ case LOWERED:
+ paintSoftBevel(g, x, y, width, height,
+ getShadowOuterColor(c), getShadowInnerColor(c),
+ getHighlightInnerColor(c), getHighlightOuterColor(c));
+ break;
+ }
+ }
+
+
+ /**
+ * Measures the width of this border.
+ *
+ * @param c the component whose border is to be measured.
+ *
+ * @return an Insets object whose <code>left</code>, <code>right</code>,
+ * <code>top</code> and <code>bottom</code> fields indicate the
+ * width of the border at the respective edge.
+ *
+ * @see #getBorderInsets(java.awt.Component, java.awt.Insets)
+ */
+ public Insets getBorderInsets(Component c)
+ {
+ return new Insets(3, 3, 3, 3);
+ }
+
+
+ /**
+ * Measures the width of this border, storing the results into a
+ * pre-existing Insets object.
+ *
+ * @param insets an Insets object for holding the result values.
+ * After invoking this method, the <code>left</code>,
+ * <code>right</code>, <code>top</code> and
+ * <code>bottom</code> fields indicate the width of the
+ * border at the respective edge.
+ *
+ * @return the same object that was passed for <code>insets</code>.
+ *
+ * @see #getBorderInsets()
+ */
+ public Insets getBorderInsets(Component c, Insets insets)
+ {
+ insets.left = insets.right = insets.top = insets.bottom = 3;
+ return insets;
+ }
+
+
+ /**
+ * Determines whether this border fills every pixel in its area
+ * when painting.
+ *
+ * <p>The enlarged view (see documentation for constructors) shows
+ * that a SoftBevelBorder does not paint all pixels. Therefore,
+ * this method always returns <code>false</code>.
+ *
+ * @return <code>false</code>.
+ */
+ public boolean isBorderOpaque()
+ {
+ return false;
+ }
+
+
+ /**
+ * Paints a soft bevel in four colors.
+ *
+ * <pre>
+ * @@@@@@@@@@@.
+ * @@.........# @ = color a
+ * @.. # . = color b
+ * @. # X = color c
+ * .. X# # = color d
+ * . ##########</pre>
+ *
+ * @param g the graphics for painting.
+ * @param x the horizontal position for painting the border.
+ * @param y the vertical position for painting the border.
+ * @param width the width of the available area for painting the border.
+ * @param height the height of the available area for painting the border.
+ * @param a the color for the outer side of the top and left edges.
+ * @param b the color for the inner side of the top and left edges.
+ * @param c the color for the inner side of the bottom and right edges.
+ * @param d the color for the outer side of the bottom and right edges.
+ */
+ private static void paintSoftBevel(Graphics g,
+ int x, int y, int width, int height,
+ Color a, Color b, Color c, Color d)
+ {
+ Color oldColor;
+
+ oldColor = g.getColor();
+ g.translate(x, y);
+ width = width - 1;
+ height = height - 1;
+
+ try
+ {
+ /* To understand this code, it might be helpful to look at the
+ * images that are included with the JavaDoc, especially
+ * SoftBevelBorder-3.png. They are located in the "doc-files"
+ * subdirectory.
+ */
+ g.setColor(a);
+ g.drawLine(0, 0, width - 1, 0); // a, horizontal
+ g.drawLine(0, 1, 2, 1); // a, horizontal
+ g.drawLine(0, 2, 0, height - 1); // a, vertical
+
+ g.setColor(b);
+ g.drawLine(width, 0, width, 0); // b, horizontal
+ g.drawLine(2, 1, width - 1, 1); // b, horizontal
+ g.drawLine(1, 2, 2, 2); // b, horizontal
+ g.drawLine(1, 3, 1, height - 1); // b, vertical
+ g.drawLine(0, height - 1, 0, height); // b, vertical
+
+ g.setColor(c);
+ g.drawLine(width - 1, height - 1, // c, one pixel
+ width - 1, height - 1);
+
+ g.setColor(d);
+ g.drawLine(2, height, width, height); // d, horizontal
+ g.drawLine(width, 2, width, height - 1); // d, vertical
+ }
+ finally
+ {
+ g.translate(-x, -y);
+ g.setColor(oldColor);
+ }
+ }
+}
+
/* TitledBorder.java --
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of GNU Classpath.
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.Rectangle;
+import java.awt.Shape;
+import javax.swing.UIManager;
-public class TitledBorder extends AbstractBorder
+
+/**
+ * A border that paints a title on top of another border.
+ *
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
+public class TitledBorder
+ extends AbstractBorder
{
- public static final int ABOVE_BOTTOM = 4;
+ /**
+ * A value for the <code>titlePosition</code> property that vertically
+ * positions the title text at the default vertical position, which
+ * is in the middle of the top line of the border.
+ *
+ * @see #getTitlePosition()
+ * @see #setTitlePosition(int)
+ */
+ public static final int DEFAULT_POSITION = 0;
+
+
+ /**
+ * A value for the <code>titlePosition</code> property that vertically
+ * positions the title text above the top line of the border.
+ *
+ * @see #getTitlePosition()
+ * @see #setTitlePosition(int)
+ */
public static final int ABOVE_TOP = 1;
- public static final int BELOW_BOTTOM = 6;
+
+
+ /**
+ * A value for the <code>titlePosition</code> property that vertically
+ * positions the title text at the middle of the top line
+ * of the border.
+ *
+ * @see #getTitlePosition()
+ * @see #setTitlePosition(int)
+ */
+ public static final int TOP = 2;
+
+
+ /**
+ * A value for the <code>titlePosition</code> property that vertically
+ * positions the title text below the top line of the border.
+ *
+ * @see #getTitlePosition()
+ * @see #setTitlePosition(int)
+ */
public static final int BELOW_TOP = 3;
+
+
+ /**
+ * A value for the <code>titlePosition</code> property that vertically
+ * positions the title text above the bottom line of the border.
+ *
+ * @see #getTitlePosition()
+ * @see #setTitlePosition(int)
+ */
+ public static final int ABOVE_BOTTOM = 4;
+
+
+ /**
+ * A value for the <code>titlePosition</code> property that vertically
+ * positions the title text at the center of the bottom line
+ * of the border.
+ *
+ * @see #getTitlePosition()
+ * @see #setTitlePosition(int)
+ */
public static final int BOTTOM = 5;
- public static final int CENTER = 2;
+
+
+ /**
+ * A value for the <code>titlePosition</code> property that vertically
+ * positions the title text below the bottom line of the border.
+ *
+ * @see #getTitlePosition()
+ * @see #setTitlePosition(int)
+ */
+ public static final int BELOW_BOTTOM = 6;
+
+
+ /**
+ * A value for the <code>titleJustification</code> property that
+ * horizontally aligns the title text with either the left or the
+ * right edge of the border, depending on the orientation of the
+ * component nested into the border. If the component orientation
+ * is left-to-right, the title text is aligned with the left edge;
+ * otherwise, it is aligned with the right edge. This is the same
+ * behavior as with {@link #LEADING}.
+ *
+ * @see #getTitleJustification()
+ * @see #setTitleJustification(int)
+ * @see java.awt.ComponentOrientation#isLeftToRight()
+ */
public static final int DEFAULT_JUSTIFICATION = 0;
- public static final int DEFAULT_POSITION = 0;
- public static final int LEADING = 4;
+
+
+ /**
+ * A value for the <code>titleJustification</code> property that
+ * horizontally aligns the title text with the left-hand edge of
+ * the border.
+ *
+ * @see #getTitleJustification()
+ * @see #setTitleJustification(int)
+ */
public static final int LEFT = 1;
+
+
+ /**
+ * A value for the <code>titleJustification</code> property that
+ * horizontally aligns the title text with the center of the border.
+ *
+ * @see #getTitleJustification()
+ * @see #setTitleJustification(int)
+ */
+ public static final int CENTER = 2;
+
+
+ /**
+ * A value for the <code>titleJustification</code> property that
+ * horizontally aligns the title text with the right-hand edge of
+ * the border.
+ *
+ * @see #getTitleJustification()
+ * @see #setTitleJustification(int)
+ */
public static final int RIGHT = 3;
- public static final int TOP = 2;
+
+
+ /**
+ * A value for the <code>titleJustification</code> property that
+ * horizontally aligns the title text with either the left or the
+ * right edge of the border, depending on the orientation of the
+ * component nested into the border. If the component orientation
+ * is left-to-right, the title text is aligned with the left edge;
+ * otherwise, it is aligned with the right edge. This is the same
+ * behavior as with {@link #DEFAULT_JUSTIFICATION}.
+ *
+ * @see #getTitleJustification()
+ * @see #setTitleJustification(int)
+ * @see java.awt.ComponentOrientation#isLeftToRight()
+ */
+ public static final int LEADING = 4;
+
+
+ /**
+ * A value for the <code>titleJustification</code> property that
+ * horizontally aligns the title text with either the right or the
+ * left edge of the border, depending on the orientation of the
+ * component nested into the border. If the component orientation
+ * is left-to-right, the title text is aligned with the right edge;
+ * otherwise, it is aligned with the left edge.
+ *
+ * @see #getTitleJustification()
+ * @see #setTitleJustification(int)
+ * @see java.awt.ComponentOrientation#isLeftToRight()
+ */
public static final int TRAILING = 5;
+
+ /**
+ * The number of pixels between the inside of {@link #border}
+ * and the bordered component.
+ */
protected static final int EDGE_SPACING = 2;
+
+
+ /**
+ * The number of pixels between the outside of this TitledBorder
+ * and the beginning (if left-aligned) or end (if right-aligned)
+ * of the title text.
+ */
protected static final int TEXT_INSET_H = 5;
+
+
+ /**
+ * The number of pixels between the title text and {@link #border}.
+ * This value is only relevant if the title text does not intersect
+ * {@link #border}. No intersection occurs if {@link #titlePosition}
+ * is one of {@link #ABOVE_TOP}, {@link #BELOW_TOP}, {@link #ABOVE_BOTTOM},
+ * or {@link #BELOW_BOTTOM}.
+ */
protected static final int TEXT_SPACING = 2;
- protected Border border;
+
+ /**
+ * Determined using the <code>serialver</code> tool of Apple/Sun JDK 1.3.1
+ * on MacOS X 10.1.5.
+ */
+ static final long serialVersionUID = 8012999415147721601L;
+
+
+ /**
+ * The title, or <code>null</code> to display no title.
+ */
protected String title;
- protected Color titleColor;
- protected Font titleFont;
- protected int titleJustification;
- protected int titlePosition;
- private static Border defaultBorder = new LineBorder (Color.black);
- private static Font defaultFont = null;
- private static Color defaultColor = Color.black;
+
+ /**
+ * The border underneath the title. If this value is
+ * <code>null</code>, the border will be retrieved from the {@link
+ * javax.swing.UIManager}’s defaults table using the key
+ * <code>"TitledBorder.border"</code>.
+ */
+ protected Border border;
+
- public TitledBorder (String title)
+ /**
+ * The vertical position of the title text relative to the border,
+ * which is one of {@link #ABOVE_TOP}, {@link #TOP}, {@link
+ * #BELOW_TOP}, {@link #ABOVE_BOTTOM}, {@link #BOTTOM}, {@link
+ * #BELOW_BOTTOM}, or {@link #DEFAULT_POSITION}.
+ */
+ protected int titlePosition;
+
+
+ /**
+ * The horizontal alignment of the title text in relation to the
+ * border, which is one of {@link #LEFT}, {@link #CENTER}, {@link
+ * #RIGHT}, {@link #LEADING}, {@link #TRAILING}, or {@link
+ * #DEFAULT_JUSTIFICATION}.
+ */
+ protected int titleJustification;
+
+
+ /**
+ * The font for displaying the title text. If this value is
+ * <code>null</code>, the font will be retrieved from the {@link
+ * javax.swing.UIManager}’s defaults table using the key
+ * <code>"TitledBorder.font"</code>.
+ */
+ protected Font titleFont;
+
+
+ /**
+ * The color for displaying the title text. If this value is
+ * <code>null</code>, the color will be retrieved from the {@link
+ * javax.swing.UIManager}’s defaults table using the key
+ * <code>"TitledBorder.titleColor"</code>.
+ */
+ protected Color titleColor;
+
+
+ /**
+ * Constructs a TitledBorder given the text of its title.
+ *
+ * @param title the title text, or <code>null</code> to use no title text.
+ */
+ public TitledBorder(String title)
{
- this (defaultBorder, title, DEFAULT_JUSTIFICATION, DEFAULT_POSITION,
- defaultFont, defaultColor);
+ this(/* border */ null,
+ title, DEFAULT_JUSTIFICATION, DEFAULT_POSITION,
+ /* titleFont */ null, /* titleColor */ null);
}
- public TitledBorder (Border border)
+
+ /**
+ * Constructs an initially untitled TitledBorder given another border.
+ *
+ * @param border the border underneath the title, or <code>null</code>
+ * to use a default from the current look and feel.
+ */
+ public TitledBorder(Border border)
{
- this (border, "", DEFAULT_JUSTIFICATION, DEFAULT_POSITION, defaultFont,
- defaultColor);
+ this(border, /* title */ "", DEFAULT_JUSTIFICATION, DEFAULT_POSITION,
+ /* titleFont */ null, /* titleColor */ null);
}
- public TitledBorder (Border border, String title)
+
+ /**
+ * Constructs a TitledBorder given its border and title text.
+ *
+ * @param border the border underneath the title, or <code>null</code>
+ * to use a default from the current look and feel.
+ *
+ * @param title the title text, or <code>null</code> to use no title
+ * text.
+ */
+ public TitledBorder(Border border, String title)
{
- this (border, title, DEFAULT_JUSTIFICATION, DEFAULT_POSITION, defaultFont,
- defaultColor);
+ this(border, title, DEFAULT_JUSTIFICATION, DEFAULT_POSITION,
+ /* titleFont */ null, /* titleColor */ null);
}
- public TitledBorder (Border border, String title, int titleJustification,
- int titlePosition)
+
+ /**
+ * Constructs a TitledBorder given its border, title text, horizontal
+ * alignment, and vertical position.
+ *
+ * @param border the border underneath the title, or <code>null</code>
+ * to use a default from the current look and feel.
+ *
+ * @param title the title text, or <code>null</code> to use no title
+ * text.
+ *
+ * @param titleJustification the horizontal alignment of the title
+ * text in relation to the border. The value must be one of
+ * {@link #LEFT}, {@link #CENTER}, {@link #RIGHT}, {@link #LEADING},
+ * {@link #TRAILING}, or {@link #DEFAULT_JUSTIFICATION}.
+
+ * @param titlePosition the vertical position of the title text
+ * in relation to the border. The value must be one of
+ * {@link #ABOVE_TOP}, {@link #TOP}, {@link #BELOW_TOP},
+ * {@link #ABOVE_BOTTOM}, {@link #BOTTOM}, {@link #BELOW_BOTTOM},
+ * or {@link #DEFAULT_POSITION}.
+ *
+ * @throws IllegalArgumentException if <code>titleJustification</code>
+ * or <code>titlePosition</code> have an unsupported value.
+ */
+ public TitledBorder(Border border, String title, int titleJustification,
+ int titlePosition)
{
- this (border, title, titleJustification, titlePosition, defaultFont,
- defaultColor);
+ this(border, title, titleJustification, titlePosition,
+ /* titleFont */ null, /* titleColor */ null);
}
- public TitledBorder (Border border, String title, int titleJustification,
- int titlePosition, Font titleFont)
+
+ /**
+ * Constructs a TitledBorder given its border, title text, horizontal
+ * alignment, vertical position, and font.
+ *
+ * @param border the border underneath the title, or <code>null</code>
+ * to use a default from the current look and feel.
+ *
+ * @param title the title text, or <code>null</code> to use no title
+ * text.
+ *
+ * @param titleJustification the horizontal alignment of the title
+ * text in relation to the border. The value must be one of
+ * {@link #LEFT}, {@link #CENTER}, {@link #RIGHT}, {@link #LEADING},
+ * {@link #TRAILING}, or {@link #DEFAULT_JUSTIFICATION}.
+ *
+ * @param titlePosition the vertical position of the title text
+ * in relation to the border. The value must be one of
+ * {@link #ABOVE_TOP}, {@link #TOP}, {@link #BELOW_TOP},
+ * {@link #ABOVE_BOTTOM}, {@link #BOTTOM}, {@link #BELOW_BOTTOM},
+ * or {@link #DEFAULT_POSITION}.
+ *
+ * @param titleFont the font for the title text, or <code>null</code>
+ * to use a default from the current look and feel.
+ *
+ * @throws IllegalArgumentException if <code>titleJustification</code>
+ * or <code>titlePosition</code> have an unsupported value.
+ */
+ public TitledBorder(Border border, String title, int titleJustification,
+ int titlePosition, Font titleFont)
{
- this (border, title, titleJustification, titlePosition, titleFont,
- defaultColor);
+ this(border, title, titleJustification, titlePosition, titleFont,
+ /* titleColor */ null);
}
- public TitledBorder (Border border, String title, int titleJustification,
- int titlePosition, Font titleFont, Color titleColor)
+
+ /**
+ * Constructs a TitledBorder given its border, title text, horizontal
+ * alignment, vertical position, font, and color.
+ *
+ * @param border the border underneath the title, or <code>null</code>
+ * to use a default from the current look and feel.
+ *
+ * @param title the title text, or <code>null</code> to use no title
+ * text.
+ *
+ * @param titleJustification the horizontal alignment of the title
+ * text in relation to the border. The value must be one of
+ * {@link #LEFT}, {@link #CENTER}, {@link #RIGHT}, {@link #LEADING},
+ * {@link #TRAILING}, or {@link #DEFAULT_JUSTIFICATION}.
+ *
+ * @param titlePosition the vertical position of the title text
+ * in relation to the border. The value must be one of
+ * {@link #ABOVE_TOP}, {@link #TOP}, {@link #BELOW_TOP},
+ * {@link #ABOVE_BOTTOM}, {@link #BOTTOM}, {@link #BELOW_BOTTOM},
+ * or {@link #DEFAULT_POSITION}.
+ *
+ * @param titleFont the font for the title text, or <code>null</code>
+ * to use a default from the current look and feel.
+ *
+ * @param titleColor the color for the title text, or <code>null</code>
+ * to use a default from the current look and feel.
+ *
+ * @throws IllegalArgumentException if <code>titleJustification</code>
+ * or <code>titlePosition</code> have an unsupported value.
+ */
+ public TitledBorder(Border border, String title, int titleJustification,
+ int titlePosition, Font titleFont, Color titleColor)
{
this.border = border;
this.title = title;
- this.titleJustification = titleJustification;
+
+ /* Invoking the setter methods ensures that the newly constructed
+ * TitledBorder has valid property values.
+ */
+ setTitleJustification(titleJustification);
+ setTitlePosition(titlePosition);
+
+ this.titleFont = titleFont;
+ this.titleColor = titleColor;
+ }
+
+
+ /**
+ * Paints the border and the title text.
+ *
+ * @param c the component whose border is to be painted.
+ * @param g the graphics for painting.
+ * @param x the horizontal position for painting the border.
+ * @param y the vertical position for painting the border.
+ * @param width the width of the available area for painting the border.
+ * @param height the height of the available area for painting the border.
+ */
+ public void paintBorder(Component c, Graphics g,
+ int x, int y, int width, int height)
+ {
+ Measurements mes = getMeasurements(c);
+ Font oldFont = g.getFont();
+ Color oldColor = g.getColor();
+
+ /**
+ * A local helper class for painting the border without changing
+ * any pixels inside the rectangle of the title text.
+ */
+ class BorderPainter
+ {
+ private Component c;
+ private Border b;
+ private int x, y, width, height;
+
+ /**
+ * Constructs a BorderPainter.
+ *
+ * @param c the component whose border is being painted.
+ * @param b the border object.
+ * @param x the x coordinate of the rectangle delimiting the border.
+ * @param y the y coordinate of the rectangle delimiting the border.
+ * @param width the width of the rectangle delimiting the border.
+ * @param height the width of the rectangle delimiting the border.
+ */
+ public BorderPainter(Component c, Border b,
+ int x, int y, int width, int height)
+ {
+ this.c = c;
+ this.b = b;
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ }
+
+
+ /**
+ * Paints the entire border.
+ */
+ public void paint(Graphics g)
+ {
+ if (b != null)
+ b.paintBorder(c, g, x, y, width - 1, height - 1);
+ }
+
+
+ /**
+ * Paints the border, clipping the drawing operation to a
+ * given rectangular area.
+ */
+ private void paint(Graphics g,
+ int clipX, int clipY, int clipWidth, int clipHeight)
+ {
+ Shape oldClip = g.getClip();
+ try
+ {
+ g.clipRect(clipX, clipY, clipWidth, clipHeight);
+ paint(g);
+ }
+ finally
+ {
+ g.setClip(oldClip);
+ }
+ }
+
+
+ /**
+ * Paints the border without affecting a given rectangular area.
+ * This is used for painting the border without drawing anything
+ * underneath the title text.
+ *
+ * <p>Since we do not want to introduce unnecessary dependencies
+ * on Java 2D, we perform the clipping without constructive geometry
+ * (provided by java.awt.geom.Area). Instead, the border’s
+ * bounding rectangle is split into smaller parts, which are then
+ * clipped and painted individually.:
+ *
+ * <p><pre>
+ * +--------------------+ +--------------------+
+ * | | | 1 |
+ * | +--------+ | +---+--------+-------+
+ * | | hole | | |====> | 2 | hole | 3 |
+ * | +--------+ | |---+--------+-------+
+ * | | | 4 |
+ * +--------------------+ +--------------------+</pre>
+ *
+ */
+ public void paintExcept(Graphics g,
+ int holeX, int holeY, int holeWidth, int holeHeight)
+ {
+ int stripeHeight;
+
+ stripeHeight = holeY - y;
+ if (stripeHeight > 0)
+ paint(g, x, y, width, stripeHeight); // patch #1 in the image above
+
+ stripeHeight = holeHeight;
+ if (stripeHeight > 0)
+ {
+ paint(g, x, holeY, holeX - x, stripeHeight); // patches #2 and #3
+ paint(g, holeX + holeWidth, holeY, width - (holeX + holeWidth), stripeHeight);
+ }
+
+ stripeHeight = height - (holeY - y + holeHeight);
+ if (stripeHeight > 0)
+ paint(g, x, y + height - stripeHeight, width, stripeHeight); // #4
+ }
+ };
+
+ BorderPainter bp;
+ int textX, textY, borderWidth, borderHeight;
+
+ borderWidth = width - (mes.borderSpacing.left + mes.borderSpacing.right);
+ borderHeight = height - (mes.borderSpacing.top + mes.borderSpacing.bottom);
+ bp = new BorderPainter(c, getBorder(),
+ x + mes.borderSpacing.left, y + mes.borderSpacing.top,
+ borderWidth, borderHeight);
+
+ switch (getRealTitleJustification(c))
+ {
+ case LEFT:
+ textX = x + TEXT_INSET_H;
+ break;
+
+ case CENTER:
+ textX = x + (borderWidth - mes.textWidth) / 2;
+ break;
+
+ case RIGHT:
+ textX = x + borderWidth - (mes.textWidth + TEXT_INSET_H);
+ break;
+
+ default:
+ throw new IllegalStateException();
+ }
+
+ switch (titlePosition)
+ {
+ case ABOVE_TOP:
+ textY = y;
+ break;
+
+ case TOP:
+ case DEFAULT_POSITION:
+ default:
+ textY = y + mes.borderSpacing.top + mes.borderInsets.top - mes.textAscent;
+ break;
+
+ case BELOW_TOP:
+ textY = y + mes.borderSpacing.top + mes.borderInsets.top + TEXT_SPACING;
+ break;
+
+ case ABOVE_BOTTOM:
+ textY = y + height - mes.borderSpacing.bottom - mes.borderInsets.bottom
+ - TEXT_SPACING - (mes.textAscent + mes.textDescent);
+ break;
+
+ case BOTTOM:
+ case BELOW_BOTTOM:
+ textY = y + height - (mes.textAscent + mes.textDescent);
+ break;
+ }
+
+ if (mes.trimmedText == null)
+ bp.paint(g);
+ else
+ {
+ try
+ {
+ g.setFont(mes.font);
+ g.setColor(getTitleColor());
+ g.drawString(mes.trimmedText, textX, textY + mes.textAscent);
+ }
+ finally
+ {
+ g.setFont(oldFont);
+ g.setColor(oldColor);
+ }
+ bp.paintExcept(g, textX - 2, textY,
+ mes.textWidth + 2, mes.textAscent + mes.textDescent);
+ }
+ }
+
+
+ /**
+ * Measures the width of this border.
+ *
+ * @param c the component whose border is to be measured.
+ *
+ * @return an Insets object whose <code>left</code>, <code>right</code>,
+ * <code>top</code> and <code>bottom</code> fields indicate the
+ * width of the border at the respective edge.
+ *
+ * @see #getBorderInsets(java.awt.Component, java.awt.Insets)
+ */
+ public Insets getBorderInsets(Component c)
+ {
+ return getBorderInsets(c, new Insets(0, 0, 0, 0));
+ }
+
+
+ /**
+ * Measures the width of this border, storing the results into a
+ * pre-existing Insets object.
+ *
+ * @param insets an Insets object for holding the result values.
+ * After invoking this method, the <code>left</code>,
+ * <code>right</code>, <code>top</code> and
+ * <code>bottom</code> fields indicate the width of the
+ * border at the respective edge.
+ *
+ * @return the same object that was passed for <code>insets</code>.
+ *
+ * @see #getBorderInsets()
+ */
+ public Insets getBorderInsets(Component c, Insets insets)
+ {
+ return getMeasurements(c).getContentInsets(insets);
+ }
+
+
+ /**
+ * Returns <code>false</code>, indicating that there are pixels inside
+ * the area of this border where the background shines through.
+ *
+ * @return <code>false</code>.
+ */
+ public boolean isBorderOpaque()
+ {
+ /* Note that the AbstractBorder.isBorderOpaque would also return
+ * false, so there is actually no need to override the inherited
+ * implementation. However, GNU Classpath strives for exact
+ * compatibility with the Sun reference implementation, which
+ * overrides isBorderOpaque for unknown reasons.
+ */
+ return false;
+ }
+
+
+ /**
+ * Returns the text of the title.
+ *
+ * @return the title text, or <code>null</code> if no title is
+ * displayed.
+ */
+ public String getTitle()
+ {
+ return title;
+ }
+
+
+ /**
+ * Retrieves the border underneath the title. If no border has been
+ * set, or if it has been set to<code>null</code>, the current
+ * {@link javax.swing.LookAndFeel} will be asked for a border
+ * using the key <code>"TitledBorder.border"</code>.
+ *
+ * @return a border, or <code>null</code> if the current LookAndFeel
+ * does not provide a border for the key
+ * <code>"TitledBorder.border"</code>.
+ *
+ * @see javax.swing.UIManager#getBorder(Object)
+ */
+ public Border getBorder()
+ {
+ if (border != null)
+ return border;
+
+ return UIManager.getBorder("TitledBorder.border");
+ }
+
+
+ /**
+ * Returns the vertical position of the title text in relation
+ * to the border.
+ *
+ * @return one of the values {@link #ABOVE_TOP}, {@link #TOP},
+ * {@link #BELOW_TOP}, {@link #ABOVE_BOTTOM}, {@link #BOTTOM},
+ * {@link #BELOW_BOTTOM}, or {@link #DEFAULT_POSITION}.
+ */
+ public int getTitlePosition()
+ {
+ return titlePosition;
+ }
+
+
+ /**
+ * Returns the horizontal alignment of the title text in relation to
+ * the border.
+ *
+ * @return one of the values {@link #LEFT}, {@link #CENTER}, {@link
+ * #RIGHT}, {@link #LEADING}, {@link #TRAILING}, or {@link
+ * #DEFAULT_JUSTIFICATION}.
+ */
+ public int getTitleJustification()
+ {
+ return titleJustification;
+ }
+
+
+ /**
+ * Retrieves the font for displaying the title text. If no font has
+ * been set, or if it has been set to<code>null</code>, the current
+ * {@link javax.swing.LookAndFeel} will be asked for a font
+ * using the key <code>"TitledBorder.font"</code>.
+ *
+ * @return a font, or <code>null</code> if the current LookAndFeel
+ * does not provide a font for the key
+ * <code>"TitledBorder.font"</code>.
+ *
+ * @see javax.swing.UIManager#getFont(Object)
+ */
+ public Font getTitleFont()
+ {
+ if (titleFont != null)
+ return titleFont;
+
+ return UIManager.getFont("TitledBorder.font");
+ }
+
+
+ /**
+ * Retrieves the color for displaying the title text. If no color has
+ * been set, or if it has been set to<code>null</code>, the current
+ * {@link javax.swing.LookAndFeel} will be asked for a color
+ * using the key <code>"TitledBorder.titleColor"</code>.
+ *
+ * @return a color, or <code>null</code> if the current LookAndFeel
+ * does not provide a color for the key
+ * <code>"TitledBorder.titleColor"</code>.
+ *
+ * @see javax.swing.UIManager#getColor(Object)
+ */
+ public Color getTitleColor()
+ {
+ if (titleColor != null)
+ return titleColor;
+
+ return UIManager.getColor("TitledBorder.titleColor");
+ }
+
+
+ /**
+ * Sets the text of the title.
+ *
+ * @param title the new title text, or <code>null</code> for displaying
+ * no text at all.
+ */
+ public void setTitle(String title)
+ {
+ // Swing borders are not JavaBeans, thus no need to fire an event.
+ this.title = title;
+ }
+
+
+ /**
+ * Sets the border underneath the title.
+ *
+ * @param border a border, or <code>null</code> to use the
+ * border that is supplied by the current LookAndFeel.
+ *
+ * @see #getBorder()
+ */
+ public void setBorder(Border border)
+ {
+ // Swing borders are not JavaBeans, thus no need to fire an event.
+ this.border = border;
+ }
+
+
+ /**
+ * Sets the vertical position of the title text in relation
+ * to the border.
+ *
+ * @param titlePosition one of the values {@link #ABOVE_TOP},
+ * {@link #TOP}, {@link #BELOW_TOP}, {@link #ABOVE_BOTTOM},
+ * {@link #BOTTOM}, {@link #BELOW_BOTTOM},
+ * or {@link #DEFAULT_POSITION}.
+ *
+ * @throws IllegalArgumentException if an unsupported value is passed
+ * for <code>titlePosition</code>.
+ */
+ public void setTitlePosition(int titlePosition)
+ {
+ if ((titlePosition < DEFAULT_POSITION) || (titlePosition > BELOW_BOTTOM))
+ throw new IllegalArgumentException();
+
+ // Swing borders are not JavaBeans, thus no need to fire an event.
this.titlePosition = titlePosition;
+ }
+
+
+ /**
+ * Sets the horizontal alignment of the title text in relation to the border.
+ *
+ * @param titleJustification the new alignment, which must be one of
+ * {@link #LEFT}, {@link #CENTER}, {@link #RIGHT}, {@link #LEADING},
+ * {@link #TRAILING}, or {@link #DEFAULT_JUSTIFICATION}.
+ *
+ * @throws IllegalArgumentException if an unsupported value is passed
+ * for <code>titleJustification</code>.
+ */
+ public void setTitleJustification(int titleJustification)
+ {
+ if ((titleJustification < DEFAULT_JUSTIFICATION)
+ || (titleJustification > TRAILING))
+ throw new IllegalArgumentException();
+
+ // Swing borders are not JavaBeans, thus no need to fire an event.
+ this.titleJustification = titleJustification;
+ }
+
+
+ /**
+ * Sets the font for displaying the title text.
+ *
+ * @param titleFont the font, or <code>null</code> to use the font
+ * provided by the current {@link javax.swing.LookAndFeel}.
+ *
+ * @see #getTitleFont()
+ */
+ public void setTitleFont(Font titleFont)
+ {
+ // Swing borders are not JavaBeans, thus no need to fire an event.
this.titleFont = titleFont;
+ }
+
+
+ /**
+ * Sets the color for displaying the title text.
+ *
+ * @param titleColor the color, or <code>null</code> to use the color
+ * provided by the current {@link javax.swing.LookAndFeel}.
+ *
+ * @see #getTitleColor()
+ */
+ public void setTitleColor(Color titleColor)
+ {
+ // Swing borders are not JavaBeans, thus no need to fire an event.
this.titleColor = titleColor;
}
-
- public Insets getBorderInsets(Component c,
- Insets s)
+
+
+ /**
+ * Calculates the minimum size needed for displaying the border
+ * and its title.
+ *
+ * @param c the Component for which this TitledBorder consitutes
+ * a border.
+ */
+ public Dimension getMinimumSize(Component c)
+ {
+ return getMeasurements(c).getMinimumSize();
+ }
+
+
+ /**
+ * Returns the font that is used for displaying the title text for
+ * a given Component.
+ *
+ * @param c the Component for which this TitledBorder is the border.
+ *
+ * @return The font returned by {@link #getTitleFont()}, or a fallback
+ * if {@link #getTitleFont()} returned <code>null</code>.
+ */
+ protected Font getFont(Component c)
+ {
+ Font f;
+
+ f = getTitleFont();
+ if (f != null)
+ return f;
+
+ return new Font("Dialog", Font.PLAIN, 12);
+ }
+
+
+ /**
+ * Returns the horizontal alignment of the title text in relation to
+ * the border, mapping the component-dependent alignment constants
+ * {@link #LEADING}, {@link #TRAILING} and {@link #DEFAULT_JUSTIFICATION}
+ * to the correct value according to the embedded component’s
+ * orientation.
+ *
+ * @param c the Component for which this TitledBorder is the border.
+ *
+ * @return one of the values {@link #LEFT}, {@link #CENTER}, or {@link
+ * #RIGHT}.
+ */
+ private int getRealTitleJustification(Component c)
+ {
+ switch (titleJustification)
+ {
+ case DEFAULT_JUSTIFICATION:
+ case LEADING:
+ if ((c == null) || c.getComponentOrientation().isLeftToRight())
+ return LEFT;
+ else
+ return RIGHT;
+
+ case TRAILING:
+ if ((c == null) || c.getComponentOrientation().isLeftToRight())
+ return RIGHT;
+ else
+ return LEFT;
+
+ default:
+ return titleJustification;
+ }
+ }
+
+
+ /**
+ * Performs various measurements for the current state of this TitledBorder
+ * and the given Component.
+ */
+ private Measurements getMeasurements(Component c)
+ {
+ Measurements m = new Measurements();
+ FontMetrics fmet;
+
+ m.font = getFont(c);
+ fmet = c.getFontMetrics(m.font);
+ m.border = getBorder();
+ if (m.border != null)
+ m.borderInsets = m.border.getBorderInsets(c);
+ else
+ m.borderInsets = new Insets(0, 0, 0, 0);
+
+ if (title != null)
{
- s.left = s.right = s.top = s.bottom = 5;
- return s;
+ m.trimmedText = title.trim();
+ if (m.trimmedText.length() == 0)
+ m.trimmedText = null;
}
+ m.textAscent = fmet.getAscent();
+ m.textDescent = fmet.getDescent();
+ if (m.trimmedText != null)
+ m.textWidth = fmet.stringWidth(m.trimmedText) + 3;
+
+ m.edgeSpacing = new Insets(EDGE_SPACING, EDGE_SPACING, EDGE_SPACING, EDGE_SPACING);
+ m.borderSpacing = new Insets(0, 0, 0, 0);
+
+ switch (titlePosition)
+ {
+ case ABOVE_TOP:
+ m.borderSpacing.top += m.textAscent + m.textDescent + TEXT_SPACING;
+ break;
+
+ case BELOW_TOP:
+ m.edgeSpacing.top += m.textAscent + m.textDescent + TEXT_SPACING;
+ break;
+
+ case ABOVE_BOTTOM:
+ m.edgeSpacing.bottom += m.textAscent + m.textDescent + TEXT_SPACING;
+ break;
+
+ case BOTTOM:
+ m.edgeSpacing.bottom += Math.max(m.textAscent - m.borderInsets.bottom, 0);
+ m.borderSpacing.bottom += m.textDescent;
+ break;
+
+ case BELOW_BOTTOM:
+ m.borderSpacing.bottom += m.textAscent + m.textDescent + TEXT_SPACING;
+ break;
+
+ default:
+ m.borderSpacing.top += m.textAscent;
+ }
+
+ return m;
+ }
+
+
+ /**
+ * A private helper class for holding the result of measuring the
+ * distances of a TitledBorder. While it would be possible to cache
+ * these objects, it does not seem to be worth the effort. Note that
+ * invalidating the cache would be tricky, especially since there is
+ * no notification mechanism that would inform the cache when
+ * border has changed, so it would return different insets.
+ */
+ private static class Measurements
+ {
+ /**
+ * The font used for displaying the title text. Note that it can
+ * well be that the TitledBorder’s font is <code>null</code>,
+ * which means that the font is to be retrieved from the current
+ * LookAndFeel. In this case, this <code>font</code> field will
+ * contain the result of the retrieval. Therefore, it is safe
+ * to assume that his <code>font</code> field will never have
+ * a <code>null</code> value.
+ */
+ Font font;
+
+
+ /**
+ * The number of pixels between the base line and the top of the
+ * text box.
+ */
+ int textAscent;
+
+
+ /**
+ * The number of pixels between the base line and the bottom of
+ * the text box.
+ */
+ int textDescent;
+
+
+ /**
+ * The title text after removing leading and trailing white space
+ * characters. If the title consists only of white space, the
+ * value of <code>trimmedText</code> will be <code>null</code>.
+ */
+ String trimmedText;
+
+
+ /**
+ * The width of the trimmed title text in pixels.
+ */
+ int textWidth;
+
+
+ /**
+ * The border that constitues the "interior" border
+ * underneath the title text.
+ */
+ Border border;
+
+
+ /**
+ * The distance between the TitledBorder and the interior border.
+ */
+ Insets borderSpacing;
+
+ /**
+ * The width of the interior border, as returned by
+ * <code>border.getBorderInsets()</code>.
+ */
+ Insets borderInsets;
+
- public boolean isBorderOpaque()
+ /**
+ * The distance between the interior border and the nested
+ * Component for which this TitledBorder is a border.
+ */
+ Insets edgeSpacing;
+
+
+ /**
+ * Determines the insets of the nested component when it has a
+ * TitledBorder as its border. Used by {@link
+ * TitledBorder#getBorderInsets()}.
+ *
+ * @param i an Insets object for storing the results into, or
+ * <code>null</code> to cause the creation of a
+ * new instance.
+ *
+ * @return the <code>i</code> object, or a new Insets object
+ * if <code>null</code> was passed for <code>i</code>.
+ */
+ public Insets getContentInsets(Insets i)
{
- return false;
+ if (i == null)
+ i = new Insets(0, 0, 0, 0);
+ i.left = borderSpacing.left + borderInsets.left + edgeSpacing.left;
+ i.right = borderSpacing.right + borderInsets.right + edgeSpacing.right;
+ i.top = borderSpacing.top + borderInsets.top + edgeSpacing.top;
+ i.bottom = borderSpacing.bottom + borderInsets.bottom + edgeSpacing.bottom;
+ return i;
}
-
- public void paintBorder(Component c,
- Graphics g,
- int x,
- int y,
- int width,
- int height)
+
+
+ /**
+ * Calculates the minimum size needed for displaying the border
+ * and its title. Used by {@link TitledBorder#getMiminumSize()}.
+ */
+ public Dimension getMinimumSize()
{
+ int width;
+ Insets insets;
+
+ insets = getContentInsets(null);
+ width = Math.max(insets.left + insets.right, textWidth + 2 * TEXT_INSET_H);
+ return new Dimension(width, insets.top + insets.bottom);
}
+ }
}
-
/* BorderUIResource.java
- Copyright (C) 1999 Free Software Foundation, Inc.
+ Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of GNU Classpath.
package javax.swing.plaf;
+
import javax.swing.border.*;
import javax.swing.Icon;
import java.io.Serializable;
import java.awt.Color;
/**
+ * A wrapper for {@link javax.swing.border.Border} that also
+ * implements the {@link UIResource} marker interface. This is useful
+ * for implementing pluggable look-and-feels: When switching the
+ * current LookAndFeel, only those borders are replaced that are
+ * marked as {@link UIResource}. For this reason, a look-and-feel
+ * should always install borders that implement
+ * <code>UIResource</code>, such as the borders provided by this
+ * class.
+ *
* @serial
* @serialField delegate Border the <code>Border</code> wrapped
- * @author Brian Jones
+ *
+ * @author Brian Jones (cbj@gnu.org)
+ * @author Sascha Brawer (brawer@dandelis.ch)
*/
public class BorderUIResource
- extends Object
- implements Border, UIResource, Serializable
+ extends Object
+ implements Border, UIResource, Serializable
{
+ /**
+ * Verified using the <code>serialver</code> tool
+ * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5.
+ */
static final long serialVersionUID = -3440553684010079691L;
- private Border delegate;
+ /**
+ * A shared instance of an {@link EtchedBorderUIResource}, or
+ * <code>null</code> if the {@link #getEtchedBorderUIResource()}
+ * method has not yet been called.
+ */
+ private static Border etchedBorderUIResource;
+
+
+ /**
+ * A shared instance of a {@link BevelBorderUIResource} whose
+ * <code>bevelType</code> is {@link
+ * javax.swing.border.BevelBorder#LOWERED}, or <code>null</code> if
+ * the {@link #getLoweredBevelBorderUIResource()} has not yet been
+ * called.
+ */
+ private static Border loweredBevelBorderUIResource;
+
+
+ /**
+ * A shared instance of a {@link BevelBorderUIResource} whose
+ * <code>bevelType</code> is {@link
+ * javax.swing.border.BevelBorder#RAISED}, or <code>null</code> if
+ * the {@link #getRaisedBevelBorderUIResource()} has not yet been
+ * called.
+ */
+ private static Border raisedBevelBorderUIResource;
+
+
+ /**
+ * A shared instance of a {@link LineBorderUIResource} for
+ * a one-pixel thick black line, or <code>null</code> if
+ * the {@link #getBlackLineBorderUIResource()} has not yet been
+ * called.
+ */
+ private static Border blackLineBorderUIResource;
+
+
+ /**
+ * Returns a shared instance of an etched border which also
+ * is marked as an {@link UIResource}.
+ *
+ * @see javax.swing.border.EtchedBorder
+ */
+ public static Border getEtchedBorderUIResource()
+ {
+ /* Swing is not designed to be thread-safe, so there is no
+ * need to synchronize the access to the global variable.
+ */
+ if (etchedBorderUIResource == null)
+ etchedBorderUIResource = new EtchedBorderUIResource();
+ return etchedBorderUIResource;
+ }
+
+
+ /**
+ * Returns a shared instance of {@link BevelBorderUIResource} whose
+ * <code>bevelType</code> is {@link
+ * javax.swing.border.BevelBorder#LOWERED}.
+ *
+ * @see javax.swing.border.BevelBorder
+ */
+ public static Border getLoweredBevelBorderUIResource()
+ {
+ /* Swing is not designed to be thread-safe, so there is no
+ * need to synchronize the access to the global variable.
+ */
+ if (loweredBevelBorderUIResource == null)
+ loweredBevelBorderUIResource = new BevelBorderUIResource(
+ BevelBorder.LOWERED);
+ return loweredBevelBorderUIResource;
+ }
+
+
+ /**
+ * Returns a shared instance of {@link BevelBorderUIResource} whose
+ * <code>bevelType</code> is {@link
+ * javax.swing.border.BevelBorder#RAISED}.
+ *
+ * @see javax.swing.border.BevelBorder
+ */
+ public static Border getRaisedBevelBorderUIResource()
+ {
+ /* Swing is not designed to be thread-safe, so there is no
+ * need to synchronize the access to the global variable.
+ */
+ if (raisedBevelBorderUIResource == null)
+ raisedBevelBorderUIResource = new BevelBorderUIResource(
+ BevelBorder.RAISED);
+ return raisedBevelBorderUIResource;
+ }
+
+
+ /**
+ * Returns a shared instance of {@link LineBorderUIResource} for
+ * a black, one-pixel width border.
+ *
+ * @see javax.swing.border.LineBorder
+ */
+ public static Border getBlackLineBorderUIResource()
+ {
+ /* Swing is not designed to be thread-safe, so there is no
+ * need to synchronize the access to the global variable.
+ */
+ if (blackLineBorderUIResource == null)
+ blackLineBorderUIResource = new LineBorderUIResource(Color.black);
+ return blackLineBorderUIResource;
+ }
+
+
+ /**
+ * The wrapped border.
+ */
+ private Border delegate;
+
+
+ /**
+ * Constructs a <code>BorderUIResource</code> for wrapping
+ * a <code>Border</code> object.
+ *
+ * @param delegate the border to be wrapped.
+ */
+ public BorderUIResource(Border delegate)
+ {
+ if (delegate == null)
+ throw new IllegalArgumentException();
+
+ this.delegate = delegate;
+ }
+
+
+ /**
+ * Paints the border around an enclosed component by calling
+ * the <code>paintBorder</code> method of the wrapped delegate.
+ *
+ * @param c the component whose border is to be painted.
+ * @param g the graphics for painting.
+ * @param x the horizontal position for painting the border.
+ * @param y the vertical position for painting the border.
+ * @param width the width of the available area for painting the border.
+ * @param height the height of the available area for painting the border.
+ */
+ public void paintBorder(Component c, Graphics g,
+ int x, int y, int width, int height)
+ {
+ delegate.paintBorder(c, g, x, y, width, height);
+ }
+
+
+ /**
+ * Measures the width of this border by calling the
+ * <code>getBorderInsets</code> method of the wrapped
+ * delegate.
+ *
+ * @param c the component whose border is to be measured.
+ *
+ * @return an Insets object whose <code>left</code>, <code>right</code>,
+ * <code>top</code> and <code>bottom</code> fields indicate the
+ * width of the border at the respective edge.
+ */
+ public Insets getBorderInsets(Component c)
+ {
+ return delegate.getBorderInsets(c);
+ }
+
+
+ /**
+ * Determines whether this border fills every pixel in its area
+ * when painting by calling the <code>isBorderOpaque</code>
+ * method of the wrapped delegate.
+ *
+ * @return <code>true</code> if the border is fully opaque, or
+ * <code>false</code> if some pixels of the background
+ * can shine through the border.
+ */
+ public boolean isBorderOpaque()
+ {
+ return delegate.isBorderOpaque();
+ }
+
+
+ /**
+ * A {@link javax.swing.border.BevelBorder} that also implements the
+ * {@link UIResource} marker interface. This is useful for
+ * implementing pluggable look-and-feels: When switching the current
+ * LookAndFeel, only those borders are replaced that are marked as
+ * {@link UIResource}. For this reason, a look-and-feel should
+ * always install borders that implement <code>UIResource</code>,
+ * such as the borders provided by this class.
+ *
+ * @author Brian Jones (cbj@gnu.org)
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
+ public static class BevelBorderUIResource
+ extends BevelBorder
+ implements UIResource, Serializable
+ {
/**
- * Creates a <code>UIResource</code> wrapper for a <code>Border</code>
- * object.
- *
- * @param delegate the border to be wrapped
+ * Constructs a BevelBorderUIResource whose colors will be derived
+ * from the background of the enclosed component. The background
+ * color is retrieved each time the border is painted, so a border
+ * constructed by this method will automatically reflect a change
+ * to the component’s background color.
+ *
+ * <p><img src="../border/BevelBorder-1.png" width="500" height="150"
+ * alt="[An illustration showing raised and lowered BevelBorders]" />
+ *
+ * @param bevelType the desired appearance of the border. The value
+ * must be either {@link javax.swing.border.BevelBorder#RAISED}
+ * or {@link javax.swing.border.BevelBorder#LOWERED}.
+ *
+ * @throws IllegalArgumentException if <code>bevelType</code> has
+ * an unsupported value.
+ */
+ public BevelBorderUIResource(int bevelType)
+ {
+ super(bevelType);
+ }
+
+
+ /**
+ * Constructs a BevelBorderUIResource given its appearance type
+ * and two colors for its highlight and shadow.
+ *
+ * <p><img src="../border/BevelBorder-2.png" width="500" height="150"
+ * alt="[An illustration showing BevelBorders that were constructed
+ * with this method]" />
+ *
+ * @param bevelType the desired appearance of the border. The value
+ * must be either {@link javax.swing.border.BevelBorder#RAISED}
+ * or {@link javax.swing.border.BevelBorder#LOWERED}.
+ *
+ * @param highlight the color that will be used for the inner side
+ * of the highlighted edges (top and left if if
+ * <code>bevelType</code> is {@link
+ * javax.swing.border.BevelBorder#RAISED}; bottom and right
+ * otherwise). The color for the outer side is a brightened
+ * version of this color.
+ *
+ * @param shadow the color that will be used for the outer side of
+ * the shadowed edges (bottom and right if
+ * <code>bevelType</code> is {@link
+ * javax.swing.border.BevelBorder#RAISED}; top and left
+ * otherwise). The color for the inner side is a brightened
+ * version of this color.
+ *
+ * @throws IllegalArgumentException if <code>bevelType</code> has
+ * an unsupported value.
+ *
+ * @throws NullPointerException if <code>highlight</code> or
+ * <code>shadow</code> is <code>null</code>.
*/
- public BorderUIResource(Border delegate)
+ public BevelBorderUIResource(int bevelType,
+ Color highlight,
+ Color shadow)
{
- this.delegate = delegate;
+ super(bevelType, highlight, shadow);
}
+
/**
+ * Constructs a BevelBorderUIResource given its appearance type
+ * and all its colors.
+ *
+ * <p><img src="../border/BevelBorder-3.png" width="500" height="150"
+ * alt="[An illustration showing BevelBorders that were constructed
+ * with this method]" />
+ *
+ * @param bevelType the desired appearance of the border. The value
+ * must be either {@link javax.swing.border.BevelBorder#RAISED}
+ * or {@link javax.swing.border.BevelBorder#LOWERED}.
+ *
+ * @param highlightOuter the color that will be used for the outer
+ * side of the highlighted edges (top and left if
+ * <code>bevelType</code> is {@link
+ * javax.swing.border.BevelBorder#RAISED}; bottom and right
+ * otherwise).
+ *
+ * @param highlightInner the color that will be used for the inner
+ * side of the highlighted edges.
+ *
+ * @param shadowOuter the color that will be used for the outer
+ * side of the shadowed edges (bottom and right if
+ * <code>bevelType</code> is {@link
+ * javax.swing.border.BevelBorder#RAISED}; top and left
+ * otherwise).
+ *
+ * @param shadowInner the color that will be used for the inner
+ * side of the shadowed edges.
+ *
+ * @throws IllegalArgumentException if <code>bevelType</code> has
+ * an unsupported value.
+ *
+ * @throws NullPointerException if one of the passed colors
+ * is <code>null</code>.
*/
- public static Border getEtchedBorderUIResource() {
- return null;
+ public BevelBorderUIResource(int bevelType,
+ Color highlightOuter,
+ Color highlightInner,
+ Color shadowOuter,
+ Color shadowInner)
+ {
+ super(bevelType,
+ highlightOuter, highlightInner,
+ shadowOuter, shadowInner);
}
-
+ }
+
+
+ /**
+ * A {@link javax.swing.border.CompoundBorder} that also implements the
+ * {@link UIResource} marker interface. This is useful for
+ * implementing pluggable look-and-feels: When switching the current
+ * LookAndFeel, only those borders are replaced that are marked as
+ * {@link UIResource}. For this reason, a look-and-feel should
+ * always install borders that implement <code>UIResource</code>,
+ * such as the borders provided by this class.
+ *
+ * @author Brian Jones (cbj@gnu.org)
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
+ public static class CompoundBorderUIResource
+ extends CompoundBorder
+ implements UIResource, Serializable
+ {
/**
+ * Constructs a CompoundBorderUIResource with the specified inside
+ * and outside borders.
+ *
+ * @param outsideBorder the outside border, which is painted to the
+ * outside of both <code>insideBorder</code> and the enclosed
+ * component. It is acceptable to pass <code>null</code>, in
+ * which case no outside border is painted.
+ *
+ * @param insideBorder the inside border, which is painted to
+ * between <code>outsideBorder</code> and the enclosed
+ * component. It is acceptable to pass <code>null</code>, in
+ * which case no inside border is painted.
*/
- public static Border getLoweredBevelBorderUIResource() {
- return null;
+ public CompoundBorderUIResource(Border outsideBorder,
+ Border insideBorder)
+ {
+ super(outsideBorder, insideBorder);
}
-
+ }
+
+
+ /**
+ * An {@link javax.swing.border.EmptyBorder} that also implements the
+ * {@link UIResource} marker interface. This is useful for
+ * implementing pluggable look-and-feels: When switching the current
+ * LookAndFeel, only those borders are replaced that are marked as
+ * {@link UIResource}. For this reason, a look-and-feel should
+ * always install borders that implement <code>UIResource</code>,
+ * such as the borders provided by this class.
+ *
+ * <p><img src="../border/EmptyBorder-1.png" width="290" height="200"
+ * alt="[An illustration of EmptyBorder]" />
+ *
+ * @author Brian Jones (cbj@gnu.org)
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
+ public static class EmptyBorderUIResource
+ extends EmptyBorder
+ implements UIResource, Serializable
+ {
/**
+ * Constructs an empty border given the number of pixels required
+ * on each side.
+ *
+ * @param top the number of pixels that the border will need
+ * for its top edge.
+ *
+ * @param left the number of pixels that the border will need
+ * for its left edge.
+ *
+ * @param bottom the number of pixels that the border will need
+ * for its bottom edge.
+ *
+ * @param right the number of pixels that the border will need
+ * for its right edge.
*/
- public static Border getRaisedBevelBorderUIResource() {
- return null;
+ public EmptyBorderUIResource(int top, int left, int bottom, int right)
+ {
+ super(top, left, bottom, right);
}
-
+
+
/**
+ * Constructs an empty border given the number of pixels required
+ * on each side, passed in an Insets object.
+ *
+ * @param insets the Insets for the new border.
*/
- public static Border getBlackLineBorderUIResource() {
- return null;
+ public EmptyBorderUIResource(Insets insets)
+ {
+ super(insets);
}
-
+ }
+
+
+ /**
+ * An {@link javax.swing.border.EtchedBorder} that also implements the
+ * {@link UIResource} marker interface. This is useful for
+ * implementing pluggable look-and-feels: When switching the current
+ * LookAndFeel, only those borders are replaced that are marked as
+ * {@link UIResource}. For this reason, a look-and-feel should
+ * always install borders that implement <code>UIResource</code>,
+ * such as the borders provided by this class.
+ *
+ * <p><img src="../border/EtchedBorder-1.png" width="500" height="200"
+ * alt="[An illustration of the two EtchedBorder variants]" />
+ *
+ * @author Brian Jones (cbj@gnu.org)
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
+ public static class EtchedBorderUIResource
+ extends EtchedBorder
+ implements UIResource, Serializable
+ {
/**
+ * Constructs an EtchedBorderUIResource that appears lowered into
+ * the surface. The colors will be derived from the background
+ * color of the enclosed Component when the border gets painted.
*/
- public void paintBorder(Component c, Graphics g, int x, int y,
- int width, int height) { }
-
+ public EtchedBorderUIResource()
+ {
+ super();
+ }
+
+
/**
+ * Constructs an EtchedBorderUIResource with the specified
+ * appearance. The colors will be derived from the background
+ * color of the enclosed Component when the border gets painted.
+ *
+ * <p><img src="../border/EtchedBorder-1.png" width="500" height="200"
+ * alt="[An illustration of the two EtchedBorder variants]" />
+ *
+ * @param etchType the desired appearance of the border. The value
+ * must be either {@link javax.swing.border.EtchedBorder#RAISED}
+ * or {@link javax.swing.border.EtchedBorder#LOWERED}.
+ *
+ * @throws IllegalArgumentException if <code>etchType</code> has
+ * an unsupported value.
*/
- public Insets getBorderInsets(Component c) {
- return null;
+ public EtchedBorderUIResource(int etchType)
+ {
+ super(etchType);
}
-
+
+
/**
+ * Constructs a lowered EtchedBorderUIResource, explicitly
+ * selecting the colors that will be used for highlight and
+ * shadow.
+ *
+ * @param highlight the color that will be used for painting
+ * the highlight part of the border.
+ *
+ * @param shadow the color that will be used for painting
+ * the shadow part of the border.
+ *
+ * @see #EtchedBorderUIResource(int, Color, Color)
*/
- public boolean isBorderOpaque() {
- return false;
+ public EtchedBorderUIResource(Color highlight, Color shadow)
+ {
+ super(highlight, shadow);
}
-
+
+
/**
- * @serial
+ * Constructs an EtchedBorderUIResource with the specified
+ * appearance, explicitly selecting the colors that will be used
+ * for highlight and shadow.
+ *
+ * <p><img src="../border/EtchedBorder-2.png" width="500"
+ * height="200" alt="[An illustration that shows which pixels get
+ * painted in what color]" />
+ *
+ * @param etchType the desired appearance of the border. The value
+ * must be either {@link javax.swing.border.EtchedBorder#RAISED}
+ * or {@link javax.swing.border.EtchedBorder#LOWERED}.
+ *
+ * @param highlight the color that will be used for painting
+ * the highlight part of the border.
+ *
+ * @param shadow the color that will be used for painting
+ * the shadow part of the border.
+ *
+ * @throws IllegalArgumentException if <code>etchType</code> has
+ * an unsupported value.
*/
- public static class BevelBorderUIResource
- extends BevelBorder
- implements UIResource, Serializable
+ public EtchedBorderUIResource(int etchType,
+ Color highlight, Color shadow)
{
- public BevelBorderUIResource(int bevelType)
- {
- super (bevelType);
- }
-
- public BevelBorderUIResource(int bevelType,
- Color highlight,
- Color shadow)
- {
- super (bevelType, highlight, shadow);
- }
- public BevelBorderUIResource(int bevelType,
- Color highlightOuter,
- Color highlightInner,
- Color shadowOuter,
- Color shadowInner)
- {
- super (bevelType, highlightOuter, highlightInner, shadowOuter,
- shadowInner);
- }
+ super(etchType, highlight, shadow);
}
-
+ }
+
+
+ /**
+ * A {@link javax.swing.border.LineBorder} that also implements the
+ * {@link UIResource} marker interface. This is useful for
+ * implementing pluggable look-and-feels: When switching the current
+ * LookAndFeel, only those borders are replaced that are marked as
+ * {@link UIResource}. For this reason, a look-and-feel should
+ * always install borders that implement <code>UIResource</code>,
+ * such as the borders provided by this class.
+ *
+ * <p><img src="../border/LineBorder-1.png" width="500" height="200"
+ * alt="[An illustration of two LineBorders] />
+ *
+ * @author Brian Jones (cbj@gnu.org)
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
+ public static class LineBorderUIResource
+ extends LineBorder
+ implements UIResource, Serializable
+ {
/**
- * @serial
+ * Constructs a LineBorderUIResource given its color. The border
+ * will be one pixel thick and have plain corners.
+ *
+ * @param color the color for drawing the border.
*/
- public static class CompoundBorderUIResource
- extends CompoundBorder
- implements UIResource, Serializable
+ public LineBorderUIResource(Color color)
{
- public CompoundBorderUIResource(Border outsideBorder,
- Border insideBorder)
- {
- super (outsideBorder, insideBorder);
- }
+ super(color);
}
-
+
+
/**
- * @serial
+ * Constructs a LineBorder given its color and thickness. The
+ * border will have plain corners.
+ *
+ * @param color the color for drawing the border.
+ * @param thickness the width of the line in pixels.
*/
- public static class EmptyBorderUIResource
- extends EmptyBorder
- implements UIResource, Serializable
+ public LineBorderUIResource(Color color, int thickness)
{
- public EmptyBorderUIResource(int top, int left, int bottom, int right)
- {
- this(new Insets(top,left,bottom,right));
- }
-
- public EmptyBorderUIResource(Insets insets)
- {
- super (insets);
- }
+ super(color, thickness);
}
+
+
+ /* Note: Since JDK1.3, javax.swing.border.LineBorder also has a
+ * constructor which accepts a value for the roundedCorners
+ * property. However, as of JDK1.4.1, the LineBorderUIResource
+ * subclass does not have a corresponding constructor.
+ *
+ * A request for enhancing the Swing API has been filed with Sun.
+ * It currently is under review, its "review ID" is 188305.
+ *
+ * -- Sascha Brawer (brawer@dandelis.ch)
+ */
+ }
+
+ /**
+ * A {@link javax.swing.border.MatteBorder} that also implements the
+ * {@link UIResource} marker interface. This is useful for
+ * implementing pluggable look-and-feels: When switching the current
+ * LookAndFeel, only those borders are replaced that are marked as
+ * {@link UIResource}. For this reason, a look-and-feel should
+ * always install borders that implement <code>UIResource</code>,
+ * such as the borders provided by this class.
+ *
+ * <p><img src="../border/MatteBorder-1.png" width="500" height="150"
+ * alt="[An illustration of two MatteBorders] />
+ *
+ * @author Brian Jones (cbj@gnu.org)
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
+ public static class MatteBorderUIResource
+ extends MatteBorder
+ implements UIResource, Serializable
+ {
/**
- * @serial
+ * Constructs a MatteBorderUIResource given the width on each side
+ * and a fill color.
+ *
+ * <p><img src="../border/MatteBorder-2.png" width="500" height="150"
+ * alt="[A picture of a MatteBorder made by this constructor]" />
+ *
+ * @param top the width of the border at its top edge.
+ * @param left the width of the border at its left edge.
+ * @param bottom the width of the border at its bottom edge.
+ * @param right the width of the border at its right edge.
+ * @param matteColor the color for filling the border.
*/
- public static class EtchedBorderUIResource
- extends EtchedBorder
- implements UIResource, Serializable
+ public MatteBorderUIResource(int top, int left,
+ int bottom, int right,
+ Color color)
{
- public EtchedBorderUIResource() { }
- public EtchedBorderUIResource(int etchType)
- {
- super (etchType);
- }
- public EtchedBorderUIResource(Color highlight, Color shadow)
- {
- super (highlight, shadow);
- }
- public EtchedBorderUIResource(int etchType, Color highlight,
- Color shadow)
- {
- super (etchType, highlight, shadow);
- }
-
+ super(top, left, bottom, right, color);
}
-
+
+
+ /**
+ * Constructs a MatteBorderUIResource given the width on each side
+ * and an icon for tiling the border area.
+ *
+ * <p><img src="../border/MatteBorder-4.png" width="500"
+ * height="150" alt="[A picture of a MatteBorder made by this
+ * constructor]" />
+ *
+ * @param top the width of the border at its top edge.
+ * @param left the width of the border at its left edge.
+ * @param bottom the width of the border at its bottom edge.
+ * @param right the width of the border at its right edge.
+ * @param tileIcon an icon for tiling the border area.
+ */
+ public MatteBorderUIResource(int top, int left,
+ int bottom, int right,
+ Icon tileIcon)
+ {
+ super(top, left, bottom, right, tileIcon);
+ }
+
+
/**
- * @serial
+ * Constructs a MatteBorderUIResource given an icon for tiling the
+ * border area. The icon width is used for the border insets at
+ * the left and right edge, the icon height for the top and bottom
+ * edge.
+ *
+ * <p><img src="../border/MatteBorder-6.png" width="500" height="150"
+ * alt="[A picture of a MatteBorder made by this constructor]" />
+ *
+ * @param tileIcon an icon for tiling the border area.
*/
- public static class LineBorderUIResource
- extends LineBorder
- implements UIResource, Serializable
+ public MatteBorderUIResource(Icon tileIcon)
{
- public LineBorderUIResource(Color color)
- {
- super (color);
- }
- public LineBorderUIResource(Color color,
- int thickness)
- {
- super (color, thickness);
- }
+ super(tileIcon);
+ }
+ }
+
+
+ /**
+ * A {@link javax.swing.border.TitledBorder} that also implements the
+ * {@link UIResource} marker interface. This is useful for
+ * implementing pluggable look-and-feels: When switching the current
+ * LookAndFeel, only those borders are replaced that are marked as
+ * {@link UIResource}. For this reason, a look-and-feel should
+ * always install borders that implement <code>UIResource</code>,
+ * such as the borders provided by this class.
+ *
+ * @author Brian Jones (cbj@gnu.org)
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
+ public static class TitledBorderUIResource
+ extends TitledBorder
+ implements UIResource, Serializable
+ {
+ /**
+ * Constructs a TitledBorderUIResource given the text of its title.
+ *
+ * @param title the title text, or <code>null</code> to use no
+ * title text.
+ */
+ public TitledBorderUIResource(String title)
+ {
+ super(title);
+ }
+
+
+ /**
+ * Constructs an initially untitled TitledBorderUIResource
+ * given another border.
+ *
+ * @param border the border underneath the title, or
+ * <code>null</code> to use a default from
+ * the current look and feel.
+ */
+ public TitledBorderUIResource(Border border)
+ {
+ super(border);
+ }
+
+
+ /**
+ * Constructs a TitledBorder given its border and title text.
+ *
+ * @param border the border underneath the title, or
+ * <code>null</code> to use a default from
+ * the current look and feel.
+ *
+ * @param title the title text, or <code>null</code>
+ * to use no title text.
+ */
+ public TitledBorderUIResource(Border border, String title)
+ {
+ super(border, title);
}
+
/**
- * @serial
+ * Constructs a TitledBorderUIResource given its border, title
+ * text, horizontal alignment, and vertical position.
+ *
+ * @param border the border underneath the title, or
+ * <code>null</code> to use a default
+ * from the current look and feel.
+ *
+ * @param title the title text, or <code>null</code>
+ * to use no title text.
+ *
+ * @param titleJustification the horizontal alignment of the title
+ * text in relation to the border. The value must be one of
+ * {@link javax.swing.border.TitledBorder#LEFT},
+ * {@link javax.swing.border.TitledBorder#CENTER},
+ * {@link javax.swing.border.TitledBorder#RIGHT},
+ * {@link javax.swing.border.TitledBorder#LEADING},
+ * {@link javax.swing.border.TitledBorder#TRAILING}, or
+ * {@link javax.swing.border.TitledBorder#DEFAULT_JUSTIFICATION}.
+ *
+ * @param titlePosition the vertical position of the title text
+ * in relation to the border. The value must be one of
+ * {@link javax.swing.border.TitledBorder#ABOVE_TOP},
+ * {@link javax.swing.border.TitledBorder#TOP},
+ * {@link javax.swing.border.TitledBorder#BELOW_TOP},
+ * {@link javax.swing.border.TitledBorder#ABOVE_BOTTOM},
+ * {@link javax.swing.border.TitledBorder#BOTTOM},
+ * {@link javax.swing.border.TitledBorder#BELOW_BOTTOM},
+ * or {@link javax.swing.border.TitledBorder#DEFAULT_POSITION}.
+ *
+ * @throws IllegalArgumentException if <code>titleJustification</code>
+ * or <code>titlePosition</code> have an unsupported value.
*/
- public static class MatteBorderUIResource
- extends MatteBorder
- implements UIResource, Serializable
+ public TitledBorderUIResource(Border border, String title,
+ int titleJustification,
+ int titlePosition)
{
- public MatteBorderUIResource(int top, int left, int bottom,
- int right, Color color)
- {
- super (new Insets (top, left, bottom, right), color);
- }
- public MatteBorderUIResource(int top, int left, int bottom,
- int right, Icon tileIcon)
- {
- super (new Insets (top, left, bottom, right), tileIcon);
-
- }
- public MatteBorderUIResource(Icon tileIcon)
- {
- super (tileIcon);
- }
+ super(border, title, titleJustification, titlePosition);
}
+
+ /**
+ * Constructs a TitledBorder given its border, title text,
+ * horizontal alignment, vertical position, and font.
+ *
+ * @param border the border underneath the title, or
+ * <code>null</code> to use a default
+ * from the current look and feel.
+ *
+ * @param title the title text, or <code>null</code>
+ * to use no title text.
+ *
+ * @param titleJustification the horizontal alignment of the title
+ * text in relation to the border. The value must be one of
+ * {@link javax.swing.border.TitledBorder#LEFT},
+ * {@link javax.swing.border.TitledBorder#CENTER},
+ * {@link javax.swing.border.TitledBorder#RIGHT},
+ * {@link javax.swing.border.TitledBorder#LEADING},
+ * {@link javax.swing.border.TitledBorder#TRAILING}, or
+ * {@link javax.swing.border.TitledBorder#DEFAULT_JUSTIFICATION}.
+ *
+ * @param titlePosition the vertical position of the title text
+ * in relation to the border. The value must be one of
+ * {@link javax.swing.border.TitledBorder#ABOVE_TOP},
+ * {@link javax.swing.border.TitledBorder#TOP},
+ * {@link javax.swing.border.TitledBorder#BELOW_TOP},
+ * {@link javax.swing.border.TitledBorder#ABOVE_BOTTOM},
+ * {@link javax.swing.border.TitledBorder#BOTTOM},
+ * {@link javax.swing.border.TitledBorder#BELOW_BOTTOM},
+ * or {@link javax.swing.border.TitledBorder#DEFAULT_POSITION}.
+ *
+ * @param titleFont the font for the title text, or <code>null</code>
+ * to use a default from the current look and feel.
+ *
+ * @throws IllegalArgumentException if <code>titleJustification</code>
+ * or <code>titlePosition</code> have an unsupported value.
+ */
+ public TitledBorderUIResource(Border border, String title,
+ int titleJustification,
+ int titlePosition,
+ Font titleFont)
+ {
+ super(border, title, titleJustification, titlePosition,
+ titleFont);
+ }
+
+
/**
- * @serial
+ * Constructs a TitledBorder given its border, title text,
+ * horizontal alignment, vertical position, font, and color.
+ *
+ * @param border the border underneath the title, or
+ * <code>null</code> to use a default
+ * from the current look and feel.
+ *
+ * @param title the title text, or <code>null</code>
+ * to use no title text.
+ *
+ * @param titleJustification the horizontal alignment of the title
+ * text in relation to the border. The value must be one of
+ * {@link javax.swing.border.TitledBorder#LEFT},
+ * {@link javax.swing.border.TitledBorder#CENTER},
+ * {@link javax.swing.border.TitledBorder#RIGHT},
+ * {@link javax.swing.border.TitledBorder#LEADING},
+ * {@link javax.swing.border.TitledBorder#TRAILING}, or
+ * {@link javax.swing.border.TitledBorder#DEFAULT_JUSTIFICATION}.
+ *
+ * @param titlePosition the vertical position of the title text
+ * in relation to the border. The value must be one of
+ * {@link javax.swing.border.TitledBorder#ABOVE_TOP},
+ * {@link javax.swing.border.TitledBorder#TOP},
+ * {@link javax.swing.border.TitledBorder#BELOW_TOP},
+ * {@link javax.swing.border.TitledBorder#ABOVE_BOTTOM},
+ * {@link javax.swing.border.TitledBorder#BOTTOM},
+ * {@link javax.swing.border.TitledBorder#BELOW_BOTTOM},
+ * or {@link javax.swing.border.TitledBorder#DEFAULT_POSITION}.
+ *
+ * @param titleFont the font for the title text, or <code>null</code>
+ * to use a default from the current look and feel.
+ *
+ * @param titleColor the color for the title text, or <code>null</code>
+ * to use a default from the current look and feel.
+ *
+ * @throws IllegalArgumentException if <code>titleJustification</code>
+ * or <code>titlePosition</code> have an unsupported value.
*/
- public static class TitledBorderUIResource
- extends TitledBorder
- implements UIResource, Serializable
+ public TitledBorderUIResource(Border border, String title,
+ int titleJustification, int titlePosition,
+ Font titleFont, Color titleColor)
{
- TitledBorderUIResource(String title)
- {
- super (title);
- }
- TitledBorderUIResource(Border border)
- {
- super (border);
- }
- TitledBorderUIResource(Border border, String title)
- {
- super (border, title);
- }
- TitledBorderUIResource(Border border, String title,
- int titleJustification, int titlePosition)
- {
- super (border, title, titleJustification, titlePosition);
- }
- TitledBorderUIResource(Border border, String title,
- int titleJustification, int titlePosition,
- Font titleFont)
- {
- super (border, title, titleJustification, titlePosition, titleFont);
- }
- TitledBorderUIResource(Border border, String title,
- int titleJustification, int titlePosition,
- Font titleFont, Color titleColor)
- {
- super (border, title, titleJustification, titlePosition, titleFont, titleColor);
- }
+ super(border, title, titleJustification, titlePosition,
+ titleFont, titleColor);
}
+ }
}
/* BasicBorders.java
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of GNU Classpath.
package javax.swing.plaf.basic;
+
import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Insets;
+import java.io.Serializable;
+import javax.swing.AbstractButton;
+import javax.swing.ButtonModel;
+import javax.swing.JButton;
+import javax.swing.JPopupMenu;
+import javax.swing.JToolBar;
+import javax.swing.UIDefaults;
+import javax.swing.UIManager;
+import javax.swing.border.AbstractBorder;
+import javax.swing.border.Border;
+import javax.swing.plaf.UIResource;
+import javax.swing.plaf.BorderUIResource;
+
+
/**
- * STUBBED
+ * Provides various borders for the Basic look and feel.
+ *
+ * @author Sascha Brawer (brawer@dandelis.ch)
*/
public class BasicBorders
{
+ /**
+ * A MarginBorder that gets shared by multiple components.
+ * Created on demand by the private helper function {@link
+ * #getMarginBorder()}.
+ */
+ private static MarginBorder sharedMarginBorder;
+
+
+ /**
+ * Returns a border that is suitable for a button.
+ *
+ * <p>The colors of the border are retrieved from the
+ * <code>UIDefaults</code> of the currently active look and feel
+ * using the keys <code>“Button.shadow”</code>,
+ * <code>“Button.darkShadow”</code>,
+ * <code>“Button.light”</code>, and
+ * <code>“Button.highlight”</code>.
+ *
+ * <p><img src="BasicBorders.ButtonBorder-1.png" width="300"
+ * height="170" alt="[A screen shot of the returned border]" />
+ *
+ * @return a {@link
+ * javax.swing.plaf.BorderUIResource#CompoundBorderUIResource}
+ * whose outer border is a {@link #ButtonBorder} and whose
+ * inner border is a {@link #MarginBorder}.
+ */
+ public static Border getButtonBorder()
+ {
+ UIDefaults defaults;
+ Border outer;
+
+ defaults = UIManager.getLookAndFeelDefaults();
+
+ /* The keys for UIDefaults have been determined by writing a
+ * test program that dumps the UIDefaults to stdout; that program
+ * was run on a JDK 1.4.1_01 for GNU/Linux. Note that in the API,
+ * the key "light" is usually called "highlight", and "highlight"
+ * is usually called "lightHighlight".
+ */
+ outer = new ButtonBorder(defaults.getColor("Button.shadow"),
+ defaults.getColor("Button.darkShadow"),
+ defaults.getColor("Button.light"),
+ defaults.getColor("Button.highlight"));
+
+ /* While the inner border is shared between multiple buttons,
+ * we do not share the outer border because ButtonBorders store
+ * their border colors. We cannot guarantee that the colors
+ * (which come from UIDefaults) are unchanged between invocations
+ * of getButtonBorder. We could store the last colors, and share
+ * the button border if the colors are the same as in the last
+ * invocation, but it probably is not worth the effort.
+ */
+ return new BorderUIResource.CompoundBorderUIResource(
+ outer,
+ /* inner */ getMarginBorder());
+ }
+
+
+ /**
+ * Returns a shared MarginBorder.
+ */
+ static Border getMarginBorder() // intentionally not public
+ {
+ /* Swing is not designed to be thread-safe, so there is no
+ * need to synchronize the access to the global variable.
+ */
+ if (sharedMarginBorder == null)
+ sharedMarginBorder = new MarginBorder();
+
+ return sharedMarginBorder;
+ }
+
+
+ /**
+ * A border whose appearance depends on the state of
+ * the enclosed button.
+ *
+ * <p><img src="BasicBorders.ButtonBorder-1.png" width="300"
+ * height="170" alt="[A screen shot of this border]" />
+ *
+ * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel
+ *
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
public static class ButtonBorder
+ extends AbstractBorder
+ implements Serializable, UIResource
{
- } // class ButtonBorder
+ /**
+ * Determined using the <code>serialver</code> tool
+ * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5.
+ */
+ static final long serialVersionUID = -157053874580739687L;
+
+
+ /**
+ * The color for drawing the shaded parts of the border.
+ * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel
+ */
+ protected Color shadow;
+
+
+ /**
+ * The color for drawing the dark shaded parts of the border.
+ * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel
+ */
+ protected Color darkShadow;
+
+
+ /**
+ * The color for drawing the highlighted parts of the border.
+ * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel
+ */
+ protected Color highlight;
+
+
+ /**
+ * The color for drawing the bright highlighted parts of the border.
+ * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel
+ */
+ protected Color lightHighlight;
+
+
+ /**
+ * Constructs a new border for drawing a button in the Basic
+ * look and feel.
+ *
+ * @param shadow the shadow color.
+ * @param darkShadow a darker variant of the shadow color.
+ * @param highlight the highlight color.
+ * @param lightHighlight a brighter variant of the highlight color.
+ */
+ public ButtonBorder(Color shadow, Color darkShadow,
+ Color highlight, Color lightHighlight)
+ {
+ /* These colors usually come from the UIDefaults of the current
+ * look and feel. Use fallback values if the colors are not
+ * supplied. The API specification is silent about what
+ * behavior is expected for null colors, so users should not
+ * rely on this fallback (which is why it is not documented in
+ * the above Javadoc).
+ */
+ this.shadow = (shadow != null) ? shadow : Color.gray;
+ this.darkShadow = (darkShadow != null) ? darkShadow : Color.black;
+ this.highlight = (highlight != null) ? highlight : Color.lightGray;
+ this.lightHighlight = (lightHighlight != null)
+ ? lightHighlight
+ : Color.white;
+ }
+
+
+ /**
+ * Paints the ButtonBorder around a given component.
+ *
+ * @param c the component whose border is to be painted.
+ * @param g the graphics for painting.
+ * @param x the horizontal position for painting the border.
+ * @param y the vertical position for painting the border.
+ * @param width the width of the available area for painting the border.
+ * @param height the height of the available area for painting the border.
+ *
+ * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel
+ */
+ public void paintBorder(Component c, Graphics g,
+ int x, int y, int width, int height)
+ {
+ ButtonModel bmodel = null;
+
+ if (c instanceof AbstractButton)
+ bmodel = ((AbstractButton) c).getModel();
+
+ BasicGraphicsUtils.drawBezel(
+ g, x, y, width, height,
+ /* pressed */ (bmodel != null)
+ && /* mouse button pressed */ bmodel.isPressed()
+ && /* mouse inside */ bmodel.isArmed(),
+ /* default */ (c instanceof JButton)
+ && ((JButton) c).isDefaultButton(),
+ shadow, darkShadow, highlight, lightHighlight);
+ }
+
+
+ /**
+ * Measures the width of this border.
+ *
+ * <p>Although the thickness of the actually painted border
+ * depends on the state of the enclosed component, this
+ * measurement always returns the same amount of pixels. Indeed,
+ * it would be rather confusing if a button was appearing to
+ * change its size depending on whether it is pressed or not.
+ *
+ * @param c the component whose border is to be measured.
+ *
+ * @return an Insets object whose <code>left</code>,
+ * <code>right</code>, <code>top</code> and
+ * <code>bottom</code> fields indicate the width of the
+ * border at the respective edge.
+ *
+ * @see #getBorderInsets(java.awt.Component, java.awt.Insets)
+ */
+ public Insets getBorderInsets(Component c)
+ {
+ /* There is no obvious reason for overriding this method, but we
+ * try to have exactly the same API as the Sun reference
+ * implementation.
+ */
+ return getBorderInsets(c, null);
+ }
+
+
+ /**
+ * Measures the width of this border, storing the results into a
+ * pre-existing Insets object.
+ *
+ * <p>Although the thickness of the actually painted border
+ * depends on the state of the enclosed component, this
+ * measurement always returns the same amount of pixels. Indeed,
+ * it would be rather confusing if a button was appearing to
+ * change its size depending on whether it is pressed or not.
+ *
+ * @param insets an Insets object for holding the result values.
+ * After invoking this method, the <code>left</code>,
+ * <code>right</code>, <code>top</code> and
+ * <code>bottom</code> fields indicate the width of the
+ * border at the respective edge.
+ *
+ * @return the same object that was passed for <code>insets</code>.
+ *
+ * @see #getBorderInsets()
+ */
+ public Insets getBorderInsets(Component c, Insets insets)
+ {
+ /* The exact amount has been determined using a test program
+ * that was run on the Sun reference implementation. With
+ * Apple/Sun JDK 1.3.1 on MacOS X 10.1.5, the result is
+ * [3, 3, 3, 3]. With Sun JDK 1.4.1_01 on Linux/x86, the
+ * result is [2, 3, 3, 3]. We use the values from the 1.4.1_01
+ * release.
+ */
+ if (insets == null)
+ return new Insets(2, 3, 3, 3);
+
+ insets.top = 2;
+ insets.bottom = insets.left = insets.right = 3;
+ return insets;
+ }
+ }
+
+
public static class FieldBorder
{
public FieldBorder(Color shadow, Color darkShadow,
{
}
} // class FieldBorder
+
+
+ /**
+ * An invisible, but spacing border whose margin is determined
+ * by calling the <code>getMargin()</code> method of the enclosed
+ * component. If the enclosed component has no such method,
+ * this border will not occupy any space.
+ *
+ * <p><img src="BasicBorders.MarginBorder-1.png" width="325"
+ * height="200" alt="[An illustration that shows how MarginBorder
+ * determines its borders]" />
+ *
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
public static class MarginBorder
+ extends AbstractBorder
+ implements Serializable, UIResource
{
- } // class MarginBorder
+ /**
+ * Determined using the <code>serialver</code> tool
+ * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5.
+ */
+ static final long serialVersionUID = -3035848353448896090L;
+
+
+ /**
+ * Constructs a new MarginBorder.
+ */
+ public MarginBorder()
+ {
+ }
+
+
+ /**
+ * Measures the width of this border.
+ *
+ * @param c the component whose border is to be measured.
+ *
+ * @return an Insets object whose <code>left</code>, <code>right</code>,
+ * <code>top</code> and <code>bottom</code> fields indicate the
+ * width of the border at the respective edge.
+ *
+ * @see #getBorderInsets(java.awt.Component, java.awt.Insets)
+ */
+ public Insets getBorderInsets(Component c)
+ {
+ return getBorderInsets(c, new Insets(0, 0, 0, 0));
+ }
+
+
+ /**
+ * Determines the insets of this border by calling the
+ * <code>getMargin()</code> method of the enclosed component. The
+ * resulting margin will be stored into the the <code>left</code>,
+ * <code>right</code>, <code>top</code> and <code>bottom</code>
+ * fields of the passed <code>insets</code> parameter.
+ *
+ * <p>Unfortunately, <code>getMargin()</code> is not a method of
+ * {@link javax.swing.JComponent} or some other common superclass
+ * of things with margins. While reflection could be used to
+ * determine the existence of this method, this would be slow on
+ * many virtual machines. Therefore, the current implementation
+ * knows about {@link javax.swing.AbstractButton#getMargin()},
+ * {@link javax.swing.JPopupMenu#getMargin()}, and {@link
+ * javax.swing.JToolBar#getMargin()}. If <code>c</code> is an
+ * instance of a known class, the respective
+ * <code>getMargin()</code> method is called to determine the
+ * correct margin. Otherwise, a zero-width margin is returned.
+ *
+ * @param c the component whose border is to be measured.
+ *
+ * @return the same object that was passed for <code>insets</code>,
+ * but with changed fields.
+ */
+ public Insets getBorderInsets(Component c, Insets insets)
+ {
+ Insets margin = null;
+
+ /* This is terrible object-oriented design. See the above Javadoc
+ * for an excuse.
+ */
+ if (c instanceof AbstractButton)
+ margin = ((AbstractButton) c).getMargin();
+ else if (c instanceof JPopupMenu)
+ margin = ((JPopupMenu) c).getMargin();
+ else if (c instanceof JToolBar)
+ margin = ((JToolBar) c).getMargin();
+
+ if (margin == null)
+ insets.top = insets.left = insets.bottom = insets.right = 0;
+ else
+ {
+ insets.top = margin.top;
+ insets.left = margin.left;
+ insets.bottom = margin.bottom;
+ insets.right = margin.right;
+ }
+
+ return insets;
+ }
+ }
+
+
public static class MenuBarBorder
{
public MenuBarBorder(Color shadow, Color highlight)
public Dimension getPreferredSize(JComponent c)
{
AbstractButton b = (AbstractButton)c;
- Dimension d = BasicGraphicsUtils.getPreferredSize(b,
- gap,
- b.getText(),
- b.getIcon(),
- b.getVerticalAlignment(),
- b.getHorizontalAlignment(),
- b.getHorizontalTextPosition(),
- b.getVerticalTextPosition());
+ Dimension d = BasicGraphicsUtils.getPreferredButtonSize(b, gap);
// System.out.println("^^^^^^^^^^^^^^^^^^^^^^ BASIC-PREF="+d + ",T="+b.text);
return d;
}
g.setFont(f);
- FontMetrics fm = SwingUtilities.getFontMetrics(f);
+ FontMetrics fm = g.getFontMetrics(f);
Insets i = c.getInsets();
g.setFont(f);
- FontMetrics fm = SwingUtilities.getFontMetrics(f);
+ FontMetrics fm = g.getFontMetrics(f);
g.setColor(c.isEnabled() ? textColor : disabledTextColor);
public Dimension getPreferredSize(JComponent c)
{
AbstractButton b = (AbstractButton)c;
- Dimension d = BasicGraphicsUtils.getPreferredSize(b,
- gap,
- b.getText(),
- b.getIcon(),
- b.getVerticalAlignment(),
- b.getHorizontalAlignment(),
- b.getHorizontalTextPosition(),
- b.getVerticalTextPosition());
-
+ Dimension d = BasicGraphicsUtils.getPreferredButtonSize(b, gap);
//System.out.println("^^^^^^^^^^^^^^^^^^^^^^ BASIC-PREF="+d + ",T="+b.text);
return d;
}
/* BasicGraphicsUtils.java
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of GNU Classpath.
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
-
package javax.swing.plaf.basic;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Insets;
+import java.awt.Rectangle;
+
+import java.awt.font.FontRenderContext;
+import java.awt.font.LineMetrics;
+import java.awt.font.TextLayout;
-import java.awt.*;
-import javax.swing.*;
+import java.awt.geom.Rectangle2D;
+import javax.swing.AbstractButton;
+import javax.swing.SwingUtilities;
+
+/**
+ * A utility class providing commonly used drawing and measurement
+ * routines.
+ *
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
public class BasicGraphicsUtils
-{
- public static Dimension getPreferredSize(JComponent b,
- int gap,
- String text,
- Icon icon,
- int va,
- int ha,
- int htp,
- int vtp)
+{
+ /**
+ * Constructor. It is utterly unclear why this class should
+ * be constructable, but this is what the API specification
+ * says.
+ */
+ public BasicGraphicsUtils()
+ {
+ }
+
+
+ /**
+ * Draws a rectangle that appears etched into the surface, given
+ * four colors that are used for drawing.
+ *
+ * <p><img src="BasicGraphicsUtils-1.png" width="360"
+ * height="200" alt="[An illustration that shows which pixels
+ * get painted in what color]" />
+ *
+ * @param g the graphics into which the rectangle is drawn.
+ * @param x the x coordinate of the rectangle.
+ * @param y the y coordinate of the rectangle.
+ * @param width the width of the rectangle in pixels.
+ * @param height the height of the rectangle in pixels.
+ *
+ * @param shadow the color that will be used for painting
+ * the outer side of the top and left edges.
+ *
+ * @param darkShadow the color that will be used for painting
+ * the inner side of the top and left edges.
+ *
+ * @param highlight the color that will be used for painting
+ * the inner side of the bottom and right edges.
+ *
+ * @param lightHighlight the color that will be used for painting
+ * the outer side of the bottom and right edges.
+ *
+ * @see #getEtchedInsets()
+ * @see javax.swing.border.EtchedBorder
+ */
+ public static void drawEtchedRect(Graphics g,
+ int x, int y, int width, int height,
+ Color shadow, Color darkShadow,
+ Color highlight, Color lightHighlight)
+ {
+ Color oldColor;
+ int x2, y2;
+
+ oldColor = g.getColor();
+ x2 = x + width - 1;
+ y2 = y + height - 1;
+
+ try
{
- JComponent c = b;
- // this is a staight copy from BasicButtonUI.paint()
- //
- Rectangle tr = new Rectangle();
- Rectangle ir = new Rectangle();
- Rectangle vr = new Rectangle();
-
- Font f = c.getFont();
-
- FontMetrics fm = SwingUtilities.getFontMetrics(f);
-
- Insets i = c.getInsets();
-
- vr.x = i.left;
- vr.y = i.top;
- vr.width = b.getWidth() - (i.right + i.left);
- vr.height = b.getHeight() - (i.bottom + i.top);
-
- // System.out.println(" VIEW-RECT-BUTTON="+vr+", insets="+i);
-
- String tt = SwingUtilities.layoutCompoundLabel(b,
- fm,
- text,
- icon,
- va,
- ha,
- vtp,
- htp,
- vr,
- ir,
- tr,
- gap);
-
- Rectangle r = ir.union(tr);
-
- Insets insets = b.getInsets();
- r.width += insets.left + insets.right;
- r.height += insets.top + insets.bottom;
-
- // System.out.println("COMPUTED SIZE FOR PREF_SIZE="+r);
-
- return r.getSize();
+ /* To understand this code, it might be helpful to look at the
+ * image "BasicGraphicsUtils-1.png" that is included with the
+ * JavaDoc. The file is located in the "doc-files" subdirectory.
+ *
+ * (x2, y2) is the coordinate of the most right and bottom pixel
+ * to be painted.
+ */
+ g.setColor(shadow);
+ g.drawLine(x, y, x2 - 1, y); // top, outer
+ g.drawLine(x, y + 1, x, y2 - 1); // left, outer
+
+ g.setColor(darkShadow);
+ g.drawLine(x + 1, y + 1, x2 - 2, y + 1); // top, inner
+ g.drawLine(x + 1, y + 2, x + 1, y2 - 2); // left, inner
+
+ g.setColor(highlight);
+ g.drawLine(x + 1, y2 - 1, x2 - 1, y2 - 1); // bottom, inner
+ g.drawLine(x2 - 1, y + 1, x2 - 1, y2 - 2); // right, inner
+
+ g.setColor(lightHighlight);
+ g.drawLine(x, y2, x2, y2); // bottom, outer
+ g.drawLine(x2, y, x2, y2 - 1); // right, outer
+ }
+ finally
+ {
+ g.setColor(oldColor);
}
+ }
+
+
+ /**
+ * Determines the width of the border that gets painted by
+ * {@link #drawEtchedRect}.
+ *
+ * @return an <code>Insets</code> object whose <code>top</code>,
+ * <code>left</code>, <code>bottom</code> and
+ * <code>right</code> field contain the border width at the
+ * respective edge in pixels.
+ */
+ public static Insets getEtchedInsets()
+ {
+ return new Insets(2, 2, 2, 2);
+ }
+
+
+ /**
+ * Draws a rectangle that appears etched into the surface, given
+ * two colors that are used for drawing.
+ *
+ * <p><img src="BasicGraphicsUtils-2.png" width="360"
+ * height="200" alt="[An illustration that shows which pixels
+ * get painted in what color]" />
+ *
+ * @param g the graphics into which the rectangle is drawn.
+ * @param x the x coordinate of the rectangle.
+ * @param y the y coordinate of the rectangle.
+ * @param width the width of the rectangle in pixels.
+ * @param height the height of the rectangle in pixels.
+ *
+ * @param shadow the color that will be used for painting the outer
+ * side of the top and left edges, and for the inner side of
+ * the bottom and right ones.
+ *
+ * @param highlight the color that will be used for painting the
+ * inner side of the top and left edges, and for the outer
+ * side of the bottom and right ones.
+ *
+ * @see #getGrooveInsets()
+ * @see javax.swing.border.EtchedBorder
+ */
+ public static void drawGroove(Graphics g,
+ int x, int y, int width, int height,
+ Color shadow, Color highlight)
+ {
+ /* To understand this, it might be helpful to look at the image
+ * "BasicGraphicsUtils-2.png" that is included with the JavaDoc,
+ * and to compare it with "BasicGraphicsUtils-1.png" which shows
+ * the pixels painted by drawEtchedRect. These image files are
+ * located in the "doc-files" subdirectory.
+ */
+ drawEtchedRect(g, x, y, width, height,
+ /* outer topLeft */ shadow,
+ /* inner topLeft */ highlight,
+ /* inner bottomRight */ shadow,
+ /* outer bottomRight */ highlight);
+ }
+
- public static void drawString(Graphics g,
- String text,
- int underlinedChar,
- int x,
- int y)
+ /**
+ * Determines the width of the border that gets painted by
+ * {@link #drawGroove}.
+ *
+ * @return an <code>Insets</code> object whose <code>top</code>,
+ * <code>left</code>, <code>bottom</code> and
+ * <code>right</code> field contain the border width at the
+ * respective edge in pixels.
+ */
+ public static Insets getGrooveInsets()
+ {
+ return new Insets(2, 2, 2, 2);
+ }
+
+
+ /**
+ * Draws a border that is suitable for buttons of the Basic look and
+ * feel.
+ *
+ * <p><img src="BasicGraphicsUtils-3.png" width="500"
+ * height="300" alt="[An illustration that shows which pixels
+ * get painted in what color]" />
+ *
+ * @param g the graphics into which the rectangle is drawn.
+ * @param x the x coordinate of the rectangle.
+ * @param y the y coordinate of the rectangle.
+ * @param width the width of the rectangle in pixels.
+ * @param height the height of the rectangle in pixels.
+ *
+ * @param isPressed <code>true</code> to draw the button border
+ * with a pressed-in appearance; <code>false</code> for
+ * normal (unpressed) appearance.
+ *
+ * @param isDefault <code>true</code> to draw the border with
+ * the appearance it has when hitting the enter key in a
+ * dialog will simulate a click to this button;
+ * <code>false</code> for normal appearance.
+ *
+ * @param shadow the shadow color.
+ * @param darkShadow a darker variant of the shadow color.
+ * @param highlight the highlight color.
+ * @param lightHighlight a brighter variant of the highlight color.
+ */
+ public static void drawBezel(Graphics g,
+ int x, int y, int width, int height,
+ boolean isPressed, boolean isDefault,
+ Color shadow, Color darkShadow,
+ Color highlight, Color lightHighlight)
+ {
+ Color oldColor = g.getColor();
+
+ /* To understand this, it might be helpful to look at the image
+ * "BasicGraphicsUtils-3.png" that is included with the JavaDoc,
+ * and to compare it with "BasicGraphicsUtils-1.png" which shows
+ * the pixels painted by drawEtchedRect. These image files are
+ * located in the "doc-files" subdirectory.
+ */
+ try
{
- g.drawString(text, x, y);
+ if ((isPressed == false) && (isDefault == false))
+ {
+ drawEtchedRect(g, x, y, width, height,
+ lightHighlight, highlight,
+ shadow, darkShadow);
+ }
+
+ if ((isPressed == true) && (isDefault == false))
+ {
+ g.setColor(shadow);
+ g.drawRect(x + 1, y + 1, width - 2, height - 2);
+ }
+
+ if ((isPressed == false) && (isDefault == true))
+ {
+ g.setColor(darkShadow);
+ g.drawRect(x, y, width - 1, height - 1);
+ drawEtchedRect(g, x + 1, y + 1, width - 2, height - 2,
+ lightHighlight, highlight,
+ shadow, darkShadow);
+ }
+
+ if ((isPressed == true) && (isDefault == true))
+ {
+ g.setColor(darkShadow);
+ g.drawRect(x, y, width - 1, height - 1);
+ g.setColor(shadow);
+ g.drawRect(x + 1, y + 1, width - 3, height - 3);
+ }
}
-}
+ finally
+ {
+ g.setColor(oldColor);
+ }
+ }
+
+
+ /**
+ * Draws a rectangle that appears lowered into the surface, given
+ * four colors that are used for drawing.
+ *
+ * <p><img src="BasicGraphicsUtils-4.png" width="360"
+ * height="200" alt="[An illustration that shows which pixels
+ * get painted in what color]" />
+ *
+ * <p><strong>Compatibility with the Sun reference
+ * implementation:</strong> The Sun reference implementation seems
+ * to ignore the <code>x</code> and <code>y</code> arguments, at
+ * least in JDK 1.3.1 and 1.4.1_01. The method always draws the
+ * rectangular area at location (0, 0). A bug report has been filed
+ * with Sun; its “bug ID” is 4880003. The GNU Classpath
+ * implementation behaves correctly, thus not replicating this bug.
+ *
+ * @param g the graphics into which the rectangle is drawn.
+ * @param x the x coordinate of the rectangle.
+ * @param y the y coordinate of the rectangle.
+ * @param width the width of the rectangle in pixels.
+ * @param height the height of the rectangle in pixels.
+ *
+ * @param shadow the color that will be used for painting
+ * the inner side of the top and left edges.
+ *
+ * @param darkShadow the color that will be used for painting
+ * the outer side of the top and left edges.
+ *
+ * @param highlight the color that will be used for painting
+ * the inner side of the bottom and right edges.
+ *
+ * @param lightHighlight the color that will be used for painting
+ * the outer side of the bottom and right edges.
+ */
+ public static void drawLoweredBezel(Graphics g,
+ int x, int y, int width, int height,
+ Color shadow, Color darkShadow,
+ Color highlight, Color lightHighlight)
+ {
+ /* Like drawEtchedRect, but swapping darkShadow and shadow.
+ *
+ * To understand this, it might be helpful to look at the image
+ * "BasicGraphicsUtils-4.png" that is included with the JavaDoc,
+ * and to compare it with "BasicGraphicsUtils-1.png" which shows
+ * the pixels painted by drawEtchedRect. These image files are
+ * located in the "doc-files" subdirectory.
+ */
+ drawEtchedRect(g, x, y, width, height,
+ darkShadow, shadow,
+ highlight, lightHighlight);
+ }
+
+
+ /**
+ * Draws a String at the given location, underlining the first
+ * occurence of a specified character. The algorithm for determining
+ * the underlined position is not sensitive to case. If the
+ * character is not part of <code>text</code>, the text will be
+ * drawn without underlining. Drawing is performed in the current
+ * color and font of <code>g</code>.
+ *
+ * <p><img src="BasicGraphicsUtils-5.png" width="500"
+ * height="100" alt="[An illustration showing how to use the
+ * method]" />
+ *
+ * @param g the graphics into which the String is drawn.
+ *
+ * @param text the String to draw.
+ *
+ * @param underlinedChar the character whose first occurence in
+ * <code>text</code> will be underlined. It is not clear
+ * why the API specification declares this argument to be
+ * of type <code>int</code> instead of <code>char</code>.
+ * While this would allow to pass Unicode characters outside
+ * Basic Multilingual Plane 0 (U+0000 .. U+FFFE), at least
+ * the GNU Classpath implementation does not underline
+ * anything if <code>underlinedChar</code> is outside
+ * the range of <code>char</code>.
+ *
+ * @param x the x coordinate of the text, as it would be passed to
+ * {@link java.awt.Graphics#drawString(java.lang.String,
+ * int, int)}.
+ *
+ * @param y the y coordinate of the text, as it would be passed to
+ * {@link java.awt.Graphics#drawString(java.lang.String,
+ * int, int)}.
+ */
+ public static void drawString(Graphics g, String text,
+ int underlinedChar, int x, int y)
+ {
+ int index = -1;
+
+ /* It is intentional that lower case is used. In some languages,
+ * the set of lowercase characters is larger than the set of
+ * uppercase ones. Therefore, it is good practice to use lowercase
+ * for such comparisons (which really means that the author of this
+ * code can vaguely remember having read some Unicode techreport
+ * with this recommendation, but is too lazy to look for the URL).
+ */
+ if ((underlinedChar >= 0) || (underlinedChar <= 0xffff))
+ index = text.toLowerCase().indexOf(
+ Character.toLowerCase((char) underlinedChar));
+
+ drawStringUnderlineCharAt(g, text, index, x, y);
+ }
+ /**
+ * Draws a String at the given location, underlining the character
+ * at the specified index. Drawing is performed in the current color
+ * and font of <code>g</code>.
+ *
+ * <p><img src="BasicGraphicsUtils-5.png" width="500"
+ * height="100" alt="[An illustration showing how to use the
+ * method]" />
+ *
+ * @param g the graphics into which the String is drawn.
+ *
+ * @param text the String to draw.
+ *
+ * @param underlinedIndex the index of the underlined character in
+ * <code>text</code>. If <code>underlinedIndex</code> falls
+ * outside the range <code>[0, text.length() - 1]</code>, the
+ * text will be drawn without underlining anything.
+ *
+ * @param x the x coordinate of the text, as it would be passed to
+ * {@link java.awt.Graphics#drawString(java.lang.String,
+ * int, int)}.
+ *
+ * @param y the y coordinate of the text, as it would be passed to
+ * {@link java.awt.Graphics#drawString(java.lang.String,
+ * int, int)}.
+ *
+ * @since 1.4
+ */
+ public static void drawStringUnderlineCharAt(Graphics g, String text,
+ int underlinedIndex,
+ int x, int y)
+ {
+ Graphics2D g2;
+ Rectangle2D.Double underline;
+ FontRenderContext frc;
+ FontMetrics fmet;
+ LineMetrics lineMetrics;
+ Font font;
+ TextLayout layout;
+ double underlineX1, underlineX2;
+ boolean drawUnderline;
+ int textLength;
+ textLength = text.length();
+ if (textLength == 0)
+ return;
+ drawUnderline = (underlinedIndex >= 0) && (underlinedIndex < textLength);
+ if (!(g instanceof Graphics2D))
+ {
+ /* Fall-back. This is likely to produce garbage for any text
+ * containing right-to-left (Hebrew or Arabic) characters, even
+ * if the underlined character is left-to-right.
+ */
+ g.drawString(text, x, y);
+ if (drawUnderline)
+ {
+ fmet = g.getFontMetrics();
+ g.fillRect(
+ /* x */ x + fmet.stringWidth(text.substring(0, underlinedIndex)),
+ /* y */ y + fmet.getDescent() - 1,
+ /* width */ fmet.charWidth(text.charAt(underlinedIndex)),
+ /* height */ 1);
+ }
+
+ return;
+ }
+ g2 = (Graphics2D) g;
+ font = g2.getFont();
+ frc = g2.getFontRenderContext();
+ lineMetrics = font.getLineMetrics(text, frc);
+ layout = new TextLayout(text, font, frc);
+
+ /* Draw the text. */
+ layout.draw(g2, x, y);
+ if (!drawUnderline)
+ return;
+
+ underlineX1 = x + layout.getLogicalHighlightShape(
+ underlinedIndex, underlinedIndex).getBounds2D().getX();
+ underlineX2 = x + layout.getLogicalHighlightShape(
+ underlinedIndex + 1, underlinedIndex + 1).getBounds2D().getX();
+
+ underline = new Rectangle2D.Double();
+ if (underlineX1 < underlineX2)
+ {
+ underline.x = underlineX1;
+ underline.width = underlineX2 - underlineX1;
+ }
+ else
+ {
+ underline.x = underlineX2;
+ underline.width = underlineX1 - underlineX2;
+ }
+
+
+ underline.height = lineMetrics.getUnderlineThickness();
+ underline.y = lineMetrics.getUnderlineOffset();
+ if (underline.y == 0)
+ {
+ /* Some fonts do not specify an underline offset, although they
+ * actually should do so. In that case, the result of calling
+ * lineMetrics.getUnderlineOffset() will be zero. Since it would
+ * look very ugly if the underline was be positioned immediately
+ * below the baseline, we check for this and move the underline
+ * below the descent, as shown in the following ASCII picture:
+ *
+ * ##### ##### #
+ * # # # #
+ * # # # #
+ * # # # #
+ * ##### ###### ---- baseline (0)
+ * #
+ * #
+ * ------------------###----------- lineMetrics.getDescent()
+ */
+ underline.y = lineMetrics.getDescent();
+ }
+
+ underline.y += y;
+ g2.fill(underline);
+ }
+
+
+ /**
+ * Draws a rectangle, simulating a dotted stroke by painting only
+ * every second pixel along the one-pixel thick edge. The color of
+ * those pixels is the current color of the Graphics <code>g</code>.
+ * Any other pixels are left unchanged.
+ *
+ * <p><img src="BasicGraphicsUtils-7.png" width="360"
+ * height="200" alt="[An illustration that shows which pixels
+ * get painted]" />
+ *
+ * @param g the graphics into which the rectangle is drawn.
+ * @param x the x coordinate of the rectangle.
+ * @param y the y coordinate of the rectangle.
+ * @param width the width of the rectangle in pixels.
+ * @param height the height of the rectangle in pixels.
+ */
+ public static void drawDashedRect(Graphics g,
+ int x, int y, int width, int height)
+ {
+ int right = x + width - 1;
+ int bottom = y + height - 1;
+
+ /* Draw the top and bottom edge of the dotted rectangle. */
+ for (int i = x; i <= right; i += 2)
+ {
+ g.drawLine(i, y, i, y);
+ g.drawLine(i, bottom, i, bottom);
+ }
+
+ /* Draw the left and right edge of the dotted rectangle. */
+ for (int i = y; i <= bottom; i += 2)
+ {
+ g.drawLine(x, i, x, i);
+ g.drawLine(right, i, right, i);
+ }
+ }
+
+
+ /**
+ * Determines the preferred width and height of an AbstractButton,
+ * given the gap between the button’s text and icon.
+ *
+ * @param b the button whose preferred size is determined.
+ *
+ * @param textIconGap the gap between the button’s text and
+ * icon.
+ *
+ * @return a <code>Dimension</code> object whose <code>width</code>
+ * and <code>height</code> fields indicate the preferred
+ * extent in pixels.
+ *
+ * @see javax.swing.SwingUtilities#layoutCompoundLabel
+ */
+ public static Dimension getPreferredButtonSize(AbstractButton b,
+ int textIconGap)
+ {
+ Rectangle contentRect;
+ Rectangle viewRect;
+ Rectangle iconRect = new Rectangle();
+ Rectangle textRect = new Rectangle();
+ Insets insets = b.getInsets();
+
+ /* For determining the ideal size, do not assume a size restriction. */
+ viewRect = new Rectangle(0, 0,
+ /* width */ Integer.MAX_VALUE,
+ /* height */ Integer.MAX_VALUE);
+
+ /* java.awt.Toolkit.getFontMetrics is deprecated. However, it
+ * seems not obvious how to get to the correct FontMetrics object
+ * otherwise. The real problem probably is that the method
+ * javax.swing.SwingUtilities.layoutCompundLabel should take a
+ * LineMetrics, not a FontMetrics argument. But fixing this that
+ * would change the public API.
+ */
+ SwingUtilities.layoutCompoundLabel(
+ b, // for the component orientation
+ b.getToolkit().getFontMetrics(b.getFont()), // see comment above
+ b.getText(),
+ b.getIcon(),
+ b.getVerticalAlignment(),
+ b.getHorizontalAlignment(),
+ b.getVerticalTextPosition(),
+ b.getHorizontalTextPosition(),
+ viewRect, iconRect, textRect,
+ textIconGap);
+
+
+ /* +------------------------+ +------------------------+
+ * | | | |
+ * | ICON | | CONTENTCONTENTCONTENT |
+ * | TEXTTEXTTEXT | --> | CONTENTCONTENTCONTENT |
+ * | TEXTTEXTTEXT | | CONTENTCONTENTCONTENT |
+ * +------------------------+ +------------------------+
+ */
+ contentRect = textRect.union(iconRect);
+
+ return new Dimension(insets.left + contentRect.width + insets.right,
+ insets.top + contentRect.height + insets.bottom);
+ }
+}
public Dimension getPreferredSize(JComponent c)
{
JLabel b = (JLabel)c;
+ /*
+ We cannot use this method because it is not part of the
+ official Swing API.
+
Dimension d = BasicGraphicsUtils.getPreferredSize(b,
gap,
b.getText(),
b.getHorizontalTextPosition(),
b.getVerticalTextPosition());
System.out.println("JLABEL->^^^^^^^^^^^^^^^^^^^^^^ BASIC-PREF="+d + ",T="+b.getText());
- return d;
+ */
+ return new Dimension(100, 30);
}
g.setFont(f);
- FontMetrics fm = SwingUtilities.getFontMetrics(f);
+ FontMetrics fm = g.getFontMetrics(f);
Insets i = c.getInsets();
public Dimension getPreferredSize(JComponent c)
{
AbstractButton b = (AbstractButton)c;
- Dimension d = BasicGraphicsUtils.getPreferredSize(b,
- gap,
- b.getText(),
- b.getIcon(),
- b.getVerticalAlignment(),
- b.getHorizontalAlignment(),
- b.getHorizontalTextPosition(),
- b.getVerticalTextPosition());
+ Dimension d = BasicGraphicsUtils.getPreferredButtonSize(b, gap);
// and add a little something for the circles:
public Dimension getPreferredSize(JComponent c)
{
AbstractButton b = (AbstractButton)c;
- Dimension d = BasicGraphicsUtils.getPreferredSize(b,
- gap,
- b.getText(),
- b.getIcon(),
- b.getVerticalAlignment(),
- b.getHorizontalAlignment(),
- b.getHorizontalTextPosition(),
- b.getVerticalTextPosition());
+ Dimension d = BasicGraphicsUtils.getPreferredButtonSize(b, gap);
//System.out.println("^^^^^^^^^^^^^^^^^^^^^^ BASIC-PREF="+d + ",T="+b.text);
return d;