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