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 */ 021package org.biojava.bio.gui.glyph; 022 023import java.awt.Color; 024import java.awt.Graphics2D; 025import java.awt.Paint; 026import java.awt.Shape; 027import java.awt.geom.GeneralPath; 028import java.awt.geom.Rectangle2D; 029 030import org.biojava.bio.seq.StrandedFeature; 031 032/** 033 * A Glyph that paints an arrow shape within the bounds. The 034 * <code>setDirection</code> method allows the decision of the direction, to 035 * which the arrow points. 036 * 037 * @author Mark Southern 038 * @author <a href="mailto:andreas.draeger@uni-tuebingen.de">Andreas Dräger</a> 039 * @since 1.5 040 */ 041public class ArrowGlyph implements Glyph { 042 private Paint fillPaint; 043 044 private Paint outerPaint; 045 046 private Rectangle2D.Float bounds; 047 048 private Shape arrowShape; 049 050 /** 051 * Creates a new <code>ArrowGlyph</code>, which is filled with the color 052 * blue by default. 053 */ 054 public ArrowGlyph() { 055 this(Color.BLUE, Color.BLACK); 056 } 057 058 /** 059 * Creates a new <code>ArrowGlyph</code>, which is filled with the given 060 * color. 061 * 062 * @param fillPaint Paint properties to fill this arrow. 063 * @param outerPaint Paint properties of the outer border of this arrow. 064 */ 065 public ArrowGlyph(Paint fillPaint, Paint outerPaint) { 066 this.fillPaint = fillPaint; 067 this.outerPaint = outerPaint; 068 this.bounds = new Rectangle2D.Float(0, 0, 0, 0); 069 } 070 071 /** 072 * This constructs an arrow in the given bounds, which is colored blue. 073 * 074 * @param bounds 075 */ 076 public ArrowGlyph(Rectangle2D.Float bounds) { 077 this(bounds, Color.BLUE, Color.BLACK); 078 } 079 080 /** 081 * Constructor which sets both the size of this arrow and its color. 082 * 083 * @param bounds 084 * @param fillPaint 085 */ 086 public ArrowGlyph(Rectangle2D.Float bounds, Paint fillPaint, Paint outerPaint) { 087 this(fillPaint, outerPaint); 088 setBounds(bounds); 089 } 090 091 /* 092 * (non-Javadoc) 093 * 094 * see org.biojava.bio.gui.glyph.Glyph#getBounds() 095 */ 096 public Rectangle2D.Float getBounds() { 097 return bounds; 098 } 099 100 /* 101 * (non-Javadoc) 102 * 103 * see org.biojava.bio.gui.glyph.Glyph#setBounds(java.awt.geom.Rectangle2D.Float) 104 */ 105 public void setBounds(Rectangle2D.Float r) { 106 if (bounds.equals(r)) return; 107 bounds = r; 108 } 109 110 /** 111 * This method allows you to decide in which direction the arrow has to point. 112 * The definition of directions is equal to the definition of 113 * {@link StrandedFeature}. 114 * 115 * @param direction 116 * A +1 means to the right, -1 to the left an 0 (and any other value) 117 * produces a rectangular shape without arrows at its end. 118 */ 119 public void setDirection(int direction) { 120 float q1 = bounds.height * 0.25F; 121 float q2 = bounds.height * 0.5F; 122 float q3 = bounds.height * 0.75F; 123 float arrowHeadSize = bounds.height; 124 GeneralPath p = new GeneralPath(); 125 126 switch (direction) { 127 case +1: // to the right 128 if ((bounds.width - arrowHeadSize) > 0) { 129 p.moveTo(bounds.x, bounds.y + q1); 130 p.lineTo(bounds.x + bounds.width - arrowHeadSize, bounds.y + q1); 131 p.lineTo(bounds.x + bounds.width - arrowHeadSize, bounds.y); 132 p.lineTo(bounds.x + bounds.width, bounds.y + q2); 133 p.lineTo(bounds.x + bounds.width - arrowHeadSize, bounds.y 134 + bounds.height); 135 p.lineTo(bounds.x + bounds.width - arrowHeadSize, bounds.y + q3); 136 p.lineTo(bounds.x, bounds.y + q3); 137 } else { 138 p.moveTo(bounds.x, bounds.y); 139 p.lineTo(bounds.x + bounds.width, bounds.y + q2); 140 p.lineTo(bounds.x, bounds.y + bounds.height); 141 } 142 break; 143 case -1: // to the left 144 if ((bounds.width - arrowHeadSize) > 0) { 145 p.moveTo(bounds.x + bounds.width, bounds.y + q1); 146 p.lineTo(bounds.x + arrowHeadSize, bounds.y + q1); 147 p.lineTo(bounds.x + arrowHeadSize, bounds.y); 148 p.lineTo(bounds.x, bounds.y + q2); 149 p.lineTo(bounds.x + arrowHeadSize, bounds.y + bounds.height); 150 p.lineTo(bounds.x + arrowHeadSize, bounds.y + q3); 151 p.lineTo(bounds.x + bounds.width, bounds.y + q3); 152 } else { 153 p.moveTo(bounds.x + bounds.width, bounds.y); 154 p.lineTo(bounds.x + bounds.width, bounds.y + bounds.height); 155 p.lineTo(bounds.x, bounds.y + q2); 156 } 157 break; 158 default: // unknown 159 // we cannot draw an arrow, we should draw a rectangle shape instead. 160 p.moveTo(bounds.x, bounds.y + q1); 161 p.lineTo(bounds.x + bounds.width, bounds.y + q1); 162 p.lineTo(bounds.x + bounds.width, bounds.y + q3); 163 p.lineTo(bounds.x, bounds.y + q3); 164 break; 165 } 166 p.closePath(); 167 arrowShape = p; 168 } 169 170 public void render(Graphics2D g) { 171 if ((bounds.height > 0) && (bounds.width > 0) && (arrowShape == null)) 172 setDirection(0); 173 if (arrowShape != null) { 174 g.setPaint(fillPaint); 175 g.fill(arrowShape); 176 g.setPaint(outerPaint); 177 g.draw(arrowShape); 178 } 179 } 180 181 /** 182 * Returns the paint properties of this glyph. 183 * 184 * @return the fillPaint 185 */ 186 public Paint getFillPaint() { 187 return fillPaint; 188 } 189 190 /** 191 * Allows you to set the paint properties of this glyph. 192 * 193 * @param fillPaint 194 */ 195 public void setFillPaint(Paint fillPaint) { 196 this.fillPaint = fillPaint; 197 } 198 199 /** 200 * Returns the paint properties of the outer line of this glyph. 201 * 202 * @return the outerPaint 203 */ 204 public Paint getOuterPaint() { 205 return outerPaint; 206 } 207 208 /** 209 * Allows setting the paint properties of the outer line of this glyph to the 210 * given value. 211 * 212 * @param outerPaint 213 */ 214 public void setOuterPaint(Paint outerPaint) { 215 this.outerPaint = outerPaint; 216 } 217 218}