private boolean nodeOverlapsRectangle(Node node, Rectangle r2) { Rectangle r1 = node.getBounds(); return (r1.x <= (r2.x + r2.width)) && ((r1.x + r1.width) >= r2.x) && (r1.y <= (r2.y + r2.height)) && ((r1.y + r1.height) >= r2.y); }
private Divider dividerAt(Node root, int x, int y) { if (root instanceof Divider) { Divider divider = (Divider) root; return (divider.getBounds().contains(x, y)) ? divider : null; } else if (root instanceof Split) { Split split = (Split) root; for (Node child : split.getChildren()) { if (child.getBounds().contains(x, y)) return dividerAt(child, x, y); } } return null; }
private void minimizeSplitBounds(Split split, Rectangle bounds) { Rectangle splitBounds = new Rectangle(bounds.x, bounds.y, 0, 0); List<Node> splitChildren = split.getChildren(); Node lastChild = splitChildren.get(splitChildren.size() - 1); Rectangle lastChildBounds = lastChild.getBounds(); if (split.isRowLayout()) { int lastChildMaxX = lastChildBounds.x + lastChildBounds.width; splitBounds.add(lastChildMaxX, bounds.y + bounds.height); } else { int lastChildMaxY = lastChildBounds.y + lastChildBounds.height; splitBounds.add(bounds.x + bounds.width, lastChildMaxY); } split.setBounds(splitBounds); }
private void drawCrosses(Graphics g, List<Node> nodes, Rectangle clip) { Graphics2D g2 = (Graphics2D) g; Stroke oldStroke = g2.getStroke(); Stroke stroke = new BasicStroke(DefaultRenderConstants.DEFAULT_RED_CROSS_WIDTH); g2.setStroke(stroke); Paint oldPaint = g2.getPaint(); g2.setColor(Color.RED); for (Node node : nodes) { Rectangle r = node.getBounds(); if (!clip.intersects(r)) continue; g2.drawLine(r.x, r.y, r.x + r.width, r.y + r.height); g2.drawLine(r.x, r.y + r.height, r.x + r.width, r.y); } g2.setStroke(oldStroke); g2.setPaint(oldPaint); }
private void drawComponents( Graphics g, List<Renderable> comps, Rectangle clip, boolean drawEdgeFirst) { List<HyperEdge> edges = new ArrayList<HyperEdge>(); for (Renderable obj : comps) { if (obj instanceof HyperEdge) edges.add((HyperEdge) obj); } if (drawEdgeFirst) { // Draw HyperEdges for (HyperEdge reaction : edges) { // Have to validate connect nodes first in case empty bounds List<Node> nodes = reaction.getConnectedNodes(); for (Node node : nodes) node.validateBounds(g); reaction.validateConnectInfo(); if (clip.intersects(reaction.getBounds())) reaction.render(g); } } // Draw complexes now drawComplexes(comps, clip, g); for (Renderable obj : comps) { if (obj instanceof RenderableCompartment || obj instanceof RenderableComplex || obj instanceof RenderablePathway) continue; // Escape it. It should be drawn earlier. if (obj instanceof Node) { Node node = (Node) obj; if (getHidePrivateNote() && (node instanceof Note) && ((Note) node).isPrivate()) continue; node.validateBounds(g); if (clip.intersects(node.getBounds())) node.render(g); } } if (!drawEdgeFirst) { // Draw HyperEdges for (HyperEdge reaction : edges) { reaction.validateConnectInfo(); if (clip.intersects(reaction.getBounds())) reaction.render(g); } } }
private void layoutGrow(Split split, Rectangle bounds) { Rectangle splitBounds = split.getBounds(); ListIterator<Node> splitChildren = split.getChildren().listIterator(); Node lastWeightedChild = split.lastWeightedChild(); /* Layout the Split's child Nodes' along the X axis. The bounds * of each child will have the same y coordinate and height as the * layoutGrow() bounds argument. Extra width is allocated to the * to each child with a non-zero weight: * newWidth = currentWidth + (extraWidth * splitChild.getWeight()) * Any extraWidth "left over" (that's availableWidth in the loop * below) is given to the last child. Note that Dividers always * have a weight of zero, and they're never the last child. */ if (split.isRowLayout()) { double x = bounds.getX(); double extraWidth = bounds.getWidth() - splitBounds.getWidth(); double availableWidth = extraWidth; while (splitChildren.hasNext()) { Node splitChild = splitChildren.next(); Rectangle splitChildBounds = splitChild.getBounds(); double splitChildWeight = splitChild.getWeight(); if (!splitChildren.hasNext()) { double newWidth = bounds.getMaxX() - x; Rectangle newSplitChildBounds = boundsWithXandWidth(bounds, x, newWidth); layout2(splitChild, newSplitChildBounds); } else if ((availableWidth > 0.0) && (splitChildWeight > 0.0)) { double allocatedWidth = (splitChild.equals(lastWeightedChild)) ? availableWidth : Math.rint(splitChildWeight * extraWidth); double newWidth = splitChildBounds.getWidth() + allocatedWidth; Rectangle newSplitChildBounds = boundsWithXandWidth(bounds, x, newWidth); layout2(splitChild, newSplitChildBounds); availableWidth -= allocatedWidth; } else { double existingWidth = splitChildBounds.getWidth(); Rectangle newSplitChildBounds = boundsWithXandWidth(bounds, x, existingWidth); layout2(splitChild, newSplitChildBounds); } x = splitChild.getBounds().getMaxX(); } } /* Layout the Split's child Nodes' along the Y axis. The bounds * of each child will have the same x coordinate and width as the * layoutGrow() bounds argument. Extra height is allocated to the * to each child with a non-zero weight: * newHeight = currentHeight + (extraHeight * splitChild.getWeight()) * Any extraHeight "left over" (that's availableHeight in the loop * below) is given to the last child. Note that Dividers always * have a weight of zero, and they're never the last child. */ else { double y = bounds.getY(); double extraHeight = bounds.getMaxY() - splitBounds.getHeight(); double availableHeight = extraHeight; while (splitChildren.hasNext()) { Node splitChild = splitChildren.next(); Rectangle splitChildBounds = splitChild.getBounds(); double splitChildWeight = splitChild.getWeight(); if (!splitChildren.hasNext()) { double newHeight = bounds.getMaxY() - y; Rectangle newSplitChildBounds = boundsWithYandHeight(bounds, y, newHeight); layout2(splitChild, newSplitChildBounds); } else if ((availableHeight > 0.0) && (splitChildWeight > 0.0)) { double allocatedHeight = (splitChild.equals(lastWeightedChild)) ? availableHeight : Math.rint(splitChildWeight * extraHeight); double newHeight = splitChildBounds.getHeight() + allocatedHeight; Rectangle newSplitChildBounds = boundsWithYandHeight(bounds, y, newHeight); layout2(splitChild, newSplitChildBounds); availableHeight -= allocatedHeight; } else { double existingHeight = splitChildBounds.getHeight(); Rectangle newSplitChildBounds = boundsWithYandHeight(bounds, y, existingHeight); layout2(splitChild, newSplitChildBounds); } y = splitChild.getBounds().getMaxY(); } } }
private void layoutShrink(Split split, Rectangle bounds) { Rectangle splitBounds = split.getBounds(); ListIterator<Node> splitChildren = split.getChildren().listIterator(); if (split.isRowLayout()) { int totalWidth = 0; // sum of the children's widths int minWeightedWidth = 0; // sum of the weighted childrens' min widths int totalWeightedWidth = 0; // sum of the weighted childrens' widths for (Node splitChild : split.getChildren()) { int nodeWidth = splitChild.getBounds().width; int nodeMinWidth = Math.min(nodeWidth, minimumNodeSize(splitChild).width); totalWidth += nodeWidth; if (splitChild.getWeight() > 0.0) { minWeightedWidth += nodeMinWidth; totalWeightedWidth += nodeWidth; } } double x = bounds.getX(); double extraWidth = splitBounds.getWidth() - bounds.getWidth(); double availableWidth = extraWidth; boolean onlyShrinkWeightedComponents = (totalWeightedWidth - minWeightedWidth) > extraWidth; while (splitChildren.hasNext()) { Node splitChild = splitChildren.next(); Rectangle splitChildBounds = splitChild.getBounds(); double minSplitChildWidth = minimumNodeSize(splitChild).getWidth(); double splitChildWeight = (onlyShrinkWeightedComponents) ? splitChild.getWeight() : (splitChildBounds.getWidth() / totalWidth); if (!splitChildren.hasNext()) { double newWidth = Math.max(minSplitChildWidth, bounds.getMaxX() - x); Rectangle newSplitChildBounds = boundsWithXandWidth(bounds, x, newWidth); layout2(splitChild, newSplitChildBounds); } else if ((availableWidth > 0.0) && (splitChildWeight > 0.0)) { double allocatedWidth = Math.rint(splitChildWeight * extraWidth); double oldWidth = splitChildBounds.getWidth(); double newWidth = Math.max(minSplitChildWidth, oldWidth - allocatedWidth); Rectangle newSplitChildBounds = boundsWithXandWidth(bounds, x, newWidth); layout2(splitChild, newSplitChildBounds); availableWidth -= (oldWidth - splitChild.getBounds().getWidth()); } else { double existingWidth = splitChildBounds.getWidth(); Rectangle newSplitChildBounds = boundsWithXandWidth(bounds, x, existingWidth); layout2(splitChild, newSplitChildBounds); } x = splitChild.getBounds().getMaxX(); } } else { int totalHeight = 0; // sum of the children's heights int minWeightedHeight = 0; // sum of the weighted childrens' min heights int totalWeightedHeight = 0; // sum of the weighted childrens' heights for (Node splitChild : split.getChildren()) { int nodeHeight = splitChild.getBounds().height; int nodeMinHeight = Math.min(nodeHeight, minimumNodeSize(splitChild).height); totalHeight += nodeHeight; if (splitChild.getWeight() > 0.0) { minWeightedHeight += nodeMinHeight; totalWeightedHeight += nodeHeight; } } double y = bounds.getY(); double extraHeight = splitBounds.getHeight() - bounds.getHeight(); double availableHeight = extraHeight; boolean onlyShrinkWeightedComponents = (totalWeightedHeight - minWeightedHeight) > extraHeight; while (splitChildren.hasNext()) { Node splitChild = splitChildren.next(); Rectangle splitChildBounds = splitChild.getBounds(); double minSplitChildHeight = minimumNodeSize(splitChild).getHeight(); double splitChildWeight = (onlyShrinkWeightedComponents) ? splitChild.getWeight() : (splitChildBounds.getHeight() / totalHeight); if (!splitChildren.hasNext()) { double oldHeight = splitChildBounds.getHeight(); double newHeight = Math.max(minSplitChildHeight, bounds.getMaxY() - y); Rectangle newSplitChildBounds = boundsWithYandHeight(bounds, y, newHeight); layout2(splitChild, newSplitChildBounds); availableHeight -= (oldHeight - splitChild.getBounds().getHeight()); } else if ((availableHeight > 0.0) && (splitChildWeight > 0.0)) { double allocatedHeight = Math.rint(splitChildWeight * extraHeight); double oldHeight = splitChildBounds.getHeight(); double newHeight = Math.max(minSplitChildHeight, oldHeight - allocatedHeight); Rectangle newSplitChildBounds = boundsWithYandHeight(bounds, y, newHeight); layout2(splitChild, newSplitChildBounds); availableHeight -= (oldHeight - splitChild.getBounds().getHeight()); } else { double existingHeight = splitChildBounds.getHeight(); Rectangle newSplitChildBounds = boundsWithYandHeight(bounds, y, existingHeight); layout2(splitChild, newSplitChildBounds); } y = splitChild.getBounds().getMaxY(); } } /* The bounds of the Split node root are set to be * big enough to contain all of its children. Since * Leaf children can't be reduced below their * (corresponding java.awt.Component) minimum sizes, * the size of the Split's bounds maybe be larger than * the bounds we were asked to fit within. */ minimizeSplitBounds(split, bounds); }
/** Automatically layout this RenderableComplex. */ public void layout() { if (hideComponents) { return; // Don't do layout for hiding components } List list = getComponents(); if (list == null || list.size() == 0) return; int size = list.size(); int c = (int) Math.ceil(Math.sqrt(size)); Node rs[][] = new Node[c][c]; int index = 0; // Distribute for (int i = 0; i < c && index < size; i++) { // Row for (int j = 0; j < c && index < size; j++) { // Col rs[i][j] = (Node) list.get(index); index++; } } // Assign positions // Original position int x = position.x; int y = position.y; Dimension layerSize = new Dimension(); boolean isDone = false; Node r = null; Rectangle bounds = null; int dx = 0; int x0 = 0; int y0 = 0; for (int i = 0; i < c && !isDone; i++) { // Row // Get the center for each layer layerSize.width = 0; layerSize.height = 0; for (int j = 0; j < c; j++) { // Col if (rs[i][j] == null) { isDone = true; break; } r = rs[i][j]; if (r.getStoiBounds() != null) { layerSize.width += r.getStoiBounds().width; } if (r.getBounds() != null) { layerSize.width += r.getBounds().width; if (r.getBounds().height > layerSize.height) layerSize.height = r.getBounds().height; } else { layerSize.width += Node.getNodeWidth(); layerSize.height += 20; // arbitrarily } } if (layerSize.width == 0) // nothing is layered. break; // Assign positions to this layer. x = -layerSize.width / 2 + position.x; y += layerSize.height / 2; for (int j = 0; j < c; j++) { if (rs[i][j] == null) break; r = rs[i][j]; // All are nodes dx = 0; if (r.getStoiBounds() != null) dx = r.getStoiBounds().width; if (r.getBounds() != null) dx += r.getBounds().width / 2; else dx += Node.getNodeWidth() / 2; x += dx; x0 = r.position.x; y0 = r.position.y; // Need to call move to change positions of components in subcomplexes. r.move(x - x0, y - y0); dx += 1; // A little cushion x += dx; // Move to the right end } y += layerSize.height / 2 + 2; // Make subunits look together } // Want to keep at the original position x0 = position.x; y0 = position.y; setBoundsFromComponents(); dx = x0 - position.x; int dy = y0 - position.y; move(dx, dy); // Should not call the following method since it will invalidate the // layout results. invalidateTextBounds(); }