/* (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; } } }