13d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta/*
23d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * Copyright (C) 2014 The Android Open Source Project
33d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta *
43d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * Licensed under the Apache License, Version 2.0 (the "License");
53d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * you may not use this file except in compliance with the License.
63d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * You may obtain a copy of the License at
73d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta *
83d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta *      http://www.apache.org/licenses/LICENSE-2.0
93d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta *
103d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * Unless required by applicable law or agreed to in writing, software
113d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * distributed under the License is distributed on an "AS IS" BASIS,
123d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * See the License for the specific language governing permissions and
143d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * limitations under the License.
153d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta */
163d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
173d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Guptapackage android.view;
183d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
19442aee6bc1abfb143dcfa1ba60d696e576d066c4Deepanshu Guptaimport android.annotation.NonNull;
203d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
213d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Guptaimport java.awt.Graphics2D;
223d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Guptaimport java.awt.Image;
233d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Guptaimport java.awt.image.BufferedImage;
243d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Guptaimport java.awt.image.DataBufferInt;
253d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Guptaimport java.io.IOException;
263d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Guptaimport java.io.InputStream;
273d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
283d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Guptaimport javax.imageio.ImageIO;
293d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
303d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Guptapublic class ShadowPainter {
313d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
323d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    /**
333d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * Adds a drop shadow to a semi-transparent image (of an arbitrary shape) and returns it as a
343d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * new image. This method attempts to mimic the same visual characteristics as the rectangular
353d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * shadow painting methods in this class, {@link #createRectangularDropShadow(java.awt.image.BufferedImage)}
363d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * and {@link #createSmallRectangularDropShadow(java.awt.image.BufferedImage)}.
371245caa7fd9c5cbf21fe5f5effe317dfbebc064aDiego Perez     * <p/>
381245caa7fd9c5cbf21fe5f5effe317dfbebc064aDiego Perez     * If shadowSize is less or equals to 1, no shadow will be painted and the source image will be
391245caa7fd9c5cbf21fe5f5effe317dfbebc064aDiego Perez     * returned instead.
403d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     *
413d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param source the source image
423d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param shadowSize the size of the shadow, normally {@link #SHADOW_SIZE or {@link
433d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * #SMALL_SHADOW_SIZE}}
443d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     *
451245caa7fd9c5cbf21fe5f5effe317dfbebc064aDiego Perez     * @return an image with the shadow painted in or the source image if shadowSize <= 1
463d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     */
473d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    @NonNull
483d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    public static BufferedImage createDropShadow(BufferedImage source, int shadowSize) {
493d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        shadowSize /= 2; // make shadow size have the same meaning as in the other shadow paint methods in this class
503d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
513d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        return createDropShadow(source, shadowSize, 0.7f, 0);
523d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    }
533d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
543d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    /**
553d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * Creates a drop shadow of a given image and returns a new image which shows the input image on
563d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * top of its drop shadow.
573d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * <p/>
583d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * <b>NOTE: If the shape is rectangular and opaque, consider using {@link
593d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * #drawRectangleShadow(Graphics2D, int, int, int, int)} instead.</b>
603d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     *
613d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param source the source image to be shadowed
623d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param shadowSize the size of the shadow in pixels
633d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param shadowOpacity the opacity of the shadow, with 0=transparent and 1=opaque
643d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param shadowRgb the RGB int to use for the shadow color
653d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     *
661245caa7fd9c5cbf21fe5f5effe317dfbebc064aDiego Perez     * @return a new image with the source image on top of its shadow when shadowSize > 0 or the
671245caa7fd9c5cbf21fe5f5effe317dfbebc064aDiego Perez     * source image otherwise
683d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     */
693d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    @SuppressWarnings({"SuspiciousNameCombination", "UnnecessaryLocalVariable"})  // Imported code
703d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    public static BufferedImage createDropShadow(BufferedImage source, int shadowSize,
713d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            float shadowOpacity, int shadowRgb) {
721245caa7fd9c5cbf21fe5f5effe317dfbebc064aDiego Perez        if (shadowSize <= 0) {
733c8e871ab7811a05cf5fc3debe798e342dc19ee9Diego Perez            return source;
743c8e871ab7811a05cf5fc3debe798e342dc19ee9Diego Perez        }
753d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
763d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        // This code is based on
773d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        //      http://www.jroller.com/gfx/entry/non_rectangular_shadow
783d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
793d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        BufferedImage image;
803d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        int width = source.getWidth();
813d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        int height = source.getHeight();
823d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        image = new BufferedImage(width + SHADOW_SIZE, height + SHADOW_SIZE,
833d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                BufferedImage.TYPE_INT_ARGB);
843d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
853d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        Graphics2D g2 = image.createGraphics();
863d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        g2.drawImage(image, shadowSize, shadowSize, null);
873d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
883d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        int dstWidth = image.getWidth();
893d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        int dstHeight = image.getHeight();
903d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
913d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        int left = (shadowSize - 1) >> 1;
923d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        int right = shadowSize - left;
933d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        int xStart = left;
943d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        int xStop = dstWidth - right;
953d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        int yStart = left;
963d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        int yStop = dstHeight - right;
973d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
983d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        shadowRgb &= 0x00FFFFFF;
993d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
1003d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        int[] aHistory = new int[shadowSize];
1013d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        int historyIdx;
1023d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
1033d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        int aSum;
1043d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
1053d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        int[] dataBuffer = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
1063d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        int lastPixelOffset = right * dstWidth;
1073d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        float sumDivider = shadowOpacity / shadowSize;
1083d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
1093d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        // horizontal pass
1103d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        for (int y = 0, bufferOffset = 0; y < dstHeight; y++, bufferOffset = y * dstWidth) {
1113d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            aSum = 0;
1123d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            historyIdx = 0;
1133d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            for (int x = 0; x < shadowSize; x++, bufferOffset++) {
1143d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                int a = dataBuffer[bufferOffset] >>> 24;
1153d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                aHistory[x] = a;
1163d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                aSum += a;
1173d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            }
1183d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
1193d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            bufferOffset -= right;
1203d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
1213d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            for (int x = xStart; x < xStop; x++, bufferOffset++) {
1223d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                int a = (int) (aSum * sumDivider);
1233d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                dataBuffer[bufferOffset] = a << 24 | shadowRgb;
1243d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
1253d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                // subtract the oldest pixel from the sum
1263d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                aSum -= aHistory[historyIdx];
1273d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
1283d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                // get the latest pixel
1293d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                a = dataBuffer[bufferOffset + right] >>> 24;
1303d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                aHistory[historyIdx] = a;
1313d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                aSum += a;
1323d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
1333d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                if (++historyIdx >= shadowSize) {
1343d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                    historyIdx -= shadowSize;
1353d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                }
1363d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            }
1373d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        }
1383d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        // vertical pass
1393d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        for (int x = 0, bufferOffset = 0; x < dstWidth; x++, bufferOffset = x) {
1403d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            aSum = 0;
1413d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            historyIdx = 0;
1423d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            for (int y = 0; y < shadowSize; y++, bufferOffset += dstWidth) {
1433d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                int a = dataBuffer[bufferOffset] >>> 24;
1443d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                aHistory[y] = a;
1453d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                aSum += a;
1463d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            }
1473d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
1483d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            bufferOffset -= lastPixelOffset;
1493d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
1503d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            for (int y = yStart; y < yStop; y++, bufferOffset += dstWidth) {
1513d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                int a = (int) (aSum * sumDivider);
1523d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                dataBuffer[bufferOffset] = a << 24 | shadowRgb;
1533d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
1543d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                // subtract the oldest pixel from the sum
1553d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                aSum -= aHistory[historyIdx];
1563d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
1573d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                // get the latest pixel
1583d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                a = dataBuffer[bufferOffset + lastPixelOffset] >>> 24;
1593d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                aHistory[historyIdx] = a;
1603d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                aSum += a;
1613d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
1623d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                if (++historyIdx >= shadowSize) {
1633d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                    historyIdx -= shadowSize;
1643d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                }
1653d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            }
1663d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        }
1673d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
1683d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        g2.drawImage(source, null, 0, 0);
1693d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        g2.dispose();
1703d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
1713d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        return image;
1723d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    }
1733d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
1743d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    /**
1753d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * Draws a rectangular drop shadow (of size {@link #SHADOW_SIZE} by {@link #SHADOW_SIZE} around
1763d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * the given source and returns a new image with both combined
1773d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     *
1783d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param source the source image
1793d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     *
1803d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @return the source image with a drop shadow on the bottom and right
1813d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     */
1823d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    @SuppressWarnings("UnusedDeclaration")
1833d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    public static BufferedImage createRectangularDropShadow(BufferedImage source) {
1843d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        int type = source.getType();
1853d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        if (type == BufferedImage.TYPE_CUSTOM) {
1863d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            type = BufferedImage.TYPE_INT_ARGB;
1873d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        }
1883d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
1893d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        int width = source.getWidth();
1903d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        int height = source.getHeight();
1913d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        BufferedImage image;
1923d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        image = new BufferedImage(width + SHADOW_SIZE, height + SHADOW_SIZE, type);
1933d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        Graphics2D g = image.createGraphics();
1943d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        g.drawImage(source, 0, 0, null);
1953d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        drawRectangleShadow(image, 0, 0, width, height);
1963d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        g.dispose();
1973d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
1983d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        return image;
1993d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    }
2003d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
2013d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    /**
2023d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * Draws a small rectangular drop shadow (of size {@link #SMALL_SHADOW_SIZE} by {@link
2033d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * #SMALL_SHADOW_SIZE} around the given source and returns a new image with both combined
2043d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     *
2053d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param source the source image
2063d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     *
2073d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @return the source image with a drop shadow on the bottom and right
2083d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     */
2093d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    @SuppressWarnings("UnusedDeclaration")
2103d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    public static BufferedImage createSmallRectangularDropShadow(BufferedImage source) {
2113d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        int type = source.getType();
2123d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        if (type == BufferedImage.TYPE_CUSTOM) {
2133d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            type = BufferedImage.TYPE_INT_ARGB;
2143d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        }
2153d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
2163d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        int width = source.getWidth();
2173d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        int height = source.getHeight();
2183d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
2193d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        BufferedImage image;
2203d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        image = new BufferedImage(width + SMALL_SHADOW_SIZE, height + SMALL_SHADOW_SIZE, type);
2213d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
2223d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        Graphics2D g = image.createGraphics();
2233d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        g.drawImage(source, 0, 0, null);
2243d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        drawSmallRectangleShadow(image, 0, 0, width, height);
2253d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        g.dispose();
2263d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
2273d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        return image;
2283d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    }
2293d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
2303d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    /**
2313d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * Draws a drop shadow for the given rectangle into the given context. It will not draw anything
2323d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * if the rectangle is smaller than a minimum determined by the assets used to draw the shadow
2333d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * graphics. The size of the shadow is {@link #SHADOW_SIZE}.
2343d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     *
2353d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param image the image to draw the shadow into
2363d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param x the left coordinate of the left hand side of the rectangle
2373d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param y the top coordinate of the top of the rectangle
2383d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param width the width of the rectangle
2393d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param height the height of the rectangle
2403d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     */
2413d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    public static void drawRectangleShadow(BufferedImage image,
2423d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            int x, int y, int width, int height) {
2433d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        Graphics2D gc = image.createGraphics();
2443d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        try {
2453d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            drawRectangleShadow(gc, x, y, width, height);
2463d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        } finally {
2473d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            gc.dispose();
2483d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        }
2493d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    }
2503d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
2513d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    /**
2523d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * Draws a small drop shadow for the given rectangle into the given context. It will not draw
2533d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * anything if the rectangle is smaller than a minimum determined by the assets used to draw the
2543d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * shadow graphics. The size of the shadow is {@link #SMALL_SHADOW_SIZE}.
2553d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     *
2563d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param image the image to draw the shadow into
2573d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param x the left coordinate of the left hand side of the rectangle
2583d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param y the top coordinate of the top of the rectangle
2593d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param width the width of the rectangle
2603d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param height the height of the rectangle
2613d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     */
2623d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    public static void drawSmallRectangleShadow(BufferedImage image,
2633d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            int x, int y, int width, int height) {
2643d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        Graphics2D gc = image.createGraphics();
2653d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        try {
2663d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            drawSmallRectangleShadow(gc, x, y, width, height);
2673d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        } finally {
2683d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            gc.dispose();
2693d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        }
2703d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    }
2713d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
2723d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    /**
2733d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * The width and height of the drop shadow painted by
2743d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * {@link #drawRectangleShadow(Graphics2D, int, int, int, int)}
2753d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     */
2763d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    public static final int SHADOW_SIZE = 20; // DO NOT EDIT. This corresponds to bitmap graphics
2773d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
2783d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    /**
2793d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * The width and height of the drop shadow painted by
2803d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * {@link #drawSmallRectangleShadow(Graphics2D, int, int, int, int)}
2813d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     */
2823d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    public static final int SMALL_SHADOW_SIZE = 10; // DO NOT EDIT. Corresponds to bitmap graphics
2833d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
2843d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    /**
2853d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * Draws a drop shadow for the given rectangle into the given context. It will not draw anything
2863d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * if the rectangle is smaller than a minimum determined by the assets used to draw the shadow
2873d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * graphics.
2883d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     *
2893d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param gc the graphics context to draw into
2903d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param x the left coordinate of the left hand side of the rectangle
2913d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param y the top coordinate of the top of the rectangle
2923d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param width the width of the rectangle
2933d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param height the height of the rectangle
2943d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     */
2953d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    public static void drawRectangleShadow(Graphics2D gc, int x, int y, int width, int height) {
2963d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        assert ShadowBottomLeft != null;
2973d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        assert ShadowBottomRight.getWidth(null) == SHADOW_SIZE;
2983d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        assert ShadowBottomRight.getHeight(null) == SHADOW_SIZE;
2993d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
3003d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        int blWidth = ShadowBottomLeft.getWidth(null);
3013d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        int trHeight = ShadowTopRight.getHeight(null);
3023d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        if (width < blWidth) {
3033d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            return;
3043d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        }
3053d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        if (height < trHeight) {
3063d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            return;
3073d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        }
3083d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
3093d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        gc.drawImage(ShadowBottomLeft, x - ShadowBottomLeft.getWidth(null), y + height, null);
3103d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        gc.drawImage(ShadowBottomRight, x + width, y + height, null);
3113d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        gc.drawImage(ShadowTopRight, x + width, y, null);
3123d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        gc.drawImage(ShadowTopLeft, x - ShadowTopLeft.getWidth(null), y, null);
3133d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        gc.drawImage(ShadowBottom,
3143d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                x, y + height, x + width, y + height + ShadowBottom.getHeight(null),
3153d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                0, 0, ShadowBottom.getWidth(null), ShadowBottom.getHeight(null), null);
3163d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        gc.drawImage(ShadowRight,
3173d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                x + width, y + ShadowTopRight.getHeight(null), x + width + ShadowRight.getWidth(null), y + height,
3183d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                0, 0, ShadowRight.getWidth(null), ShadowRight.getHeight(null), null);
3193d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        gc.drawImage(ShadowLeft,
3203d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                x - ShadowLeft.getWidth(null), y + ShadowTopLeft.getHeight(null), x, y + height,
3213d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                0, 0, ShadowLeft.getWidth(null), ShadowLeft.getHeight(null), null);
3223d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    }
3233d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
3243d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    /**
3253d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * Draws a small drop shadow for the given rectangle into the given context. It will not draw
3263d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * anything if the rectangle is smaller than a minimum determined by the assets used to draw the
3273d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * shadow graphics.
3283d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * <p/>
3293d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     *
3303d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param gc the graphics context to draw into
3313d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param x the left coordinate of the left hand side of the rectangle
3323d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param y the top coordinate of the top of the rectangle
3333d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param width the width of the rectangle
3343d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     * @param height the height of the rectangle
3353d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta     */
3363d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    public static void drawSmallRectangleShadow(Graphics2D gc, int x, int y, int width,
3373d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            int height) {
3383d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        assert Shadow2BottomLeft != null;
3393d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        assert Shadow2TopRight != null;
3403d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        assert Shadow2BottomRight.getWidth(null) == SMALL_SHADOW_SIZE;
3413d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        assert Shadow2BottomRight.getHeight(null) == SMALL_SHADOW_SIZE;
3423d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
3433d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        int blWidth = Shadow2BottomLeft.getWidth(null);
3443d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        int trHeight = Shadow2TopRight.getHeight(null);
3453d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        if (width < blWidth) {
3463d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            return;
3473d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        }
3483d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        if (height < trHeight) {
3493d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            return;
3503d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        }
3513d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
3523d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        gc.drawImage(Shadow2BottomLeft, x - Shadow2BottomLeft.getWidth(null), y + height, null);
3533d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        gc.drawImage(Shadow2BottomRight, x + width, y + height, null);
3543d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        gc.drawImage(Shadow2TopRight, x + width, y, null);
3553d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        gc.drawImage(Shadow2TopLeft, x - Shadow2TopLeft.getWidth(null), y, null);
3563d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        gc.drawImage(Shadow2Bottom,
3573d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                x, y + height, x + width, y + height + Shadow2Bottom.getHeight(null),
3583d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                0, 0, Shadow2Bottom.getWidth(null), Shadow2Bottom.getHeight(null), null);
3593d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        gc.drawImage(Shadow2Right,
3603d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                x + width, y + Shadow2TopRight.getHeight(null), x + width + Shadow2Right.getWidth(null), y + height,
3613d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                0, 0, Shadow2Right.getWidth(null), Shadow2Right.getHeight(null), null);
3623d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        gc.drawImage(Shadow2Left,
3633d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                x - Shadow2Left.getWidth(null), y + Shadow2TopLeft.getHeight(null), x, y + height,
3643d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                0, 0, Shadow2Left.getWidth(null), Shadow2Left.getHeight(null), null);
3653d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    }
3663d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
3673d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    private static Image loadIcon(String name) {
3683d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        InputStream inputStream = ShadowPainter.class.getResourceAsStream(name);
3693d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        if (inputStream == null) {
3703d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            throw new RuntimeException("Unable to load image for shadow: " + name);
3713d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        }
3723d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        try {
3733d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            return ImageIO.read(inputStream);
3743d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        } catch (IOException e) {
3753d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            throw new RuntimeException("Unable to load image for shadow:" + name, e);
3763d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        } finally {
3773d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            try {
3783d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                inputStream.close();
3793d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            } catch (IOException e) {
3803d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta                // ignore.
3813d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta            }
3823d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta        }
3833d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    }
3843d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
3853d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    // Shadow graphics. This was generated by creating a drop shadow in
3863d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    // Gimp, using the parameters x offset=10, y offset=10, blur radius=10,
3873d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    // (for the small drop shadows x offset=10, y offset=10, blur radius=10)
3883d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    // color=black, and opacity=51. These values attempt to make a shadow
3893d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    // that is legible both for dark and light themes, on top of the
3903d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    // canvas background (rgb(150,150,150). Darker shadows would tend to
3913d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    // blend into the foreground for a dark holo screen, and lighter shadows
3923d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    // would be hard to spot on the canvas background. If you make adjustments,
3933d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    // make sure to check the shadow with both dark and light themes.
3943d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    //
3953d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    // After making the graphics, I cut out the top right, bottom left
3963d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    // and bottom right corners as 20x20 images, and these are reproduced by
3973d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    // painting them in the corresponding places in the target graphics context.
3983d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    // I then grabbed a single horizontal gradient line from the middle of the
3993d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    // right edge,and a single vertical gradient line from the bottom. These
4003d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    // are then painted scaled/stretched in the target to fill the gaps between
4013d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    // the three corner images.
4023d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    //
4033d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    // Filenames: bl=bottom left, b=bottom, br=bottom right, r=right, tr=top right
4043d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
4053d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    // Normal Drop Shadow
4063d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    private static final Image ShadowBottom = loadIcon("/icons/shadow-b.png");
4073d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    private static final Image ShadowBottomLeft = loadIcon("/icons/shadow-bl.png");
4083d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    private static final Image ShadowBottomRight = loadIcon("/icons/shadow-br.png");
4093d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    private static final Image ShadowRight = loadIcon("/icons/shadow-r.png");
4103d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    private static final Image ShadowTopRight = loadIcon("/icons/shadow-tr.png");
4113d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    private static final Image ShadowTopLeft = loadIcon("/icons/shadow-tl.png");
4123d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    private static final Image ShadowLeft = loadIcon("/icons/shadow-l.png");
4133d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta
4143d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    // Small Drop Shadow
4153d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    private static final Image Shadow2Bottom = loadIcon("/icons/shadow2-b.png");
4163d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    private static final Image Shadow2BottomLeft = loadIcon("/icons/shadow2-bl.png");
4173d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    private static final Image Shadow2BottomRight = loadIcon("/icons/shadow2-br.png");
4183d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    private static final Image Shadow2Right = loadIcon("/icons/shadow2-r.png");
4193d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    private static final Image Shadow2TopRight = loadIcon("/icons/shadow2-tr.png");
4203d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    private static final Image Shadow2TopLeft = loadIcon("/icons/shadow2-tl.png");
4213d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta    private static final Image Shadow2Left = loadIcon("/icons/shadow2-l.png");
4223d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta}
423