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()); } } } }