001/*
002 * $Id: MatteBorderExt.java 4147 2012-02-01 17:13:24Z kschaefe $
003 *
004 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005 * Santa Clara, California 95054, U.S.A. All rights reserved.
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 * 
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015 * Lesser General Public License for more details.
016 * 
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this library; if not, write to the Free Software
019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
020 */
021
022package org.jdesktop.swingx.border;
023
024import java.awt.Color;
025import java.awt.Component;
026import java.awt.Graphics;
027import java.awt.Insets;
028
029import javax.swing.Icon;
030import javax.swing.border.MatteBorder;
031
032import org.jdesktop.beans.JavaBean;
033
034/**
035 * Matte border that allows specialized icons for corners and sides.
036 *
037 * @author Ramesh Gupta
038 */
039@JavaBean
040public class MatteBorderExt extends MatteBorder {
041    protected Icon[] tileIcons = null;
042    private Icon defaultIcon = null;
043
044    /**
045     * Draws a matte border using specialized icons for corners and sides. If
046         * tileIcons is null, or if the length of tileIcons array is less than 2, this
047         * defaults to the {@link javax.swing.border.MatteBorder superclass} behavior.
048         * Otherwise, tileIcons must specify icons in clockwise order, starting with
049         * the top-left icon at index zero, culminating with the left icon at index 7.
050     * If the length of the tileIcons array is greater than 1, but less than 8,
051     * then tileIcons[0] is used to paint the corners, and tileIcons[1] is used
052         * to paint the sides, with icons rotated as necessary. Other icons, if any,
053     * are ignored.
054     *
055     * @param top top inset
056     * @param left left inset
057     * @param bottom bottom inset
058     * @param right right inset
059     * @param tileIcons array of icons starting with top-left in index 0,
060     * continuing clockwise through the rest of the indices
061     */
062    public MatteBorderExt(int top, int left, int bottom, int right,
063                          Icon[] tileIcons) {
064        super(top, left, bottom, right,
065              (tileIcons == null) || (tileIcons.length == 0) ? null :
066              tileIcons[0]);
067        this.tileIcons = tileIcons;
068    }
069
070    /**
071     * @see MatteBorder#MatteBorder(int, int, int, int, java.awt.Color)
072     */
073    public MatteBorderExt(int top, int left, int bottom, int right,
074                          Color matteColor) {
075        super(top, left, bottom, right, matteColor);
076    }
077
078    /**
079     * @see MatteBorder#MatteBorder(java.awt.Insets, java.awt.Color)
080     */
081    public MatteBorderExt(Insets borderInsets, Color matteColor) {
082        super(borderInsets, matteColor);
083    }
084
085    /**
086     * @see MatteBorder#MatteBorder(int, int, int, int, javax.swing.Icon)
087     */
088    public MatteBorderExt(int top, int left, int bottom, int right,
089                          Icon tileIcon) {
090        super(top, left, bottom, right, tileIcon);
091    }
092
093    /**
094     * @see MatteBorder#MatteBorder(java.awt.Insets, javax.swing.Icon)
095     */
096    public MatteBorderExt(Insets borderInsets, Icon tileIcon) {
097        super(borderInsets, tileIcon);
098    }
099
100    /**
101     * @see MatteBorder#MatteBorder(javax.swing.Icon)
102     */
103    public MatteBorderExt(Icon tileIcon) {
104        super(tileIcon);
105    }
106
107    /**
108     * Returns the icons used by this border
109     *
110     * @return the icons used by this border
111     */
112    public Icon[] getTileIcons() {
113        return tileIcons;
114    }
115
116    /**
117     * {@inheritDoc}
118     */
119    @Override
120    public void paintBorder(Component c, Graphics g, int x, int y,
121                            int width, int height) {
122        if ( (tileIcons == null) || (tileIcons.length < 2)) {
123            super.paintBorder(c, g, x, y, width, height);
124            return;
125        }
126
127        Insets insets = getBorderInsets(c);
128        int clipWidth, clipHeight;
129
130        clipWidth = Math.min(width, insets.left); // clip to component width or insets
131        clipHeight = Math.min(height, insets.top); // clip to component height or insets
132
133        if ( (clipWidth <= 0) || (clipHeight <= 0)) {
134            return; // nothing to paint
135        }
136
137        // We now know that we have at least two icons!
138
139        Color oldColor = g.getColor(); // restore before exiting
140        g.translate(x, y);    // restore before exiting
141
142        for (int i = 0; i < tileIcons.length; i++) {
143            // Make sure we have an icon to paint with
144            if (tileIcons[i] == null) {
145                tileIcons[i] = getDefaultIcon();
146            }
147        }
148
149        paintTopLeft(c, g, 0, 0, insets.left, insets.top);
150        paintTop(c, g, insets.left, 0, width - insets.left - insets.right, insets.top);
151        paintTopRight(c, g, width - insets.right, 0, insets.right, insets.top);
152        paintRight(c, g, width - insets.right, insets.top, insets.right, height - insets.top - insets.bottom);
153        paintBottomRight(c, g, width - insets.right, height - insets.bottom, insets.right, insets.bottom);
154        paintBottom(c, g, insets.left, height - insets.bottom, width - insets.left - insets.right, insets.bottom);
155        paintBottomLeft(c, g, 0, height - insets.bottom, insets.left, insets.bottom);
156        paintLeft(c, g, 0, insets.top, insets.left, height - insets.top - insets.bottom);
157
158        g.translate( -x, -y); // restore
159        g.setColor(oldColor); // restore
160
161    }
162
163    protected void paint(Icon icon, Component c, Graphics g, int x, int y,
164                             int width, int height) {
165        Graphics cg = g.create();
166        
167        try {
168            cg.setClip(x, y, width, height);
169            int tileW = icon.getIconWidth();
170            int tileH = icon.getIconHeight();
171            int xpos, ypos, startx, starty;
172            for (ypos = 0; height - ypos > 0; ypos += tileH) {
173                for (xpos = 0; width - xpos > 0; xpos += tileW) {
174                    icon.paintIcon(c, cg, x + xpos, y + ypos);
175                }
176            }
177        } finally {
178            cg.dispose();
179        }
180    }
181
182    /**
183     * Only called by paintBorder()
184     */
185    protected void paintTopLeft(Component c, Graphics g, int x, int y, int width, int height) {
186        Graphics cg = g.create();
187        
188        try {
189            cg.setClip(x, y, width, height);
190            tileIcons[0].paintIcon(c, cg, x, y);
191        } finally {
192            cg.dispose();
193        }
194    }
195
196    /**
197     * Only called by paintBorder()
198     */
199    protected void paintTop(Component c, Graphics g, int x, int y, int width, int height) {
200        paint(tileIcons[1], c, g, x, y, width, height);
201    }
202
203    /**
204     * Only called by paintBorder()
205     */
206    protected void paintTopRight(Component c, Graphics g, int x, int y, int width, int height) {
207        if (tileIcons.length == 8) {
208            paint(tileIcons[2], c, g, x, y, width, height);
209        }
210        else {
211            Icon icon = tileIcons[0];
212            /** @todo Rotate -90 and paint icon */
213        }
214    }
215
216    /**
217     * Only called by paintBorder()
218     */
219    protected void paintRight(Component c, Graphics g, int x, int y, int width, int height) {
220        if (tileIcons.length == 8) {
221            paint(tileIcons[3], c, g, x, y, width, height);
222        }
223        else {
224            Icon icon = tileIcons[1];
225            /** @todo Rotate -90 and paint icon */
226        }
227    }
228
229    /**
230     * Only called by paintBorder()
231     */
232    protected void paintBottomRight(Component c, Graphics g, int x, int y, int width, int height) {
233        if (tileIcons.length == 8) {
234            paint(tileIcons[4], c, g, x, y, width, height);
235        }
236        else {
237            Icon icon = tileIcons[0];
238            /** @todo Rotate -180 and paint icon */
239        }
240    }
241
242    /**
243     * Only called by paintBorder()
244     */
245    protected void paintBottom(Component c, Graphics g, int x, int y, int width, int height) {
246        if (tileIcons.length == 8) {
247            paint(tileIcons[5], c, g, x, y, width, height);
248        }
249        else {
250            Icon icon = tileIcons[1];
251            /** @todo Rotate -180 and paint icon */
252        }
253    }
254
255    /**
256     * Only called by paintBorder()
257     */
258    protected void paintBottomLeft(Component c, Graphics g, int x, int y, int width, int height) {
259        if (tileIcons.length == 8) {
260            paint(tileIcons[6], c, g, x, y, width, height);
261        }
262        else {
263            Icon icon = tileIcons[0];
264            /** @todo Rotate -270 and paint icon */
265        }
266    }
267
268    /**
269     * Only called by paintBorder()
270     */
271    protected void paintLeft(Component c, Graphics g, int x, int y, int width, int height) {
272        if (tileIcons.length == 8) {
273            paint(tileIcons[7], c, g, x, y, width, height);
274        }
275        else {
276            Icon icon = tileIcons[1];
277            /** @todo Rotate -270 and paint icon */
278        }
279    }
280
281    /**
282     * Only called by paintBorder()
283     */
284    protected Icon getDefaultIcon() {
285        if (defaultIcon == null) {
286            defaultIcon = new Icon() {
287                private int width = 3;
288                private int height = 3;
289
290                public int getIconWidth() {
291                    return width;
292                }
293
294                public int getIconHeight() {
295                    return height;
296                }
297
298                public void paintIcon(Component c, Graphics g, int x, int y) {
299                    g.setColor(c.getBackground().darker().darker());
300                    //g.translate(x, y);
301                    g.fillRect(x, y, width, height);
302                }
303            };
304        }
305        return defaultIcon;
306    }
307}