0N/A/*
2362N/A * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
0N/A *
0N/A * Redistribution and use in source and binary forms, with or without
0N/A * modification, are permitted provided that the following conditions
0N/A * are met:
0N/A *
0N/A * - Redistributions of source code must retain the above copyright
0N/A * notice, this list of conditions and the following disclaimer.
0N/A *
0N/A * - Redistributions in binary form must reproduce the above copyright
0N/A * notice, this list of conditions and the following disclaimer in the
0N/A * documentation and/or other materials provided with the distribution.
0N/A *
2362N/A * - Neither the name of Oracle nor the names of its
0N/A * contributors may be used to endorse or promote products derived
0N/A * from this software without specific prior written permission.
0N/A *
0N/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
0N/A * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
0N/A * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
0N/A * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
0N/A * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0N/A * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0N/A * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
0N/A * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
0N/A * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
0N/A * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0N/A * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0N/A */
0N/A
4378N/A/*
4378N/A * This source code is provided to illustrate the usage of a given feature
4378N/A * or technique and has been deliberately simplified. Additional steps
4378N/A * required for a production-quality application, such as security checks,
4378N/A * input validation and proper error handling, might not be present in
4378N/A * this sample code.
4378N/A */
4378N/A
4378N/A
0N/A
0N/Aimport java.awt.BorderLayout;
0N/Aimport java.awt.Color;
0N/Aimport java.awt.Cursor;
0N/Aimport java.awt.Dimension;
0N/Aimport java.awt.Font;
0N/Aimport java.awt.FontMetrics;
0N/Aimport java.awt.Graphics;
0N/Aimport java.awt.Graphics2D;
0N/Aimport java.awt.GraphicsConfiguration;
0N/Aimport java.awt.GraphicsEnvironment;
0N/Aimport java.awt.Point;
0N/Aimport java.awt.Rectangle;
0N/Aimport java.awt.RenderingHints;
0N/Aimport java.awt.Toolkit;
0N/Aimport java.awt.event.AdjustmentEvent;
0N/Aimport java.awt.event.AdjustmentListener;
0N/Aimport java.awt.event.ComponentAdapter;
0N/Aimport java.awt.event.ComponentEvent;
0N/Aimport java.awt.event.MouseEvent;
0N/Aimport java.awt.event.MouseListener;
0N/Aimport java.awt.event.MouseMotionListener;
0N/Aimport java.awt.font.FontRenderContext;
0N/Aimport java.awt.font.GlyphVector;
0N/Aimport java.awt.font.LineBreakMeasurer;
0N/Aimport java.awt.font.TextLayout;
0N/Aimport java.awt.geom.AffineTransform;
0N/Aimport java.awt.geom.NoninvertibleTransformException;
0N/Aimport java.awt.geom.Rectangle2D;
0N/Aimport java.awt.image.BufferedImage;
0N/Aimport java.awt.print.PageFormat;
0N/Aimport java.awt.print.Printable;
0N/Aimport java.awt.print.PrinterJob;
0N/Aimport java.io.BufferedOutputStream;
0N/Aimport java.io.FileOutputStream;
0N/Aimport java.text.AttributedString;
0N/Aimport java.util.EnumSet;
0N/Aimport java.util.Vector;
0N/A
0N/Aimport javax.imageio.*;
0N/Aimport javax.swing.*;
0N/A
0N/Aimport static java.awt.RenderingHints.*;
0N/A
0N/A/**
0N/A * FontPanel.java
0N/A *
0N/A * @author Shinsuke Fukuda
0N/A * @author Ankit Patel [Conversion to Swing - 01/07/30]
0N/A */
0N/A
0N/A/// This panel is combination of the text drawing area of Font2DTest
0N/A/// and the custom controlled scroll bar
0N/A
0N/Apublic final class FontPanel extends JPanel implements AdjustmentListener {
0N/A
0N/A /// Drawing Option Constants
0N/A private final String STYLES[] =
0N/A { "plain", "bold", "italic", "bold italic" };
0N/A
0N/A private final int NONE = 0;
0N/A private final int SCALE = 1;
0N/A private final int SHEAR = 2;
0N/A private final int ROTATE = 3;
0N/A private final String TRANSFORMS[] =
0N/A { "with no transforms", "with scaling", "with Shearing", "with rotation" };
0N/A
0N/A private final int DRAW_STRING = 0;
0N/A private final int DRAW_CHARS = 1;
0N/A private final int DRAW_BYTES = 2;
0N/A private final int DRAW_GLYPHV = 3;
0N/A private final int TL_DRAW = 4;
0N/A private final int GV_OUTLINE = 5;
0N/A private final int TL_OUTLINE = 6;
0N/A private final String METHODS[] = {
0N/A "drawString", "drawChars", "drawBytes", "drawGlyphVector",
0N/A "TextLayout.draw", "GlyphVector.getOutline", "TextLayout.getOutline" };
0N/A
0N/A public final int RANGE_TEXT = 0;
0N/A public final int ALL_GLYPHS = 1;
0N/A public final int USER_TEXT = 2;
0N/A public final int FILE_TEXT = 3;
0N/A private final String MS_OPENING[] =
0N/A { " Unicode ", " Glyph Code ", " lines ", " lines " };
0N/A private final String MS_CLOSING[] =
0N/A { "", "", " of User Text ", " of LineBreakMeasurer-reformatted Text " };
0N/A
0N/A /// General Graphics Variable
0N/A private final JScrollBar verticalBar;
0N/A private final FontCanvas fc;
0N/A private boolean updateBackBuffer = true;
0N/A private boolean updateFontMetrics = true;
0N/A private boolean updateFont = true;
0N/A private boolean force16Cols = false;
0N/A public boolean showingError = false;
0N/A private int g2Transform = NONE; /// ABP
0N/A
0N/A /// Printing constants and variables
0N/A public final int ONE_PAGE = 0;
0N/A public final int CUR_RANGE = 1;
0N/A public final int ALL_TEXT = 2;
0N/A private int printMode = ONE_PAGE;
0N/A private PageFormat page = null;
0N/A private PrinterJob printer = null;
0N/A
0N/A /// Text drawing variables
0N/A private String fontName = "Dialog";
0N/A private float fontSize = 12;
0N/A private int fontStyle = Font.PLAIN;
0N/A private int fontTransform = NONE;
0N/A private Font testFont = null;
0N/A private Object antiAliasType = VALUE_TEXT_ANTIALIAS_DEFAULT;
0N/A private Object fractionalMetricsType = VALUE_FRACTIONALMETRICS_DEFAULT;
0N/A private Object lcdContrast = getDefaultLCDContrast();
0N/A private int drawMethod = DRAW_STRING;
0N/A private int textToUse = RANGE_TEXT;
0N/A private String userText[] = null;
0N/A private String fileText[] = null;
0N/A private int drawRange[] = { 0x0000, 0x007f };
0N/A private String fontInfos[] = new String[2];
0N/A private boolean showGrid = true;
0N/A
0N/A /// Parent Font2DTest panel
0N/A private final Font2DTest f2dt;
0N/A private final JFrame parent;
0N/A
0N/A public FontPanel( Font2DTest demo, JFrame f ) {
0N/A f2dt = demo;
0N/A parent = f;
0N/A
0N/A verticalBar = new JScrollBar ( JScrollBar.VERTICAL );
0N/A fc = new FontCanvas();
0N/A
0N/A this.setLayout( new BorderLayout() );
0N/A this.add( "Center", fc );
0N/A this.add( "East", verticalBar );
0N/A
0N/A verticalBar.addAdjustmentListener( this );
0N/A this.addComponentListener( new ComponentAdapter() {
0N/A public void componentResized( ComponentEvent e ) {
0N/A updateBackBuffer = true;
0N/A updateFontMetrics = true;
0N/A }
0N/A });
0N/A
0N/A /// Initialize font and its infos
0N/A testFont = new Font(fontName, fontStyle, (int)fontSize);
0N/A if ((float)((int)fontSize) != fontSize) {
0N/A testFont = testFont.deriveFont(fontSize);
0N/A }
0N/A updateFontInfo();
0N/A }
0N/A
0N/A public Dimension getPreferredSize() {
0N/A return new Dimension(600, 200);
0N/A }
0N/A
0N/A /// Functions called by the main programs to set the various parameters
0N/A
0N/A public void setTransformG2( int transform ) {
0N/A g2Transform = transform;
0N/A updateBackBuffer = true;
0N/A updateFontMetrics = true;
0N/A fc.repaint();
0N/A }
0N/A
0N/A /// convenience fcn to create AffineTransform of appropriate type
0N/A private AffineTransform getAffineTransform( int transform ) {
0N/A /// ABP
0N/A AffineTransform at = new AffineTransform();
0N/A switch ( transform )
0N/A {
0N/A case SCALE:
0N/A at.setToScale( 1.5f, 1.5f ); break;
0N/A case ROTATE:
0N/A at.setToRotation( Math.PI / 6 ); break;
0N/A case SHEAR:
0N/A at.setToShear( 0.4f, 0 ); break;
0N/A case NONE:
0N/A break;
0N/A default:
0N/A //System.err.println( "Illegal G2 Transform Arg: " + transform);
0N/A break;
0N/A }
0N/A
0N/A return at;
0N/A }
0N/A
0N/A public void setFontParams(Object obj, float size,
0N/A int style, int transform) {
0N/A setFontParams( (String)obj, size, style, transform );
0N/A }
0N/A
0N/A public void setFontParams(String name, float size,
0N/A int style, int transform) {
0N/A boolean fontModified = false;
0N/A if ( !name.equals( fontName ) || style != fontStyle )
0N/A fontModified = true;
0N/A
0N/A fontName = name;
0N/A fontSize = size;
0N/A fontStyle = style;
0N/A fontTransform = transform;
0N/A
0N/A /// Recreate the font as specified
0N/A testFont = new Font(fontName, fontStyle, (int)fontSize);
0N/A if ((float)((int)fontSize) != fontSize) {
0N/A testFont = testFont.deriveFont(fontSize);
0N/A }
0N/A
0N/A if ( fontTransform != NONE ) {
0N/A AffineTransform at = getAffineTransform( fontTransform );
0N/A testFont = testFont.deriveFont( at );
0N/A }
0N/A updateBackBuffer = true;
0N/A updateFontMetrics = true;
0N/A fc.repaint();
0N/A if ( fontModified ) {
0N/A /// Tell main panel to update the font info
0N/A updateFontInfo();
0N/A f2dt.fireUpdateFontInfo();
0N/A }
0N/A }
0N/A
0N/A public void setRenderingHints( Object aa, Object fm, Object contrast) {
0N/A antiAliasType = ((AAValues)aa).getHint();
0N/A fractionalMetricsType = ((FMValues)fm).getHint();
0N/A lcdContrast = contrast;
0N/A updateBackBuffer = true;
0N/A updateFontMetrics = true;
0N/A fc.repaint();
0N/A }
0N/A
0N/A public void setDrawMethod( int i ) {
0N/A drawMethod = i;
0N/A updateBackBuffer = true;
0N/A fc.repaint();
0N/A }
0N/A
0N/A public void setTextToDraw( int i, int range[],
0N/A String textSet[], String fileData[] ) {
0N/A textToUse = i;
0N/A
0N/A if ( textToUse == RANGE_TEXT )
0N/A drawRange = range;
0N/A else if ( textToUse == ALL_GLYPHS )
0N/A drawMethod = DRAW_GLYPHV;
0N/A else if ( textToUse == USER_TEXT )
0N/A userText = textSet;
0N/A else if ( textToUse == FILE_TEXT ) {
0N/A fileText = fileData;
0N/A drawMethod = TL_DRAW;
0N/A }
0N/A
0N/A updateBackBuffer = true;
0N/A updateFontMetrics = true;
0N/A fc.repaint();
0N/A updateFontInfo();
0N/A }
0N/A
0N/A public void setGridDisplay( boolean b ) {
0N/A showGrid = b;
0N/A updateBackBuffer = true;
0N/A fc.repaint();
0N/A }
0N/A
0N/A public void setForce16Columns( boolean b ) {
0N/A force16Cols = b;
0N/A updateBackBuffer = true;
0N/A updateFontMetrics = true;
0N/A fc.repaint();
0N/A }
0N/A
0N/A /// Prints out the text display area
0N/A public void doPrint( int i ) {
0N/A if ( printer == null ) {
0N/A printer = PrinterJob.getPrinterJob();
0N/A page = printer.defaultPage();
0N/A }
0N/A printMode = i;
0N/A printer.setPrintable( fc, page );
0N/A
0N/A if ( printer.printDialog() ) {
0N/A try {
0N/A printer.print();
0N/A }
0N/A catch ( Exception e ) {
0N/A f2dt.fireChangeStatus( "ERROR: Printing Failed; See Stack Trace", true );
0N/A }
0N/A }
0N/A }
0N/A
0N/A /// Displays the page setup dialog and updates PageFormat info
0N/A public void doPageSetup() {
0N/A if ( printer == null ) {
0N/A printer = PrinterJob.getPrinterJob();
0N/A page = printer.defaultPage();
0N/A }
0N/A page = printer.pageDialog( page );
0N/A }
0N/A
0N/A /// Obtains the information about selected font
0N/A private void updateFontInfo() {
0N/A int numGlyphs = 0, numCharsInRange = drawRange[1] - drawRange[0] + 1;
0N/A fontInfos[0] = "Font Face Name: " + testFont.getFontName();
0N/A fontInfos[1] = "Glyphs in This Range: ";
0N/A
0N/A if ( textToUse == RANGE_TEXT ) {
0N/A for ( int i = drawRange[0]; i < drawRange[1]; i++ )
0N/A if ( testFont.canDisplay( i ))
0N/A numGlyphs++;
0N/A fontInfos[1] = fontInfos[1] + numGlyphs + " / " + numCharsInRange;
0N/A }
0N/A else
0N/A fontInfos[1] = null;
0N/A }
0N/A
0N/A /// Accessor for the font information
0N/A public String[] getFontInfo() {
0N/A return fontInfos;
0N/A }
0N/A
0N/A /// Collects the currectly set options and returns them as string
0N/A public String getCurrentOptions() {
0N/A /// Create a new String to store the options
0N/A /// The array will contain all 8 setting (font name, size...) and
0N/A /// character range or user text data used (no file text data)
0N/A int userTextSize = 0;
0N/A String options;
0N/A
0N/A options = ( fontName + "\n" + fontSize + "\n" + fontStyle + "\n" +
0N/A fontTransform + "\n" + g2Transform + "\n"+
0N/A textToUse + "\n" + drawMethod + "\n" +
0N/A AAValues.getHintVal(antiAliasType) + "\n" +
0N/A FMValues.getHintVal(fractionalMetricsType) + "\n" +
0N/A lcdContrast + "\n");
0N/A if ( textToUse == USER_TEXT )
0N/A for ( int i = 0; i < userText.length; i++ )
0N/A options += ( userText[i] + "\n" );
0N/A
0N/A return options;
0N/A }
0N/A
0N/A /// Reload all options and refreshes the canvas
0N/A public void loadOptions( boolean grid, boolean force16, int start, int end,
0N/A String name, float size, int style,
0N/A int transform, int g2transform,
0N/A int text, int method, int aa, int fm,
0N/A int contrast, String user[] ) {
0N/A int range[] = { start, end };
0N/A
0N/A /// Since repaint call has a low priority, these functions will finish
0N/A /// before the actual repainting is done
0N/A setGridDisplay( grid );
0N/A setForce16Columns( force16 );
0N/A // previous call to readTextFile has already set the text to draw
0N/A if (textToUse != FILE_TEXT) {
0N/A setTextToDraw( text, range, user, null );
0N/A }
0N/A setFontParams( name, size, style, transform );
0N/A setTransformG2( g2transform ); // ABP
0N/A setDrawMethod( method );
0N/A setRenderingHints(AAValues.getValue(aa), FMValues.getValue(fm),
0N/A new Integer(contrast));
0N/A }
0N/A
0N/A /// Writes the current screen to PNG file
0N/A public void doSavePNG( String fileName ) {
0N/A fc.writePNG( fileName );
0N/A }
0N/A
0N/A /// When scrolled using the scroll bar, update the backbuffer
0N/A public void adjustmentValueChanged( AdjustmentEvent e ) {
0N/A updateBackBuffer = true;
0N/A fc.repaint();
0N/A }
0N/A
0N/A public void paintComponent( Graphics g ) {
0N/A // Windows does not repaint correctly, after
0N/A // a zoom. Thus, we need to force the canvas
0N/A // to repaint, but only once. After the first repaint,
0N/A // everything stabilizes. [ABP]
0N/A fc.repaint();
0N/A }
0N/A
0N/A /// Inner class definition...
0N/A
0N/A /// Inner panel that holds the actual drawing area and its routines
0N/A private class FontCanvas extends JPanel implements MouseListener, MouseMotionListener, Printable {
0N/A
0N/A /// Number of characters that will fit across and down this canvas
0N/A private int numCharAcross, numCharDown;
0N/A
0N/A /// First and last character/line that will be drawn
0N/A /// Limit is the end of range/text where no more draw will be done
0N/A private int drawStart, drawEnd, drawLimit;
0N/A
0N/A /// FontMetrics variables
0N/A /// Here, gridWidth is equivalent to maxAdvance (slightly bigger though)
0N/A /// and gridHeight is equivalent to lineHeight
0N/A private int maxAscent, maxDescent, gridWidth = 0, gridHeight = 0;
0N/A
0N/A /// Offset from the top left edge of the canvas where the draw will start
0N/A private int canvasInset_X = 5, canvasInset_Y = 5;
0N/A
0N/A /// Offscreen buffer of this canvas
0N/A private BufferedImage backBuffer = null;
0N/A
0N/A /// LineBreak'ed TextLayout vector
0N/A private Vector lineBreakTLs = null;
0N/A
0N/A /// Whether the current draw command requested is for printing
0N/A private boolean isPrinting = false;
0N/A
0N/A /// Other printing infos
0N/A private int lastPage, printPageNumber, currentlyShownChar = 0;
0N/A private final int PR_OFFSET = 10;
0N/A private final int PR_TITLE_LINEHEIGHT = 30;
0N/A
0N/A /// Information about zooming (used with range text draw)
0N/A private final JWindow zoomWindow;
0N/A private BufferedImage zoomImage = null;
0N/A private int mouseOverCharX = -1, mouseOverCharY = -1;
0N/A private int currMouseOverChar = -1, prevZoomChar = -1;
0N/A private float ZOOM = 2.0f;
0N/A private boolean nowZooming = false;
0N/A private boolean firstTime = true;
0N/A// ABP
0N/A
0N/A /// Status bar message backup
0N/A private String backupStatusString = null;
0N/A
0N/A /// Error constants
0N/A private final String ERRORS[] = {
0N/A "ERROR: drawBytes cannot handle characters beyond 0x00FF. Select different range or draw methods.",
0N/A "ERROR: Cannot fit text with the current font size. Resize the window or use smaller font size.",
0N/A "ERROR: Cannot print with the current font size. Use smaller font size.",
0N/A };
0N/A
0N/A private final int DRAW_BYTES_ERROR = 0;
0N/A private final int CANT_FIT_DRAW = 1;
0N/A private final int CANT_FIT_PRINT = 2;
0N/A
0N/A /// Other variables
0N/A private final Cursor blankCursor;
0N/A
0N/A public FontCanvas() {
0N/A this.addMouseListener( this );
0N/A this.addMouseMotionListener( this );
0N/A this.setForeground( Color.black );
0N/A this.setBackground( Color.white );
0N/A
0N/A /// Creates an invisble pointer by giving it bogus image
0N/A /// Possibly find a workaround for this...
0N/A Toolkit tk = Toolkit.getDefaultToolkit();
0N/A byte bogus[] = { (byte) 0 };
0N/A blankCursor =
0N/A tk.createCustomCursor( tk.createImage( bogus ), new Point(0, 0), "" );
0N/A
0N/A zoomWindow = new JWindow( parent ) {
0N/A public void paint( Graphics g ) {
0N/A g.drawImage( zoomImage, 0, 0, zoomWindow );
0N/A }
0N/A };
0N/A zoomWindow.setCursor( blankCursor );
0N/A zoomWindow.pack();
0N/A }
0N/A
0N/A public boolean firstTime() { return firstTime; }
0N/A public void refresh() {
0N/A firstTime = false;
0N/A updateBackBuffer = true;
0N/A repaint();
0N/A }
0N/A
0N/A /// Sets the font, hints, according to the set parameters
0N/A private void setParams( Graphics2D g2 ) {
0N/A g2.setFont( testFont );
0N/A g2.setRenderingHint(KEY_TEXT_ANTIALIASING, antiAliasType);
0N/A g2.setRenderingHint(KEY_FRACTIONALMETRICS, fractionalMetricsType);
0N/A g2.setRenderingHint(KEY_TEXT_LCD_CONTRAST, lcdContrast);
0N/A /* I am preserving a somewhat dubious behaviour of this program.
0N/A * Outline text would be drawn anti-aliased by setting the
0N/A * graphics anti-aliasing hint if the text anti-aliasing hint
0N/A * was set. The dubious element here is that people simply
0N/A * using this program may think this is built-in behaviour
0N/A * but its not - at least not when the app explictly draws
0N/A * outline text.
0N/A * This becomes more dubious in cases such as "GASP" where the
0N/A * size at which text is AA'ed is not something you can easily
0N/A * calculate, so mimicing that behaviour isn't going to be easy.
0N/A * So I precisely preserve the behaviour : this is done only
0N/A * if the AA value is "ON". Its not applied in the other cases.
0N/A */
0N/A if (antiAliasType == VALUE_TEXT_ANTIALIAS_ON &&
0N/A (drawMethod == TL_OUTLINE || drawMethod == GV_OUTLINE)) {
0N/A g2.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON);
0N/A } else {
0N/A g2.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_OFF);
0N/A }
0N/A }
0N/A
0N/A /// Draws the grid (Used for unicode/glyph range drawing)
0N/A private void drawGrid( Graphics2D g2 ) {
0N/A int totalGridWidth = numCharAcross * gridWidth;
0N/A int totalGridHeight = numCharDown * gridHeight;
0N/A
0N/A g2.setColor( Color.black );
0N/A for ( int i = 0; i < numCharDown + 1; i++ )
0N/A g2.drawLine( canvasInset_X, i * gridHeight + canvasInset_Y,
0N/A canvasInset_X + totalGridWidth, i * gridHeight + canvasInset_Y );
0N/A for ( int i = 0; i < numCharAcross + 1; i++ )
0N/A g2.drawLine( i * gridWidth + canvasInset_X, canvasInset_Y,
0N/A i * gridWidth + canvasInset_X, canvasInset_Y + totalGridHeight );
0N/A }
0N/A
0N/A /// Draws one character at time onto the canvas according to
0N/A /// the method requested (Used for RANGE_TEXT and ALL_GLYPHS)
0N/A public void modeSpecificDrawChar( Graphics2D g2, int charCode,
0N/A int baseX, int baseY ) {
0N/A GlyphVector gv;
0N/A int oneGlyph[] = { charCode };
0N/A char charArray[] = Character.toChars( charCode );
0N/A
0N/A FontRenderContext frc = g2.getFontRenderContext();
0N/A AffineTransform oldTX = g2.getTransform();
0N/A
0N/A /// Create GlyphVector to measure the exact visual advance
0N/A /// Using that number, adjust the position of the character drawn
0N/A if ( textToUse == ALL_GLYPHS )
0N/A gv = testFont.createGlyphVector( frc, oneGlyph );
0N/A else
0N/A gv = testFont.createGlyphVector( frc, charArray );
0N/A Rectangle2D r2d2 = gv.getPixelBounds(frc, 0, 0);
0N/A int shiftedX = baseX;
0N/A // getPixelBounds returns a result in device space.
0N/A // we need to convert back to user space to be able to
0N/A // calculate the shift as baseX is in user space.
0N/A try {
0N/A double pt[] = new double[4];
0N/A pt[0] = r2d2.getX();
0N/A pt[1] = r2d2.getY();
0N/A pt[2] = r2d2.getX()+r2d2.getWidth();
0N/A pt[3] = r2d2.getY()+r2d2.getHeight();
0N/A oldTX.inverseTransform(pt,0,pt,0,2);
0N/A shiftedX = baseX - (int) ( pt[2] / 2 + pt[0] );
0N/A } catch (NoninvertibleTransformException e) {
0N/A }
0N/A
0N/A /// ABP - keep track of old tform, restore it later
0N/A
0N/A g2.translate( shiftedX, baseY );
0N/A g2.transform( getAffineTransform( g2Transform ) );
0N/A
0N/A if ( textToUse == ALL_GLYPHS )
0N/A g2.drawGlyphVector( gv, 0f, 0f );
0N/A else {
0N/A if ( testFont.canDisplay( charCode ))
0N/A g2.setColor( Color.black );
0N/A else {
0N/A g2.setColor( Color.lightGray );
0N/A }
0N/A
0N/A switch ( drawMethod ) {
0N/A case DRAW_STRING:
0N/A g2.drawString( new String( charArray ), 0, 0 );
0N/A break;
0N/A case DRAW_CHARS:
0N/A g2.drawChars( charArray, 0, 1, 0, 0 );
0N/A break;
0N/A case DRAW_BYTES:
0N/A if ( charCode > 0xff )
0N/A throw new CannotDrawException( DRAW_BYTES_ERROR );
0N/A byte oneByte[] = { (byte) charCode };
0N/A g2.drawBytes( oneByte, 0, 1, 0, 0 );
0N/A break;
0N/A case DRAW_GLYPHV:
0N/A g2.drawGlyphVector( gv, 0f, 0f );
0N/A break;
0N/A case TL_DRAW:
0N/A TextLayout tl = new TextLayout( new String( charArray ), testFont, frc );
0N/A tl.draw( g2, 0f, 0f );
0N/A break;
0N/A case GV_OUTLINE:
0N/A r2d2 = gv.getVisualBounds();
0N/A shiftedX = baseX - (int) ( r2d2.getWidth() / 2 + r2d2.getX() );
0N/A g2.draw( gv.getOutline( 0f, 0f ));
0N/A break;
0N/A case TL_OUTLINE:
0N/A r2d2 = gv.getVisualBounds();
0N/A shiftedX = baseX - (int) ( r2d2.getWidth() / 2 + r2d2.getX() );
0N/A TextLayout tlo =
0N/A new TextLayout( new String( charArray ), testFont,
0N/A g2.getFontRenderContext() );
0N/A g2.draw( tlo.getOutline( null ));
0N/A }
0N/A }
0N/A
0N/A /// ABP - restore old tform
0N/A g2.setTransform ( oldTX );
0N/A }
0N/A
0N/A /// Draws one line of text at given position
0N/A private void modeSpecificDrawLine( Graphics2D g2, String line,
0N/A int baseX, int baseY ) {
0N/A /// ABP - keep track of old tform, restore it later
0N/A AffineTransform oldTx = null;
0N/A oldTx = g2.getTransform();
0N/A g2.translate( baseX, baseY );
0N/A g2.transform( getAffineTransform( g2Transform ) );
0N/A
0N/A switch ( drawMethod ) {
0N/A case DRAW_STRING:
0N/A g2.drawString( line, 0, 0 );
0N/A break;
0N/A case DRAW_CHARS:
0N/A g2.drawChars( line.toCharArray(), 0, line.length(), 0, 0 );
0N/A break;
0N/A case DRAW_BYTES:
0N/A try {
0N/A byte lineBytes[] = line.getBytes( "ISO-8859-1" );
0N/A g2.drawBytes( lineBytes, 0, lineBytes.length, 0, 0 );
0N/A }
0N/A catch ( Exception e ) {
0N/A e.printStackTrace();
0N/A }
0N/A break;
0N/A case DRAW_GLYPHV:
0N/A GlyphVector gv =
0N/A testFont.createGlyphVector( g2.getFontRenderContext(), line );
0N/A g2.drawGlyphVector( gv, (float) 0, (float) 0 );
0N/A break;
0N/A case TL_DRAW:
0N/A TextLayout tl = new TextLayout( line, testFont,
0N/A g2.getFontRenderContext() );
0N/A tl.draw( g2, (float) 0, (float) 0 );
0N/A break;
0N/A case GV_OUTLINE:
0N/A GlyphVector gvo =
0N/A testFont.createGlyphVector( g2.getFontRenderContext(), line );
0N/A g2.draw( gvo.getOutline( (float) 0, (float) 0 ));
0N/A break;
0N/A case TL_OUTLINE:
0N/A TextLayout tlo =
0N/A new TextLayout( line, testFont,
0N/A g2.getFontRenderContext() );
0N/A AffineTransform at = new AffineTransform();
0N/A g2.draw( tlo.getOutline( at ));
0N/A }
0N/A
0N/A /// ABP - restore old tform
0N/A g2.setTransform ( oldTx );
0N/A
0N/A }
0N/A
0N/A /// Draws one line of text at given position
0N/A private void tlDrawLine( Graphics2D g2, TextLayout tl,
0N/A float baseX, float baseY ) {
0N/A /// ABP - keep track of old tform, restore it later
0N/A AffineTransform oldTx = null;
0N/A oldTx = g2.getTransform();
0N/A g2.translate( baseX, baseY );
0N/A g2.transform( getAffineTransform( g2Transform ) );
0N/A
0N/A tl.draw( g2, (float) 0, (float) 0 );
0N/A
0N/A /// ABP - restore old tform
0N/A g2.setTransform ( oldTx );
0N/A
0N/A }
0N/A
0N/A
0N/A /// If textToUse is set to range drawing, then convert
0N/A /// int to hex string and prepends 0s to make it length 4
0N/A /// Otherwise line number was fed; simply return number + 1 converted to String
0N/A /// (This is because first line is 1, not 0)
0N/A private String modeSpecificNumStr( int i ) {
0N/A if ( textToUse == USER_TEXT || textToUse == FILE_TEXT )
0N/A return String.valueOf( i + 1 );
0N/A
0N/A StringBuffer s = new StringBuffer( Integer.toHexString( i ));
0N/A while ( s.length() < 4 )
0N/A s.insert( 0, "0" );
0N/A return s.toString().toUpperCase();
0N/A }
0N/A
0N/A /// Resets the scrollbar to display correct range of text currently on screen
0N/A /// (This scrollbar is not part of a "ScrollPane". It merely simulates its effect by
0N/A /// indicating the necessary area to be drawn within the panel.
0N/A /// By doing this, it prevents creating gigantic panel when large text range,
0N/A /// i.e. CJK Ideographs, is requested)
0N/A private void resetScrollbar( int oldValue ) {
0N/A int totalNumRows = 1, numCharToDisplay;
0N/A if ( textToUse == RANGE_TEXT || textToUse == ALL_GLYPHS ) {
0N/A if ( textToUse == RANGE_TEXT )
0N/A numCharToDisplay = drawRange[1] - drawRange[0];
0N/A else /// textToUse == ALL_GLYPHS
0N/A numCharToDisplay = testFont.getNumGlyphs();
0N/A
0N/A totalNumRows = numCharToDisplay / numCharAcross;
0N/A if ( numCharToDisplay % numCharAcross != 0 )
0N/A totalNumRows++;
0N/A if ( oldValue / numCharAcross > totalNumRows )
0N/A oldValue = 0;
0N/A
0N/A verticalBar.setValues( oldValue / numCharAcross,
0N/A numCharDown, 0, totalNumRows );
0N/A }
0N/A else {
0N/A if ( textToUse == USER_TEXT )
0N/A totalNumRows = userText.length;
0N/A else /// textToUse == FILE_TEXT;
0N/A totalNumRows = lineBreakTLs.size();
0N/A verticalBar.setValues( oldValue, numCharDown, 0, totalNumRows );
0N/A }
0N/A if ( totalNumRows <= numCharDown && drawStart == 0) {
0N/A verticalBar.setEnabled( false );
0N/A }
0N/A else {
0N/A verticalBar.setEnabled( true );
0N/A }
0N/A }
0N/A
0N/A /// Calculates the font's metrics that will be used for draw
0N/A private void calcFontMetrics( Graphics2D g2d, int w, int h ) {
0N/A FontMetrics fm;
0N/A Graphics2D g2 = (Graphics2D)g2d.create();
0N/A
0N/A /// ABP
0N/A if ( g2Transform != NONE && textToUse != FILE_TEXT ) {
0N/A g2.setFont( g2.getFont().deriveFont( getAffineTransform( g2Transform )) );
0N/A fm = g2.getFontMetrics();
0N/A }
0N/A else {
0N/A fm = g2.getFontMetrics();
0N/A }
0N/A
0N/A maxAscent = fm.getMaxAscent();
0N/A maxDescent = fm.getMaxDescent();
0N/A if (maxAscent == 0) maxAscent = 10;
0N/A if (maxDescent == 0) maxDescent = 5;
0N/A if ( textToUse == RANGE_TEXT || textToUse == ALL_GLYPHS ) {
0N/A /// Give slight extra room for each character
0N/A maxAscent += 3;
0N/A maxDescent += 3;
0N/A gridWidth = fm.getMaxAdvance() + 6;
0N/A gridHeight = maxAscent + maxDescent;
0N/A if ( force16Cols )
0N/A numCharAcross = 16;
0N/A else
0N/A numCharAcross = ( w - 10 ) / gridWidth;
0N/A numCharDown = ( h - 10 ) / gridHeight;
0N/A
0N/A canvasInset_X = ( w - numCharAcross * gridWidth ) / 2;
0N/A canvasInset_Y = ( h - numCharDown * gridHeight ) / 2;
0N/A if ( numCharDown == 0 || numCharAcross == 0 )
0N/A throw new CannotDrawException( isPrinting ? CANT_FIT_PRINT : CANT_FIT_DRAW );
0N/A
0N/A if ( !isPrinting )
0N/A resetScrollbar( verticalBar.getValue() * numCharAcross );
0N/A }
0N/A else {
0N/A maxDescent += fm.getLeading();
0N/A canvasInset_X = 5;
0N/A canvasInset_Y = 5;
0N/A /// gridWidth and numCharAcross will not be used in this mode...
0N/A gridHeight = maxAscent + maxDescent;
0N/A numCharDown = ( h - canvasInset_Y * 2 ) / gridHeight;
0N/A
0N/A if ( numCharDown == 0 )
0N/A throw new CannotDrawException( isPrinting ? CANT_FIT_PRINT : CANT_FIT_DRAW );
0N/A /// If this is text loaded from file, prepares the LineBreak'ed
0N/A /// text layout at this point
0N/A if ( textToUse == FILE_TEXT ) {
0N/A if ( !isPrinting )
0N/A f2dt.fireChangeStatus( "LineBreaking Text... Please Wait", false );
0N/A lineBreakTLs = new Vector();
0N/A for ( int i = 0; i < fileText.length; i++ ) {
0N/A AttributedString as =
0N/A new AttributedString( fileText[i], g2.getFont().getAttributes() );
0N/A
0N/A LineBreakMeasurer lbm =
0N/A new LineBreakMeasurer( as.getIterator(), g2.getFontRenderContext() );
0N/A
0N/A while ( lbm.getPosition() < fileText[i].length() )
0N/A lineBreakTLs.add( lbm.nextLayout( (float) w ));
0N/A
0N/A }
0N/A }
0N/A if ( !isPrinting )
0N/A resetScrollbar( verticalBar.getValue() );
0N/A }
0N/A }
0N/A
0N/A /// Calculates the amount of text that will be displayed on screen
0N/A private void calcTextRange() {
0N/A String displaying = null;
0N/A
0N/A if ( textToUse == RANGE_TEXT || textToUse == ALL_GLYPHS ) {
0N/A if ( isPrinting )
0N/A if ( printMode == ONE_PAGE )
0N/A drawStart = currentlyShownChar;
0N/A else /// printMode == CUR_RANGE
0N/A drawStart = numCharAcross * numCharDown * printPageNumber;
0N/A else
0N/A drawStart = verticalBar.getValue() * numCharAcross;
0N/A if ( textToUse == RANGE_TEXT ) {
0N/A drawStart += drawRange[0];
0N/A drawLimit = drawRange[1];
0N/A }
0N/A else
0N/A drawLimit = testFont.getNumGlyphs();
0N/A drawEnd = drawStart + numCharAcross * numCharDown - 1;
0N/A
0N/A if ( drawEnd >= drawLimit )
0N/A drawEnd = drawLimit;
0N/A }
0N/A else {
0N/A if ( isPrinting )
0N/A if ( printMode == ONE_PAGE )
0N/A drawStart = currentlyShownChar;
0N/A else /// printMode == ALL_TEXT
0N/A drawStart = numCharDown * printPageNumber;
0N/A else {
0N/A drawStart = verticalBar.getValue();
0N/A }
0N/A
0N/A drawEnd = drawStart + numCharDown - 1;
0N/A
0N/A if ( textToUse == USER_TEXT )
0N/A drawLimit = userText.length - 1;
0N/A else
0N/A drawLimit = lineBreakTLs.size() - 1;
0N/A
0N/A if ( drawEnd >= drawLimit )
0N/A drawEnd = drawLimit;
0N/A }
0N/A
0N/A // ABP
0N/A if ( drawStart > drawEnd ) {
0N/A drawStart = 0;
0N/A verticalBar.setValue(drawStart);
0N/A }
0N/A
0N/A
0N/A /// Change the status bar if not printing...
0N/A if ( !isPrinting ) {
0N/A backupStatusString = ( "Displaying" + MS_OPENING[textToUse] +
0N/A modeSpecificNumStr( drawStart ) + " to " +
0N/A modeSpecificNumStr( drawEnd ) +
0N/A MS_CLOSING[textToUse] );
0N/A f2dt.fireChangeStatus( backupStatusString, false );
0N/A }
0N/A }
0N/A
0N/A /// Draws text according to the parameters set by Font2DTest GUI
0N/A private void drawText( Graphics g, int w, int h ) {
0N/A Graphics2D g2;
0N/A
0N/A /// Create back buffer when not printing, and its Graphics2D
0N/A /// Then set drawing parameters for that Graphics2D object
0N/A if ( isPrinting )
0N/A g2 = (Graphics2D) g;
0N/A else {
0N/A backBuffer = (BufferedImage) this.createImage( w, h );
0N/A g2 = backBuffer.createGraphics();
0N/A g2.setColor(Color.white);
0N/A g2.fillRect(0, 0, w, h);
0N/A g2.setColor(Color.black);
0N/A }
0N/A
0N/A /// sets font, RenderingHints.
0N/A setParams( g2 );
0N/A
0N/A /// If flag is set, recalculate fontMetrics and reset the scrollbar
0N/A if ( updateFontMetrics || isPrinting ) {
0N/A /// NOTE: re-calculates in case G2 transform
0N/A /// is something other than NONE
0N/A calcFontMetrics( g2, w, h );
0N/A updateFontMetrics = false;
0N/A }
0N/A /// Calculate the amount of text that can be drawn...
0N/A calcTextRange();
0N/A
0N/A /// Draw according to the set "Text to Use" mode
0N/A if ( textToUse == RANGE_TEXT || textToUse == ALL_GLYPHS ) {
0N/A int charToDraw = drawStart;
0N/A if ( showGrid )
0N/A drawGrid( g2 );
0N/A if ( !isPrinting )
0N/A g.drawImage( backBuffer, 0, 0, this );
0N/A
0N/A for ( int i = 0; i < numCharDown && charToDraw <= drawEnd; i++ ) {
0N/A for ( int j = 0; j < numCharAcross && charToDraw <= drawEnd; j++, charToDraw++ ) {
0N/A int gridLocX = j * gridWidth + canvasInset_X;
0N/A int gridLocY = i * gridHeight + canvasInset_Y;
0N/A
0N/A modeSpecificDrawChar( g2, charToDraw,
0N/A gridLocX + gridWidth / 2,
0N/A gridLocY + maxAscent );
0N/A //if ( !isPrinting ) {
0N/A // g.setClip( gridLocX, gridLocY, gridWidth + 1, gridHeight + 1 );
0N/A // g.drawImage( backBuffer, 0, 0, this );
0N/A //}
0N/A
0N/A }
0N/A }
0N/A }
0N/A else if ( textToUse == USER_TEXT ) {
0N/A g2.drawRect( 0, 0, w - 1, h - 1 );
0N/A if ( !isPrinting )
0N/A g.drawImage( backBuffer, 0, 0, this );
0N/A
0N/A for ( int i = drawStart; i <= drawEnd; i++ ) {
0N/A int lineStartX = canvasInset_Y;
0N/A int lineStartY = ( i - drawStart ) * gridHeight + maxAscent;
0N/A modeSpecificDrawLine( g2, userText[i], lineStartX, lineStartY );
0N/A }
0N/A }
0N/A else {
0N/A float xPos, yPos = (float) canvasInset_Y;
0N/A g2.drawRect( 0, 0, w - 1, h - 1 );
0N/A if ( !isPrinting )
0N/A g.drawImage( backBuffer, 0, 0, this );
0N/A
0N/A for ( int i = drawStart; i <= drawEnd; i++ ) {
0N/A TextLayout oneLine = (TextLayout) lineBreakTLs.elementAt( i );
0N/A xPos =
0N/A oneLine.isLeftToRight() ?
0N/A canvasInset_X : ( (float) w - oneLine.getAdvance() - canvasInset_X );
0N/A
0N/A float fmData[] = {0, oneLine.getAscent(), 0, oneLine.getDescent(), 0, oneLine.getLeading()};
0N/A if (g2Transform != NONE) {
0N/A AffineTransform at = getAffineTransform(g2Transform);
0N/A at.transform( fmData, 0, fmData, 0, 3);
0N/A }
0N/A //yPos += oneLine.getAscent();
0N/A yPos += fmData[1]; // ascent
0N/A //oneLine.draw( g2, xPos, yPos );
0N/A tlDrawLine( g2, oneLine, xPos, yPos );
0N/A //yPos += oneLine.getDescent() + oneLine.getLeading();
0N/A yPos += fmData[3] + fmData[5]; // descent + leading
0N/A }
0N/A }
0N/A if ( !isPrinting )
0N/A g.drawImage( backBuffer, 0, 0, this );
0N/A g2.dispose();
0N/A }
0N/A
0N/A /// Component paintComponent function...
0N/A /// Draws/Refreshes canvas according to flag(s) set by other functions
0N/A public void paintComponent( Graphics g ) {
0N/A if ( updateBackBuffer ) {
0N/A Dimension d = this.getSize();
0N/A isPrinting = false;
0N/A try {
0N/A drawText( g, d.width, d.height );
0N/A }
0N/A catch ( CannotDrawException e ) {
0N/A f2dt.fireChangeStatus( ERRORS[ e.id ], true );
0N/A super.paintComponent(g);
0N/A return;
0N/A }
0N/A }
0N/A else {
0N/A /// Screen refresh
0N/A g.drawImage( backBuffer, 0, 0, this );
0N/A }
0N/A
0N/A showingError = false;
0N/A updateBackBuffer = false;
0N/A }
0N/A
0N/A /// Printable interface function
0N/A /// Component print function...
0N/A public int print( Graphics g, PageFormat pf, int pageIndex ) {
0N/A if ( pageIndex == 0 ) {
0N/A /// Reset the last page index to max...
0N/A lastPage = Integer.MAX_VALUE;
0N/A currentlyShownChar = verticalBar.getValue() * numCharAcross;
0N/A }
0N/A
0N/A if ( printMode == ONE_PAGE ) {
0N/A if ( pageIndex > 0 )
0N/A return NO_SUCH_PAGE;
0N/A }
0N/A else {
0N/A if ( pageIndex > lastPage )
0N/A return NO_SUCH_PAGE;
0N/A }
0N/A
0N/A int pageWidth = (int) pf.getImageableWidth();
0N/A int pageHeight = (int) pf.getImageableHeight();
0N/A /// Back up metrics and other drawing info before printing modifies it
0N/A int backupDrawStart = drawStart, backupDrawEnd = drawEnd;
0N/A int backupNumCharAcross = numCharAcross, backupNumCharDown = numCharDown;
0N/A Vector backupLineBreakTLs = null;
0N/A if ( textToUse == FILE_TEXT )
0N/A backupLineBreakTLs = (Vector) lineBreakTLs.clone();
0N/A
0N/A printPageNumber = pageIndex;
0N/A isPrinting = true;
0N/A /// Push the actual draw area 60 down to allow info to be printed
0N/A g.translate( (int) pf.getImageableX(), (int) pf.getImageableY() + 60 );
0N/A try {
0N/A drawText( g, pageWidth, pageHeight - 60 );
0N/A }
0N/A catch ( CannotDrawException e ) {
0N/A f2dt.fireChangeStatus( ERRORS[ e.id ], true );
0N/A return NO_SUCH_PAGE;
0N/A }
0N/A
0N/A /// Draw information about what is being printed
0N/A String hints = ( " with antialias " + antiAliasType + "and" +
0N/A " fractional metrics " + fractionalMetricsType +
0N/A " and lcd contrast = " + lcdContrast);
0N/A String infoLine1 = ( "Printing" + MS_OPENING[textToUse] +
0N/A modeSpecificNumStr( drawStart ) + " to " +
0N/A modeSpecificNumStr( drawEnd ) + MS_CLOSING[textToUse] );
0N/A String infoLine2 = ( "With " + fontName + " " + STYLES[fontStyle] + " at " +
0N/A fontSize + " point size " + TRANSFORMS[fontTransform] );
0N/A String infoLine3 = "Using " + METHODS[drawMethod] + hints;
0N/A String infoLine4 = "Page: " + ( pageIndex + 1 );
0N/A g.setFont( new Font( "dialog", Font.PLAIN, 12 ));
0N/A g.setColor( Color.black );
0N/A g.translate( 0, -60 );
0N/A g.drawString( infoLine1, 15, 10 );
0N/A g.drawString( infoLine2, 15, 22 );
0N/A g.drawString( infoLine3, 15, 34 );
0N/A g.drawString( infoLine4, 15, 46 );
0N/A
0N/A if ( drawEnd == drawLimit )
0N/A /// This indicates that the draw will be completed with this page
0N/A lastPage = pageIndex;
0N/A
0N/A /// Restore the changed values back...
0N/A /// This is important for JScrollBar settings and LineBreak'ed TLs
0N/A drawStart = backupDrawStart;
0N/A drawEnd = backupDrawEnd;
0N/A numCharAcross = backupNumCharAcross;
0N/A numCharDown = backupNumCharDown;
0N/A if ( textToUse == FILE_TEXT )
0N/A lineBreakTLs = backupLineBreakTLs;
0N/A return PAGE_EXISTS;
0N/A }
0N/A
0N/A /// Ouputs the current canvas into a given PNG file
0N/A public void writePNG( String fileName ) {
0N/A try {
0N/A ImageIO.write(backBuffer, "png", new java.io.File(fileName));
0N/A }
0N/A catch ( Exception e ) {
0N/A f2dt.fireChangeStatus( "ERROR: Failed to Save PNG image; See stack trace", true );
0N/A e.printStackTrace();
0N/A }
0N/A }
0N/A
0N/A /// Figures out whether a character at the pointer location is valid
0N/A /// And if so, updates mouse location informations, as well as
0N/A /// the information on the status bar
0N/A private boolean checkMouseLoc( MouseEvent e ) {
0N/A if ( gridWidth != 0 && gridHeight != 0 )
0N/A if ( textToUse == RANGE_TEXT || textToUse == ALL_GLYPHS ) {
0N/A int charLocX = ( e.getX() - canvasInset_X ) / gridWidth;
0N/A int charLocY = ( e.getY() - canvasInset_Y ) / gridHeight;
0N/A
0N/A /// Check to make sure the mouse click location is within drawn area
0N/A if ( charLocX >= 0 && charLocY >= 0 &&
0N/A charLocX < numCharAcross && charLocY < numCharDown ) {
0N/A int mouseOverChar =
0N/A charLocX + ( verticalBar.getValue() + charLocY ) * numCharAcross;
0N/A if ( textToUse == RANGE_TEXT )
0N/A mouseOverChar += drawRange[0];
0N/A if ( mouseOverChar > drawEnd )
0N/A return false;
0N/A
0N/A mouseOverCharX = charLocX;
0N/A mouseOverCharY = charLocY;
0N/A currMouseOverChar = mouseOverChar;
0N/A /// Update status bar
0N/A f2dt.fireChangeStatus( "Pointing to" + MS_OPENING[textToUse] +
0N/A modeSpecificNumStr( mouseOverChar ), false );
0N/A return true;
0N/A }
0N/A }
0N/A return false;
0N/A }
0N/A
0N/A /// Shows (updates) the character zoom window
0N/A public void showZoomed() {
0N/A GlyphVector gv;
0N/A Font backup = testFont;
0N/A Point canvasLoc = this.getLocationOnScreen();
0N/A
0N/A /// Calculate the zoom area's location and size...
0N/A int dialogOffsetX = (int) ( gridWidth * ( ZOOM - 1 ) / 2 );
0N/A int dialogOffsetY = (int) ( gridHeight * ( ZOOM - 1 ) / 2 );
0N/A int zoomAreaX =
0N/A mouseOverCharX * gridWidth + canvasInset_X - dialogOffsetX;
0N/A int zoomAreaY =
0N/A mouseOverCharY * gridHeight + canvasInset_Y - dialogOffsetY;
0N/A int zoomAreaWidth = (int) ( gridWidth * ZOOM );
0N/A int zoomAreaHeight = (int) ( gridHeight * ZOOM );
0N/A
0N/A /// Position and set size of zoom window as needed
0N/A zoomWindow.setLocation( canvasLoc.x + zoomAreaX, canvasLoc.y + zoomAreaY );
0N/A if ( !nowZooming ) {
0N/A if ( zoomWindow.getWarningString() != null )
0N/A /// If this is not opened as a "secure" window,
0N/A /// it has a banner below the zoom dialog which makes it look really BAD
0N/A /// So enlarge it by a bit
0N/A zoomWindow.setSize( zoomAreaWidth + 1, zoomAreaHeight + 20 );
0N/A else
0N/A zoomWindow.setSize( zoomAreaWidth + 1, zoomAreaHeight + 1 );
0N/A }
0N/A
0N/A /// Prepare zoomed image
0N/A zoomImage =
0N/A (BufferedImage) zoomWindow.createImage( zoomAreaWidth + 1,
0N/A zoomAreaHeight + 1 );
0N/A Graphics2D g2 = (Graphics2D) zoomImage.getGraphics();
0N/A testFont = testFont.deriveFont( fontSize * ZOOM );
0N/A setParams( g2 );
0N/A g2.setColor( Color.white );
0N/A g2.fillRect( 0, 0, zoomAreaWidth, zoomAreaHeight );
0N/A g2.setColor( Color.black );
0N/A g2.drawRect( 0, 0, zoomAreaWidth, zoomAreaHeight );
0N/A modeSpecificDrawChar( g2, currMouseOverChar,
0N/A zoomAreaWidth / 2, (int) ( maxAscent * ZOOM ));
0N/A g2.dispose();
0N/A if ( !nowZooming )
0N/A zoomWindow.show();
0N/A /// This is sort of redundant... since there is a paint function
0N/A /// inside zoomWindow definition that does the drawImage.
0N/A /// (I should be able to call just repaint() here)
0N/A /// However, for some reason, that paint function fails to respond
0N/A /// from second time and on; So I have to force the paint here...
0N/A zoomWindow.getGraphics().drawImage( zoomImage, 0, 0, this );
0N/A
0N/A nowZooming = true;
0N/A prevZoomChar = currMouseOverChar;
0N/A testFont = backup;
0N/A
0N/A // Windows does not repaint correctly, after
0N/A // a zoom. Thus, we need to force the canvas
0N/A // to repaint, but only once. After the first repaint,
0N/A // everything stabilizes. [ABP]
0N/A if ( firstTime() ) {
0N/A refresh();
0N/A }
0N/A }
0N/A
0N/A /// Listener Functions
0N/A
0N/A /// MouseListener interface function
0N/A /// Zooms a character when mouse is pressed above it
0N/A public void mousePressed( MouseEvent e ) {
0N/A if ( !showingError) {
0N/A if ( checkMouseLoc( e )) {
0N/A showZoomed();
0N/A this.setCursor( blankCursor );
0N/A }
0N/A }
0N/A }
0N/A
0N/A /// MouseListener interface function
0N/A /// Redraws the area that was drawn over by zoomed character
0N/A public void mouseReleased( MouseEvent e ) {
0N/A if ( textToUse == RANGE_TEXT || textToUse == ALL_GLYPHS ) {
0N/A if ( nowZooming )
0N/A zoomWindow.hide();
0N/A nowZooming = false;
0N/A }
0N/A this.setCursor( Cursor.getDefaultCursor() );
0N/A }
0N/A
0N/A /// MouseListener interface function
0N/A /// Resets the status bar to display range instead of a specific character
0N/A public void mouseExited( MouseEvent e ) {
0N/A if ( !showingError && !nowZooming )
0N/A f2dt.fireChangeStatus( backupStatusString, false );
0N/A }
0N/A
0N/A /// MouseMotionListener interface function
0N/A /// Adjusts the status bar message when mouse moves over a character
0N/A public void mouseMoved( MouseEvent e ) {
0N/A if ( !showingError ) {
0N/A if ( !checkMouseLoc( e ))
0N/A f2dt.fireChangeStatus( backupStatusString, false );
0N/A }
0N/A }
0N/A
0N/A /// MouseMotionListener interface function
0N/A /// Scrolls the zoomed character when mouse is dragged
0N/A public void mouseDragged( MouseEvent e ) {
0N/A if ( !showingError )
0N/A if ( nowZooming ) {
0N/A if ( checkMouseLoc( e ) && currMouseOverChar != prevZoomChar )
0N/A showZoomed();
0N/A }
0N/A }
0N/A
0N/A /// Empty function to comply with interface requirement
0N/A public void mouseClicked( MouseEvent e ) {}
0N/A public void mouseEntered( MouseEvent e ) {}
0N/A }
0N/A
0N/A private final class CannotDrawException extends RuntimeException {
0N/A /// Error ID
0N/A public final int id;
0N/A
0N/A public CannotDrawException( int i ) {
0N/A id = i;
0N/A }
0N/A }
0N/A
0N/A enum FMValues {
0N/A FMDEFAULT ("DEFAULT", VALUE_FRACTIONALMETRICS_DEFAULT),
0N/A FMOFF ("OFF", VALUE_FRACTIONALMETRICS_OFF),
0N/A FMON ("ON", VALUE_FRACTIONALMETRICS_ON);
0N/A
0N/A private String name;
0N/A private Object hint;
0N/A
0N/A private static FMValues[] valArray;
0N/A
0N/A FMValues(String s, Object o) {
0N/A name = s;
0N/A hint = o;
0N/A }
0N/A
0N/A public String toString() {
0N/A return name;
0N/A }
0N/A
0N/A public Object getHint() {
0N/A return hint;
0N/A }
0N/A public static Object getValue(int ordinal) {
0N/A if (valArray == null) {
0N/A valArray = (FMValues[])EnumSet.allOf(FMValues.class).toArray(new FMValues[0]);
0N/A }
0N/A for (int i=0;i<valArray.length;i++) {
0N/A if (valArray[i].ordinal() == ordinal) {
0N/A return valArray[i];
0N/A }
0N/A }
0N/A return valArray[0];
0N/A }
0N/A private static FMValues[] getArray() {
0N/A if (valArray == null) {
0N/A valArray = (FMValues[])EnumSet.allOf(FMValues.class).toArray(new FMValues[0]);
0N/A }
0N/A return valArray;
0N/A }
0N/A
0N/A public static int getHintVal(Object hint) {
0N/A getArray();
0N/A for (int i=0;i<valArray.length;i++) {
0N/A if (valArray[i].getHint() == hint) {
0N/A return i;
0N/A }
0N/A }
0N/A return 0;
0N/A }
0N/A }
0N/A
0N/A enum AAValues {
0N/A AADEFAULT ("DEFAULT", VALUE_TEXT_ANTIALIAS_DEFAULT),
0N/A AAOFF ("OFF", VALUE_TEXT_ANTIALIAS_OFF),
0N/A AAON ("ON", VALUE_TEXT_ANTIALIAS_ON),
0N/A AAGASP ("GASP", VALUE_TEXT_ANTIALIAS_GASP),
0N/A AALCDHRGB ("LCD_HRGB", VALUE_TEXT_ANTIALIAS_LCD_HRGB),
0N/A AALCDHBGR ("LCD_HBGR", VALUE_TEXT_ANTIALIAS_LCD_HBGR),
0N/A AALCDVRGB ("LCD_VRGB", VALUE_TEXT_ANTIALIAS_LCD_VRGB),
0N/A AALCDVBGR ("LCD_VBGR", VALUE_TEXT_ANTIALIAS_LCD_VBGR);
0N/A
0N/A private String name;
0N/A private Object hint;
0N/A
0N/A private static AAValues[] valArray;
0N/A
0N/A AAValues(String s, Object o) {
0N/A name = s;
0N/A hint = o;
0N/A }
0N/A
0N/A public String toString() {
0N/A return name;
0N/A }
0N/A
0N/A public Object getHint() {
0N/A return hint;
0N/A }
0N/A
0N/A public static boolean isLCDMode(Object o) {
0N/A return (o instanceof AAValues &&
0N/A ((AAValues)o).ordinal() >= AALCDHRGB.ordinal());
0N/A }
0N/A
0N/A public static Object getValue(int ordinal) {
0N/A if (valArray == null) {
0N/A valArray = (AAValues[])EnumSet.allOf(AAValues.class).toArray(new AAValues[0]);
0N/A }
0N/A for (int i=0;i<valArray.length;i++) {
0N/A if (valArray[i].ordinal() == ordinal) {
0N/A return valArray[i];
0N/A }
0N/A }
0N/A return valArray[0];
0N/A }
0N/A
0N/A private static AAValues[] getArray() {
0N/A if (valArray == null) {
0N/A Object [] oa = EnumSet.allOf(AAValues.class).toArray(new AAValues[0]);
0N/A valArray = (AAValues[])(EnumSet.allOf(AAValues.class).toArray(new AAValues[0]));
0N/A }
0N/A return valArray;
0N/A }
0N/A
0N/A public static int getHintVal(Object hint) {
0N/A getArray();
0N/A for (int i=0;i<valArray.length;i++) {
0N/A if (valArray[i].getHint() == hint) {
0N/A return i;
0N/A }
0N/A }
0N/A return 0;
0N/A }
0N/A
0N/A }
0N/A
0N/A private static Integer defaultContrast;
0N/A static Integer getDefaultLCDContrast() {
0N/A if (defaultContrast == null) {
0N/A GraphicsConfiguration gc =
0N/A GraphicsEnvironment.getLocalGraphicsEnvironment().
0N/A getDefaultScreenDevice().getDefaultConfiguration();
0N/A Graphics2D g2d =
0N/A (Graphics2D)(gc.createCompatibleImage(1,1).getGraphics());
0N/A defaultContrast = (Integer)
0N/A g2d.getRenderingHint(RenderingHints.KEY_TEXT_LCD_CONTRAST);
0N/A }
0N/A return defaultContrast;
0N/A }
0N/A}