/**** 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 //