/* * [AntiAliastedFontedTextArea.java] * * Summary: TextArea that lets you use any font, not just the AWT logical fonts, with or without anti-aliasing. * * Copyright: (c) 2009-2017 Roedy Green, Canadian Mind Products, http://mindprod.com * * Licence: This software may be copied and used freely for any purpose but military. * http://mindprod.com/contact/nonmil.html * * Requires: JDK 1.8+ * * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/ * * Version History: * 2.9 2009-01-23 add Kanji digits to font samples */ package com.mindprod.fontshowerawt; import java.awt.Canvas; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.RenderingHints; import static java.lang.System.*; /** * TextArea that lets you use any font, not just the AWT logical fonts, with or without anti-aliasing. *

* It does not handle copy/paste operations the way TextArea does. Further, it has only one * method to change the text displayed, setTextLines. * * @author Roedy Green, Canadian Mind Products * @version 2.9 2009-01-23 add Kanji digits to font samples * @since 2009 */ final class AntiAliastedFontedTextArea extends Canvas { /** * true if want extra debug output */ private static final boolean DEBUGGING = false; /** * pixels margin below text */ private static final int BOTTOM_MARGIN = 8; /** * pixels margin to left of text */ private static final int LEFT_MARGIN = 5; /** * pixels margin to right of text */ private static final int RIGHT_MARGIN = 4; /** * pixels margin above text */ private static final int TOP_MARGIN = 0; /** * Dimensions of the scrollable footprint. Start with dummy in case we get queried before set called. */ private Dimension dimension = new Dimension( 10, 10 ); /** * Text to render, as an array of Strings, one per line */ private String[] textLines; /** * true if want anti-aliased fonts */ private boolean antialias = true; /** * compont is not ready for a dry run until addNotify has been called. */ private boolean readyForDryRun = false; /** * Constructor */ public AntiAliastedFontedTextArea() { } /** * dry run at drawing to figure out preferred size */ private void dryRun() { if ( !readyForDryRun ) { return; } Font font = this.getFont(); FontMetrics fm = this.getFontMetrics( font ); int leading = font.getSize() + 4; int width = 0; for ( final String textLine : textLines ) { width = Math.max( width, fm.stringWidth( textLine ) ); } width += LEFT_MARGIN + RIGHT_MARGIN; int height = textLines.length * leading + TOP_MARGIN + BOTTOM_MARGIN; dimension = new Dimension( width, height ); // only available in 1.5+ // this.setMinimumSize( dimension ); // this.setPreferredSize( dimension ); // this.setMaximumSize( dimension ); this.invalidate(); } /** * does drawing, like paint. * * @param g where to paint */ private void render( Graphics2D g ) { // No need to clear the background of just the clip region // because update handles this: // g.setColor( this.getBackground() ); // g.fillRect ( r.x, r.y, r.width, r.height ); g.setColor( this.getForeground() ); Font font = this.getFont(); g.setFont( font ); int leading = font.getSize() + 4; // avoid painting outside the clipregion Rectangle r = g.getClipBounds(); int firstLine = Math.max( 0, ( r.y - TOP_MARGIN ) / leading ); int lastLine = Math.min( ( r.y + r.height - TOP_MARGIN + leading - 1 ) / leading, textLines.length - 1 ); if ( DEBUGGING ) { out.println( "render " + firstLine + " " + lastLine ); } for ( int i = firstLine; i <= lastLine; i++ ) { // x,y is bottom left corner of text g.drawString( textLines[ i ], LEFT_MARGIN, TOP_MARGIN + ( i + 1 ) * leading ); } } // end render /** * AWT calls this when Component Canvas peer is ready, So we can get at FontMetrics etc. */ public void addNotify() { super.addNotify(); readyForDryRun = true; dryRun(); } /** * Gets the maximum size of this component. * * @return a dimension object indicating this component's maximum size. * @see #getPreferredSize() */ public Dimension getMaximumSize() { return dimension; } /** * Gets the minimum size of this component. * * @return a dimension object indicating this component's minimum size. * @see #getPreferredSize() */ public Dimension getMinimumSize() { return dimension; } /** * Gets the preferred size of this component. * * @return a dimension object indicating this component's preferred size * @see #getMinimumSize() */ public Dimension getPreferredSize() { return dimension; } /** * called whenever system has a slice to render * * @param g Graphics defining where and region to paint. */ public void paint( Graphics g ) { Graphics2D g2d = ( Graphics2D ) g; if ( antialias ) { g2d.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON ); g2d.setRenderingHint( RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY ); // if wanted to smooth geometric shapes too // g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, // RenderingHints.VALUE_ANTIALIAS_ON ); } render( g2d ); } /** * Control whether fonts are antialiased. Takes extra time, but makes smoother edges. * * @param antialias true if want anti-aliasing. */ public void setAntialias( boolean antialias ) { this.antialias = antialias; } /** * set font for the entire display * * @param font font to display. Unlike AWT Label and TextArea you can display in any font. */ public void setFont( Font font ) { super.setFont( font ); dryRun(); } /** * set etext for the display * * @param textLines array of String, one per line to display. */ public void setTextLines( String[] textLines ) { this.textLines = textLines; dryRun(); } }