/* * @(#)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.AbstractButton; import javax.swing.ButtonModel; 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. To draw the focus * wring, wrap this border into a {@link ch.randelshofer.quaqua.border.FocusedBorder}. * * @author Werner Randelshofer * @version $Id$ */ public class QuaquaNativeButtonStateBorder extends CachedPainter implements Border, VisualMargin { private OSXAquaPainter painter; private Insets imageInsets; private Insets borderInsets; private final static int ARG_ACTIVE = 0; private final static int ARG_PRESSED = 1; private final static int ARG_DISABLED = 2; private final static int ARG_ROLLOVER = 3; private final static int ARG_SELECTED = 4; private final static int ARG_FOCUSED = 5; private final static int ARG_SIZE_VARIANT = 6;//2 bits private final static int ARG_SEGPOS = 8; private final static int ARG_WIDGET = 11;// 7 bits private final static int ARG_TRAILING_SEPARATOR = 18; public QuaquaNativeButtonStateBorder(OSXAquaPainter.Widget widget) { this(widget, new Insets(0, 0, 0, 0), new Insets(0, 0, 0, 0)); } public QuaquaNativeButtonStateBorder(OSXAquaPainter.Widget widget, Insets imageInsets, Insets borderInsets) { super(12); 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) { AbstractButton b = null; ButtonModel bm = null; Insets vm = getVisualMargin(c); x += vm.left; y += vm.top; width -= vm.left + vm.right; height -= vm.top + vm.bottom; if (c instanceof AbstractButton) { b = (AbstractButton) c; bm = b.getModel(); } int args = 0; OSXAquaPainter.State state; if (QuaquaUtilities.isOnActiveWindow(c)) { state = OSXAquaPainter.State.active; args |= 1 << ARG_ACTIVE; } else { state = OSXAquaPainter.State.inactive; } if (bm != null) { if (bm.isArmed() && bm.isPressed()) { state = OSXAquaPainter.State.pressed; args |= 1 << ARG_PRESSED; } if (!bm.isEnabled()) { state = OSXAquaPainter.State.disabled; args |= 1 << ARG_DISABLED; } if (bm.isRollover()) { state = OSXAquaPainter.State.rollover; args |= 1 << ARG_ROLLOVER; } } painter.setState(state); int value = b == null ? 0 : (b.isSelected() ? 1 : 0); painter.setValueByKey(Key.value, value); args |= value << ARG_SELECTED; boolean isFocused = QuaquaUtilities.isFocused(c); args |= (isFocused) ? 1 << ARG_FOCUSED : 0; painter.setValueByKey(OSXAquaPainter.Key.focused, isFocused ? 1 : 0); OSXAquaPainter.Size size; switch (QuaquaUtilities.getSizeVariant(c)) { case REGULAR: default: size = OSXAquaPainter.Size.regular; break; case SMALL: size = OSXAquaPainter.Size.small; break; case MINI: size = OSXAquaPainter.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 QuaquaNativeButtonStateBorder 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); } } }