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}