package polarDust.calculator; /* * Copyright (c) 1996 Sorin Lazareanu, All Rights Reserved. * * Permission to use, copy, modify, and distribute this software * and its documentation for NON-COMMERCIAL purposes and without * fee is hereby granted provided that this copyright notice * appears in all copies. * */ import java.awt.*; /** * NumDisplay01 is a component capable of displaying a 12 digit * decimal number in a floating point calculator specific format. * If the number overflows the limit of 10e13 - 1, a flashing error message is * displayed. On the left side it has letter M as a memory content flag. * *

* The source code. * * @version 0.9, 1996.06.04 * @author Sorin Lazareanu */ public class NumDisplay01 extends Canvas implements CalcDisplay, Runnable, CalcConstants { static final long lMaxDigitsFactor = 100000000000L; // 10e11d static final int iMaxDigits = 12; boolean bM = false; boolean bNewThread = true, bSuspended = true; boolean bTick = true; boolean bError = false; int iLastOp = 0; Thread thisThread = new Thread(this, "Blinking Display"); String text= " 0."; Dimension bufferDimension = new Dimension(0, 0); Image bufferImage; Graphics bufferGraphics; PrinterPanel01 printer; /** * Constructs a new display. */ public NumDisplay01() { super(); } /** * Constructs a new display, driver for a printer. * @param aPrinter the calculator printer attached. * @see PrinterPanel01 */ public NumDisplay01(PrinterPanel01 aPrinter) { super(); printer = aPrinter; } /** * @return the factor for a 12 digits display is 10e11 */ public long maxDigitsFactor() { return lMaxDigitsFactor; } /** * Displays the parameter. No output to calculator printer. * @param dReg1 the number to be displayed. * @return the number as represented on the display component. */ public double show(double dReg1) { double dResult; dResult = showNumber(dReg1, -1); return dResult; } /** * Displays the parameter with output to calculator printer if exists. * @param dReg1 the number to be displayed. * @return the number as represented on the display component. */ public double assign(double dReg1) { double dResult; if (printer != null) printer.showResult(text); dResult = showNumber(dReg1, -1); return dResult; } /** * Oputputs the operator to the calculator printer. * @param oper the representation of the operator to be printed. */ public void showOp(String oper) { if (printer != null) printer.showOp(oper); } /** * Displays the parameter. No output to calculator printer. * @param dReg1 the number to be displayed. * @param iDecimals the number of digits after the decimal point. * @return the number as represented on the display component. */ public double showWithDecimals(double dReg1, int iDecimals) { double dResult; dResult = showNumber(dReg1, iDecimals); return dResult; } /** * Displays the parameter with output to calculator printer. * @param dReg1 the number to be displayed. * @param iDecimals the number of digits after the decimal point. * @return the number as represented on the display component. */ public double assignWithDecimals(double dReg1, int iDecimals) { double dResult; if (printer != null) printer.showResult(text); dResult = showNumber(dReg1, iDecimals); return dResult; } /** * Converts a double to a string format suitable for a NumDisplay * @param dReg1 the number to be displayed. * @param iDecimals the number of digits after the decimal point. * @return the representation. */ protected synchronized String toFloatString(double dReg1, int iDecimals){ int i; char cDec[]; double dAbs = Math.abs(dReg1); long lInt, lDec, lI = 1; StringBuffer num = new StringBuffer(""), dec; StringBuffer paddedNum = new StringBuffer(""); iDecimals = Math.min(iMaxDigits, iDecimals); if (dAbs >= lMaxDigitsFactor * 10) { num.append("Error"); } else { num.append(dReg1 >= 0?"":"-"); lInt = (long)dAbs; num.append(lInt + "."); while (dAbs > lI) lI *= 10L; lDec = Math.round((dAbs - lInt + 1) * lMaxDigitsFactor * 100 / lI); // * 1000 - 10 from (... + 1) // - 10 increase the internal precision by 1 digit ( not finished) lDec = lDec / 10 + ((lDec - lDec / 10 * 10 > 5)?1:0); dec = new StringBuffer(new Long(lDec).toString()); while ( dec.length() > 1 && dec.charAt( dec.length() - 1 ) == '0' && (dec.length() - 1) > iDecimals ) { dec.setLength( Math.max(1, dec.length() - 1 )); } if (iDecimals != 0 && dec.length() > 1) { cDec = new char[ dec.length() - 1 ]; dec.getChars(1, dec.length(), cDec, 0); num.append(cDec); } } i = iMaxDigits + 2 - num.length(); while (i-- > 0) { paddedNum.append(' '); }; paddedNum.append(num); return new String(paddedNum); } protected double showNumber(double dReg1, int iDecimals){ String num = toFloatString(dReg1, iDecimals); text = num; if (num.endsWith("Error")) { bError = true; if (printer != null) printer.showResult(text); if (bNewThread) { start(); bNewThread = false; } resume(); } else { bError = false; if (!bNewThread) suspend(); } repaint(); try { dReg1 = new Double(num).doubleValue(); } catch (NumberFormatException e){ dReg1 = 0d; } return dReg1; } /** * @return the last operation generated an error (overflow). */ public boolean isError() { return bError; } /** * @param a number * @return the parameter has a zero value representation on display. */ public boolean isNotZero(double dReg) {; String num = toFloatString(dReg, -1); try { dReg = new Double(num).doubleValue(); } catch (NumberFormatException e) { dReg = 0d; }; return dReg == 0d; } /** * Shows the letter M if the parameter is not represented as a zero value. */ public double showM(double dRegM) { String num = toFloatString(dRegM, -1); try { dRegM = new Double(num).doubleValue(); } catch (NumberFormatException e) { text = num; dRegM = 0d; } bM = dRegM != 0d; repaint(); return dRegM; } /** * Sends a string to be displayed. */ public void setNumber( String aString ) { text = aString; repaint(); } public Dimension preferredSize() { return new Dimension(155, 32); } public Dimension minimumSize() { return preferredSize(); } /** * Start the thread for blinking. */ public synchronized void start() { if (!isAlive()) { thisThread.setDaemon(true); thisThread.start(); bSuspended = false; } } /** * Stops the thread for blinking. */ public void stop() { if (isAlive()) { thisThread.stop(); bNewThread = false; }; } /** * Resume or suspends the thread for blinking. */ public void toggleRunnable() { if (isAlive()) { try { if (bSuspended) resume(); else suspend(); } catch (IllegalThreadStateException e) { } } } public void suspend() { if (isAlive()) { try { //catch does'n work - no exception thrown ver1.0 thisThread.suspend(); bSuspended = true; bTick = true; repaint(); } catch (IllegalThreadStateException e) { } } } public boolean isAlive() { return thisThread.isAlive(); } public void resume() { if (isAlive()) { try { //catch does'n work - no exception thrown ver1.0 thisThread.resume(); bSuspended = false; } catch (IllegalThreadStateException e) { } } } public void run() { long lTickDuration = 250L; long lLastmS = System.currentTimeMillis(); while (thisThread != null) { try { if (bufferGraphics != null) { bTick = !bTick; } thisThread.sleep( lTickDuration - Math.max( 0L, Math.min( lTickDuration, System.currentTimeMillis() - lLastmS ) ) ); lLastmS = System.currentTimeMillis(); // Should repaint() be called only when Screen Updater thread is running ? // No specs. on Screen Updater. // The thread must be stopped before System.exit(...). repaint(); } catch (InterruptedException e) { break; } }; } public void paint(Graphics aGraphics) { update(aGraphics); } public synchronized void update(Graphics aGraphics) { int iWidth = size().width; int iHeight = size().height; int i, iBeginX, iBeginY; int iStringWidth, iFontHeight; int iFontNewSize; int iMaxScreenWidth, iMaxScreenHeight; int iScreenWidth, iScreenHeight; StringBuffer aStringBuffer = new StringBuffer(""); String aString; FontMetrics currentFontMetrics; aStringBuffer.append(bM?'M':' '); i = iMaxDigits + 2 - (bTick?text.length():0); while (i-- > 0) aStringBuffer.append(' '); aStringBuffer.append(bTick?text:""); aString = new String(aStringBuffer); iMaxScreenWidth = iWidth - 4; iMaxScreenHeight = iHeight - 4; if ( bufferDimension.width != iWidth || bufferDimension.height != iHeight ) { bufferDimension = size(); bufferImage = createImage(iWidth, iHeight); bufferGraphics = bufferImage.getGraphics(); // min. font size = 15, min. string width = 136 (15chars) iStringWidth = bufferGraphics.getFontMetrics().stringWidth(aString); iFontHeight = bufferGraphics.getFontMetrics().getAscent(); iFontNewSize = bufferGraphics.getFont().getSize() * Math.min(iMaxScreenWidth / iStringWidth, iMaxScreenHeight / iFontHeight) + 5; do { // we must loop here since the font size is not a precise defined measure. iFontNewSize--; bufferGraphics.setFont(new Font("Courier", Font.BOLD, iFontNewSize)); currentFontMetrics = bufferGraphics.getFontMetrics(); iStringWidth = currentFontMetrics.stringWidth(aString); //15chars iFontHeight = currentFontMetrics.getAscent(); } while (iStringWidth > iMaxScreenWidth || iFontHeight > iMaxScreenHeight); setFont(new Font("Courier", Font.BOLD, iFontNewSize)); aGraphics.setFont(new Font("Courier", Font.BOLD, iFontNewSize)); } currentFontMetrics = bufferGraphics.getFontMetrics(); bufferGraphics.setColor(getBackground()); bufferGraphics.fillRect(0, 0, iWidth, iHeight); bufferGraphics.setColor(Color.gray); bufferGraphics.fillRoundRect(0, 0, iWidth - 1, iHeight - 1, 15, 15); bufferGraphics.setColor(Color.black); bufferGraphics.drawRoundRect(0, 0, iWidth - 1, iHeight - 1, 15, 15); bufferGraphics.drawRoundRect(1, 1, iWidth - 3, iHeight - 3, 14, 14); iScreenWidth = currentFontMetrics.stringWidth(aString) + 2; iScreenHeight = currentFontMetrics.getAscent()+ 2; iBeginX = (iWidth + 1 - iScreenWidth) / 2; // + 1 for rounding iBeginY = (iHeight + 1 - iScreenHeight ) / 2; // + 1 for rounding bufferGraphics.setColor(Color.black); bufferGraphics.fillRoundRect( iBeginX, iBeginY, iScreenWidth, iScreenHeight, 13, 13 ); bufferGraphics.setColor(Color.green.brighter()); bufferGraphics.drawString( aString, iBeginX + 3, (iHeight + getFontMetrics(getFont()).getAscent() + 1) / 2 - 2 ); aGraphics.drawImage(bufferImage, 0, 0, this); } }