/*
* Copyright (c) 2012 Sam Harwell, Tunnel Vision Laboratories LLC
* All rights reserved.
*
* The source code of this document is proprietary work, and is not licensed for
* distribution. For information about licensing, contact Sam Harwell at:
* sam@tunnelvisionlabs.com
*/
package org.antlr.works.editor.grammar.syndiag;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class Block extends JPanel implements Element {
public static final int ALT_SEP = 10;
public static final int BLOCK_PADDING = 16;
public Block() {
this(0, 0);
}
public Block(int gutterAboveHeight, int gutterBelowHeight) {
super(new GridBagLayout());
setBorder(new EmptyBorder(gutterAboveHeight, BLOCK_PADDING, gutterBelowHeight, BLOCK_PADDING));
setOpaque(false);
}
public int getLeftGutterWidth() {
return getInsets().left;
}
public int getRightGutterWidth() {
return getInsets().right;
}
public int getTopGutterHeight() {
return getInsets().top;
}
public int getBottomGutterHeight() {
return getInsets().bottom;
}
public int getLeftJoinLineX() {
int leftx = getLeftGutterWidth() + Alt.ELEMENT_SEP / 2;
return leftx / 2;
}
public int getRightJoinLineX() {
int rightx = getWidth() - getRightGutterWidth() - Alt.ELEMENT_SEP / 2;
int brwidth = getRightGutterWidth() + Alt.ELEMENT_SEP / 2;
return rightx + brwidth / 2;
}
public int getTopOfJoinLineY() {
if (getComponentCount() == 0) {
return (int)getBounds().getCenterY();
}
Component component = getComponent(0);
if (component instanceof Element) {
return ((Element)component).getConnectionPointY();
} else {
return (int)component.getBounds().getCenterY();
}
}
public int getBottomJoinLineY() {
if (getComponentCount() == 0) {
return (int)getBounds().getCenterY();
}
Component component = getComponent(getComponentCount() - 1);
if (component instanceof Element) {
return ((Element)component).getConnectionPointY();
} else {
return (int)component.getBounds().getCenterY();
}
}
@Override
public Component add(Component comp) {
GridBagConstraints constraints = new GridBagConstraints();
constraints.gridx = 0;
constraints.anchor = GridBagConstraints.NORTHWEST;
add(comp, constraints);
return comp;
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = null;
Object prevAaHint = null;
if (g instanceof Graphics2D) {
g2 = (Graphics2D)g;
prevAaHint = g2.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
}
try {
if (g2 != null) {
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
}
if (Rule.OUTLINE_ELEMENTS) {
Color oldColor = g.getColor();
g.setColor(new Color(Color.blue.getRed(), Color.blue.getGreen(), Color.blue.getBlue(), 0xFF >> 2));
g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
g.setColor(oldColor);
}
Component[] elems = getComponents();
int leftx = getLeftGutterWidth() + Alt.ELEMENT_SEP / 2;
int rightx = getWidth() - getRightGutterWidth() - Alt.ELEMENT_SEP / 2;
int brwidth = getRightGutterWidth() + Alt.ELEMENT_SEP / 2;
int leftJoinLineX = 0 + leftx / 2;
int rightJoinLineX = rightx + brwidth / 2;
for (Component elem : elems) {
Element alt = (Element)elem;
g.drawLine(leftJoinLineX, alt.getConnectionPointY(), 0 + leftx, alt.getConnectionPointY());
if (((JComponent)elem).getComponentCount() > 0) {
Component lastElem = ((JComponent)alt).getComponent(((JComponent)alt).getComponentCount() - 1);
Rectangle lastBounds = lastElem.getBounds();
g.drawLine(getLeftGutterWidth() + lastBounds.x + lastBounds.width,
alt.getConnectionPointY(),
rightJoinLineX,
alt.getConnectionPointY());
} else {
g.drawLine(elem.getX() + elem.getWidth(), alt.getConnectionPointY(), rightJoinLineX, alt.getConnectionPointY());
}
}
if (elems.length == 0) {
return;
}
// draw vertical line on left connecting alts
int topOfJoinLineY = getTopOfJoinLineY();
int bottomJoinLineY = getBottomJoinLineY();
g.drawLine(leftJoinLineX, topOfJoinLineY, leftJoinLineX, bottomJoinLineY);
// draw horizontal line from left edge to left elementin first alt
g.drawLine(0, topOfJoinLineY, leftx / 2, topOfJoinLineY);
// draw vertical line on right connecting alts
g.drawLine(rightJoinLineX, topOfJoinLineY, rightJoinLineX, bottomJoinLineY);
// draw horizontal line from right element of first alt to right edge
g.drawLine(rightx, topOfJoinLineY, getX() + getWidth(), topOfJoinLineY);
if (elems.length > 1 && g2 != null) {
Diagram.drawArrow(rightJoinLineX, topOfJoinLineY, -Math.PI / 2, g2);
}
} finally {
if (g2 != null) {
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, prevAaHint);
}
}
}
@Override
public void updatePositions() {
for (Component child : getComponents()) {
if (child instanceof Element) {
((Element)child).updatePositions();
}
}
}
@Override
public int getConnectionPointY() {
if (getComponentCount() > 0) {
Component firstComponent = getComponent(0);
if (firstComponent instanceof Element) {
return getY() + ((Element)firstComponent).getConnectionPointY();
}
}
return (int)getBounds().getCenterY();
}
}