/* * BioJava development code * * This code may be freely distributed and modified under the * terms of the GNU Lesser General Public Licence. This should * be distributed with the code. If you do not have a copy, * see: * * http://www.gnu.org/copyleft/lesser.html * * Copyright for this code is held jointly by the individual * authors. These should be listed in @author doc comments. * * For more information on the BioJava project and its aims, * or to join the biojava-l mailing list, visit the home page * at: * * http://www.biojava.org/ * */ package org.biojava.bio.gui.sequence; import java.awt.Graphics2D; import java.awt.Paint; import java.awt.Stroke; import java.awt.geom.Rectangle2D; import org.biojava.bio.seq.Feature; import org.biojava.bio.symbol.Location; import org.biojava.utils.ChangeEvent; import org.biojava.utils.ChangeSupport; import org.biojava.utils.ChangeType; import org.biojava.utils.ChangeVetoException; /** *

RectangularBeadRenderer renders features as simple * rectangles. Their outline and fill Paint, * Stroke, feature depth, Y-axis displacement are * configurable. The height of the rectangle will be equal to half its * width, but not greater than the beadDepth set in the * constructor.

* *

An alternative bead height behaviour is available where the * rectangle height does not scale with its current width. The * setHeightScaling method should be passed a boolean * value to change this. The default is to use height scaling.

* * @author Keith James * @since 1.2 */ public class RectangularBeadRenderer extends AbstractBeadRenderer { /** * Constant HEIGHTSCALING indicating a change to the * feature height scaling policy. */ public static final ChangeType HEIGHTSCALING = new ChangeType("The height scaling policy of the features has changed", "org.biojava.bio.gui.sequence.RectangularBeadRenderer", "HEIGHTSCALING", SequenceRenderContext.LAYOUT); protected Rectangle2D rect; protected boolean scaleHeight; /** * Creates a new RectangularBeadRenderer with the * default settings. */ public RectangularBeadRenderer() { super(); rect = new Rectangle2D.Double(); scaleHeight = true; } /** * Creates a new RectangularBeadRenderer. * * @param beadDepth a double. * @param beadDisplacement a double. * @param beadOutline a Paint. * @param beadFill a Paint. * @param beadStroke a Stroke. */ public RectangularBeadRenderer(double beadDepth, double beadDisplacement, Paint beadOutline, Paint beadFill, Stroke beadStroke) { super(beadDepth, beadDisplacement, beadOutline, beadFill, beadStroke); rect = new Rectangle2D.Double(); scaleHeight = true; } /** * renderBead renders features as simple rectangle. * * @param g2 a Graphics2D. * @param f a Feature to render. * @param context a SequenceRenderContext context. */ public void renderBead(Graphics2D g2, Feature f, SequenceRenderContext context) { Location loc = f.getLocation(); int min = loc.getMin(); int max = loc.getMax(); int dif = max - min; double posXW, posYN, width, height; if (context.getDirection() == SequenceRenderContext.HORIZONTAL) { posXW = context.sequenceToGraphics(min); posYN = beadDisplacement; width = Math.max(((double) (dif + 1)) * context.getScale(), 1.0); if (scaleHeight) { height = Math.min(beadDepth, width / 2.0); // If the bead height occupies less than the full height // of the renderer, move it down so that it is central if (height < beadDepth) posYN += ((beadDepth - height) / 2.0); } else { height = beadDepth; } rect.setRect(posXW, posYN, Math.floor(width), Math.floor(height)); } else { posXW = beadDisplacement; posYN = context.sequenceToGraphics(min); height = Math.max(((double) dif + 1) * context.getScale(), 1.0); if (scaleHeight) { width = Math.min(beadDepth, height / 2.0); if (width < beadDepth) posXW += ((beadDepth - width) / 2.0); } else { width = beadDepth; } rect.setRect(posXW, posYN, Math.floor(width), Math.floor(height)); } g2.setPaint(beadFill); g2.fill(rect); g2.setStroke(beadStroke); g2.setPaint(beadOutline); g2.draw(rect); } /** * getDepth calculates the depth required by this * renderer to display its beads. * * @param context a SequenceRenderContext. * * @return a double. */ public double getDepth(SequenceRenderContext context) { // Get max depth of delegates using base class method double maxDepth = super.getDepth(context); return Math.max(maxDepth, (beadDepth + beadDisplacement)); } /** * getHeightScaling returns the state of the height * scaling policy. * * @return a boolean true if height scaling is * enabled. */ public boolean getHeightScaling() { return scaleHeight; } /** * setHeightScaling sets the height scaling * policy. Default behaviour is for this to be enabled leading to * features being drawn with a height equal to half their width, * subject to a maximum height restriction equal to the * beadDepth set in the constructor. If disabled, * features will always be drawn at the maximum height allowed by * the beadDepth parameter. * * @param isEnabled a boolean. * * @exception ChangeVetoException if an error occurs. */ public void setHeightScaling(boolean isEnabled) throws ChangeVetoException { if (hasListeners()) { ChangeSupport cs = getChangeSupport(SequenceRenderContext.LAYOUT); synchronized(cs) { ChangeEvent ce = new ChangeEvent(this, SequenceRenderContext.LAYOUT, null, null, new ChangeEvent(this, HEIGHTSCALING, new Boolean(scaleHeight), new Boolean(isEnabled))); cs.firePreChangeEvent(ce); scaleHeight = isEnabled; cs.firePostChangeEvent(ce); } } else { scaleHeight = isEnabled; } } }