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&auml;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}