/*
File: ArbitraryGraphicsCanvas.java
Copyright (c) 2006, The Cytoscape Consortium (www.cytoscape.org)
The Cytoscape Consortium is:
- Institute for Systems Biology
- University of California San Diego
- Memorial Sloan-Kettering Cancer Center
- Institut Pasteur
- Agilent Technologies
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of the License, or
any later version.
This library 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. The software and
documentation provided hereunder is on an "as is" basis, and the
Institute for Systems Biology and the Whitehead Institute
have no obligations to provide maintenance, support,
updates, enhancements or modifications. In no event shall the
Institute for Systems Biology and the Whitehead Institute
be liable to any party for direct, indirect, special,
incidental or consequential damages, including lost profits, arising
out of the use of this software and its documentation, even if the
Institute for Systems Biology and the Whitehead Institute
have been advised of the possibility of such damage. See
the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this library; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
// package
package ding.view;
import giny.model.GraphPerspective;
import giny.model.Node;
import giny.view.NodeView;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Component;
import java.awt.Composite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
/**
* This class extends cytoscape.view.CytoscapeCanvas. Its meant
* to live within a ding.view.DGraphView class. It is the canvas
* used for arbitrary graphics drawing (background & foreground panes).
*/
public class ArbitraryGraphicsCanvas extends DingCanvas implements ViewportChangeListener {
/**
* Testing boolean to quickly turn on/off anchor nodes.
*/
private static final boolean USE_REPOSITION_CODE = true;
/**
* Our reference to the GraphPerspective our view belongs to
*/
private final GraphPerspective m_graphPerspective;
/**
* Our reference to the DGraphView we live within
*/
private final DGraphView m_dGraphView;
/**
* Our reference to the inner canvas
*/
private final InnerCanvas m_innerCanvas;
private final Map<Component, Point> m_componentToPointMap;
/**
* Constructor.
*
* @param graphPerspective GraphPerspective
* @param dGraphView DGraphView
* @param innerCanvas InnerCanvas
* @param backgroundColor Color
* @param isVisible boolean
* @param isOpaque boolean
*/
public ArbitraryGraphicsCanvas(GraphPerspective graphPerspective, DGraphView dGraphView,
InnerCanvas innerCanvas, Color backgroundColor,
boolean isVisible, boolean isOpaque) {
// init members
m_graphPerspective = graphPerspective;
m_dGraphView = dGraphView;
m_innerCanvas = innerCanvas;
m_backgroundColor = backgroundColor;
m_isVisible = isVisible;
m_isOpaque = isOpaque;
m_componentToPointMap = new HashMap<Component, Point>();
}
public Component add(Component component) {
if (USE_REPOSITION_CODE) {
final double[] nodeCanvasCoordinates = new double[2];
nodeCanvasCoordinates[0] = component.getX();
nodeCanvasCoordinates[1] = component.getY();
m_dGraphView.xformComponentToNodeCoords(nodeCanvasCoordinates);
Point nodePos=new Point( (int)nodeCanvasCoordinates[0], (int)nodeCanvasCoordinates[1]);
// add to map
m_componentToPointMap.put(component, nodePos);
}
// do our stuff
return super.add(component);
}
public void remove(Component component){
if (USE_REPOSITION_CODE) {
m_componentToPointMap.remove(component);
}
// do our stuff
super.remove(component);
}
/**
* Our implementation of ViewportChangeListener.
*/
public void viewportChanged(int viewportWidth, int viewportHeight, double newXCenter,
double newYCenter, double newScaleFactor) {
if (USE_REPOSITION_CODE) {
if (setBoundsChildren())
repaint();
}
}
public void modifyComponentLocation(int x,int y, int componentNum){
if(USE_REPOSITION_CODE){
final Point nodePos = m_componentToPointMap.get(this.getComponent(componentNum));
final double[] nodeCanvasCoordinates = new double[2];
nodeCanvasCoordinates[0] = x;
nodeCanvasCoordinates[1] = y;
m_dGraphView.xformComponentToNodeCoords(nodeCanvasCoordinates);
nodePos.x=(int)nodeCanvasCoordinates[0];
nodePos.y=(int)nodeCanvasCoordinates[1];
}
}
/**
* Our implementation of JComponent setBounds.
*/
public void setBounds(int x, int y, int width, int height) {
super.setBounds(x, y, width, height);
// our bounds have changed, create a new image with new size
if ((width > 1) && (height > 1)) {
// create the buffered image
m_img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
// update childrens bounds
if (USE_REPOSITION_CODE) {
setBoundsChildren();
}
}
}
/**
* Our implementation of paint.
* Invoked by Swing to draw components.
*
* @param graphics Graphics
*/
public void paint(Graphics graphics) {
// only paint if we have an image to paint on
if (m_img != null) {
// get image graphics
final Graphics2D image2D = ((BufferedImage) m_img).createGraphics();
// first clear the image
clearImage(image2D);
// now paint children
if (m_isVisible){
int num=this.getComponentCount();
for(int i=0;i<num;i++){
this.getComponent(i).paint(image2D);
}
}
image2D.dispose();
// render image
graphics.drawImage(m_img, 0, 0, null);
}
}
@Override
public Component getComponentAt(int x, int y) {
int n=getComponentCount();
for(int i=0;i<n;i++){
Component c=this.getComponent(i).getComponentAt(x, y);
if(c!=null)
return c;
}
return null;
}
/**
* Invoke this method to print the component.
*
* @param graphics Graphics
*/
public void print(Graphics graphics) {
int num=this.getComponentCount();
for(int i=0;i<num;i++){
this.getComponent(i).print(graphics);
}
}
private boolean setBoundsChildren() {
// get list of child components
Component[] components = getComponents();
// no components, outta here
if (components.length == 0)
return false;
// interate through the components
for (Component c : components) {
// get node
Point node = m_componentToPointMap.get(c);
// new image coordinates
double[] currentNodeCoordinates = new double[2];
currentNodeCoordinates[0] = node.getX();
currentNodeCoordinates[1] = node.getY();
AffineTransform transform = m_innerCanvas.getAffineTransform();
transform.transform(currentNodeCoordinates, 0, currentNodeCoordinates, 0, 1);
// set bounds
c.setBounds((int) currentNodeCoordinates[0], (int) currentNodeCoordinates[1],
c.getWidth(), c.getHeight());
}
// outta here
return true;
}
/**
* Utility function to clean the background of the image,
* using m_backgroundColor
*
* image2D Graphics2D
*/
private void clearImage(Graphics2D image2D) {
// set color alpha based on opacity setting
int alpha = (m_isOpaque) ? 255 : 0;
Color backgroundColor = new Color(m_backgroundColor.getRed(), m_backgroundColor.getGreen(),
m_backgroundColor.getBlue(), alpha);
// set the alpha composite on the image, and clear its area
Composite origComposite = image2D.getComposite();
image2D.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC));
image2D.setPaint(backgroundColor);
image2D.fillRect(0, 0, m_img.getWidth(null), m_img.getHeight(null));
image2D.setComposite(origComposite);
}
}