/* Copyright (c) 2008 Bluendo S.r.L.
* See about.html for details about license.
*
* $Id: UILabel.java 1578 2009-06-16 11:07:59Z luca $
*/
/**
*
*/
package it.yup.ui;
import it.yup.util.Utils;
import java.util.Enumeration;
import java.util.Vector;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
/**
* @author luca
*
*/
public class UILabel extends UIItem {
String text;
Image img;
boolean flip = false;
private Vector textLines = null;
/**
* The font used to paint the Label
*/
Font font = null;
/**
* The text of the label is "wrapped" it text is too long to fit a single
* line only if wrappable is set to true. Subclasses are likely to override
* this behaviour.
*/
boolean wrappable = false;
public UILabel(String text) {
this(null, text);
}
public UILabel(Image img) {
this(img, "");
}
/**
* @param screen
*/
public UILabel(Image img, String text) {
this.img = img;
this.text = text;
// if an img is present it is a nonsense to have the
// label wrapped! or not ?
if (this.img != null) this.wrappable = false;
// TODO Auto-generated constructor stub
}
/*
* Used to indicated the anchor point for the label with the same syntax as
* Graphics (TOP, VCENTER,BOTTOM, LEFT, HCENTER,RIGHT ). It is possible to
* use them in or like: anchorPoint = Graphics.TOP | Graphics.LEFT; the
* default value is Graphics.VCENTER | Graphics.LEFT.
*/
int anchorPoint = Graphics.TOP | Graphics.LEFT;
private int imgAnchorPoint = -1;
/**
* used to get the different components of the acnhorPoint,
*/
private int[] divideAP() {
int[] result = new int[2];
result[0] = (this.anchorPoint & Graphics.TOP) > 0 ? Graphics.TOP
: ((this.anchorPoint & Graphics.VCENTER) > 0 ? Graphics.VCENTER
: ((this.anchorPoint & Graphics.BOTTOM) > 0 ? Graphics.BOTTOM
: 0));
result[1] = (this.anchorPoint & Graphics.LEFT) > 0 ? Graphics.LEFT
: ((this.anchorPoint & Graphics.HCENTER) > 0 ? Graphics.HCENTER
: ((this.anchorPoint & Graphics.RIGHT) > 0 ? Graphics.RIGHT
: 0));
return result;
}
int getTextWidth(String textLine, Font font) {
return font.stringWidth(textLine);
}
private void paintLine(Graphics g, int w, int h, Image imgLine,
String textLine) {
int lineHeight = 0;
int lineWidth = 0;
int textHeight = 0, textWidth = 0, imgHeight = 0;
Font usedFont = (this.font != null ? this.font : g.getFont());
if (imgLine != null) {
lineHeight = imgLine.getHeight() + 2;
imgHeight = imgLine.getHeight();
}
// if (imgHeight < g.getFont().getHeight() + 2) {
// imgHeight = g.getFont().getHeight() + 2;
// }
if (h > lineHeight) {
lineHeight = h;
}
textHeight = usedFont.getHeight();
textWidth = getTextWidth(textLine, usedFont);
// text and Image must have an offset from the TOP
// in order to be aligned
int imgVerticalOffset = (lineHeight - imgHeight - 2) / 2;
int textVerticalOffset = (lineHeight - textHeight - 2) / 2;
// the horizontalSpace left "free"; must be set depending on the
// orientation
int horizontalSpace = 0;
lineWidth = 0;
if (imgLine != null) lineWidth += imgLine.getWidth() + 3
+ getTextWidth(textLine, usedFont);
else
lineWidth = getTextWidth(textLine, usedFont) + 2;
if (w > lineWidth) {
horizontalSpace = w - lineWidth;
this.width = w;
}
int horizontalAnchor = this.divideAP()[1];
switch (horizontalAnchor) {
case Graphics.LEFT:
horizontalSpace = 0;
break;
case Graphics.HCENTER:
horizontalSpace /= 2;
break;
case Graphics.RIGHT:
break;
default:
break;
}
// first erase background
g.setColor(getBg_color() >= 0 ? getBg_color() : UIConfig.bg_color);
if (this.getGradientColor() < 0) g.fillRect(0, 0, w, lineHeight);
else {
g.fillRect(0, 0, w, lineHeight / 2);
g.setColor(this.getGradientColor());
g.fillRect(0, lineHeight / 2, w, lineHeight - (lineHeight / 2));
}
// than paint in case it is needed
if (selected) {
int offset = 0;
if (imgLine != null) offset = imgVerticalOffset;
if (textLine != null
&& (textVerticalOffset < offset || imgLine == null)) offset = textVerticalOffset;
g.setColor(this.getSelectedColor());
int selHeight = java.lang.Math.max(imgHeight, textHeight) + 2;
if (this.getGradientSelectedColor() < 0) g.fillRect(0, offset, w,
selHeight);
else {
g.fillRect(0, offset, w, selHeight / 2);
g.setColor(this.getGradientSelectedColor());
g.fillRect(0, selHeight / 2, w, selHeight - (selHeight / 2));
}
}
g.setColor(selected ? UIConfig.header_fg : UIConfig.fg_color);
if (this.fg_color >= 0) g.setColor(this.fg_color);
if (flip == false) {
if (this.img != null) {
// if the imgAnchorPoint is set it means image must be overridden
int imgHOffset = 1;
if (this.imgAnchorPoint != Graphics.LEFT) imgHOffset += horizontalSpace;
g.drawImage(imgLine, imgHOffset, 1 + imgVerticalOffset,
Graphics.LEFT | Graphics.TOP);
// g.drawString(textLine,
// imgLine.getWidth() + 2 + horizontalSpace,
// 1 + textVerticalOffset, Graphics.LEFT | Graphics.TOP);
paintTextLine(g, textLine, imgLine.getWidth() + 2
+ horizontalSpace, 1 + textVerticalOffset);
} else {
// g.drawString(textLine, 1 + horizontalSpace,
// 1 + textVerticalOffset, Graphics.LEFT | Graphics.TOP);
paintTextLine(g, textLine, 1 + horizontalSpace,
1 + textVerticalOffset);
}
} else {
// g.drawString(textLine, 1 + horizontalSpace, 1 +
// textVerticalOffset,
// Graphics.LEFT | Graphics.TOP);
paintTextLine(g, textLine, 1 + horizontalSpace,
1 + textVerticalOffset);
if (this.img != null) {
g.drawImage(imgLine, textWidth + 2 + horizontalSpace,
1 + imgVerticalOffset, Graphics.LEFT | Graphics.TOP);
}
}
}
void paintTextLine(Graphics g, String textLine, int horizontalSpace,
int verticalSpace) {
g.drawString(textLine, horizontalSpace, verticalSpace, Graphics.LEFT
| Graphics.TOP);
}
/*
* String[] split(String original, String separator) { Vector nodes = new
* Vector(); // Parse nodes into vector int index =
* original.indexOf(separator); while (index >= 0) {
* nodes.addElement(original.substring(0, index)); original =
* original.substring(index + separator.length()); index =
* original.indexOf(separator); } // Get the last node
* nodes.addElement(original); // Create splitted string array String[]
* result = new String[nodes.size()]; if (nodes.size() > 0) { for (int loop =
* 0; loop < nodes.size(); loop++) result[loop] = (String)
* nodes.elementAt(loop); } return result; }
*
*/
/*
* (non-Javadoc)
*
* @see it.yup.ui.UIItem#paint(javax.microedition.lcdui.Graphics, int, int)
*/
protected void paint(Graphics g, int w, int h) {
Font oldFont = g.getFont();
if (this.font != null) g.setFont(this.font);
this.height = 0;
this.width = 0;
if (this.img != null) {
if (this.text != null && this.text.length() >= 2) {
this.width += img.getWidth() + 3
+ g.getFont().stringWidth(text);
} else
this.width += img.getWidth() + 2;
} else
this.width = g.getFont().stringWidth(text) + 2;
// if the label is not wrappable we remove the extra characters
// we must check that image is not wider than w
if (this.wrappable == false) {
if (this.width > w && (this.img == null || this.img.getWidth() < w)) {
// String newText = new String(this.text);
// do {
// this.width = 0;
// int index = newText.length() - 2;
// if (index < 0) index = 0;
// newText = newText.substring(0, Math.max(newText.length() - 2,0));
// if (img != null) this.width += img.getWidth() + 3
// + g.getFont().stringWidth(newText + "...");
// else
// this.width = g.getFont().stringWidth(newText + "...") + 2;
// } while (this.width > w && newText.length() > 0);
String newText = new String("");
int index = 0;
this.width = 0;
while (this.width < w) {
newText = newText + this.text.charAt(index);
this.width = g.getFont().stringWidth(newText + "...") + 2;
if (img != null) this.width += (img.getWidth() + 1);
index++;
}
if (newText.length() > 1) newText = newText.substring(0,
newText.length() - 2);
newText = newText + "...";
paintLine(g, w, h, img, newText);
} else {
paintLine(g, w, h, img, this.text);
}
} else {
this.width = w;
// just in case it has not been called before
Font usedFont = (this.font != null ? this.font : g.getFont());
if (textLines == null) {
computeTextLines(usedFont, this.width);
}
this.height = (usedFont.getHeight() + 2) * this.textLines.size();
int originalY = g.getTranslateY();
int reservedHeight = g.getFont().getHeight() + 2;
g.translate(0, (h - (reservedHeight * this.textLines.size())) / 2);
for (int i = 0; i < textLines.size(); i++) {
String subStr = (String) textLines.elementAt(i);
paintLine(g, w, reservedHeight, img, subStr);
g.translate(0, reservedHeight);
}
g.translate(0, originalY - g.getTranslateY());
}
// #mdebug
//@ // System.out.println("Drawn UILabel '" + text + "' at: ("
//@ // + g.getTranslateX() + ", " + g.getTranslateY() + ")"
//@ // + (selected ? "S" : ""));
// #enddebug
g.setFont(oldFont);
}
public void computeTextLines(Font usedFont, int w) {
textLines = new Vector();
Vector splittedVector = Utils.tokenize(this.text.replace('\t', ' '),
new String[] { "\n", " " }, true);
String[] splittedStrings = new String[splittedVector.size()];
if (splittedVector.size() > 0) {
for (int loop = 0; loop < splittedVector.size(); loop++)
splittedStrings[loop] = (String) splittedVector.elementAt(loop);
} else {
// for "white lines"
splittedStrings = new String[] { " " };
}
int index = 0;
String tempString = "";
while (index < splittedStrings.length) {
do {
tempString = tempString + splittedStrings[index];
index++;
} while (index < splittedStrings.length
&& getTextWidth(tempString + splittedStrings[index],
usedFont) < w
&& (splittedStrings[index].compareTo("\n") != 0));
tempString = tempString.trim();
// just in case the line is empty it is not shown
if (tempString.length() > 0) {
// just in case the string is toooooooooo big
Vector longStrings = splitLongStrings(tempString, w, usedFont);
for (Enumeration en = longStrings.elements(); en
.hasMoreElements();) {
String s = (String) en.nextElement();
s = s.trim();
if (s.length() == 0) s = " ";
textLines.addElement(s);
}
}
tempString = "";
}
}
private Vector splitLongStrings(String longString, int w, Font usedFont) {
if (getTextWidth(longString, usedFont) < w) {
Vector v = new Vector();
v.addElement(longString);
return v;
}
Vector retVector = new Vector();
String tempString = "";
int index = 0;
while (longString.length() > 0) {
while (index <= longString.length()) {
int stringLength = getTextWidth(tempString, usedFont);
if (stringLength > w) {
index--;
tempString = longString.substring(0, index - 1);
break;
}
tempString = longString.substring(0, index);
index++;
}
retVector.addElement(tempString);
if (index - 1 < longString.length()) {
longString = longString.substring(index - 1, longString
.length());
}
if (index - 1 == longString.length()) break;
tempString = "";
index = 0;
}
return retVector;
}
/**
* @return the flip
*/
public boolean isFlip() {
return flip;
}
/**
* @param flip
* the flip to set
*/
public void setFlip(boolean flip) {
this.flip = flip;
}
/**
* {@inheritDoc}
*
*/
public int getHeight(Graphics g) {
Font usedFont = (this.font != null ? this.font : g.getFont());
this.height = 0;
if (this.wrappable == false) {
if (img != null) this.height = img.getHeight() + 2;
if (usedFont.getHeight() + 2 > this.height) this.height = usedFont
.getHeight() + 2;
} else {
int fontHeight = usedFont.getHeight();
if (textLines == null) {
computeTextLines(usedFont, this.width);
}
if (img != null) this.height = img.getHeight() + 2;
int tempHeight = (fontHeight + 2) * this.textLines.size();
if (tempHeight > this.height) this.height = tempHeight;
}
return height;
}
/**
* @return this label text
*/
public String getText() {
return text;
}
/**
* Sets/changes the text for this label
*
* @param _text
*/
public void setText(String _text) {
if (text.equals(_text) == false) this.textLines = null;
text = _text;
dirty = true;
// reset the text lines for wrappable labels
// only when needed and avoid recomputing lines
}
/**
* @param anchorPoint
* the anchorPoint to set
*/
public void setAnchorPoint(int anchorPoint) {
this.anchorPoint = anchorPoint;
}
/**
* @return the anchorPoint
*/
public int getAnchorPoint() {
return anchorPoint;
}
/**
* @param wrappable
* the wrappable to set
*/
public void setWrappable(boolean wrappable, int width) {
if (this.img != null) return;
if (wrappable != this.wrappable) this.setDirty(true);
this.wrappable = wrappable;
// if (this.width != width)
// this.textLines = null;
this.width = width;
}
/**
* @return the wrappable
*/
public boolean isWrappable() {
return wrappable;
}
/**
* @param font
* the font to set
*/
public void setFont(Font font) {
this.font = font;
}
/**
* @return the font
*/
public Font getFont() {
return font;
}
/**
* @return the img
*/
public Image getImg() {
return img;
}
/**
* @param img
* the img to set
*/
public void setImg(Image img) {
if (this.img == img) return;
this.dirty = true;
this.img = img;
this.wrappable = false;
}
/**
* @param textLines
* the textLines to set
*/
public void setTextLines(Vector textLines) {
this.textLines = textLines;
this.dirty = true;
}
/**
* @return the textLines
*/
public Vector getTextLines() {
return textLines;
}
public void setImgAnchorPoint(int imgAnchorPoint) {
this.imgAnchorPoint = imgAnchorPoint;
}
public int getImgAnchorPoint() {
return imgAnchorPoint;
}
}