001/*
002 Copyright (c) 1998-2014 The Regents of the University of California
003 All rights reserved.
004 Permission is hereby granted, without written agreement and without
005 license or royalty fees, to use, copy, modify, and distribute this
006 software and its documentation for any purpose, provided that the above
007 copyright notice and the following two paragraphs appear in all copies
008 of this software.
009
010 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
011 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
012 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
013 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
014 SUCH DAMAGE.
015
016 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
017 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
018 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
019 PROVIDED HEREUNDER IS ON AN  BASIS, AND THE UNIVERSITY OF
020 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
021 ENHANCEMENTS, OR MODIFICATIONS.
022
023 PT_COPYRIGHT_VERSION_2
024 COPYRIGHTENDKEY
025 *
026 */
027package ptolemy.vergil.kernel;
028
029import java.awt.Color;
030import java.awt.Composite;
031import java.awt.Graphics2D;
032import java.awt.Paint;
033import java.awt.Stroke;
034import java.awt.geom.Rectangle2D;
035
036import diva.canvas.DamageRegion;
037import diva.canvas.Figure;
038import diva.canvas.FigureDecorator;
039import diva.canvas.toolbox.BasicHighlighter;
040
041/** A decorator figure that displays a shadow behind the
042 *  figure. The highlighter has several options to control
043 *  the color, transparency, and size. Currently, this
044 *
045 * @version        $Id$
046 * @author         Edward A. Lee
047@version $Id$
048@since Ptolemy II 10.0
049 */
050public class ShadowHighlighter extends BasicHighlighter {
051
052    /** Create a new shadow with a default paint and size.
053     */
054    public ShadowHighlighter() {
055        super(Color.gray, 6.0f);
056    }
057
058    /** Create a new shadow with the given paint and halo.
059     *  @param paint The paint.
060     *  @param halo The halo, which is the size of the shadow.
061     */
062    public ShadowHighlighter(Paint paint, float halo) {
063        super(paint, halo);
064    }
065
066    /** Create a new shadow with the given paint, size.
067     *  and compositing operation.
068     *  @param paint The paint.
069     *  @param halo The halo, which is the size of the shadow.
070     *  @param composite The compositing operation.
071     */
072    public ShadowHighlighter(Paint paint, float halo, Composite composite) {
073        super(paint, halo, composite);
074    }
075
076    /** Create a new shadow with the given paint, size,
077     *  compositing operation, and stroke.  This shadow
078     *  draws an outline only and does not fill it.
079     *  @param paint The paint.
080     *  @param halo The halo, which is the size of the shadow.
081     *  @param composite The compositing operation.
082     *  @param stroke The stroke
083     */
084    public ShadowHighlighter(Paint paint, float halo, Composite composite,
085            Stroke stroke) {
086        super(paint, halo, composite, stroke);
087    }
088
089    /** Get the bounds. This is the child's bounding box stretched
090     *  by the "halo."
091     *  @return The bounds.
092     */
093    @Override
094    public Rectangle2D getBounds() {
095        Rectangle2D b = getChild().getBounds();
096        Rectangle2D bounds = new Rectangle2D.Double(b.getX(),
097                b.getY() + getHalo(), b.getWidth() + getHalo(),
098                b.getHeight() + getHalo());
099        return bounds;
100    }
101
102    /** Create a new instance of this shadower. The new
103     *  instance will have the same paint, size, and composite
104     *  as this one.
105     *  @param figure The figure, ignored in this method.
106     *  @return A new instance of the ShadowHighlighter class.
107     */
108    @Override
109    public FigureDecorator newInstance(Figure figure) {
110        return new ShadowHighlighter(getPaint(), getHalo(), getComposite(),
111                getStroke());
112    }
113
114    /** Paint the figure. This method first paints the shadow over
115     *  the contained figure's bounding box stretched by the size. It
116     *  then paints the contained figure.
117     *  @param g The Graphics2D context.
118     */
119    @Override
120    public void paint(Graphics2D g) {
121        Composite composite = getComposite();
122        if (composite != null) {
123            g.setComposite(composite);
124        }
125
126        g.setPaint(getPaint());
127
128        // Draw the shadow
129        // Rectangle2D bounds = getChild().getBounds();
130        // FIXME: Can we draw non-rectangular shadows???
131        Rectangle2D bounds = getChild().getShape().getBounds2D();
132        double x = bounds.getX() + getHalo();
133        double y = bounds.getY() + getHalo();
134        double w = bounds.getWidth();
135        double h = bounds.getHeight();
136
137        if (getStroke() == null) {
138            g.fill(new Rectangle2D.Double(x, y, w, h));
139        } else {
140            g.setStroke(getStroke());
141            g.draw(new Rectangle2D.Double(x, y, w, h));
142        }
143
144        // Draw the child
145        getChild().paint(g);
146    }
147
148    /** Request a repaint of the figure and shadow.
149     * This method reads the bounding box of the shadowed
150     * figure, and requests a repaint of that box stretched
151     * in each direction by the size.
152     */
153    @Override
154    public void repaint() {
155        Rectangle2D bounds = getChild().getBounds();
156        double x = bounds.getX();
157        double y = bounds.getY();
158        double w = bounds.getWidth() + getHalo();
159        double h = bounds.getHeight() + getHalo();
160
161        getParent().repaint(DamageRegion
162                .createDamageRegion(getTransformContext(), x, y, w, h));
163    }
164}