/* * @(#)QuaquaNativeButtonStateBorder.java * * Copyright (c) 2011 Werner Randelshofer, Immensee, Switzerland. * All rights reserved. * * You may not use, copy or modify this file, except in compliance with the * license agreement you entered into with Werner Randelshofer. * For details see accompanying license terms. */ package ch.randelshofer.quaqua.border; import ch.randelshofer.quaqua.VisualMargin; import javax.swing.JComponent; import ch.randelshofer.quaqua.QuaquaUtilities; import ch.randelshofer.quaqua.osx.OSXAquaPainter; import ch.randelshofer.quaqua.util.CachedPainter; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.Image; import java.awt.Insets; import java.awt.image.BufferedImage; import javax.swing.border.Border; import static ch.randelshofer.quaqua.osx.OSXAquaPainter.*; /** * Native Aqua border for an {@code AbstractButton}. * This border draws everything except the focus ring. * <p> * To draw the focus wring, wrap this border into a * {@link ch.randelshofer.quaqua.border.FocusedBorder}. * <p> * This border is not suited for large components because it creates a * temporary BufferedImage with the same size of the component. * * @author Werner Randelshofer * @version $Id$ */ public class QuaquaNativeBorder extends CachedPainter implements Border, VisualMargin { protected OSXAquaPainter painter; protected Insets imageInsets; protected Insets borderInsets; protected final static int ARG_ACTIVE = 0; protected final static int ARG_PRESSED = 1; protected final static int ARG_DISABLED = 2; protected final static int ARG_ROLLOVER = 3; protected final static int ARG_SELECTED = 4; protected final static int ARG_FOCUSED = 5; protected final static int ARG_SIZE_VARIANT = 6;//2 bits protected final static int ARG_SEGPOS = 8; protected final static int ARG_WIDGET = 11;// 7 bits protected final static int ARG_TRAILING_SEPARATOR = 18; protected final static int ARG_ORIENTATION=19; public QuaquaNativeBorder(OSXAquaPainter.Widget widget) { this(12,widget, new Insets(0, 0, 0, 0), new Insets(0, 0, 0, 0)); } public QuaquaNativeBorder(int cacheSize,OSXAquaPainter.Widget widget) { this(cacheSize,widget, new Insets(0, 0, 0, 0), new Insets(0, 0, 0, 0)); } public QuaquaNativeBorder(OSXAquaPainter.Widget widget, Insets imageInsets, Insets borderInsets) { this(12,widget,imageInsets,borderInsets); } public QuaquaNativeBorder(int cacheSize,OSXAquaPainter.Widget widget, Insets imageInsets, Insets borderInsets) { super(cacheSize); painter = new OSXAquaPainter(); painter.setWidget(widget); this.imageInsets = imageInsets; this.borderInsets = borderInsets; } @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { Insets vm = getVisualMargin(c); x += vm.left; y += vm.top; width -= vm.left + vm.right; height -= vm.top + vm.bottom; int args = 0; State state; if (QuaquaUtilities.isOnActiveWindow(c)) { state = State.active; args |= 1 << ARG_ACTIVE; } else { state = State.inactive; } if (!c.isEnabled()) { state = State.disabled; args |= 1 << ARG_DISABLED; } painter.setState(state); boolean isFocused = QuaquaUtilities.isFocused(c); args |= (isFocused) ? 1 << ARG_FOCUSED : 0; painter.setValueByKey(Key.focused, isFocused ? 1 : 0); Size size; switch (QuaquaUtilities.getSizeVariant(c)) { case REGULAR: default: size = Size.regular; break; case SMALL: size = Size.small; break; case MINI: size = Size.mini; break; } painter.setSize(size); args |= size.getId() << ARG_SIZE_VARIANT; paint(c, g, x, y, width, height, args); } @Override protected Image createImage(Component c, int w, int h, GraphicsConfiguration config) { return new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE); } @Override protected void paintToImage(Component c, Image img, int w, int h, Object args) { Graphics2D ig = (Graphics2D) img.getGraphics(); ig.setColor(new Color(0x0, true)); ig.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC)); ig.fillRect(0, 0, img.getWidth(null), img.getHeight(null)); ig.dispose(); painter.paint((BufferedImage) img,// imageInsets.left, imageInsets.top,// w - imageInsets.left - imageInsets.right, // h - imageInsets.top - imageInsets.bottom); } @Override protected void paintToImage(Component c, Graphics g, int w, int h, Object args) { // round up image size to reduce memory thrashing BufferedImage img=(BufferedImage)createImage(c,(w/32+1)*32,(h/32+1)*32,null); paintToImage(c,img,w,h,args); g.drawImage(img, 0, 0, null); img.flush(); } public Insets getBorderInsets(Component c) { return (Insets) borderInsets.clone(); } public boolean isBorderOpaque() { return false; } public Insets getVisualMargin(Component c) { Insets vm = null; if (c instanceof JComponent) { vm = (Insets) ((JComponent) c).getClientProperty("Quaqua.Component.visualMargin"); } return vm == null ? new Insets(0, 0, 0, 0) : (Insets) vm.clone(); } public static class UIResource extends QuaquaNativeBorder implements javax.swing.plaf.UIResource { public UIResource(OSXAquaPainter.Widget widget) { super(widget); } /** * Creates a new instance. * All borders must have the same dimensions. */ public UIResource(OSXAquaPainter.Widget widget, Insets imageInsets, Insets borderInsets) { super(widget, imageInsets, borderInsets); } } }