/*
* Copyright (C) 2012 Jason Gedge <http://www.gedge.ca>
*
* This file is part of the OpGraph project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
*/
package ca.gedge.opgraph.app.components.canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.TexturePaint;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.IdentityHashMap;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
import ca.gedge.opgraph.OpLink;
import ca.gedge.opgraph.OpNode;
import ca.gedge.opgraph.Processor;
import ca.gedge.opgraph.app.util.GUIHelper;
/**
* A full-canvas component to draw debug things on top of everything else.
*/
class DebugOverlay extends JComponent {
/** Dark mask for shaded nodes */
static final Paint DARK_MASK;
/** Light mask for shaded nodes */
static final Paint LIGHT_MASK;
/** Mask for error node */
static final Paint ERROR_MASK;
static {
final int W = 4;
final int H = 4;
// Creates a crosshatch texture
final BufferedImage texture = new BufferedImage(W, H, BufferedImage.TYPE_INT_ARGB);
{
final Graphics2D g = texture.createGraphics();
g.setColor(new Color(0, 0, 0, 200));
g.drawLine(0, 0, W - 1, H - 1);
g.drawLine(0, H - 1, W - 1, 0);
}
DARK_MASK = new TexturePaint(texture, new Rectangle2D.Double(0, 0, W, H));
LIGHT_MASK = new Color(0, 0, 0, 127);
ERROR_MASK = new Color(255, 0, 0, 50);
}
/** The parent canvas */
private final GraphCanvas canvas;
/**
* Default constructor.
*
* @param canvas the parent canvas
*/
public DebugOverlay(GraphCanvas canvas) {
this.canvas = canvas;
setOpaque(false);
setBackground(null);
}
@Override
public Dimension getPreferredSize() {
return null;
}
@Override
protected void paintComponent(Graphics gfx) {
final Processor context = canvas.getDocument().getProcessingContext();
if(context != null) {
// Get the context which is operating on the graph this
// canvas is currently viewing
Processor activeContext = context;
while(activeContext.getMacroContext() != null && activeContext.getGraphOfContext() != canvas.getDocument().getGraph())
activeContext = activeContext.getMacroContext();
// If the current graph has an associated processing context
if(activeContext != null) {
// Find directly connected nodes
final Graphics2D g = (Graphics2D)gfx;
final IdentityHashMap<CanvasNode, Boolean> connectedNodes = new IdentityHashMap<CanvasNode, Boolean>();
final OpNode currentNode = activeContext.getCurrentNodeOfContext();
if(currentNode != null) {
for(OpLink link : canvas.getDocument().getGraph().getIncomingEdges(currentNode))
connectedNodes.put( canvas.getNode(link.getSource()), true );
for(OpLink link : canvas.getDocument().getGraph().getOutgoingEdges(currentNode))
connectedNodes.put( canvas.getNode(link.getDestination()), true );
}
// Draw masks over nodes
final Paint oldPaint = g.getPaint();
for(OpNode node : canvas.getDocument().getGraph().getVertices()) {
final CanvasNode canvasNode = canvas.getNode(node);
final Rectangle bounds = SwingUtilities.convertRectangle(canvasNode, GUIHelper.getInterior(canvasNode), this);
--bounds.x;
--bounds.y;
bounds.width += 2;
bounds.height += 2;
if(node == currentNode) {
if(context.getError() != null) {
g.setPaint(ERROR_MASK);
g.fill(bounds);
}
} else {
g.setPaint(LIGHT_MASK);
g.fill(bounds);
if(!connectedNodes.containsKey(canvasNode)) {
g.setPaint(DARK_MASK);
g.fill(bounds);
}
}
}
g.setPaint(oldPaint);
}
}
}
}