/* * Numeric.java - Numeric controls class. * * Copyright (c) 1996 Chuck McManis, 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. * * CHUCK MCMANIS 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. CHUCK MCMANIS * SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT * OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. */ import java.applet.Applet; import java.awt.*; import java.util.StringTokenizer; import java.util.Random; import util.comm.*; /** * This is a numeric indicator class. It extends on the capabilites * of SimpleNumeric in that it also has the ability to label itself * and to take control messages on a separate channel. */ public class Numeric extends VJApplet implements Runnable { Thread updater = null; boolean updaterStarted = false; int wholePart = 5; int fractionalPart = 0; boolean isSigned = false; String myLabel = null; long currentValue = 0; DataChannelMux myChannel = null; double minValue, maxValue; double multiple = 1; Font numberFont = new Font("Courier", Font.BOLD, 14); Font labelFont = new Font("Helvetica", Font.BOLD, 14); Color bkGround, dkColor, brColor; void parseFormat(String data) { int w = 5, f = 0; StringTokenizer s = new StringTokenizer(data, ","); try { w = Integer.parseInt(s.nextToken()); f = Integer.parseInt(s.nextToken()); } catch (NumberFormatException e1) { System.out.println("Unrecognized values in format, ignored."); return; } catch (NullPointerException e2) { System.out.println("Insufficient # of parameters."); return; } wholePart = w; fractionalPart = f; for (int i = f; i > 0; i--) { multiple *= 10; } } String channelName; String controlName; String idName; public void init() { String x; bkGround = getColor("bgcolor", Color.lightGray); brColor = bkGround.brighter(); dkColor = bkGround.darker(); channelName = getString("datachannel", "BOGUS"); controlName = getString("controlchannel", null); idName=getString("id", null); x = getParameter("format"); if (x != null) parseFormat(x); minValue = getDouble("minvalue", 0.0); maxValue = getDouble("maxvalue", 100.0); myLabel = getParameter("label"); } char tmp[] = new char[40]; String formattedValue(long value) { boolean wasNeg = false; int ndx = tmp.length - 1; String result; if (value < 0) { wasNeg = true; value = Math.abs(value); } int totalLen = fractionalPart + wholePart + 1; if (fractionalPart != 0) totalLen++; for (int i = 0; i < fractionalPart; i++) { long nextValue = value / 10; tmp[ndx--] = (char)('0' + (value - nextValue*10)); value = nextValue; } if (fractionalPart > 0) tmp[ndx--] = '.'; for (int i = 0; i < wholePart; i++) { long nextValue = value/10; tmp[ndx--] = (char) ('0' + (value - nextValue * 10)); value = nextValue; if (value == 0) break; } if (value != 0) { ndx = tmp.length - 1; for (int i = 0; i < fractionalPart; i--) tmp[ndx--] = '*'; if (fractionalPart > 0) tmp[ndx--] = '.'; for (int i = 0; i < wholePart; i++) tmp[ndx--] = '*'; } if (wasNeg) tmp[ndx--] = '-'; while ((tmp.length - (ndx+1)) < totalLen) { tmp[ndx--] = ' '; } try { result = new String(tmp, ndx+1, tmp.length - (ndx+1)); } catch (StringIndexOutOfBoundsException e) { result = "ERROR"; } return (result); } public void paint(Graphics g) { String numbers; FontMetrics fm; int actualWidth, actualHeight; int offX, offY; g.setColor(bkGround); g.fillRect(0, 0, myWidth, myHeight); g.setFont(numberFont); fm = g.getFontMetrics(); int charWidth = fm.stringWidth("0"); actualWidth = charWidth * (wholePart + fractionalPart + 1) + 4; if (fractionalPart != 0) actualWidth += charWidth; // space for the period actualHeight = fm.getHeight() + 4; offX = myWidth - (actualWidth + 1); offY = (myHeight - actualHeight) / 2; g.setColor(Color.black); g.fillRect(offX, offY, actualWidth, actualHeight); g.setColor(dkColor); g.drawLine(offX, offY, offX+actualWidth, offY); g.drawLine(offX, offY, offX, offY+actualHeight); g.setColor(brColor); g.drawLine(offX+actualWidth, offY, offX+actualWidth, offY+actualHeight); g.drawLine(offX, offY+actualHeight, offX+actualWidth, offY+actualHeight); g.setColor(Color.white); numbers = formattedValue(currentValue); g.drawString(numbers, offX+2, fm.getAscent() + offY + 2); if (myLabel != null) { g.setFont(labelFont); g.setColor(Color.black); fm = offscreen.getFontMetrics(); charWidth = fm.stringWidth(myLabel+" "); g.drawString(myLabel, offX - (charWidth + 1), offY + fm.getAscent() + 2); } } DataChannel localChannel; String chans[]; public void start() { System.out.println("Numeric:: start()"); updater = new Thread(this); localChannel = DataChannel.getChannel(idName, updater, 8); if (controlName != null) { chans = new String[2]; chans[0] = channelName; chans[1] = controlName; } else { chans = new String[1]; chans[0] = channelName; } myChannel = new DataChannelMux(chans, idName); updater.start(); } public void stop() { System.out.println("Numeric:: stop()"); // myChannel.releaseChannel(updater); updater = null; } void parseControl(String ctl) { if (ctl.startsWith("minvalue:")) { try { minValue = Double.valueOf(ctl.substring(9)).doubleValue(); setValue(0.0); return; } catch (NumberFormatException e) { return; } } else if (ctl.startsWith("maxvalue:")) { try { maxValue = Double.valueOf(ctl.substring(9)).doubleValue(); setValue(0.0); return; } catch (NumberFormatException e) { return; } } else if (ctl.startsWith("label:")) { myLabel = ctl.substring(6); } return; } void setValue(double x) { currentValue = (long) (((((maxValue - minValue) * x) / 2000.0) + minValue) * multiple); } public void run() { String ctl; double x = 0; MuxItem z; while (Thread.currentThread() == updater) { repaint(); try { z = (MuxItem)(localChannel.getValue()); switch (z.index()) { case 0: x = ((Integer)(z.value())).doubleValue(); setValue(x); break; case 1: parseControl((String)(z.value())); break; } } catch (DataChannelOverrun e) { System.out.println("Numeric: OVERRUN!"); } catch (DataChannelShutdown e) { System.out.println("Numeric thread shutting down."); return; } catch (DataChannelTimeout e) { continue; } catch (DataChannelException ee) { System.out.println("We're dead."); ee.printStackTrace(); } } } }