/**** FlexLabel.java ****/
/*********************************************************************
* Copyright (c) 1991 - 1998 Jerry Smith.
*
* This software is provided for demonstration purposes only. As
* freely-distributed, modifiable source code, this software carries
* absolutely no warranty. Jerry Smith disclaims all warranties for
* this software, including any implied warranties of merchantability
* and fitness, and shall not be liable for damages of any type
* resulting from its use.
* Permission to use, copy, modify, and distribute this source code
* for any purpose and without fee is hereby granted, provided that
* the above copyright and this permission notice appear in all
* copies and supporting documentation, and provided that Jerry Smith
* not be named in advertising or publicity pertaining to the
* redistribution of this software without specific, written prior
* permission.
*********************************************************************/
/*********************************************************************
FlexLabel is a flexible alternative to AWT's Label object. It
supports string labels, image labels, or both. FlexLabel recognizes
either a newline character ('\n') or the embedded character sequence
"
" as a line separator in the label. The latter is necessary for
a JavaBeans environment that allows textfield-based editing of
properties such as the label value.
Currently, FlexLabel provides no special event-handling beyond that
of its superclass Canvas.
*********************************************************************/
package flexlabel;
import java.awt.*;
import java.awt.image.*;
import java.util.*;
public class FlexLabel extends Canvas implements ImageObserver,
Runnable, java.io.Serializable {
//
// Constants (configuration):
//
public static final int ALIGN_LEFT = -1; // the default
public static final int ALIGN_RIGHT = -2;
public static final int ALIGN_CENTER = -3;
public static final int IMAGE_LEFT = -4;
public static final int IMAGE_RIGHT = -5;
public static final int IMAGE_TOP = -6; // the default
public static final int IMAGE_BOTTOM = -7;
public static final String ALIGN_LEFT_STR = "Align Left";
public static final String ALIGN_RIGHT_STR = "Align Right";
public static final String ALIGN_CENTER_STR = "Align Center";
public static final String IMAGE_LEFT_STR = "Image Left";
public static final String IMAGE_RIGHT_STR = "Image Right";
public static final String IMAGE_TOP_STR = "Image Top";
public static final String IMAGE_BOTTOM_STR = "Image Bottom";
public static final int H_SPACE = 2; // the default
public static final int V_SPACE = 2; // the default
//
// Arbitrary delimiter: don't replace with system line separator
//
private static final String LINE_SEPARATOR = "\n";
private static final String ALT_LINE_SEPARATOR = "
";
private static final String LABEL = "Your label
goes here!";
private static final String IMAGE_MSG = "Error loading image...";
//
// Instance variables:
//
private int alignment; // {ALIGN_LEFT,ALIGN_RIGHT,ALIGN_CENTER}
private int imagePosition; // {IMAGE_LEFT,IMAGE_RIGHT,
// IMAGE_TOP,IMAGE_BOTTOM}
private int pHeight, pWidth;
private int labelAreaHeight, labelAreaWidth;
private int hSpace, vSpace;
private int rowHeight, rowAscent;
private int[] rowWidth;
private int rowCount;
private String[] row;
private transient Image image = null;
private String imageFile;
private boolean imageError, imageLoaded, useAltLineSep;
private transient Thread imageLoader = null;
//
// Constructors:
//
public FlexLabel(String label, int hSpace, int vSpace,
int alignment, int imagePosition) {
this.hSpace = hSpace;
this.vSpace = vSpace;
this.alignment = alignment;
this.imagePosition = imagePosition;
image = null;
initializeCommon();
initialize(label);
} // FlexLabel //
public FlexLabel(String label, int hSpace, int vSpace,
int alignment) {
this(label, hSpace, vSpace, alignment, IMAGE_TOP);
} // FlexLabel //
public FlexLabel(String label, int hSpace, int vSpace) {
this(label, hSpace, vSpace, ALIGN_CENTER);
} // FlexLabel //
public FlexLabel(String label, int alignment) {
this(label, H_SPACE, V_SPACE, alignment);
} // FlexLabel //
public FlexLabel(String label) {
this(label, H_SPACE, V_SPACE, ALIGN_CENTER);
} // FlexLabel //
public FlexLabel() {
this(LABEL, H_SPACE, V_SPACE, ALIGN_CENTER);
} // FlexLabel //
public FlexLabel(Image image, int hSpace, int vSpace,
int alignment, int imagePosition) {
this.hSpace = hSpace;
this.vSpace = vSpace;
this.alignment = alignment;
this.imagePosition = imagePosition;
initializeCommon();
initialize(image);
} // FlexLabel //
public FlexLabel(Image image, int hSpace, int vSpace,
int alignment) {
this(image, hSpace, vSpace, alignment, IMAGE_TOP);
} // FlexLabel //
//
// Public methods:
//
public boolean imageUpdate(Image image, int status,
int x, int y, int width, int height) {
if (imageError)
return false;
if ((status & ImageObserver.ABORT) != 0) {
imageError = true;
image = null;
return false;
}
return (status & ImageObserver.ALLBITS) != 1;
} // imageUpdate //
public void run() {
while (!imageLoaded && !imageError) {
calculatePreferredDimensions();
repaint();
try {
imageLoader.sleep(250);
}
catch (InterruptedException e) {
}
}
forceResize();
} // run //
public void paint(Graphics g) {
update(g);
} // paint //
public void update(Graphics g) {
g.clearRect(0, 0, getSize().width, getSize().height);
displayImage(g);
displayLabel(g);
} // update //
public void addNotify() {
super.addNotify();
calculatePreferredDimensions();
} // addNotify //
public synchronized Dimension getPreferredSize() {
calculatePreferredDimensions();
return new Dimension(pWidth, pHeight);
} // getPreferredSize //
public synchronized Dimension getMinimumSize() {
calculatePreferredDimensions();
return new Dimension(pWidth, pHeight);
} // getMinimumSize //
public synchronized String getLabelWithLinefeeds() {
String label = "";
for (int i = 0; i < row.length; i++) {
label += row[i];
if (i < (row.length - 1))
label += LINE_SEPARATOR;
}
return label;
} // getLabelWithLinefeeds //
public synchronized String getLabelWithSeparators() {
String label = "";
for (int i = 0; i < row.length; i++) {
label += row[i];
if (i < (row.length - 1))
label += useAltLineSep ? ALT_LINE_SEPARATOR : LINE_SEPARATOR;
}
return label;
} // getLabelWithSeparators //
public synchronized String getLabel() {
return replaceEscapeSequences(getLabelWithSeparators());
} // getLabel //
public synchronized void setLabel(String label) {
initialize(label);
calculatePreferredDimensions();
forceResize();
repaint();
} // setLabel //
public synchronized String getImageFile() {
return imageFile;
} // getImageFile //
public synchronized void setImageFile(String imageFile) {
if (imageFile == null)
return;
this.imageFile = imageFile;
if (imageFile.length() == 0) {
resetImageState();
initialize(getLabel());
}
else if (imageFile.equalsIgnoreCase("none") ||
imageFile.equalsIgnoreCase("reset")
) {
resetImageState();
initialize(getLabel());
}
else {
imageError = false;
image = Toolkit.getDefaultToolkit().getImage(imageFile);
initialize(image);
}
calculatePreferredDimensions();
forceResize();
repaint();
} // setImageFile //
public synchronized void setImage(Image image) {
imageError = false;
initialize(image);
calculatePreferredDimensions();
forceResize();
repaint();
} // setImage //
public synchronized void setFont(Font font) {
super.setFont(font);
calculatePreferredDimensions();
forceResize();
repaint();
} // setFont //
public synchronized void setForeground(Color color) {
super.setForeground(color);
repaint();
} // setForeground //
public synchronized void setBackground(Color color) {
super.setBackground(color);
repaint();
} // setBackground //
public synchronized int getAlignment() {
return alignment;
} // getAlignment //
public synchronized void setAlignment(int alignment) {
this.alignment = alignment;
calculatePreferredDimensions();
forceResize();
repaint();
} // setAlignment //
public int getImagePosition() {
return imagePosition;
} // getImagePosition //
public synchronized void setImagePosition(int imagePosition) {
this.imagePosition = imagePosition;
calculatePreferredDimensions();
forceResize();
repaint();
} // setImagePosition //
public int getHorizontalSpace() {
return hSpace;
} // getHorizontalSpace //
public synchronized void setHorizontalSpace(int space) {
if (space >= 0) {
hSpace = space;
calculatePreferredDimensions();
forceResize();
}
} // setHorizontalSpace //
public int getVerticalSpace() {
return vSpace;
} // getVerticalSpace //
public synchronized void setVerticalSpace(int space) {
if (space >= 0) {
vSpace = space;
calculatePreferredDimensions();
forceResize();
}
} // setVerticalSpace //
public void forceResize() {
Component parent = getParent();
if (parent != null) {
parent.invalidate();
parent.doLayout();
}
} // forceResize //
public String toString() {
String strAlignment, strPosition;
if (alignment == ALIGN_LEFT)
strAlignment = "ALIGN_LEFT";
else if (alignment == ALIGN_CENTER)
strAlignment = "ALIGN_CENTER";
else if (alignment == ALIGN_RIGHT)
strAlignment = "ALIGN_RIGHT";
else
strAlignment = "unknown";
if (imagePosition == IMAGE_LEFT)
strPosition = "IMAGE_LEFT";
else if (imagePosition == IMAGE_RIGHT)
strPosition = "IMAGE_RIGHT";
else if (imagePosition == IMAGE_TOP)
strPosition = "IMAGE_TOP";
else if (imagePosition == IMAGE_BOTTOM)
strPosition = "IMAGE_BOTTOM";
else
strPosition = "unknown";
return "[" + "width = " + pWidth + ", height = " + pHeight +
", hSpace = " + hSpace + ", vSpace = " + vSpace +
", alignment = " + strAlignment +
", imagePosition = " + strPosition + "]";
} // toString //
//
// Protected methods:
//
protected synchronized void initializeCommon() {
resetImageState();
useAltLineSep = true;
rowCount = 0;
labelAreaHeight = 0;
labelAreaWidth = 0;
pHeight = 0;
pWidth = 0;
} // initializeCommon //
protected synchronized void resetImageState() {
image = null;
imageFile = "";
imageError = false;
imageLoaded = false;
imageLoader = null;
}
protected synchronized void initialize(String label) {
String lbl = processEscapeSequences(label);
//
// using newlines as line separators?
//
useAltLineSep = !(lbl.indexOf(LINE_SEPARATOR.charAt(0)) != -1);
if (useAltLineSep) {
StringDelimiter d = new StringDelimiter(lbl, ALT_LINE_SEPARATOR);
rowCount = d.countTokens();
row = new String[rowCount];
rowWidth = new int[rowCount];
for (int i = 0; i < rowCount; i++)
row[i] = d.nextToken();
}
else {
StringTokenizer t = new StringTokenizer(lbl, LINE_SEPARATOR);
rowCount = t.countTokens();
row = new String[rowCount];
rowWidth = new int[rowCount];
for (int i = 0; i < rowCount; i++)
row[i] = t.nextToken();
}
} // initialize //
protected synchronized void initialize(Image image) {
if (imageError)
return;
this.image = image;
if (image == null)
return;
imageLoader = new Thread(this);
imageLoader.start();
} // initialize //
protected synchronized void calculatePreferredDimensions() {
Font f = getFont();
FontMetrics fm = (f != null) ? getFontMetrics(f) : null;
if (fm != null) {
rowHeight = fm.getHeight();
rowAscent = fm.getAscent();
}
pWidth = pHeight = 0;
if (fm != null && rowCount > 0) {
for (int i = 0; i < rowCount; i++) {
rowWidth[i] = fm.stringWidth(row[i]);
if (rowWidth[i] > pWidth)
pWidth = rowWidth[i];
}
labelAreaHeight = pHeight = rowHeight * rowCount;
labelAreaWidth = pWidth;
}
pWidth += 2 * hSpace;
pHeight += 2 * vSpace;
if (image != null) {
int h = image.getHeight(this);
int w = image.getWidth(this);
switch (imagePosition) {
case IMAGE_TOP:
if (w > (pWidth - (2 * hSpace)))
pWidth = w + (2 * hSpace);
if (h > -1)
pHeight += h + vSpace;
break;
case IMAGE_BOTTOM:
if (w > (pWidth - (2 * hSpace)))
pWidth = w + (2 * hSpace);
if (h > -1)
pHeight += h + vSpace;
break;
case IMAGE_LEFT:
if (h > (pHeight - (2 * vSpace)))
pHeight = h + (2 * vSpace);
if (w > -1)
pWidth += w + hSpace;
break;
case IMAGE_RIGHT:
if (h > (pHeight - (2 * vSpace)))
pHeight = h + (2 * vSpace);
if (w > -1)
pWidth += w + hSpace;
break;
default:
System.out.println(
"FlexLabel: invalid image alignment constant!");
return;
}
}
} // calculatePreferredDimensions //
protected void displayLabel(Graphics g) {
if (rowCount < 1)
return;
int x = hSpace;
int y = vSpace;
if (image != null && !imageError) {
int h = image.getHeight(this);
int w = image.getWidth(this);
if (h > -1 && w > -1) {
switch (imagePosition) {
case IMAGE_TOP:
if (alignment == ALIGN_CENTER)
x = (getSize().width - labelAreaWidth) / 2;
else if (alignment == ALIGN_RIGHT)
x = getSize().width - labelAreaWidth - hSpace;
y += h + vSpace;
break;
case IMAGE_LEFT:
if (alignment == ALIGN_CENTER)
x += w + hSpace + ((getSize().width - pWidth) / 2);
else if (alignment == ALIGN_RIGHT)
x = getSize().width - labelAreaWidth - hSpace;
else
x += w + hSpace;
y += (getSize().height - pHeight) / 2;
y += (h - labelAreaHeight) / 2;
break;
case IMAGE_RIGHT:
if (alignment == ALIGN_CENTER)
x += (getSize().width - pWidth) / 2;
else if (alignment == ALIGN_RIGHT)
x += getSize().width - pWidth;
y += (getSize().height - pHeight) / 2;
y += (h - labelAreaHeight) / 2;
break;
case IMAGE_BOTTOM:
if (alignment == ALIGN_CENTER)
x = (getSize().width - labelAreaWidth) / 2;
else if (alignment == ALIGN_RIGHT)
x = getSize().width - labelAreaWidth - hSpace;
y = (getSize().height - pHeight) + vSpace;
break;
default:
System.out.println(
"FlexLabel: invalid image alignment constant!");
return;
}
}
}
else {
if (alignment == ALIGN_CENTER)
x += (getSize().width - pWidth) / 2;
else if (alignment == ALIGN_RIGHT)
x = getSize().width - labelAreaWidth - hSpace;
y += (getSize().height - pHeight) / 2;
}
y += rowAscent;
for (int i = 0; i < rowCount; i++, y += rowHeight) {
int adjX = x;
switch (alignment) {
case ALIGN_LEFT:
// no further adjustment
break;
case ALIGN_RIGHT:
adjX += labelAreaWidth - rowWidth[i];
break;
case ALIGN_CENTER:
adjX += (labelAreaWidth - rowWidth[i]) / 2;
break;
default:
System.out.println(
"FlexLabel: invalid alignment constant!");
return;
}
g.drawString(row[i], adjX, y);
}
} // displayLabel //
protected void displayImage(Graphics g) {
if (image == null || imageError)
return;
int h = image.getHeight(this);
int w = image.getWidth(this);
int x = hSpace, y = vSpace;
switch (imagePosition) {
case IMAGE_TOP:
if (alignment == ALIGN_CENTER)
x = (getSize().width - w) / 2;
else if (alignment == ALIGN_RIGHT)
x = getSize().width - hSpace - w;
break;
case IMAGE_LEFT:
if (alignment == ALIGN_CENTER) {
if (rowCount > 0) // text margin required
x += (getSize().width - pWidth) / 2;
else
x = (getSize().width - w) / 2;
}
else if (alignment == ALIGN_RIGHT) {
x += getSize().width - pWidth;
if (rowCount == 0) // no text margin required
x += hSpace;
}
y += (getSize().height - pHeight) / 2;
break;
case IMAGE_RIGHT:
if (alignment == ALIGN_CENTER) {
if (rowCount > 0) // text margin required
x += labelAreaWidth + hSpace +
((getSize().width - pWidth) / 2);
else
x = (getSize().width - w) / 2;
}
else if (alignment == ALIGN_RIGHT)
x = getSize().width - w - hSpace;
else {
x += labelAreaWidth + hSpace;
if (rowCount == 0) // no text margin required
x -= hSpace;
}
y += (getSize().height - pHeight) / 2;
break;
case IMAGE_BOTTOM:
if (alignment == ALIGN_CENTER)
x = (getSize().width - w) / 2;
else if (alignment == ALIGN_RIGHT)
x = getSize().width - hSpace - w;
y = labelAreaHeight + (2 * vSpace);
y += getSize().height - pHeight;
break;
default:
System.out.println(
"FlexLabel: invalid image alignment constant!");
return;
}
imageLoaded = g.drawImage(image, x, y, this);
} // displayImage //
protected String processEscapeSequences(String in) {
StringBuffer out = new StringBuffer(in.length());
int j = 0;
for (int i = 0; i < in.length(); i++, j++) {
switch (in.charAt(i)) {
case '\\':
switch (in.charAt(i + 1)) {
case 'n':
out.insert(j, '\n');
break;
case 't':
out.insert(j, '\t');
break;
case 'b':
out.insert(j, '\b');
break;
case 'r':
out.insert(j, '\r');
break;
case 'f':
out.insert(j, '\f');
break;
case '\\':
out.insert(j, '\\');
break;
case '\'':
out.insert(j, '\'');
break;
case '\"':
out.insert(j, '\"');
break;
default:
// no error detection
if (Character.isDigit(in.charAt(i + 1))) {
String octStr = in.substring(i + 1, i + 4);
int octValue = Integer.parseInt(octStr);
out.insert(j, Character.forDigit(octValue, 8));
i += 2; // skip two *extra* chars for octal
}
else
return null;
break;
}
i++; // skip one *extra* char for backslash
break;
default:
out.insert(j, in.charAt(i)); // no special interpretation
break;
}
}
out.setLength(j);
return out.toString();
} // processEscapeSequences //
protected String replaceEscapeSequences(String in) {
StringBuffer out = new StringBuffer(in.length());
int j = 0;
for (int i = 0; i < in.length(); i++, j++) {
switch (in.charAt(i)) {
case '\n':
out.insert(j, "\\n");
j++;
break;
case '\t':
out.insert(j, "\\t");
j++;
break;
case '\b':
out.insert(j, "\\b");
j++;
break;
case '\r':
out.insert(j, "\\r");
j++;
break;
case '\f':
out.insert(j, "\\f");
j++;
break;
default:
out.insert(j, in.charAt(i)); // no special interpretation
break;
}
}
return out.toString();
} // replaceEscapeSequences //
} // FlexLabel class //