57 import java.awt.event.AdjustmentListener;
58 import java.awt.event.ComponentAdapter;
59 import java.awt.event.ComponentEvent;
60 import java.awt.event.MouseEvent;
61 import java.awt.event.MouseListener;
62 import java.awt.event.MouseMotionListener;
63 import java.awt.font.FontRenderContext;
64 import java.awt.font.GlyphVector;
65 import java.awt.font.LineBreakMeasurer;
66 import java.awt.font.TextLayout;
67 import java.awt.geom.AffineTransform;
68 import java.awt.geom.NoninvertibleTransformException;
69 import java.awt.geom.Rectangle2D;
70 import java.awt.image.BufferedImage;
71 import java.awt.print.PageFormat;
72 import java.awt.print.Printable;
73 import java.awt.print.PrinterJob;
74 import java.io.BufferedOutputStream;
75 import java.io.FileOutputStream;
76 import java.text.AttributedString;
77 import java.util.EnumSet;
78 import java.util.Vector;
79
80 import javax.imageio.*;
81 import javax.swing.*;
82
83 import static java.awt.RenderingHints.*;
84
85 /**
86 * FontPanel.java
87 *
88 * @author Shinsuke Fukuda
89 * @author Ankit Patel [Conversion to Swing - 01/07/30]
90 */
91
92 /// This panel is combination of the text drawing area of Font2DTest
93 /// and the custom controlled scroll bar
94
95 public final class FontPanel extends JPanel implements AdjustmentListener {
96
97 /// Drawing Option Constants
375 /// Reload all options and refreshes the canvas
376 public void loadOptions( boolean grid, boolean force16, int start, int end,
377 String name, float size, int style,
378 int transform, int g2transform,
379 int text, int method, int aa, int fm,
380 int contrast, String[] user ) {
381 int[] range = { start, end };
382
383 /// Since repaint call has a low priority, these functions will finish
384 /// before the actual repainting is done
385 setGridDisplay( grid );
386 setForce16Columns( force16 );
387 // previous call to readTextFile has already set the text to draw
388 if (textToUse != FILE_TEXT) {
389 setTextToDraw( text, range, user, null );
390 }
391 setFontParams( name, size, style, transform );
392 setTransformG2( g2transform ); // ABP
393 setDrawMethod( method );
394 setRenderingHints(AAValues.getValue(aa), FMValues.getValue(fm),
395 new Integer(contrast));
396 }
397
398 /// Writes the current screen to PNG file
399 public void doSavePNG( String fileName ) {
400 fc.writePNG( fileName );
401 }
402
403 /// When scrolled using the scroll bar, update the backbuffer
404 public void adjustmentValueChanged( AdjustmentEvent e ) {
405 fc.repaint();
406 }
407
408 public void paintComponent( Graphics g ) {
409 // Windows does not repaint correctly, after
410 // a zoom. Thus, we need to force the canvas
411 // to repaint, but only once. After the first repaint,
412 // everything stabilizes. [ABP]
413 fc.repaint();
414 }
415
417
418 /// Inner panel that holds the actual drawing area and its routines
419 private class FontCanvas extends JPanel implements MouseListener, MouseMotionListener, Printable {
420
421 /// Number of characters that will fit across and down this canvas
422 private int numCharAcross, numCharDown;
423
424 /// First and last character/line that will be drawn
425 /// Limit is the end of range/text where no more draw will be done
426 private int drawStart, drawEnd, drawLimit;
427
428 /// FontMetrics variables
429 /// Here, gridWidth is equivalent to maxAdvance (slightly bigger though)
430 /// and gridHeight is equivalent to lineHeight
431 private int maxAscent, maxDescent, gridWidth = 0, gridHeight = 0;
432
433 /// Offset from the top left edge of the canvas where the draw will start
434 private int canvasInset_X = 5, canvasInset_Y = 5;
435
436 /// LineBreak'ed TextLayout vector
437 private Vector lineBreakTLs = null;
438
439 /// Whether the current draw command requested is for printing
440 private boolean isPrinting = false;
441
442 /// Other printing infos
443 private int lastPage, printPageNumber, currentlyShownChar = 0;
444 private final int PR_OFFSET = 10;
445 private final int PR_TITLE_LINEHEIGHT = 30;
446
447 /// Information about zooming (used with range text draw)
448 private final JWindow zoomWindow;
449 private BufferedImage zoomImage = null;
450 private int mouseOverCharX = -1, mouseOverCharY = -1;
451 private int currMouseOverChar = -1, prevZoomChar = -1;
452 private float ZOOM = 2.0f;
453 private boolean nowZooming = false;
454 private boolean firstTime = true;
455 // ABP
456
457 /// Status bar message backup
783 throw new CannotDrawException( isPrinting ? CANT_FIT_PRINT : CANT_FIT_DRAW );
784
785 if ( !isPrinting )
786 resetScrollbar( verticalBar.getValue() * numCharAcross );
787 }
788 else {
789 maxDescent += fm.getLeading();
790 canvasInset_X = 5;
791 canvasInset_Y = 5;
792 /// gridWidth and numCharAcross will not be used in this mode...
793 gridHeight = maxAscent + maxDescent;
794 numCharDown = ( h - canvasInset_Y * 2 ) / gridHeight;
795
796 if ( numCharDown == 0 )
797 throw new CannotDrawException( isPrinting ? CANT_FIT_PRINT : CANT_FIT_DRAW );
798 /// If this is text loaded from file, prepares the LineBreak'ed
799 /// text layout at this point
800 if ( textToUse == FILE_TEXT ) {
801 if ( !isPrinting )
802 f2dt.fireChangeStatus( "LineBreaking Text... Please Wait", false );
803 lineBreakTLs = new Vector();
804 for ( int i = 0; i < fileText.length; i++ ) {
805 AttributedString as =
806 new AttributedString( fileText[i], g2.getFont().getAttributes() );
807
808 LineBreakMeasurer lbm =
809 new LineBreakMeasurer( as.getIterator(), g2.getFontRenderContext() );
810
811 while ( lbm.getPosition() < fileText[i].length() )
812 lineBreakTLs.add( lbm.nextLayout( (float) w ));
813
814 }
815 }
816 if ( !isPrinting )
817 resetScrollbar( verticalBar.getValue() );
818 }
819 }
820
821 /// Calculates the amount of text that will be displayed on screen
822 private void calcTextRange() {
823 String displaying = null;
912
913 modeSpecificDrawChar( g2, charToDraw,
914 gridLocX + gridWidth / 2,
915 gridLocY + maxAscent );
916
917 }
918 }
919 }
920 else if ( textToUse == USER_TEXT ) {
921 g2.drawRect( 0, 0, w - 1, h - 1 );
922 for ( int i = drawStart; i <= drawEnd; i++ ) {
923 int lineStartX = canvasInset_Y;
924 int lineStartY = ( i - drawStart ) * gridHeight + maxAscent;
925 modeSpecificDrawLine( g2, userText[i], lineStartX, lineStartY );
926 }
927 }
928 else {
929 float xPos, yPos = (float) canvasInset_Y;
930 g2.drawRect( 0, 0, w - 1, h - 1 );
931 for ( int i = drawStart; i <= drawEnd; i++ ) {
932 TextLayout oneLine = (TextLayout) lineBreakTLs.elementAt( i );
933 xPos =
934 oneLine.isLeftToRight() ?
935 canvasInset_X : ( (float) w - oneLine.getAdvance() - canvasInset_X );
936
937 float[] fmData = {0, oneLine.getAscent(), 0, oneLine.getDescent(), 0, oneLine.getLeading()};
938 if (g2Transform != NONE) {
939 AffineTransform at = getAffineTransform(g2Transform);
940 at.transform( fmData, 0, fmData, 0, 3);
941 }
942 //yPos += oneLine.getAscent();
943 yPos += fmData[1]; // ascent
944 //oneLine.draw( g2, xPos, yPos );
945 tlDrawLine( g2, oneLine, xPos, yPos );
946 //yPos += oneLine.getDescent() + oneLine.getLeading();
947 yPos += fmData[3] + fmData[5]; // descent + leading
948 }
949 }
950 g2.dispose();
951 }
952
975 if ( pageIndex == 0 ) {
976 /// Reset the last page index to max...
977 lastPage = Integer.MAX_VALUE;
978 currentlyShownChar = verticalBar.getValue() * numCharAcross;
979 }
980
981 if ( printMode == ONE_PAGE ) {
982 if ( pageIndex > 0 )
983 return NO_SUCH_PAGE;
984 }
985 else {
986 if ( pageIndex > lastPage )
987 return NO_SUCH_PAGE;
988 }
989
990 int pageWidth = (int) pf.getImageableWidth();
991 int pageHeight = (int) pf.getImageableHeight();
992 /// Back up metrics and other drawing info before printing modifies it
993 int backupDrawStart = drawStart, backupDrawEnd = drawEnd;
994 int backupNumCharAcross = numCharAcross, backupNumCharDown = numCharDown;
995 Vector backupLineBreakTLs = null;
996 if ( textToUse == FILE_TEXT )
997 backupLineBreakTLs = (Vector) lineBreakTLs.clone();
998
999 printPageNumber = pageIndex;
1000 isPrinting = true;
1001 /// Push the actual draw area 60 down to allow info to be printed
1002 g.translate( (int) pf.getImageableX(), (int) pf.getImageableY() + 60 );
1003 try {
1004 drawText( g, pageWidth, pageHeight - 60 );
1005 }
1006 catch ( CannotDrawException e ) {
1007 f2dt.fireChangeStatus( ERRORS[ e.id ], true );
1008 return NO_SUCH_PAGE;
1009 }
1010
1011 /// Draw information about what is being printed
1012 String hints = ( " with antialias " + antiAliasType + "and" +
1013 " fractional metrics " + fractionalMetricsType +
1014 " and lcd contrast = " + lcdContrast);
1015 String infoLine1 = ( "Printing" + MS_OPENING[textToUse] +
1016 modeSpecificNumStr( drawStart ) + " to " +
1017 modeSpecificNumStr( drawEnd ) + MS_CLOSING[textToUse] );
1120 zoomWindow.setSize( zoomAreaWidth + 1, zoomAreaHeight + 20 );
1121 else
1122 zoomWindow.setSize( zoomAreaWidth + 1, zoomAreaHeight + 1 );
1123 }
1124
1125 /// Prepare zoomed image
1126 zoomImage =
1127 (BufferedImage) zoomWindow.createImage( zoomAreaWidth + 1,
1128 zoomAreaHeight + 1 );
1129 Graphics2D g2 = (Graphics2D) zoomImage.getGraphics();
1130 testFont = testFont.deriveFont( fontSize * ZOOM );
1131 setParams( g2 );
1132 g2.setColor( Color.white );
1133 g2.fillRect( 0, 0, zoomAreaWidth, zoomAreaHeight );
1134 g2.setColor( Color.black );
1135 g2.drawRect( 0, 0, zoomAreaWidth, zoomAreaHeight );
1136 modeSpecificDrawChar( g2, currMouseOverChar,
1137 zoomAreaWidth / 2, (int) ( maxAscent * ZOOM ));
1138 g2.dispose();
1139 if ( !nowZooming )
1140 zoomWindow.show();
1141 /// This is sort of redundant... since there is a paint function
1142 /// inside zoomWindow definition that does the drawImage.
1143 /// (I should be able to call just repaint() here)
1144 /// However, for some reason, that paint function fails to respond
1145 /// from second time and on; So I have to force the paint here...
1146 zoomWindow.getGraphics().drawImage( zoomImage, 0, 0, this );
1147
1148 nowZooming = true;
1149 prevZoomChar = currMouseOverChar;
1150 testFont = backup;
1151
1152 // Windows does not repaint correctly, after
1153 // a zoom. Thus, we need to force the canvas
1154 // to repaint, but only once. After the first repaint,
1155 // everything stabilizes. [ABP]
1156 if ( firstTime() ) {
1157 refresh();
1158 }
1159 }
1160
1161 /// Listener Functions
1162
1163 /// MouseListener interface function
1164 /// Zooms a character when mouse is pressed above it
1165 public void mousePressed( MouseEvent e ) {
1166 if ( !showingError) {
1167 if ( checkMouseLoc( e )) {
1168 showZoomed();
1169 this.setCursor( blankCursor );
1170 }
1171 }
1172 }
1173
1174 /// MouseListener interface function
1175 /// Redraws the area that was drawn over by zoomed character
1176 public void mouseReleased( MouseEvent e ) {
1177 if ( textToUse == RANGE_TEXT || textToUse == ALL_GLYPHS ) {
1178 if ( nowZooming )
1179 zoomWindow.hide();
1180 nowZooming = false;
1181 }
1182 this.setCursor( Cursor.getDefaultCursor() );
1183 }
1184
1185 /// MouseListener interface function
1186 /// Resets the status bar to display range instead of a specific character
1187 public void mouseExited( MouseEvent e ) {
1188 if ( !showingError && !nowZooming )
1189 f2dt.fireChangeStatus( backupStatusString, false );
1190 }
1191
1192 /// MouseMotionListener interface function
1193 /// Adjusts the status bar message when mouse moves over a character
1194 public void mouseMoved( MouseEvent e ) {
1195 if ( !showingError ) {
1196 if ( !checkMouseLoc( e ))
1197 f2dt.fireChangeStatus( backupStatusString, false );
1198 }
1199 }
1229
1230 private String name;
1231 private Object hint;
1232
1233 private static FMValues[] valArray;
1234
1235 FMValues(String s, Object o) {
1236 name = s;
1237 hint = o;
1238 }
1239
1240 public String toString() {
1241 return name;
1242 }
1243
1244 public Object getHint() {
1245 return hint;
1246 }
1247 public static Object getValue(int ordinal) {
1248 if (valArray == null) {
1249 valArray = (FMValues[])EnumSet.allOf(FMValues.class).toArray(new FMValues[0]);
1250 }
1251 for (int i=0;i<valArray.length;i++) {
1252 if (valArray[i].ordinal() == ordinal) {
1253 return valArray[i];
1254 }
1255 }
1256 return valArray[0];
1257 }
1258 private static FMValues[] getArray() {
1259 if (valArray == null) {
1260 valArray = (FMValues[])EnumSet.allOf(FMValues.class).toArray(new FMValues[0]);
1261 }
1262 return valArray;
1263 }
1264
1265 public static int getHintVal(Object hint) {
1266 getArray();
1267 for (int i=0;i<valArray.length;i++) {
1268 if (valArray[i].getHint() == hint) {
1269 return i;
1270 }
1271 }
1272 return 0;
1273 }
1274 }
1275
1276 enum AAValues {
1277 AADEFAULT ("DEFAULT", VALUE_TEXT_ANTIALIAS_DEFAULT),
1278 AAOFF ("OFF", VALUE_TEXT_ANTIALIAS_OFF),
1279 AAON ("ON", VALUE_TEXT_ANTIALIAS_ON),
1280 AAGASP ("GASP", VALUE_TEXT_ANTIALIAS_GASP),
1291 AAValues(String s, Object o) {
1292 name = s;
1293 hint = o;
1294 }
1295
1296 public String toString() {
1297 return name;
1298 }
1299
1300 public Object getHint() {
1301 return hint;
1302 }
1303
1304 public static boolean isLCDMode(Object o) {
1305 return (o instanceof AAValues &&
1306 ((AAValues)o).ordinal() >= AALCDHRGB.ordinal());
1307 }
1308
1309 public static Object getValue(int ordinal) {
1310 if (valArray == null) {
1311 valArray = (AAValues[])EnumSet.allOf(AAValues.class).toArray(new AAValues[0]);
1312 }
1313 for (int i=0;i<valArray.length;i++) {
1314 if (valArray[i].ordinal() == ordinal) {
1315 return valArray[i];
1316 }
1317 }
1318 return valArray[0];
1319 }
1320
1321 private static AAValues[] getArray() {
1322 if (valArray == null) {
1323 Object [] oa = EnumSet.allOf(AAValues.class).toArray(new AAValues[0]);
1324 valArray = (AAValues[])(EnumSet.allOf(AAValues.class).toArray(new AAValues[0]));
1325 }
1326 return valArray;
1327 }
1328
1329 public static int getHintVal(Object hint) {
1330 getArray();
1331 for (int i=0;i<valArray.length;i++) {
1332 if (valArray[i].getHint() == hint) {
1333 return i;
1334 }
1335 }
1336 return 0;
1337 }
1338
1339 }
1340
1341 private static Integer defaultContrast;
1342 static Integer getDefaultLCDContrast() {
1343 if (defaultContrast == null) {
1344 GraphicsConfiguration gc =
|
57 import java.awt.event.AdjustmentListener;
58 import java.awt.event.ComponentAdapter;
59 import java.awt.event.ComponentEvent;
60 import java.awt.event.MouseEvent;
61 import java.awt.event.MouseListener;
62 import java.awt.event.MouseMotionListener;
63 import java.awt.font.FontRenderContext;
64 import java.awt.font.GlyphVector;
65 import java.awt.font.LineBreakMeasurer;
66 import java.awt.font.TextLayout;
67 import java.awt.geom.AffineTransform;
68 import java.awt.geom.NoninvertibleTransformException;
69 import java.awt.geom.Rectangle2D;
70 import java.awt.image.BufferedImage;
71 import java.awt.print.PageFormat;
72 import java.awt.print.Printable;
73 import java.awt.print.PrinterJob;
74 import java.io.BufferedOutputStream;
75 import java.io.FileOutputStream;
76 import java.text.AttributedString;
77 import java.util.Vector;
78
79 import javax.imageio.*;
80 import javax.swing.*;
81
82 import static java.awt.RenderingHints.*;
83
84 /**
85 * FontPanel.java
86 *
87 * @author Shinsuke Fukuda
88 * @author Ankit Patel [Conversion to Swing - 01/07/30]
89 */
90
91 /// This panel is combination of the text drawing area of Font2DTest
92 /// and the custom controlled scroll bar
93
94 public final class FontPanel extends JPanel implements AdjustmentListener {
95
96 /// Drawing Option Constants
374 /// Reload all options and refreshes the canvas
375 public void loadOptions( boolean grid, boolean force16, int start, int end,
376 String name, float size, int style,
377 int transform, int g2transform,
378 int text, int method, int aa, int fm,
379 int contrast, String[] user ) {
380 int[] range = { start, end };
381
382 /// Since repaint call has a low priority, these functions will finish
383 /// before the actual repainting is done
384 setGridDisplay( grid );
385 setForce16Columns( force16 );
386 // previous call to readTextFile has already set the text to draw
387 if (textToUse != FILE_TEXT) {
388 setTextToDraw( text, range, user, null );
389 }
390 setFontParams( name, size, style, transform );
391 setTransformG2( g2transform ); // ABP
392 setDrawMethod( method );
393 setRenderingHints(AAValues.getValue(aa), FMValues.getValue(fm),
394 Integer.valueOf(contrast));
395 }
396
397 /// Writes the current screen to PNG file
398 public void doSavePNG( String fileName ) {
399 fc.writePNG( fileName );
400 }
401
402 /// When scrolled using the scroll bar, update the backbuffer
403 public void adjustmentValueChanged( AdjustmentEvent e ) {
404 fc.repaint();
405 }
406
407 public void paintComponent( Graphics g ) {
408 // Windows does not repaint correctly, after
409 // a zoom. Thus, we need to force the canvas
410 // to repaint, but only once. After the first repaint,
411 // everything stabilizes. [ABP]
412 fc.repaint();
413 }
414
416
417 /// Inner panel that holds the actual drawing area and its routines
418 private class FontCanvas extends JPanel implements MouseListener, MouseMotionListener, Printable {
419
420 /// Number of characters that will fit across and down this canvas
421 private int numCharAcross, numCharDown;
422
423 /// First and last character/line that will be drawn
424 /// Limit is the end of range/text where no more draw will be done
425 private int drawStart, drawEnd, drawLimit;
426
427 /// FontMetrics variables
428 /// Here, gridWidth is equivalent to maxAdvance (slightly bigger though)
429 /// and gridHeight is equivalent to lineHeight
430 private int maxAscent, maxDescent, gridWidth = 0, gridHeight = 0;
431
432 /// Offset from the top left edge of the canvas where the draw will start
433 private int canvasInset_X = 5, canvasInset_Y = 5;
434
435 /// LineBreak'ed TextLayout vector
436 private Vector<TextLayout> lineBreakTLs = null;
437
438 /// Whether the current draw command requested is for printing
439 private boolean isPrinting = false;
440
441 /// Other printing infos
442 private int lastPage, printPageNumber, currentlyShownChar = 0;
443 private final int PR_OFFSET = 10;
444 private final int PR_TITLE_LINEHEIGHT = 30;
445
446 /// Information about zooming (used with range text draw)
447 private final JWindow zoomWindow;
448 private BufferedImage zoomImage = null;
449 private int mouseOverCharX = -1, mouseOverCharY = -1;
450 private int currMouseOverChar = -1, prevZoomChar = -1;
451 private float ZOOM = 2.0f;
452 private boolean nowZooming = false;
453 private boolean firstTime = true;
454 // ABP
455
456 /// Status bar message backup
782 throw new CannotDrawException( isPrinting ? CANT_FIT_PRINT : CANT_FIT_DRAW );
783
784 if ( !isPrinting )
785 resetScrollbar( verticalBar.getValue() * numCharAcross );
786 }
787 else {
788 maxDescent += fm.getLeading();
789 canvasInset_X = 5;
790 canvasInset_Y = 5;
791 /// gridWidth and numCharAcross will not be used in this mode...
792 gridHeight = maxAscent + maxDescent;
793 numCharDown = ( h - canvasInset_Y * 2 ) / gridHeight;
794
795 if ( numCharDown == 0 )
796 throw new CannotDrawException( isPrinting ? CANT_FIT_PRINT : CANT_FIT_DRAW );
797 /// If this is text loaded from file, prepares the LineBreak'ed
798 /// text layout at this point
799 if ( textToUse == FILE_TEXT ) {
800 if ( !isPrinting )
801 f2dt.fireChangeStatus( "LineBreaking Text... Please Wait", false );
802 lineBreakTLs = new Vector<>();
803 for ( int i = 0; i < fileText.length; i++ ) {
804 AttributedString as =
805 new AttributedString( fileText[i], g2.getFont().getAttributes() );
806
807 LineBreakMeasurer lbm =
808 new LineBreakMeasurer( as.getIterator(), g2.getFontRenderContext() );
809
810 while ( lbm.getPosition() < fileText[i].length() )
811 lineBreakTLs.add( lbm.nextLayout( (float) w ));
812
813 }
814 }
815 if ( !isPrinting )
816 resetScrollbar( verticalBar.getValue() );
817 }
818 }
819
820 /// Calculates the amount of text that will be displayed on screen
821 private void calcTextRange() {
822 String displaying = null;
911
912 modeSpecificDrawChar( g2, charToDraw,
913 gridLocX + gridWidth / 2,
914 gridLocY + maxAscent );
915
916 }
917 }
918 }
919 else if ( textToUse == USER_TEXT ) {
920 g2.drawRect( 0, 0, w - 1, h - 1 );
921 for ( int i = drawStart; i <= drawEnd; i++ ) {
922 int lineStartX = canvasInset_Y;
923 int lineStartY = ( i - drawStart ) * gridHeight + maxAscent;
924 modeSpecificDrawLine( g2, userText[i], lineStartX, lineStartY );
925 }
926 }
927 else {
928 float xPos, yPos = (float) canvasInset_Y;
929 g2.drawRect( 0, 0, w - 1, h - 1 );
930 for ( int i = drawStart; i <= drawEnd; i++ ) {
931 TextLayout oneLine = lineBreakTLs.elementAt( i );
932 xPos =
933 oneLine.isLeftToRight() ?
934 canvasInset_X : ( (float) w - oneLine.getAdvance() - canvasInset_X );
935
936 float[] fmData = {0, oneLine.getAscent(), 0, oneLine.getDescent(), 0, oneLine.getLeading()};
937 if (g2Transform != NONE) {
938 AffineTransform at = getAffineTransform(g2Transform);
939 at.transform( fmData, 0, fmData, 0, 3);
940 }
941 //yPos += oneLine.getAscent();
942 yPos += fmData[1]; // ascent
943 //oneLine.draw( g2, xPos, yPos );
944 tlDrawLine( g2, oneLine, xPos, yPos );
945 //yPos += oneLine.getDescent() + oneLine.getLeading();
946 yPos += fmData[3] + fmData[5]; // descent + leading
947 }
948 }
949 g2.dispose();
950 }
951
974 if ( pageIndex == 0 ) {
975 /// Reset the last page index to max...
976 lastPage = Integer.MAX_VALUE;
977 currentlyShownChar = verticalBar.getValue() * numCharAcross;
978 }
979
980 if ( printMode == ONE_PAGE ) {
981 if ( pageIndex > 0 )
982 return NO_SUCH_PAGE;
983 }
984 else {
985 if ( pageIndex > lastPage )
986 return NO_SUCH_PAGE;
987 }
988
989 int pageWidth = (int) pf.getImageableWidth();
990 int pageHeight = (int) pf.getImageableHeight();
991 /// Back up metrics and other drawing info before printing modifies it
992 int backupDrawStart = drawStart, backupDrawEnd = drawEnd;
993 int backupNumCharAcross = numCharAcross, backupNumCharDown = numCharDown;
994 Vector<TextLayout> backupLineBreakTLs = null;
995 if ( textToUse == FILE_TEXT )
996 backupLineBreakTLs = new Vector<>(lineBreakTLs);
997
998 printPageNumber = pageIndex;
999 isPrinting = true;
1000 /// Push the actual draw area 60 down to allow info to be printed
1001 g.translate( (int) pf.getImageableX(), (int) pf.getImageableY() + 60 );
1002 try {
1003 drawText( g, pageWidth, pageHeight - 60 );
1004 }
1005 catch ( CannotDrawException e ) {
1006 f2dt.fireChangeStatus( ERRORS[ e.id ], true );
1007 return NO_SUCH_PAGE;
1008 }
1009
1010 /// Draw information about what is being printed
1011 String hints = ( " with antialias " + antiAliasType + "and" +
1012 " fractional metrics " + fractionalMetricsType +
1013 " and lcd contrast = " + lcdContrast);
1014 String infoLine1 = ( "Printing" + MS_OPENING[textToUse] +
1015 modeSpecificNumStr( drawStart ) + " to " +
1016 modeSpecificNumStr( drawEnd ) + MS_CLOSING[textToUse] );
1119 zoomWindow.setSize( zoomAreaWidth + 1, zoomAreaHeight + 20 );
1120 else
1121 zoomWindow.setSize( zoomAreaWidth + 1, zoomAreaHeight + 1 );
1122 }
1123
1124 /// Prepare zoomed image
1125 zoomImage =
1126 (BufferedImage) zoomWindow.createImage( zoomAreaWidth + 1,
1127 zoomAreaHeight + 1 );
1128 Graphics2D g2 = (Graphics2D) zoomImage.getGraphics();
1129 testFont = testFont.deriveFont( fontSize * ZOOM );
1130 setParams( g2 );
1131 g2.setColor( Color.white );
1132 g2.fillRect( 0, 0, zoomAreaWidth, zoomAreaHeight );
1133 g2.setColor( Color.black );
1134 g2.drawRect( 0, 0, zoomAreaWidth, zoomAreaHeight );
1135 modeSpecificDrawChar( g2, currMouseOverChar,
1136 zoomAreaWidth / 2, (int) ( maxAscent * ZOOM ));
1137 g2.dispose();
1138 if ( !nowZooming )
1139 zoomWindow.setVisible(true);
1140 /// This is sort of redundant... since there is a paint function
1141 /// inside zoomWindow definition that does the drawImage.
1142 /// (I should be able to call just repaint() here)
1143 /// However, for some reason, that paint function fails to respond
1144 /// from second time and on; So I have to force the paint here...
1145 zoomWindow.getGraphics().drawImage( zoomImage, 0, 0, this );
1146
1147 nowZooming = true;
1148 prevZoomChar = currMouseOverChar;
1149 testFont = backup;
1150
1151 // Windows does not repaint correctly, after
1152 // a zoom. Thus, we need to force the canvas
1153 // to repaint, but only once. After the first repaint,
1154 // everything stabilizes. [ABP]
1155 if ( firstTime() ) {
1156 refresh();
1157 }
1158 }
1159
1160 /// Listener Functions
1161
1162 /// MouseListener interface function
1163 /// Zooms a character when mouse is pressed above it
1164 public void mousePressed( MouseEvent e ) {
1165 if ( !showingError) {
1166 if ( checkMouseLoc( e )) {
1167 showZoomed();
1168 this.setCursor( blankCursor );
1169 }
1170 }
1171 }
1172
1173 /// MouseListener interface function
1174 /// Redraws the area that was drawn over by zoomed character
1175 public void mouseReleased( MouseEvent e ) {
1176 if ( textToUse == RANGE_TEXT || textToUse == ALL_GLYPHS ) {
1177 if ( nowZooming )
1178 zoomWindow.setVisible(false);
1179 nowZooming = false;
1180 }
1181 this.setCursor( Cursor.getDefaultCursor() );
1182 }
1183
1184 /// MouseListener interface function
1185 /// Resets the status bar to display range instead of a specific character
1186 public void mouseExited( MouseEvent e ) {
1187 if ( !showingError && !nowZooming )
1188 f2dt.fireChangeStatus( backupStatusString, false );
1189 }
1190
1191 /// MouseMotionListener interface function
1192 /// Adjusts the status bar message when mouse moves over a character
1193 public void mouseMoved( MouseEvent e ) {
1194 if ( !showingError ) {
1195 if ( !checkMouseLoc( e ))
1196 f2dt.fireChangeStatus( backupStatusString, false );
1197 }
1198 }
1228
1229 private String name;
1230 private Object hint;
1231
1232 private static FMValues[] valArray;
1233
1234 FMValues(String s, Object o) {
1235 name = s;
1236 hint = o;
1237 }
1238
1239 public String toString() {
1240 return name;
1241 }
1242
1243 public Object getHint() {
1244 return hint;
1245 }
1246 public static Object getValue(int ordinal) {
1247 if (valArray == null) {
1248 valArray = FMValues.values();
1249 }
1250 for (int i=0;i<valArray.length;i++) {
1251 if (valArray[i].ordinal() == ordinal) {
1252 return valArray[i];
1253 }
1254 }
1255 return valArray[0];
1256 }
1257 private static FMValues[] getArray() {
1258 if (valArray == null) {
1259 valArray = FMValues.values();
1260 }
1261 return valArray;
1262 }
1263
1264 public static int getHintVal(Object hint) {
1265 getArray();
1266 for (int i=0;i<valArray.length;i++) {
1267 if (valArray[i].getHint() == hint) {
1268 return i;
1269 }
1270 }
1271 return 0;
1272 }
1273 }
1274
1275 enum AAValues {
1276 AADEFAULT ("DEFAULT", VALUE_TEXT_ANTIALIAS_DEFAULT),
1277 AAOFF ("OFF", VALUE_TEXT_ANTIALIAS_OFF),
1278 AAON ("ON", VALUE_TEXT_ANTIALIAS_ON),
1279 AAGASP ("GASP", VALUE_TEXT_ANTIALIAS_GASP),
1290 AAValues(String s, Object o) {
1291 name = s;
1292 hint = o;
1293 }
1294
1295 public String toString() {
1296 return name;
1297 }
1298
1299 public Object getHint() {
1300 return hint;
1301 }
1302
1303 public static boolean isLCDMode(Object o) {
1304 return (o instanceof AAValues &&
1305 ((AAValues)o).ordinal() >= AALCDHRGB.ordinal());
1306 }
1307
1308 public static Object getValue(int ordinal) {
1309 if (valArray == null) {
1310 valArray = AAValues.values();
1311 }
1312 for (int i=0;i<valArray.length;i++) {
1313 if (valArray[i].ordinal() == ordinal) {
1314 return valArray[i];
1315 }
1316 }
1317 return valArray[0];
1318 }
1319
1320 private static AAValues[] getArray() {
1321 if (valArray == null) {
1322 valArray = AAValues.values();
1323 }
1324 return valArray;
1325 }
1326
1327 public static int getHintVal(Object hint) {
1328 getArray();
1329 for (int i=0;i<valArray.length;i++) {
1330 if (valArray[i].getHint() == hint) {
1331 return i;
1332 }
1333 }
1334 return 0;
1335 }
1336
1337 }
1338
1339 private static Integer defaultContrast;
1340 static Integer getDefaultLCDContrast() {
1341 if (defaultContrast == null) {
1342 GraphicsConfiguration gc =
|