// CopyCat // // Continuously scrolling message board for permanent and temporary messages. // // Author Matthew Caryl // Created 16.4.96 // // SUGGESTIONS FOR NEXT TIME // Try making an array of characters to represent the message window. // One system would handle these characters, the other would push // characters in at the far end. Character system would not have to // use cliprect and would not have to think about old messages. The // other system would deal with revolving messages. To update messages // may use another id system and retyping of previous messages. // Messages have to be prioritised so that new messages come up first. // What about constant rate scrolling independant of frame update. package CopyCat; import java.awt.*; final class MessageBoard { private static int MESSAGE_TIME_ALLOWANCE = 2000; private String[] messageStrings = new String[0]; private boolean[] messagePermanent = new boolean[0]; private int messageCurrent = -1; private int messageLast = -1; private boolean messageLost; private int messageScroll = 0; private long messageExpiry; private Font messageFont = new Font("Courier", Font.PLAIN, 14); private int characterHeight; private int characterWidth; private int messageWidth; private boolean dirty; private int width; private int height; private Image image; private Graphics graphics; private void expand() { String[] ms = new String[messageStrings.length + 1]; for (int i = messageStrings.length - 1; i >= 0; i--) ms[i] = messageStrings[i]; messageStrings = ms; boolean[] mp = new boolean[messagePermanent.length + 1]; for (int i = messagePermanent.length - 1; i >= 0; i--) mp[i] = messagePermanent[i]; messagePermanent = mp; } private int spare() { for (int i = messageStrings.length - 1; i >= 0; i--) if (messageStrings[i] == null) return i; expand(); return messageStrings.length - 1; } private int next() { for (int i = messageCurrent - 1; i >= 0; i--) if (messageStrings[i] != null) return i; int stop = Math.max(messageCurrent, 0); for (int i = messageStrings.length - 1; i >= stop; i--) if (messageStrings[i] != null) return i; return -1; } private void scroll() { messageLast = messageCurrent; if (messageLast >= 0 && !messagePermanent[messageLast]) messageStrings[messageLast] = null; messageCurrent = next(); messageExpiry = System.currentTimeMillis() + MESSAGE_TIME_ALLOWANCE; if (messageCurrent != messageLast) { messageScroll = messageWidth; dirty = true; } } protected void finalize() throws Throwable { if (graphics != null) graphics.dispose(); super.finalize(); } public MessageBoard(Graphics g, int W, int H, Component C) { width = W; height = H; FontMetrics m = g.getFontMetrics(messageFont); characterHeight = m.getHeight(); characterWidth = m.charWidth(' '); messageWidth = width / characterWidth; dirty = true; image = C.createImage(W, H); graphics = image.getGraphics(); } public int post(String message, boolean permanent) { int spare = spare(); messageStrings[spare] = message; messagePermanent[spare] = permanent; if (messageCurrent < 0) scroll(); return spare; } public int post(String message) { return post(message, false); } public void update(int id, String message) { messageStrings[id] = message; if (id == messageCurrent | id == messageLast) dirty = true; } public void delete(int id) { messageStrings[id] = null; if (id == messageLast) messageLost = true; if (id == messageCurrent) scroll(); } public void paint(Graphics g, int X, int Y) { g.drawImage(image, X, Y, null); } public boolean dirty() { if (messageScroll > 0) { messageScroll--; dirty = true; } else if (System.currentTimeMillis() >= messageExpiry) scroll(); if (dirty) { graphics.setColor(Color.black); graphics.fillRect(0, 0, width, height); if (messageCurrent >= 0) { graphics.setColor(Color.white); graphics.setFont(messageFont); graphics.drawString(messageStrings[messageCurrent], 2 + messageScroll * characterWidth, (height + characterHeight) / 2 - 2); } dirty = false; return true; } else return false; } }