Package com.cburch.logisim.std.io

Source Code of com.cburch.logisim.std.io.Keyboard

/* Copyright (c) 2010, Carl Burch. License information is located in the
* com.cburch.logisim.Main source code and at www.cburch.com/logisim/. */

package com.cburch.logisim.std.io;

import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.util.ArrayList;

import com.cburch.logisim.data.Attribute;
import com.cburch.logisim.data.Attributes;
import com.cburch.logisim.data.BitWidth;
import com.cburch.logisim.data.Bounds;
import com.cburch.logisim.data.Direction;
import com.cburch.logisim.data.Value;
import com.cburch.logisim.instance.InstanceFactory;
import com.cburch.logisim.instance.InstancePainter;
import com.cburch.logisim.instance.InstancePoker;
import com.cburch.logisim.instance.InstanceState;
import com.cburch.logisim.instance.Port;
import com.cburch.logisim.instance.StdAttr;

public class Keyboard extends InstanceFactory {
  private static final int CLR = 0;
  private static final int CK = 1;
  private static final int RE = 2;
  private static final int AVL = 3;
  private static final int OUT = 4;
 
  private static final int DELAY0 = 9;
  private static final int DELAY1 = 11;

  static final int WIDTH = 145;
  static final int HEIGHT = 25;
 
  private static final Font DEFAULT_FONT = new Font("monospaced", Font.PLAIN, 12);
  private static final char FORM_FEED = '\u000c'; // control-L

  private static final Attribute<Integer> ATTR_BUFFER
    = Attributes.forIntegerRange("buflen",
        Strings.getter("keybBufferLengthAttr"), 1, 256);

  public Keyboard() {
    super("Keyboard", Strings.getter("keyboardComponent"));
    setAttributes(new Attribute[] { ATTR_BUFFER, StdAttr.EDGE_TRIGGER },
        new Object[] { Integer.valueOf(32), StdAttr.TRIG_RISING });
    setOffsetBounds(Bounds.create(0, -15, WIDTH, HEIGHT));
    setIconName("keyboard.gif");
    setInstancePoker(Poker.class);
   
    Port[] ps = new Port[5];
    ps[CLR] = new Port( 20, 10, Port.INPUT, 1);
    ps[CK= new Port00, Port.INPUT, 1);
    ps[RE= new Port( 10, 10, Port.INPUT, 1);
    ps[AVL] = new Port(130, 10, Port.OUTPUT, 1);
    ps[OUT] = new Port(140, 10, Port.OUTPUT, 7);
    ps[CLR].setToolTip(Strings.getter("keybClearTip"));
    ps[CK].setToolTip(Strings.getter("keybClockTip"));
    ps[RE].setToolTip(Strings.getter("keybEnableTip"));
    ps[AVL].setToolTip(Strings.getter("keybAvailTip"));
    ps[OUT].setToolTip(Strings.getter("keybOutputTip"));
    setPorts(ps);
  }

  @Override
  public void propagate(InstanceState circState) {
    Object trigger = circState.getAttributeValue(StdAttr.EDGE_TRIGGER);
    KeyboardData state = getKeyboardState(circState);
    Value clear = circState.getPort(CLR);
    Value clock = circState.getPort(CK);
    Value enable = circState.getPort(RE);
    char c;
   
    synchronized(state) {
      Value lastClock = state.setLastClock(clock);
      if (clear == Value.TRUE) {
        state.clear();
      } else if (enable != Value.FALSE) {
        boolean go;
        if (trigger == StdAttr.TRIG_FALLING) {
          go = lastClock == Value.TRUE && clock == Value.FALSE;
        } else {
          go = lastClock == Value.FALSE && clock == Value.TRUE;
        }
        if (go) state.dequeue();
      }
   
      c = state.getChar(0);
    }
    Value out = Value.createKnown(BitWidth.create(7), c & 0x7F);
    circState.setPort(OUT, out, DELAY0);
    circState.setPort(AVL, c != '\0' ? Value.TRUE : Value.FALSE, DELAY1);
  }
 
  @Override
  public void paintInstance(InstancePainter painter) {
    boolean showState = painter.getShowState();
    Graphics g = painter.getGraphics();
    painter.drawClock(CK, Direction.EAST);
    painter.drawBounds();
    painter.drawPort(CLR);
    painter.drawPort(RE);
    painter.drawPort(AVL);
    painter.drawPort(OUT);

    if (showState) {
      String str;
      int dispStart;
      int dispEnd;
      ArrayList<Integer> specials = new ArrayList<Integer>();
      FontMetrics fm = null;
      KeyboardData state = getKeyboardState(painter);
      synchronized(state) {
        str = state.toString();
        for (int i = state.getNextSpecial(0); i >= 0; i = state.getNextSpecial(i + 1)) {
          char c = state.getChar(i);
          specials.add(Integer.valueOf(c << 16 | i));
        }
        if (!state.isDisplayValid()) {
          fm = g.getFontMetrics(DEFAULT_FONT);
          state.updateDisplay(fm);
        }
        dispStart = state.getDisplayStart();
        dispEnd = state.getDisplayEnd();
      }
     
      if (str.length() > 0) {
        Bounds bds = painter.getBounds();
        drawBuffer(g, fm, str, dispStart, dispEnd, specials, bds);
      }
    } else {
      Bounds bds = painter.getBounds();
      int len = getBufferLength(painter.getAttributeValue(ATTR_BUFFER));
      String str = Strings.get("keybDesc", "" + len);
      FontMetrics fm = g.getFontMetrics();
      int x = bds.getX() + (WIDTH - fm.stringWidth(str)) / 2;
      int y = bds.getY() + (HEIGHT + fm.getAscent()) / 2;
      g.drawString(str, x, y);
    }
  }
   
  private void drawDots(Graphics g, int x, int y, int width, int ascent) {
    int r = width / 10;
    if (r < 1) r = 1;
    int d = 2 * r;
    if (2 * r + 1 * d <= width) g.fillOval(x + r, y - d, d, d);
    if (3 * r + 2 * d <= width) g.fillOval(x + 2 * r + d, y - d, d, d);
    if (5 * r + 3 * d <= width) g.fillOval(x + 3 * r + 2 * d, y - d, d, d);
  }
 
  private void drawBuffer(Graphics g, FontMetrics fm, String str,
      int dispStart, int dispEnd, ArrayList<Integer> specials, Bounds bds) {
    int x = bds.getX();
    int y = bds.getY();
   
    g.setFont(DEFAULT_FONT);
    if (fm == null) fm = g.getFontMetrics();
    int asc = fm.getAscent();
    int x0 = x + 8;
    int ys = y + (HEIGHT + asc) / 2;
    int dotsWidth = fm.stringWidth("m");
    int xs;
    if (dispStart > 0) {
      g.drawString(str.substring(0, 1), x0, ys);
      xs = x0 + fm.stringWidth(str.charAt(0) + "m");
      drawDots(g, xs - dotsWidth, ys, dotsWidth, asc);
      String sub = str.substring(dispStart, dispEnd);
      g.drawString(sub, xs, ys);
      if (dispEnd < str.length()) {
        drawDots(g, xs + fm.stringWidth(sub), ys, dotsWidth, asc);
      }
    } else if (dispEnd < str.length()) {
      String sub = str.substring(dispStart, dispEnd);
      xs = x0;
      g.drawString(sub, xs, ys);
      drawDots(g, xs + fm.stringWidth(sub), ys, dotsWidth, asc);
    } else {
      xs = x0;
      g.drawString(str, xs, ys);
    }

    if (specials.size() > 0) {
      drawSpecials(specials, x0, xs, ys, asc, g, fm,
          str, dispStart, dispEnd);
    }
  }
 
  private void drawSpecials(ArrayList<Integer> specials, int x0, int xs, int ys,
      int asc, Graphics g, FontMetrics fm,
      String str, int dispStart, int dispEnd) {
    int[] px = new int[3];
    int[] py = new int[3];
    for (Integer special : specials) {
      int code = special.intValue();
      int pos = code & 0xFF;
      int w0;
      int w1;
      if (pos == 0) {
        w0 = x0;
        w1 = x0 + fm.stringWidth(str.substring(0, 1));
      } else if (pos >= dispStart && pos < dispEnd) {
        w0 = xs + fm.stringWidth(str.substring(dispStart, pos));
        w1 = xs + fm.stringWidth(str.substring(dispStart, pos + 1));
      } else {
        continue; // this character is not in current view
      }
      w0++;
      w1--;
 
      int key = code >> 16;
      if (key == '\b') {
        int y1 = ys - asc / 2;
        g.drawLine(w0, y1, w1, y1);
        px[0] = w0 + 3; py[0] = y1 - 3;
        px[1] = w0;     py[1] = y1;
        px[2] = w0 + 3; py[2] = y1 + 3;
        g.drawPolyline(px, py, 3);
      } else if (key == '\n') {
        int y1 = ys - 3;
        px[0] = w1; py[0] = ys - asc;
        px[1] = w1; py[1] = y1;
        px[2] = w0; py[2] = y1;
        g.drawPolyline(px, py, 3);
        px[0] = w0 + 3; py[0] = y1 - 3;
        px[1] = w0;     py[1] = y1;
        px[2] = w0 + 3; py[2] = y1 + 3;
        g.drawPolyline(px, py, 3);
      } else if (key == FORM_FEED) {
        g.drawRect(w0, ys - asc, w1 - w0, asc);
      }
    }
  }
 
  private static int getBufferLength(Object bufferAttr) {
    if (bufferAttr instanceof Integer) return ((Integer) bufferAttr).intValue();
    else return 32;
  }
 
  private static KeyboardData getKeyboardState(InstanceState state) {
    int bufLen = getBufferLength(state.getAttributeValue(ATTR_BUFFER));
    KeyboardData ret = (KeyboardData) state.getData();
    if (ret == null) {
      ret = new KeyboardData(bufLen);
      state.setData(ret);
    } else {
      ret.updateBufferLength(bufLen);
    }
    return ret;
  }
 
  public static void addToBuffer(InstanceState state, char[] newChars) {
    KeyboardData keyboardData = getKeyboardState(state);
    for (int i = 0; i < newChars.length; i++) {
      keyboardData.insert(newChars[i]);
    }
  }
 
  public static class Poker extends InstancePoker {
    @Override
    public void keyPressed(InstanceState state, KeyEvent e) {
      KeyboardData data = getKeyboardState(state);
      boolean changed = false;
      boolean used = true;
      synchronized(data) {
        switch (e.getKeyCode()) {
        case KeyEvent.VK_DELETE: changed = data.delete(); break;
        case KeyEvent.VK_LEFT:   data.moveCursorBy(-1); break;
        case KeyEvent.VK_RIGHT:  data.moveCursorBy(1); break;
        case KeyEvent.VK_HOME:   data.setCursor(0); break;
        case KeyEvent.VK_END:    data.setCursor(Integer.MAX_VALUE); break;
        default: used = false;
        }
      }
      if (used) e.consume();
      if (changed) state.getInstance().fireInvalidated();
    }
   
    @Override
    public void keyTyped(InstanceState state, KeyEvent e) {
      KeyboardData data = getKeyboardState(state);
      char ch = e.getKeyChar();
      boolean changed = false;
      if (ch != KeyEvent.CHAR_UNDEFINED) {
        if (!Character.isISOControl(ch) || ch == '\b' || ch == '\n'
            || ch == FORM_FEED) {
          synchronized(data) { changed = data.insert(ch); }
          e.consume();
        }
      }
      if (changed) state.getInstance().fireInvalidated();
    }
   
    public void draw(InstancePainter painter) {
      KeyboardData data = getKeyboardState(painter);
      Bounds bds = painter.getInstance().getBounds();
      Graphics g = painter.getGraphics();
      FontMetrics fm = g.getFontMetrics(DEFAULT_FONT);

      String str;
      int cursor;
      int dispStart;
      synchronized(data) {
        str = data.toString();
        cursor = data.getCursorPosition();
        if (!data.isDisplayValid()) data.updateDisplay(fm);
        dispStart = data.getDisplayStart();
      }

      int asc = fm.getAscent();
      int x = bds.getX() + 8;
      if (dispStart > 0) {
        x += fm.stringWidth(str.charAt(0) + "m");
        x += fm.stringWidth(str.substring(dispStart, cursor));
      } else if (cursor >= str.length()) {
        x += fm.stringWidth(str);
      } else {
        x += fm.stringWidth(str.substring(0, cursor));
      }
      int y = bds.getY() + (bds.getHeight() + asc) / 2;
      g.drawLine(x, y - asc, x, y);
    }
  }
}
TOP

Related Classes of com.cburch.logisim.std.io.Keyboard

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.
. Contact coftware#gmail.com.