package org.limewire.ui.swing.painter; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Paint; import java.awt.geom.Arc2D; import java.awt.geom.Area; import java.awt.geom.Rectangle2D; import java.awt.geom.RoundRectangle2D; import org.jdesktop.swingx.painter.AbstractPainter; import org.jdesktop.swingx.util.PaintUtils; import org.limewire.ui.swing.util.GuiUtils; /** * Draws the search tab shape within a given bounds. */ public class SearchTabPainter<X> extends AbstractPainter<X> { private final Paint topBevelBackground; private final Paint topBevelBorder; private final boolean raiseBottomClip; private Paint background; private Area tabAreaCache = null; private int tabWidthCache = 0; private int tabHeightCache = 0; public SearchTabPainter(Paint topBevelBackground, Paint topBevelBorder, Paint background) { this(topBevelBackground, topBevelBorder, background, false); } /** * raiseBottomClip can be used to clip painting one pixel earlier. This is necessary * since currently tabs are painted over top of the bottom border of the top bar. * highlighted tabs are clipped early to use the top bar bottom border as a * high contrast bottom edge that makes them look "behind" any other front tab which * run over the same border and have no hard edge. */ public SearchTabPainter(Paint topBevelBackground, Paint topBevelBorder, Paint background, boolean raiseBottomClip) { GuiUtils.assignResources(this); this.setAntialiasing(true); this.setCacheable(true); this.topBevelBackground = topBevelBackground; this.topBevelBorder = topBevelBorder; this.raiseBottomClip = raiseBottomClip; this.background = background; } private void cacheTabArea(int width, int height) { if (this.tabWidthCache == width && this.tabHeightCache == height) return; background = PaintUtils.resizeGradient(background, 0, height); Area compound = new Area(new RoundRectangle2D.Float(10, 3, width-1-20, height-1, 20, 20)); compound.add(new Area(new Rectangle2D.Float(0,height-10-1,width-1,height-1))); compound.subtract(new Area(new Arc2D.Float(-10,height-1-21,20,20,270,90,Arc2D.PIE))); compound.subtract(new Area(new Arc2D.Float(width-1-10,height-1-21,20,20,360,270,Arc2D.PIE))); this.tabAreaCache = compound; this.tabWidthCache = width; this.tabHeightCache = height; } @Override protected void doPaint(Graphics2D g, X object, int width, int height) { cacheTabArea(width, height); if (raiseBottomClip) { g.setClip(0,0,width,height-1); } // Draw top bevel g.setPaint(this.topBevelBackground); g.fillRoundRect(10, 0, width-2-20, 20, 20, 20); // Draw top border g.setPaint(this.topBevelBorder); g.drawRoundRect(10, 0, width-2-20, 20, 20, 20); // Draw tab g.setPaint(background); g.fill(this.tabAreaCache); if (!raiseBottomClip) { // Hack for Anthony to correct the antialiasing for the bottom border and tab mixing g.setPaint(new Color(0xca,0xca,0xca)); g.drawLine(0,height-2,0,height-2); g.drawLine(width-1,height-2,width-1,height-2); g.setPaint(new Color(0xab,0xab,0xab)); g.drawLine(1,height-2,1,height-2); g.drawLine(width-2,height-2,width-2,height-2); } } }