/* * [Unicode.java] * * Summary: Java Applet to display all of the characters in the Unicode character set. * * Copyright: (c) 1996-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: * 1.0 1996-01-01 initial version * 1.1 1996-01-01 convert to CMP standards. * 1.2 2000-01-01 add Javadoc, fix deprecated methods, ANT build, Lucida Sans * font, used ActionListener to avoid action method. * 1.3 2000-01-01 change font names to new undeprecated names. * 1.4 2000-01-01 convert to JDK 1.1+ event model, using listeners and * anonymous inner classes. * 1.5 2006-03-05 reformat with IntelliJ, add Javadoc * 1.6 2008-01-02 add pad and icons * 1.7 2010-01-07 add title, about box and instructions * 1.8 2010-11-27 convert to Swing and allow any Font. Now requires JDK 1.5+. * 1.9 2014-08-24 make screen more readable, bigger font, anti-aliased. */ package com.mindprod.unicode; import com.mindprod.common18.Build; import com.mindprod.common18.CMPAboutBox; import com.mindprod.common18.FontFactory; import com.mindprod.common18.HybridJ; import com.mindprod.common18.Laf; import com.mindprod.common18.VersionCheck; import javax.swing.JApplet; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JTextArea; import java.awt.Color; import java.awt.Container; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsEnvironment; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.RenderingHints; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.util.Arrays; import java.util.Vector; /* Copyright: (c) 1996-2017 Nic Fulton, nic.fulton@reuters.com, Reuters Ltd, http://www.reuters.com. Roedy Green, Canadian Mind Products (polishing) All Rights Reserved. Permission to use, copy, modify, and distribute this software and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and without fee is hereby granted. REUTERS MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. REUTERS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). REUTERS SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES. This cop-out clause is a copy of that from JavaSoft. */ /** * Java Applet to display all of the characters in the Unicode character set. *

* The Applet displays all 256 characters in a unicode byte block, with an * offset specified by two 4 bit values (i.e. one full byte). * * @author Roedy Green, Canadian Mind Products * @version 1.9 2014-08-24 make screen more readable, bigger font, anti-aliased. * @since 1996-01-01 */ public final class Unicode extends JApplet { // delarations /** * size of cell in grid */ static final int GRIDSIZE = 30; private static final Color FOREGROUND_FOR_INSTRUCTIONS = new Color( 0x006400 )/* dark green */; /** * height of Applet box in pixels. Does not include surrounding frame. */ private static final int APPLET_HEIGHT = 850; /** * Width of Applet box in pixels. */ private static final int APPLET_WIDTH = 600; private static final int FIRST_COPYRIGHT_YEAR = 1996; /** * starting font */ private static final String defaultFontFamily = "Dialog"; /** * undisplayed copyright notice */ private static final String EMBEDDED_COPYRIGHT = "Copyright: (c) 1996-2017 Nic Fulton nic.fulton@reuters.com, Roedy Green, " + "Canadian Mind Products http://mindprod.com"; private static final String RELEASE_DATE = "2014-08-24"; private static final String TITLE_STRING = "Unicode Font Viewer"; private static final String VERSION_STRING = "1.9"; private static final Color BACKGROUND_FOR_APPLET = new Color( 0xfaf0e6 )/* linen */; private static final Color BACKGROUND_FOR_INSTRUCTIONS = Color.white; /** * for titles */ private static final Color FOREGROUND_FOR_TITLE = new Color( 0xdc143c ); /** * for for titles */ private static final Font FONT_FOR_TITLE = FontFactory.build( "Dialog", Font.BOLD, 16 ); /** * for for title second line */ private static final Font FONT_FOR_TITLE2 = FontFactory.build( "Dialog", Font.PLAIN, 14 ); private Container contentPane; /** * choice of all supported fonts */ private JComboBox fontChoices; private JLabel title; private JLabel title2; /** * how to use the program instructions */ private JTextArea instructions; /** * grd bottom and right side bars */ private RigidPanel theRigidPanel; // /declarations /** * default constructor for Unicode JApplet */ public Unicode() { } // methods /** * create all components for Applets. */ private void buildComponents() { title = new JLabel( TITLE_STRING + " " + VERSION_STRING ); title.setFont( FONT_FOR_TITLE ); title.setForeground( FOREGROUND_FOR_TITLE ); title2 = new JLabel( "released:" + RELEASE_DATE + " build:" + Build.BUILD_NUMBER ); title2.setFont( FONT_FOR_TITLE2 ); title2.setForeground( FOREGROUND_FOR_TITLE ); theRigidPanel = new RigidPanel(); buildFontChoices(); fontChoices.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent e ) { // pass String font family name not Font object theRigidPanel.setFontFamily( ( String ) fontChoices.getSelectedItem() ); } } ); instructions = new JTextArea( "To view a given hex code:\n" + "Select the first digit with the corresponding white square at the bottom.\n" + "Then select the second digit with the corresponding white square on the right" + ".\n" + "Then sight (but don't click) the third digit with the corresponding black " + "digit on the bottom.\n" + "Then sight (but don't click) the fourth digit with the corresponding black " + "square on the right.\n" + "Select various fonts to see how the glyphs change.\n" + "You can also click a grid square to see it magnified in the bottom right " + "corner.", 7 /* rows */, 80 /* cols */ ); instructions.setBackground( BACKGROUND_FOR_INSTRUCTIONS ); instructions.setForeground( FOREGROUND_FOR_INSTRUCTIONS ); instructions.setFont( FontFactory.build( "Dialog", Font.PLAIN, 12 ) ); instructions.setEditable( false ); } /** * set up fontChoices Widget with list of all possible fonts, but not listeners. */ private void buildFontChoices() { // font names final GraphicsEnvironment ge = GraphicsEnvironment .getLocalGraphicsEnvironment(); final String[] fontNames = ge.getAvailableFontFamilyNames(); // use Vector instead of ArrayList because JComboBox wants a vector final Vector v = new Vector<>( fontNames.length + 1 ); v.addAll( Arrays.asList( fontNames ) ); fontChoices = new JComboBox<>( v ); fontChoices.setMaximumSize( fontChoices.getPreferredSize() ); fontChoices.setEditable( true ); fontChoices.setSelectedItem( defaultFontFamily ); } /** * build a menu with Look & Feel and About across the top */ private void buildMenu() { // turn on anti-alias System.setProperty( "swing.aatext", "true" ); final JMenuBar menubar = new JMenuBar(); setJMenuBar( menubar ); final JMenu lafMenu = Laf.buildLookAndFeelMenu(); if ( lafMenu != null ) { menubar.add( lafMenu ); } final JMenu menuHelp = new JMenu( "Help" ); menubar.add( menuHelp ); final JMenuItem aboutItem = new JMenuItem( "About" ); menuHelp.add( aboutItem ); aboutItem.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent e ) { // open about frame new CMPAboutBox( TITLE_STRING, VERSION_STRING, "Display Unicode Characters", "in range 0..FFFF", "freeware", RELEASE_DATE, FIRST_COPYRIGHT_YEAR, "Roedy Green", "UNICODE", "1.6" ); } } ); } private void layoutComponents() { /* 0---------1------2 0 titles1 title2 fontChoice 1 rigid panel 2 instructions */ // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( title, new GridBagConstraints( 0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets( 10, 10, 10, 5 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( title2, new GridBagConstraints( 1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets( 10, 5, 10, 5 ), 0, 0 ) ); contentPane.add( fontChoices, new GridBagConstraints( 2, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets( 0, 10, 5, 5 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( theRigidPanel, new GridBagConstraints( 0, 1, 3, 1, 10.0, 10.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets( 5, 10, 0, 10 ), 0, 0 ) ); // x y w h wtx wty anchor fill T L B R padx pady contentPane.add( instructions, new GridBagConstraints( 0, 2, 3, 1, 0.0, 0.5, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets( 5, 10, 10, 10 ), 0, 0 ) ); } /** * Allow this Applet to run as as application as well. * * @param args command line arguments ignored. */ public static void main( String args[] ) { HybridJ.fireup( new Unicode(), TITLE_STRING + " " + VERSION_STRING, APPLET_WIDTH, APPLET_HEIGHT ); } // end main; /** * Called by the browser or Applet viewer to inform * this Applet that it is being reclaimed and that it should destroy * any resources that it has allocated. */ public void destroy() { contentPane = null; fontChoices = null; instructions = null; theRigidPanel = null; title2 = null; title = null; } /** * Called by the browser or Applet viewer to inform * this Applet that it has been loaded into the system. */ @Override public void init() { contentPane = this.getContentPane(); if ( !VersionCheck.isJavaVersionOK( 1, 7, 0, contentPane ) ) { return; } buildMenu(); // also initial L&F contentPane.setLayout( new GridBagLayout() ); contentPane.setBackground( BACKGROUND_FOR_APPLET ); buildComponents(); layoutComponents(); this.validate();// calculate the layouts this.setVisible( true );// Lights, Camera, Action. } /* creates the whole grind with right and top panels. */ static final class RigidPanel extends JPanel { private final TextPanel theTextPanel; /** * constructor */ RigidPanel() { // set the layout to null. i.e. hard code in all the positions // so that they don't go 'drifting' with unexpected layout // manager behaviour setLayout( null ); setBackground( Color.white ); this.setSize( Unicode.GRIDSIZE * 18, Unicode.GRIDSIZE * 18 ); // A new object to contain the single 'zoomed' character final CharPanel theCharPanel = new CharPanel(); add( theCharPanel ); theCharPanel.setBounds( Unicode.GRIDSIZE * 16, Unicode.GRIDSIZE * 16, Unicode.GRIDSIZE * 3, Unicode.GRIDSIZE * 3 ); // A new object to display the grid of characters theTextPanel = new TextPanel( theCharPanel ); add( theTextPanel ); theTextPanel.setBounds( 0, 0, Unicode.GRIDSIZE * 16, Unicode.GRIDSIZE * 16 ); // A rather crude slider for the base final BottomPanel theBottomPanel = new BottomPanel( theTextPanel ); add( theBottomPanel ); theBottomPanel.setBounds( 0, Unicode.GRIDSIZE * 16, Unicode.GRIDSIZE * 16, Unicode.GRIDSIZE * 3 ); // A rather crude slider for the side. // On reflection maybe I should have had both the bottom // and right sliders in the same class with an orientation... final RightPanel theRightPanel = new RightPanel( theTextPanel ); add( theRightPanel ); theRightPanel.setBounds( Unicode.GRIDSIZE * 16, 0, Unicode.GRIDSIZE * 3, Unicode.GRIDSIZE * 16 ); } /** * Set the font to the selected font. * * @param theFontFamily to draw the chars in */ public void setFontFamily( String theFontFamily ) { theTextPanel.setFontFamily( theFontFamily ); } } } /** * The class that contains the grid of characters. */ final class TextPanel extends JPanel { /** * panel that contains grid of rendered chars */ private final CharPanel theCharPanel; /** * current font to use for rendering */ private String theFontFamily = "Monospaced"; /** * row group 0..15 */ private int colGroup = 0; /** * col group 0..15 */ private int rowGroup = 0; /** * constructor for text panel * * @param theCharPanel panel that contains grid of rendered chars */ public TextPanel( final CharPanel theCharPanel ) { this.theCharPanel = theCharPanel; this.addMouseListener( new MouseAdapter() { /** * Invoked when a mouse button has been pressed on a component. */ public void mousePressed( MouseEvent e ) { int i = e.getX() / Unicode.GRIDSIZE; int j = e.getY() / Unicode.GRIDSIZE; theCharPanel.setChar( j, i, rowGroup, colGroup ); } } ); } /** * On paint, draw all the characters in their little boxes. */ public void paintComponent( Graphics g ) { super.paintComponent( g ); Graphics2D g2d = ( Graphics2D ) g; // turn on anti-alias g2d.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON ); g2d.setRenderingHint( RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY ); // Set the font to the selected font. final Font font = new Font( theFontFamily, Font.PLAIN, ( int ) ( .8 * Unicode.GRIDSIZE ) ); g.setFont( font ); final FontMetrics metrics = getFontMetrics( font ); g.drawRect( 0, 0, Unicode.GRIDSIZE * 16 - 1, Unicode.GRIDSIZE * 16 - 1 ); // draw the grid for ( int i = 1; i < 16; i++ ) { g.drawLine( 0, i * Unicode.GRIDSIZE, Unicode.GRIDSIZE * 16, i * Unicode.GRIDSIZE ); g.drawLine( i * Unicode.GRIDSIZE, 0, i * Unicode.GRIDSIZE, Unicode.GRIDSIZE * 16 ); } // draw all the characters for ( int i = 0; i < 16; i++ ) { for ( int j = 0; j < 16; j++ ) { // Calculate the characters UNICODE value. int anInt = j + i * 16 + rowGroup * 256 + colGroup * 4096; // draw just one char in the grid final String theCharAsString = String.valueOf( ( char ) anInt ); final int width = metrics.stringWidth( theCharAsString ); final int x = i * Unicode.GRIDSIZE + Unicode.GRIDSIZE / 2 - width / 2; final int y = j * Unicode.GRIDSIZE + Unicode.GRIDSIZE - Unicode.GRIDSIZE / 4; // center it in the box g.drawString( theCharAsString, x, y ); } } } /** * Set the offset value of the 256 character window when the sliders are being used. * * @param i column group 0..15 of char to display */ public void setColGroup( int i ) { colGroup = i; repaint(); } /** * Set the font to the selected font. * * @param theFontFamily to draw the chars in */ public void setFontFamily( String theFontFamily ) { this.theFontFamily = theFontFamily; theCharPanel.setFontFamily( theFontFamily ); repaint(); } /** * Set the offset value of the 256 character window when the sliders are being used. * * @param j row group of char to display */ public void setRowGroup( int j ) { rowGroup = j; repaint(); } } /** * The little box with the character in. this also displays the HEX value of the character that you click on */ final class CharPanel extends JPanel { /** * current font we are using for rendering */ private String theFontFamily = "Monospaced"; /** * current character we are rendering */ private char theChar; /** * first digit of unicode xxxx 0..16 */ private int digit1 = 0; /** * second digit of unicode xxxx 0..16 */ private int digit2 = 0; /** * third digit of unicode xxxx 0..16 */ private int digit3 = 0; /** * fourth digit of unicode xxxx 0..16 */ private int digit4 = 0; /** * constructor */ public CharPanel() { theChar = ( char ) 0x0020; // no listeners } /** * Draw big highlighted char in bottom right box. */ public void paintComponent( Graphics g ) { // three grid across, box two across in bottom right. super.paintComponent( g ); Graphics2D g2d = ( Graphics2D ) g; // turn on anti-alias g2d.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON ); g2d.setRenderingHint( RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY ); String aString = Integer.toString( digit1, 16 ) + Integer.toString( digit2, 16 ) + Integer.toString( digit3, 16 ) + Integer.toString( digit4, 16 ); // x,y is bottom left corner of text // bottom right corner. g.drawString( aString, Unicode.GRIDSIZE + 3, Unicode.GRIDSIZE - 3 ); // hex // thick line around big char g.drawRect( Unicode.GRIDSIZE, Unicode.GRIDSIZE, Unicode.GRIDSIZE * 2 - 1, Unicode.GRIDSIZE * 2 - 1 ); g.drawRect( Unicode.GRIDSIZE + 1, Unicode.GRIDSIZE + 1, Unicode.GRIDSIZE * 2 - 3, Unicode.GRIDSIZE * 2 - 3 ); // Get the current font then make a new BIG one (triple the size). Font fontMed = g.getFont(); // Don't use Font Factory. Want precise font, not best final Font fontBig = new Font( theFontFamily, fontMed.getStyle(), fontMed.getSize() * 3 ); g.setFont( fontBig ); final FontMetrics metrics = getFontMetrics( fontBig ); final String theCharAsString = String.valueOf( theChar ); final int width = metrics.stringWidth( theCharAsString ); // show big char g.drawString( theCharAsString, Unicode.GRIDSIZE * 2 - width / 2, Unicode.GRIDSIZE * 2 + Unicode.GRIDSIZE / 2 ); } /** * On a click change the characters value. * @param a first hex digit * * @param b second hex digit * @param c third hex digit * @param d fourth hex digit */ public void setChar( int a, int b, int c, int d ) { digit1 = d; digit2 = c; digit3 = b; digit4 = a; int i = digit4 + digit3 * 16 + digit2 * 256 + digit1 * 4096; theChar = ( char ) i; repaint(); } /** * Set the font to the selected one * * @param theFont font to draw the chars */ public void setFontFamily( String theFont ) { this.theFontFamily = theFont; repaint(); } } /** * The rather crude slider. This one is for the bottom of the applet. */ final class BottomPanel extends JPanel { /** * column group 0..15 in bottom panel */ private int colGroup = 0; /** * constructor constructor panel to contain pieces * * @param theTextPanel display the controls to select the column group */ public BottomPanel( final TextPanel theTextPanel ) { this.addMouseListener( new MouseAdapter() { /** * Invoked when a mouse button has been pressed on a component. * Catch a mousedown and reset the position of the slider if it has * changed. Redraw the character grid. */ public void mousePressed( MouseEvent e ) { int i = e.getX() / Unicode.GRIDSIZE; if ( colGroup != i && i < 16 && i >= 0 ) { colGroup = i; repaint(); theTextPanel.setColGroup( i ); } } } ); this.addMouseMotionListener( new MouseMotionAdapter() { /** * catch a mouse drag and move the slider if the position has * changed. Redraw the character grid */ public void mouseDragged( MouseEvent e ) { int i = e.getX() / Unicode.GRIDSIZE; if ( colGroup != i && i < 16 && i >= 0 ) { colGroup = i; repaint(); theTextPanel.setColGroup( i ); } } } ); } /** * draws the axes. */ public void paintComponent( Graphics g ) { super.paintComponent( g ); Graphics2D g2d = ( Graphics2D ) g; // turn on anti-alias g2d.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON ); g2d.setRenderingHint( RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY ); g.fillRect( 0, 0, Unicode.GRIDSIZE * 16, Unicode.GRIDSIZE ); Color aColor = g.getColor(); g.setColor( Color.white ); // draw x axis, white letters on black for ( int i = 0; i < 16; i++ ) { g.drawString( Integer.toString( i, 16 ), i * Unicode.GRIDSIZE + Unicode.GRIDSIZE / 4, Unicode.GRIDSIZE - 4 ); } g.setColor( aColor ); // draw y axis white letters on black g.drawRect( 0, Unicode.GRIDSIZE * 2, Unicode.GRIDSIZE * 16 - 1, Unicode.GRIDSIZE - 1 ); for ( int i = 1; i < 16; i++ ) { g.drawLine( i * Unicode.GRIDSIZE, Unicode.GRIDSIZE * 2, i * Unicode.GRIDSIZE, Unicode.GRIDSIZE * 3 ); } g.fillRect( colGroup * Unicode.GRIDSIZE, Unicode.GRIDSIZE * 2, Unicode.GRIDSIZE, Unicode.GRIDSIZE ); } } /** * The right slider, well sort of, control extending Canvas */ final class RightPanel extends JPanel { /** * row group 9..15 */ private int rowGroup = 0; /** * constructor right panel * * @param theTextPanel panel where we render the controls for row group */ public RightPanel( final TextPanel theTextPanel ) { this.addMouseListener( new MouseAdapter() { /** * Invoked when a mouse button has been pressed on a component. * catch a mousedown and reset the position of the slider if it has * changed. Redraw the character grid. */ public void mousePressed( MouseEvent e ) { int j = e.getY() / Unicode.GRIDSIZE; if ( rowGroup != j && j < 16 && j >= 0 ) { rowGroup = j; repaint(); theTextPanel.setRowGroup( j ); } } } ); this.addMouseMotionListener( new MouseMotionAdapter() { /** * catch a mouse drag and move the slider if the position has * changed. Redraw the character grid */ public void mouseDragged( MouseEvent e ) { int j = e.getY() / Unicode.GRIDSIZE; if ( rowGroup != j && j < 16 && j >= 0 ) { rowGroup = j; repaint(); theTextPanel.setRowGroup( j ); } } } ); } public void paintComponent( Graphics g ) { super.paintComponent( g ); Graphics2D g2d = ( Graphics2D ) g; // turn on anti-alias g2d.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON ); g2d.setRenderingHint( RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY ); g.fillRect( 0, 0, Unicode.GRIDSIZE, Unicode.GRIDSIZE * 16 ); Color aColor = g.getColor(); g.setColor( Color.white ); for ( int i = 0; i < 16; i++ ) { g.drawString( Integer.toString( i, 16 ), 7, i * Unicode.GRIDSIZE + 20 ); } g.setColor( aColor ); g.drawRect( Unicode.GRIDSIZE * 2, 0, Unicode.GRIDSIZE - 1, Unicode.GRIDSIZE * 16 - 1 ); for ( int i = 1; i < 16; i++ ) { g.drawLine( Unicode.GRIDSIZE * 2, i * Unicode.GRIDSIZE, Unicode.GRIDSIZE * 3, i * Unicode.GRIDSIZE ); } g.fillRect( Unicode.GRIDSIZE * 2, rowGroup * Unicode.GRIDSIZE, Unicode.GRIDSIZE, Unicode.GRIDSIZE ); } }