/* (C) 2000-2002, DIUF, http://www.unifr.ch/diuf
*
* This program 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 of the License, or (at your
* option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package iiuf.xmillum.displayable;
import iiuf.dom.DOMUtils;
import iiuf.xmillum.BrowserContext;
import iiuf.xmillum.Displayable;
import iiuf.xmillum.DisplayableClass;
import iiuf.xmillum.FlagManager;
import iiuf.xmillum.Parameter;
import iiuf.xmillum.Style;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Font;
import java.awt.Point;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.text.AttributedString;
import java.text.AttributedCharacterIterator;
import java.text.StringCharacterIterator;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
* TextArea
*
* xmillum text area. Shows text in the xmillum main window.
*
* <p>Optional initialization parameters:
* <ul>
* <li>color: color of the text
* (default: black)
* <li>family: family name (<code>helvetica</code>, <code>times</code> etc.)
* (default: <code>helvetica</code>)
* <li>size: in points
* (default: 12)
* <li>slope: <code>upright</code>, <code>slanted</code>
* (default: <code>upright</code>)
* <li>weight: <code>regular</code>, <code>medium</code>, <code>bold</code>,
* <code>extrabold</code>
* (default: <code>regular</code>)
* <li>resolution: resolution in dpi of the coordinates (used to
* calculate size of the fonts correctly)
* (default: 300)
* <li>direction: <code>l2r</code>, <code>r2l</code>
* (default: <code>l2r</code>)
* <li>background: lighten or darken the background using the given color
* (default: white)
* </ul>
*
* <p>ActionHandlers:
* <ul>
* <li>over: triggered when the mouse is over this object
* <li>click1: mouse button 1 clicked
* <li>click2: mouse button 2 clicked
* <li>click3: mouse button 3 clicked
* <li>press1: mouse button 1 press & hold
* <li>press2: mouse button 2 press & hold
* <li>press3: mouse button 3 press & hold
* </ul>
*
* @author $Author: ohitz $
* @version $Revision: 1.1 $
*/
public class TextArea extends DisplayableClass {
static Map parameters = new HashMap();
static {
parameters.put("style", new Parameter() {
public void setParam(BrowserContext c, Object o, String v) {
TextArea t = (TextArea) o;
t.style = c.styleRegistry.getStyle(v);
}
});
parameters.put("click1", new Parameter() {
public void setParam(BrowserContext c, Object o, String v) {
TextArea t = (TextArea) o;
t.click1Handler = v;
}
});
parameters.put("click2", new Parameter() {
public void setParam(BrowserContext c, Object o, String v) {
TextArea t = (TextArea) o;
t.click2Handler = v;
}
});
parameters.put("click3", new Parameter() {
public void setParam(BrowserContext c, Object o, String v) {
TextArea t = (TextArea) o;
t.click3Handler = v;
}
});
parameters.put("press1", new Parameter() {
public void setParam(BrowserContext c, Object o, String v) {
TextArea t = (TextArea) o;
t.press1Handler = v;
}
});
parameters.put("press2", new Parameter() {
public void setParam(BrowserContext c, Object o, String v) {
TextArea t = (TextArea) o;
t.press2Handler = v;
}
});
parameters.put("press3", new Parameter() {
public void setParam(BrowserContext c, Object o, String v) {
TextArea t = (TextArea) o;
t.press3Handler = v;
}
});
parameters.put("over", new Parameter() {
public void setParam(BrowserContext c, Object o, String v) {
TextArea t = (TextArea) o;
t.overHandler = v;
}
});
}
Style style;
String click1Handler = null;
String click2Handler = null;
String click3Handler = null;
String press1Handler = null;
String press2Handler = null;
String press3Handler = null;
String overHandler = null;
BrowserContext context;
public void initialize(BrowserContext c, Element e) {
context = c;
Parameter.setParameters(c, e, this, parameters);
}
public Displayable getDisplayable(Element element) {
// Create the new block
DisplayableBlock d = new DisplayableBlock(element);
try {
d.bounds = new Rectangle(Integer.parseInt(element.getAttribute("x")),
Integer.parseInt(element.getAttribute("y")),
Integer.parseInt(element.getAttribute("w")),
Integer.parseInt(element.getAttribute("h")));
} catch (NumberFormatException e) {
}
return d;
}
private class DisplayableBlock extends Displayable {
boolean visible = false;
public DisplayableBlock(Element e) {
super(e);
}
double textScale;
TextLayout[] textLines;
Point[] textPositions;
TextLayout[] getTextLines(double scale) {
if (textLines == null || textScale != scale) {
rescale(scale);
}
return textLines;
}
Point[] getTextPositions(double scale) {
if (textPositions == null || textScale != scale) {
rescale(scale);
}
return textPositions;
}
void rescale(double scale) {
Rectangle bounds = getBounds(scale);
HashMap settings = new HashMap();
settings.put(TextAttribute.FONT, new Font(style.getFontAttributes(scale)));
AttributedCharacterIterator par = (new AttributedString(element.getAttribute("text"), settings)).getIterator();
LineBreakMeasurer lbm = new LineBreakMeasurer(par, new FontRenderContext(null, false, false));
ArrayList drawList = new ArrayList();
int parEnd = par.getEndIndex();
int positionX;
int positionY = bounds.y;
lbm.setPosition(par.getBeginIndex());
while (lbm.getPosition() < parEnd) {
TextLayout layout = lbm.nextLayout(bounds.width);
positionX = bounds.x;
if (!layout.isLeftToRight()) {
positionX += bounds.width - (int) layout.getAdvance();
}
positionY += layout.getAscent();
if (positionY > bounds.y+bounds.height) break;
drawList.add(new Point(positionX, positionY));
drawList.add(layout);
positionY += layout.getDescent() + layout.getLeading();
}
textPositions = new Point[drawList.size()/2];
textLines = new TextLayout[drawList.size()/2];
textScale = scale;
for (int i = 0; i < textPositions.length; i++) {
textPositions[i] = (Point) drawList.get(i*2);
textLines[i] = (TextLayout) drawList.get(i*2+1);
}
}
public Rectangle getBounds(double scale) {
if (bounds != null) {
return new Rectangle((int) (scale * bounds.x),
(int) (scale * bounds.y),
Math.max(1, (int) Math.ceil(scale * bounds.width)),
Math.max(1, (int) Math.ceil(scale * bounds.height)));
} else {
return new Rectangle();
}
}
public void paintObject(Graphics2D g, double scale) {
Rectangle bounds = getBounds(scale);
if (style != null) style.setStyle(g);
Style[] styles = context.flagger.getStyles(element);
for (int i = 0; i < styles.length; i++) {
styles[i].setStyle(g);
}
if (style.isFilled()) {
Color c = g.getColor();
g.setColor(style.getBackground());
g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
g.setColor(c);
}
Point[] tp = getTextPositions(scale);
TextLayout[] tl = getTextLines(scale);
for (int i = 0; i < tp.length; i++) {
tl[i].draw(g, tp[i].x, tp[i].y);
}
}
public boolean mouseMovedAction(MouseEvent event) {
if (overHandler != null) {
context.actionFactory.handleAction(overHandler, null, this, context);
return true;
}
return false;
}
public boolean mouseClickedAction(MouseEvent event) {
if ((click1Handler != null) && (0 != (event.getModifiers() & MouseEvent.BUTTON1_MASK))) {
context.actionFactory.handleAction(click1Handler, null, this, context);
return true;
}
if ((click2Handler != null) && (0 != (event.getModifiers() & MouseEvent.BUTTON2_MASK))) {
context.actionFactory.handleAction(click2Handler, null, this, context);
return true;
}
if ((click3Handler != null) && (0 != (event.getModifiers() & MouseEvent.BUTTON3_MASK))) {
context.actionFactory.handleAction(click3Handler, null, this, context);
return true;
}
return super.mouseClickedAction(event);
}
public boolean mousePressedAction(MouseEvent event) {
if ((press1Handler != null) && (0 != (event.getModifiers() & MouseEvent.BUTTON1_MASK))) {
context.actionFactory.handleAction(press1Handler, null, this, context);
return true;
}
if ((press2Handler != null) && (0 != (event.getModifiers() & MouseEvent.BUTTON2_MASK))) {
context.actionFactory.handleAction(press2Handler, null, this, context);
return true;
}
if ((press3Handler != null) && (0 != (event.getModifiers() & MouseEvent.BUTTON3_MASK))) {
context.actionFactory.handleAction(press3Handler, null, this, context);
return true;
}
return false;
}
}
}