001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 */ 021 022package org.biojava.bio.gui.sequence; 023 024import java.awt.Graphics2D; 025import java.awt.Paint; 026import java.awt.Stroke; 027import java.awt.geom.Rectangle2D; 028 029import org.biojava.bio.seq.Feature; 030import org.biojava.bio.symbol.Location; 031import org.biojava.utils.ChangeEvent; 032import org.biojava.utils.ChangeSupport; 033import org.biojava.utils.ChangeType; 034import org.biojava.utils.ChangeVetoException; 035 036/** 037 * <p><code>RectangularBeadRenderer</code> renders features as simple 038 * rectangles. Their outline and fill <code>Paint</code>, 039 * <code>Stroke</code>, feature depth, Y-axis displacement are 040 * configurable. The height of the rectangle will be equal to half its 041 * width, but not greater than the <code>beadDepth</code> set in the 042 * constructor.</p> 043 * 044 * <p>An alternative bead height behaviour is available where the 045 * rectangle height does not scale with its current width. The 046 * <code>setHeightScaling</code> method should be passed a boolean 047 * value to change this. The default is to use height scaling.</p> 048 * 049 * @author Keith James 050 * @since 1.2 051 */ 052public class RectangularBeadRenderer extends AbstractBeadRenderer 053{ 054 /** 055 * Constant <code>HEIGHTSCALING</code> indicating a change to the 056 * feature height scaling policy. 057 */ 058 public static final ChangeType HEIGHTSCALING = 059 new ChangeType("The height scaling policy of the features has changed", 060 "org.biojava.bio.gui.sequence.RectangularBeadRenderer", 061 "HEIGHTSCALING", SequenceRenderContext.LAYOUT); 062 063 protected Rectangle2D rect; 064 protected boolean scaleHeight; 065 066 /** 067 * Creates a new <code>RectangularBeadRenderer</code> with the 068 * default settings. 069 */ 070 public RectangularBeadRenderer() 071 { 072 super(); 073 rect = new Rectangle2D.Double(); 074 scaleHeight = true; 075 } 076 077 /** 078 * Creates a new <code>RectangularBeadRenderer</code>. 079 * 080 * @param beadDepth a <code>double</code>. 081 * @param beadDisplacement a <code>double</code>. 082 * @param beadOutline a <code>Paint</code>. 083 * @param beadFill a <code>Paint</code>. 084 * @param beadStroke a <code>Stroke</code>. 085 */ 086 public RectangularBeadRenderer(double beadDepth, 087 double beadDisplacement, 088 Paint beadOutline, 089 Paint beadFill, 090 Stroke beadStroke) 091 { 092 super(beadDepth, beadDisplacement, beadOutline, beadFill, beadStroke); 093 rect = new Rectangle2D.Double(); 094 scaleHeight = true; 095 } 096 097 /** 098 * <code>renderBead</code> renders features as simple rectangle. 099 * 100 * @param g2 a <code>Graphics2D</code>. 101 * @param f a <code>Feature</code> to render. 102 * @param context a <code>SequenceRenderContext</code> context. 103 */ 104 public void renderBead(Graphics2D g2, 105 Feature f, 106 SequenceRenderContext context) 107 { 108 Location loc = f.getLocation(); 109 110 int min = loc.getMin(); 111 int max = loc.getMax(); 112 int dif = max - min; 113 114 double posXW, posYN, width, height; 115 116 if (context.getDirection() == SequenceRenderContext.HORIZONTAL) 117 { 118 posXW = context.sequenceToGraphics(min); 119 posYN = beadDisplacement; 120 width = Math.max(((double) (dif + 1)) * context.getScale(), 1.0); 121 122 if (scaleHeight) 123 { 124 height = Math.min(beadDepth, width / 2.0); 125 126 // If the bead height occupies less than the full height 127 // of the renderer, move it down so that it is central 128 if (height < beadDepth) 129 posYN += ((beadDepth - height) / 2.0); 130 } 131 else 132 { 133 height = beadDepth; 134 } 135 136 rect.setRect(posXW, posYN, 137 Math.floor(width), 138 Math.floor(height)); 139 } 140 else 141 { 142 posXW = beadDisplacement; 143 posYN = context.sequenceToGraphics(min); 144 height = Math.max(((double) dif + 1) * context.getScale(), 1.0); 145 146 if (scaleHeight) 147 { 148 width = Math.min(beadDepth, height / 2.0); 149 150 if (width < beadDepth) 151 posXW += ((beadDepth - width) / 2.0); 152 } 153 else 154 { 155 width = beadDepth; 156 } 157 158 rect.setRect(posXW, posYN, 159 Math.floor(width), 160 Math.floor(height)); 161 } 162 163 g2.setPaint(beadFill); 164 g2.fill(rect); 165 166 g2.setStroke(beadStroke); 167 g2.setPaint(beadOutline); 168 g2.draw(rect); 169 } 170 171 /** 172 * <code>getDepth</code> calculates the depth required by this 173 * renderer to display its beads. 174 * 175 * @param context a <code>SequenceRenderContext</code>. 176 * 177 * @return a <code>double</code>. 178 */ 179 public double getDepth(SequenceRenderContext context) 180 { 181 // Get max depth of delegates using base class method 182 double maxDepth = super.getDepth(context); 183 return Math.max(maxDepth, (beadDepth + beadDisplacement)); 184 } 185 186 /** 187 * <code>getHeightScaling</code> returns the state of the height 188 * scaling policy. 189 * 190 * @return a <code>boolean</code> true if height scaling is 191 * enabled. 192 */ 193 public boolean getHeightScaling() 194 { 195 return scaleHeight; 196 } 197 198 /** 199 * <code>setHeightScaling</code> sets the height scaling 200 * policy. Default behaviour is for this to be enabled leading to 201 * features being drawn with a height equal to half their width, 202 * subject to a maximum height restriction equal to the 203 * <code>beadDepth</code> set in the constructor. If disabled, 204 * features will always be drawn at the maximum height allowed by 205 * the <code>beadDepth</code> parameter. 206 * 207 * @param isEnabled a <code>boolean</code>. 208 * 209 * @exception ChangeVetoException if an error occurs. 210 */ 211 public void setHeightScaling(boolean isEnabled) throws ChangeVetoException 212 { 213 if (hasListeners()) 214 { 215 ChangeSupport cs = getChangeSupport(SequenceRenderContext.LAYOUT); 216 synchronized(cs) 217 { 218 ChangeEvent ce = new ChangeEvent(this, SequenceRenderContext.LAYOUT, 219 null, null, 220 new ChangeEvent(this, HEIGHTSCALING, 221 new Boolean(scaleHeight), 222 new Boolean(isEnabled))); 223 cs.firePreChangeEvent(ce); 224 scaleHeight = isEnabled; 225 cs.firePostChangeEvent(ce); 226 } 227 } 228 else 229 { 230 scaleHeight = isEnabled; 231 } 232 } 233}