Sam Reid
/* Copyright 2005, University of Colorado */
/*
* CVS Info -
* Filename : $Source$
* Branch : $Name$
* Modified by : $Author$
* Revision : $Revision$
* Date modified : $Date$
*/
package edu.colorado.phet.common.piccolophet.nodes;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.JLabel;
import javax.swing.plaf.basic.BasicHTML;
import javax.swing.text.View;
import edu.umd.cs.piccolo.PNode;
import edu.umd.cs.piccolo.util.PPaintContext;
/**
* HTMLNode is a Piccolo node for rendering HTML text.
*
* @author Chris Malley (cma...@pixelzoom.com)
* @author Sam Reid
* @version $Revision$
*/
public class HTMLNode extends PNode {
//----------------------------------------------------------------------------
// Class data
//----------------------------------------------------------------------------
private static final Font DEFAULT_FONT = new JLabel().getFont();
private static final Color DEFAULT_HTML_COLOR = Color.BLACK;
//----------------------------------------------------------------------------
// Instance data
//----------------------------------------------------------------------------
private String html;
private Font font;
private Color htmlColor;
private JLabel htmlLabel;
private View htmlView;
private final Rectangle htmlBounds; // BasicHTML$Renderer.paint requires a Rectangle
//----------------------------------------------------------------------------
// Constructors
//----------------------------------------------------------------------------
public HTMLNode() {
this( null, DEFAULT_FONT, DEFAULT_HTML_COLOR );
}
public HTMLNode( String html ) {
this( html, DEFAULT_FONT, DEFAULT_HTML_COLOR );
}
public HTMLNode( String html, Color htmlColor ) {
this( html, DEFAULT_FONT, htmlColor );
}
public HTMLNode( String html, Font font, Color htmlColor ) {
this.html = html;
this.font = font;
this.htmlColor = htmlColor;
htmlLabel = new JLabel();
htmlBounds = new Rectangle();
update();
}
//----------------------------------------------------------------------------
// Accessors
//----------------------------------------------------------------------------
/**
* Gets the HTML string.
*
* @return HTML string
*/
public String getHTML() {
return html;
}
/**
* Sets the HMTL string.
*
* @param html
*/
public void setHTML( String html ) {
if ( ( this.html != null && html == null ) || ( this.html == null && html != null ) || ( !this.html.equals( html ) ) ) {
this.html = html;
update();
}
}
/**
* Gets the font.
*
* @return the font
*/
public Font getFont() {
return font;
}
/**
* Sets the font.
*
* @param font
*/
public void setFont( Font font ) {
this.font = font;
update();
}
/**
* Gets the color used to render the HTML.
* If you want to get the paint used for the node, use getPaint.
*
* @return the color used to render the HTML.
*/
public Color getHTMLColor() {
return htmlColor;
}
/**
* Sets the color used to render the HTML.
* If you want to set the paint used for the node, use setPaint.
*
* @param color
*/
public void setHTMLColor( Color color ) {
htmlColor = color;
update();
}
//----------------------------------------------------------------------------
// Update handler
//----------------------------------------------------------------------------
/*
* Updates everything that is involved in rendering the HTML string.
* This method is called when one the HTML-related properties is modified.
*/
private void update() {
htmlLabel.setText( html );
htmlLabel.setFont( font );
htmlLabel.setForeground( htmlColor );
htmlLabel.setSize( htmlLabel.getPreferredSize() );
htmlView = BasicHTML.createHTMLView( htmlLabel, html == null ? "" : html );
htmlBounds.setRect( 0, 0, htmlView.getPreferredSpan( View.X_AXIS ), htmlView.getPreferredSpan( View.Y_AXIS ) );
setBounds( htmlBounds );
repaint();
}
//----------------------------------------------------------------------------
// PNode overrides
//----------------------------------------------------------------------------
/*
* Paints the node.
* The HTML string is painted last, so it appears on top of any child nodes.
*
* @param paintContext
*/
protected void paint( PPaintContext paintContext ) {
super.paint( paintContext );
if ( htmlLabel.getWidth() == 0 || htmlLabel.getHeight() == 0 ) {
return;
}
Graphics2D g2 = paintContext.getGraphics();
htmlView.paint( g2, htmlBounds );
}
}
Thanks
Figured this out for myself. At first I tried setting the size of the
JLabel used in HTMLNode, but this didn't have any effect. I discovered
instead that it's the bounds set in the call to htmlBounds.setRect in
HTMLNode's update method that matter, the text will be wrapped within
these bounds. The way it's implement, it seems to always set the
bounds to the width of the text if the text is written all on one
line. So I modified the update method a little and added an override
of PNode's setBounds methods so that the user can set the bounds of an
HTMLNode manually and the text will be wrapped within those bounds.
Here's the code I changed, I changed the update method and added the
setBounds methods:
//----------------------------------------------------------------------------
// Update handler
//----------------------------------------------------------------------------
/*
* Updates everything that is involved in rendering the HTML string.
* This method is called when one the HTML-related properties is modified.
*/
private void update() {
htmlLabel.setText(html);
htmlLabel.setFont(font);
htmlLabel.setForeground(htmlColor);
htmlLabel.setSize(htmlLabel.getPreferredSize());
htmlView = BasicHTML.createHTMLView(htmlLabel, html == null ?
"" : html);
htmlBounds.setRect(0, 0, getBounds().getWidth(),
getBounds().getHeight());
repaint();
}
//----------------------------------------------------------------------------
// PNode overrides
//----------------------------------------------------------------------------
@Override
public boolean setBounds(double x, double y, double width, double height) {
boolean boundsChanged = super.setBounds(x,y,width,height);
update();
return boundsChanged;
}
@Override
public boolean setBounds(java.awt.geom.Rectangle2D newBounds) {
boolean boundsChanged = super.setBounds(newBounds);
update();
return boundsChanged;
}
Full new version of the code here: http://gist.github.com/78096
You can get the height just by calling getBounds().getHeight() can't you? (A
method inherited from PNode).
I'm not actually sure which class does the text wrapping, but if you wanted a
count of the number of wraps you'd have to get it from that class, and if it
doesn't export that info you might have to modify or extend that class.