package causation.lab.plaf.basic;
// packages
import javax.swing.*;
import javax.swing.plaf.*;
import java.awt.*;
import java.util.Vector;
// custom classes
import causation.lab.plaf.WorkbenchUI;
import causation.lab.Workbench;
import causation.lab.WBVariable;
import causation.lab.Randomizer;
import causation.lab.Latent;
import causation.lab.WorkbenchEdge;
import causation.lab.PointPair;
/**
*
* The L&F for Workbenchs.
* Copyright 1999 by David Danks. All rights reserved.
*
*
* @see Workbench
* @see WorkbenchUI
* @version 0.9 Feb 26, 1999
* @author David Danks
*/
public class BasicWorkbenchUI extends WorkbenchUI {
/////////////////// Class Variables ///////////////////
private static final Color BACKGROUND = new Color(255, 255, 255);
private static final Color LABEL = new Color(102, 102, 102);
private static final Color LINE = new Color(102, 102, 102);
private static final int BREAK_OFFSET = 5;
private static final String LINE1 = "Broken";
private static final String LINE2 = "by ";
private static final String NO_LOCK_STRING = "lock";
private static final ImageIcon NO_LOCK_SIGNAL = new ImageIcon();
private static final String NO_RAND_STRING = "randomizer";
private static final ImageIcon NO_RAND_SIGNAL = new ImageIcon();
/////////////////// Constructor ///////////////////
/**
* Currently does not do any initialization
*/
public BasicWorkbenchUI() { ; }
/////////////////// Class Methods ///////////////////
/**
* @param c The JComponent the BasicWorkbenchUI is for
* @return A new instance of BasicWorkbenchUI
*/
public static ComponentUI createUI(JComponent c) {
return new BasicWorkbenchUI();
}
/////////////////// Instance Methods ///////////////////
/**
* Currently does not do anything
* @param c The JComponent that will use the BasicWorkbenchUI
*/
public void installUI(JComponent c) { ; }
/**
* Currently does not do anything
* @param c The JComponent that is no longer using the
* BasicWorkbenchUI
*/
public void uninstallUI(JComponent c) { ; }
/**
* Paints the background for the Workbench, as well as the WorkbenchEdges.
* @param g The Graphics context in which to paint the Workbench
* @param c The Workbench being painted
*/
public void paint(Graphics g, JComponent c) {
if (!(c instanceof Workbench)) return;
Workbench src = (Workbench)c;
g.setFont(src.getFont());
FontMetrics fm = g.getFontMetrics();
// don't paint in the border (if there is one)
Insets insets = src.getInsets();
g.translate(insets.left, insets.top);
int width = src.getWidth()-insets.left-insets.right;
int height = src.getHeight()-insets.top-insets.bottom;
// draw the background
g.setColor(BACKGROUND);
g.fillRect(0, 0, width, height);
// draw the bin label
g.setColor(LABEL);
int xPos = (width-fm.stringWidth(src.getBinLabel())-
src.getBinMargin().left-src.getBinMargin().right) / 2;
g.drawString(src.getBinLabel(), src.getBinMargin().left+xPos,
height-src.getBinHeight()+fm.getAscent());
// draw the bin divider
g.setColor(LINE);
int offset = height-src.getBinHeight();
for (int i=0; i=0; i--) {
WorkbenchEdge edge = (WorkbenchEdge)edges.elementAt(i);
drawArrow(edge, g);
}
// and draw the randomizer edges
Vector rands = src.getRandomizers();
for (int i=rands.size()-1; i>=0; i--) {
WorkbenchEdge edge = ((Randomizer)rands.elementAt(i)).getEdge();
drawArrow(edge, g);
}
}
/**
* Draw the arrow for a particular WorkbenchEdge for us
* @param edge The WorkbenchEdge to draw
* @param g The Graphics context in which to draw the WorkbenchEdge
*/
private void drawArrow(WorkbenchEdge edge, Graphics g) {
PointPair pp = edge.getPointPair();
g.setColor(edge.getColor());
g.drawLine(pp.from.x, pp.from.y, pp.to.x, pp.to.y);
// ...and the arrowhead
double a = pp.to.x - pp.from.x;
double b = pp.from.y - pp.to.y;
double theta = Math.atan2(b, a);
int itheta = (int)((theta * 360.0) / (2.0 * Math.PI) + 180);
g.fillArc(pp.to.x - 18, pp.to.y - 18, 36, 36,
itheta - 15, 30);
}
/**
* Draws a screen shot of the Workbench onto g
* @param g The Graphics context in which to draw the screen shot
* @param origin The origin of the screen shot (needed for translations)
* @param mult The compression multiplier
* @param expSetup Whether we're drawing an experimental setup
* @param w The Workbench to draw onto g
*/
public void drawWorkbenchImage(Graphics g, Point origin, double mult,
boolean expSetup, Workbench w) {
// draw the onWorkbench Variables
WBVariable[] vars = w.getOnWorkbenchVariables();
if (vars == null) return;
for (int i=0; i=0; i--) {
Latent l = ((Latent)latents.elementAt(i));
Rectangle bounds = l.getBounds();
Graphics sub =
g.create((int)(mult*(double)(bounds.x-origin.x)),
(int)(mult*(double)(bounds.y-origin.y)), bounds.width,
bounds.height);
l.paint(sub);
sub.dispose();
}
}
// draw the edges
if (!expSetup) {
Vector edges = w.getEdges();
for (int i=edges.size()-1; i>=0; i--) {
WorkbenchEdge edge = (WorkbenchEdge)edges.elementAt(i);
boolean drawn = false;
// if we're in SGD mode, then draw an unbroken arrow
if (w.getMode() == Workbench.SETUP_GATHER_MODE) {
drawScreenShotArrow(edge, g, origin, mult, null, w);
drawn = true;
}
// if the 'to' variable is locked or randomized, break arrow
if ((edge.getToObject() instanceof WBVariable) && !(drawn)) {
WBVariable v = (WBVariable)edge.getToObject();
if (v.isLocked()) {
Icon draw = v.getDisabledLockIcon();
if (draw != null)
drawScreenShotArrow(edge, g, origin, mult, draw, w);
else drawScreenShotArrow(edge, g, origin, mult,
NO_LOCK_SIGNAL, w);
drawn = true;
}
else if (v.isRandomized()) {
Icon draw =
v.getRandomizer().getDisabledRandomizerIcon();
if (draw != null)
drawScreenShotArrow(edge, g, origin, mult, draw, w);
else drawScreenShotArrow(edge, g, origin, mult,
NO_RAND_SIGNAL, w);
drawn = true;
}
}
// if 'from' var is locked, break arrow
if ((edge.getFromObject() instanceof WBVariable) && !(drawn)) {
WBVariable v = (WBVariable)edge.getFromObject();
if (v.isLocked()) {
Icon draw = v.getDisabledLockIcon();
if (draw != null)
drawScreenShotArrow(edge, g, origin, mult, draw, w);
else
drawScreenShotArrow(edge, g, origin, mult,
NO_LOCK_SIGNAL, w);
drawn = true;
}
}
// otherwise, draw a simple arrow
if (!(drawn))
drawScreenShotArrow(edge, g, origin, mult, null, w);
}
}
// and draw the randomizers and edges
Vector rands = w.getRandomizers();
for (int i=rands.size()-1; i>=0; i--) {
// draw the randomizer here
Randomizer rand = (Randomizer)rands.elementAt(i);
Rectangle bounds = rand.getBounds();
Graphics sub = g.create((int)(mult*(double)(bounds.x-origin.x)),
(int)(mult*(double)(bounds.y-origin.y)), bounds.width,
bounds.height);
rand.paint(sub);
sub.dispose();
drawScreenShotArrow(rand.getEdge(), g, origin, mult, null, w);
}
}
/**
* Draw the screen shot arrow for a particular WorkbenchEdge for us
* @param edge The WorkbenchEdge to draw
* @param g The Graphics context in which to draw the WorkbenchEdge
* @param origin The origin of the whole Image (used for translation)
* @param mult The compression multiplier
* @param breaker An Icon of the manipulation that broke the arrow, or
* an Integer signal, or null if it is unbroken
* @param w The Workbench
*/
private void drawScreenShotArrow(WorkbenchEdge edge, Graphics g,
Point origin, double mult, Icon breaker, Workbench w) {
// first, figure out the new rectangles for the ends of the edge,
// and then get the PointPair
Rectangle r1 = (Rectangle)edge.getFromObject().getBounds().clone();
Rectangle r2 = (Rectangle)edge.getToObject().getBounds().clone();
r1.x = (int)(mult*(double)(r1.x-origin.x));
r1.y = (int)(mult*(double)(r1.y-origin.y));
r2.x = (int)(mult*(double)(r2.x-origin.x));
r2.y = (int)(mult*(double)(r2.y-origin.y));
PointPair pp = WorkbenchEdge.calculateEdge(r1, r2);
// draw the line...
double a; double b;
Point mid = null;
if (breaker != null) {
g.setColor(WorkbenchEdge.DISABLED_COLOR);
mid = new Point((pp.from.x+pp.to.x)/2, (pp.from.y+pp.to.y)/2);
// now, determine how angled the arrow is, and draw it broken
double slope = ((double)(pp.from.y-pp.to.y))/
((double)(pp.from.x-pp.to.x));
int XOFFSET = 0; int YOFFSET = 0;
if ((slope < -1.0) || (slope > 1.0)) XOFFSET = BREAK_OFFSET;
else YOFFSET = BREAK_OFFSET;
g.drawLine(pp.from.x, pp.from.y, mid.x+XOFFSET, mid.y+YOFFSET);
g.drawLine(mid.x-XOFFSET, mid.y-YOFFSET, pp.to.x, pp.to.y);
// set a & b
a = pp.to.x - (mid.x-XOFFSET);
b = (mid.y-YOFFSET) - pp.to.y;
}
else {
g.setColor(edge.getColor());
g.drawLine(pp.from.x, pp.from.y, pp.to.x, pp.to.y);
a = pp.to.x - pp.from.x;
b = pp.from.y - pp.to.y;
}
// ...and the arrowhead
double theta = Math.atan2(b, a);
int itheta = (int)((theta * 360.0) / (2.0 * Math.PI) + 180);
g.fillArc(pp.to.x - 18, pp.to.y - 18, 36, 36,
itheta - 15, 30);
// if needed, draw the text and icon (or text, if no icon)
if (breaker != null) {
g.setFont(w.getFont());
FontMetrics fm = g.getFontMetrics(w.getFont());
int marg = fm.stringWidth(LINE1)/2;
g.drawString(LINE1, mid.x-marg, mid.y);
if (breaker == NO_LOCK_SIGNAL) {
marg = fm.stringWidth(LINE2+NO_LOCK_STRING)/2;
g.drawString(LINE2+NO_LOCK_STRING,
mid.x-marg, mid.y+fm.getAscent());
}
else if (breaker == NO_RAND_SIGNAL) {
marg = fm.stringWidth(LINE2+NO_RAND_STRING)/2;
g.drawString(LINE2+NO_RAND_STRING,
mid.x-marg, mid.y+fm.getAscent());
}
else { // there's an actual breaker icon
marg = (fm.stringWidth(LINE2)+breaker.getIconWidth())/2;
g.drawString(LINE2, mid.x-marg, mid.y+fm.getAscent());
breaker.paintIcon(w, g, mid.x-marg+fm.stringWidth(LINE2),
mid.y+fm.getAscent()-breaker.getIconHeight());
}
}
}
}