/* 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.gates;
import java.awt.Color;
import java.awt.Graphics;
import java.util.HashMap;
import com.cburch.logisim.data.Location;
import com.cburch.logisim.data.Value;
import com.cburch.logisim.instance.InstancePainter;
import com.cburch.logisim.util.GraphicsUtil;
class PainterDin {
private PainterDin() { }
static final int AND = 0;
static final int OR = 1;
static final int XOR = 2;
static final int XNOR = 3;
private static HashMap<Integer,int[]> orLenArrays = new HashMap<Integer,int[]>();
static void paintAnd(InstancePainter painter, int width, int height,
boolean drawBubble) {
paint(painter, width, height, drawBubble, AND);
}
static void paintOr(InstancePainter painter, int width, int height,
boolean drawBubble) {
paint(painter, width, height, drawBubble, OR);
}
static void paintXor(InstancePainter painter, int width, int height,
boolean drawBubble) {
paint(painter, width, height, drawBubble, XOR);
}
static void paintXnor(InstancePainter painter, int width, int height,
boolean drawBubble) {
paint(painter, width, height, drawBubble, XNOR);
}
private static void paint(InstancePainter painter, int width, int height,
boolean drawBubble, int dinType) {
Graphics g = painter.getGraphics();
int x = 0;
int xMid = -width;
int y0 = -height / 2;
if (drawBubble) {
x -= 4;
width -= 8;
}
int diam = Math.min(height, 2 * width);
if (dinType == AND) {
; // nothing to do
} else if (dinType == OR) {
paintOrLines(painter, width, height, drawBubble);
} else if (dinType == XOR || dinType == XNOR) {
int elen = Math.min(diam / 2 - 10, 20);
int ex0 = xMid + (diam / 2 - elen) / 2;
int ex1 = ex0 + elen;
g.drawLine(ex0, -5, ex1, -5);
g.drawLine(ex0, 0, ex1, 0);
g.drawLine(ex0, 5, ex1, 5);
if (dinType == XOR) {
int exMid = ex0 + elen / 2;
g.drawLine(exMid, -8, exMid, 8);
}
} else {
throw new IllegalArgumentException("unrecognized shape");
}
GraphicsUtil.switchToWidth(g, 2);
int x0 = xMid - diam / 2;
Color oldColor = g.getColor();
if (painter.getShowState()) {
Value val = painter.getPort(0);
g.setColor(val.getColor());
}
g.drawLine(x0 + diam, 0, 0, 0);
g.setColor(oldColor);
if (height <= diam) {
g.drawArc(x0, y0, diam, diam, -90, 180);
} else {
int x1 = x0 + diam;
int yy0 = -(height - diam) / 2;
int yy1 = (height - diam) / 2;
g.drawArc(x0, y0, diam, diam, 0, 90);
g.drawLine(x1, yy0, x1, yy1);
g.drawArc(x0, y0 + height - diam, diam, diam, -90, 90);
}
g.drawLine(xMid, y0, xMid, y0 + height);
if (drawBubble) {
g.fillOval(x0 + diam - 4, -4, 8, 8);
xMid += 4;
}
}
private static void paintOrLines(InstancePainter painter,
int width, int height, boolean hasBubble) {
GateAttributes baseAttrs = (GateAttributes) painter.getAttributeSet();
int inputs = baseAttrs.inputs;
GateAttributes attrs = (GateAttributes) OrGate.FACTORY.createAttributeSet();
attrs.inputs = inputs;
attrs.size = baseAttrs.size;
Graphics g = painter.getGraphics();
// draw state if appropriate
// ignore lines if in print view
int r = Math.min(height / 2, width);
Integer hash = Integer.valueOf(r << 4 | inputs);
int[] lens = orLenArrays.get(hash);
if (lens == null) {
lens = new int[inputs];
orLenArrays.put(hash, lens);
int yCurveStart = height / 2 - r;
for (int i = 0; i < inputs; i++) {
int y = OrGate.FACTORY.getInputOffset(attrs, i).getY();
if (y < 0) y = -y;
if (y <= yCurveStart) {
lens[i] = r;
} else {
int dy = y - yCurveStart;
lens[i] = (int) (Math.sqrt(r * r - dy * dy) + 0.5);
}
}
}
AbstractGate factory = hasBubble ? NorGate.FACTORY : OrGate.FACTORY;
boolean printView = painter.isPrintView() && painter.getInstance() != null;
GraphicsUtil.switchToWidth(g, 2);
for (int i = 0; i < inputs; i++) {
if (!printView || painter.isPortConnected(i)) {
Location loc = factory.getInputOffset(attrs, i);
int x = loc.getX();
int y = loc.getY();
g.drawLine(x, y, x + lens[i], y);
}
}
}
}