/*
* @(#)QuaquaNativeScrollPaneBorder.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;
import ch.randelshofer.quaqua.border.AbstractFocusedPainter;
import ch.randelshofer.quaqua.border.ImageBevelBorder;
import ch.randelshofer.quaqua.border.VisualMarginBorder;
import ch.randelshofer.quaqua.osx.OSXAquaPainter;
import ch.randelshofer.quaqua.osx.OSXAquaPainter.Size;
import ch.randelshofer.quaqua.osx.OSXAquaPainter.State;
import ch.randelshofer.quaqua.osx.OSXAquaPainter.Widget;
import ch.randelshofer.quaqua.util.Debug;
import ch.randelshofer.quaqua.util.InsetsUtil;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.image.BufferedImage;
import javax.swing.JComponent;
import javax.swing.JScrollPane;
import javax.swing.border.Border;
import javax.swing.plaf.UIResource;
import javax.swing.text.JTextComponent;
/**
* {@code QuaquaNativeScrollPaneBorder}.
*
* @author Werner Randelshofer
* @version $Id: QuaquaNativeScrollPaneBorder.java 439 2011-08-28 10:05:15Z wrandelshofer $
*/
public class QuaquaNativeScrollPaneBorder extends VisualMarginBorder implements UIResource {
private final static int ARG_SMALL_SIZE = 32;
private BufferedImage regularPainterImage;
private BufferedImage smallPainterImage;
private BufferedImage regularFocusImage;
private BufferedImage smallFocusImage;
private ImageBevelBorder regularIbb;
private ImageBevelBorder smallIbb;
private OSXAquaPainter painter;
private Insets imageInsets;
private Insets borderInsets;
public QuaquaNativeScrollPaneBorder() {
painter = new OSXAquaPainter();
imageInsets = new Insets(0, 0, 0, 0);
borderInsets = new Insets(1,1,1,1);
}
@Override
public void paintBorder(Component cc, Graphics g, int x, int y, int width, int height) {
int args = 0;
// Determine which component is relevant for the state of the border
Component c = cc;
if (c instanceof JScrollPane) {
JScrollPane sp = (JScrollPane) c;
c = sp.getViewport().getView();
if (c==null)c=sp;
}
JTextComponent b = (c instanceof JTextComponent) ? (JTextComponent) c : null;
boolean editable = b == null || b.isEditable();
// PREPARE THE PAINTER
// -------------------
{
State state;
if (QuaquaUtilities.isOnActiveWindow(c)) {
state = State.active;
args |= 1;
} else {
state = State.inactive;
}
Widget widget;
widget = Widget.frameTextField;
//widget = Widget.frameListBox;
painter.setWidget(widget);
if (!cc.isEnabled() || !editable) {
state = State.disabled;
args |= 4;
}
painter.setState(state);
boolean isFocusedAndEditable = QuaquaUtilities.isFocused(c) && editable;
args |= (isFocusedAndEditable) ? 16 : 0;
painter.setValueByKey(OSXAquaPainter.Key.focused, isFocusedAndEditable ? 1 : 0);
Size size;
switch (QuaquaUtilities.getSizeVariant(c)) {
case REGULAR:
default:
size = Size.regular;
break;
case SMALL:
size = Size.small;
args |= ARG_SMALL_SIZE;
break;
case MINI:
size = Size.small; // paint mini with small artwork
args |= ARG_SMALL_SIZE;
break;
}
painter.setSize(size);
}
// Create an ImageBevelBorder
// FIXME - We have a caching opportunity here!
// -------------------------------------------
{
Insets vm = getVisualMargin(cc);
// The painter can not render text fields in arbitrary sizes.
// We render it first into an ImageBevelBorder, and then onto the
// image.
BufferedImage painterImg;
BufferedImage ibbImg;
BufferedImage focusImg;
ImageBevelBorder ibb;
int fixedWidth, fixedHeight, fixedYOffset;
int slack = 6;
if ((args & ARG_SMALL_SIZE) == ARG_SMALL_SIZE) {
fixedWidth = 40 + slack * 2;
fixedHeight = 19 + slack * 2;
fixedYOffset = 3;
if (smallPainterImage == null) {
smallPainterImage = new BufferedImage(fixedWidth, fixedHeight, BufferedImage.TYPE_INT_ARGB_PRE);
}
painterImg = smallPainterImage;
if (smallFocusImage == null) {
smallFocusImage = new BufferedImage(fixedWidth, fixedHeight, BufferedImage.TYPE_INT_ARGB_PRE);
}
focusImg = smallFocusImage;
if (smallIbb == null) {
ibbImg = new BufferedImage(fixedWidth, fixedHeight, BufferedImage.TYPE_INT_ARGB_PRE);
ibb = smallIbb = new ImageBevelBorder(ibbImg, new Insets(4 + slack, 4 + slack, 4 + slack, 4 + slack), new Insets(4 + slack, 4 + slack, 4 + slack, 4 + slack));
} else {
ibb = smallIbb;
}
} else {
fixedWidth = 40 + slack * 2;
fixedHeight = 22 + slack * 2;
fixedYOffset = 3;
if (regularPainterImage == null) {
regularPainterImage = new BufferedImage(fixedWidth, fixedHeight, BufferedImage.TYPE_INT_ARGB_PRE);
}
painterImg = regularPainterImage;
if (regularFocusImage == null) {
regularFocusImage = new BufferedImage(fixedWidth, fixedHeight, BufferedImage.TYPE_INT_ARGB_PRE);
}
focusImg = regularFocusImage;
if (regularIbb == null) {
ibbImg = new BufferedImage(fixedWidth, fixedHeight, BufferedImage.TYPE_INT_ARGB_PRE);
ibb = regularIbb = new ImageBevelBorder(ibbImg, new Insets(8 + slack, 8 + slack, 8 + slack, 8 + slack), new Insets(8 + slack, 8 + slack, 8 + slack, 8 + slack));
} else {
ibb = regularIbb;
}
}
ibbImg = (BufferedImage) ibb.getImage();
Graphics2D pg = painterImg.createGraphics();
pg.setColor(new Color(0x0, true));
pg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC));
pg.fillRect(0, 0, painterImg.getWidth(), painterImg.getHeight());
pg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
pg.dispose();
painter.paint(painterImg,//
slack, fixedYOffset + slack,//
painterImg.getWidth() - 2 * slack, painterImg.getHeight() - 2 * slack);
Graphics2D ibbg = ibbImg.createGraphics();
ibbg.setColor(new Color(0x0, true));
ibbg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC));
ibbg.fillRect(0, 0, painterImg.getWidth(), painterImg.getHeight());
ibbg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
ibbg.drawImage(painterImg, 0, 0, null);
if (QuaquaUtilities.isFocused(c) && editable) {
AbstractFocusedPainter.paintFocusRing(painterImg, focusImg, ibbg, 0, 0);
}
ibbg.dispose();
ibb.paintBorder(c, g,//
x+imageInsets.left - slack + vm.left, //
y+imageInsets.top - slack + vm.top,//
width - imageInsets.left - imageInsets.right + 2 * slack - vm.left - vm.right, //
height - imageInsets.top - imageInsets.bottom + 2 * slack - vm.top - vm.bottom);
ibbg.dispose();
}
if (c instanceof JComponent)
Debug.paint(g, (JComponent)c, null);
}
@Override
public Insets getBorderInsets(Component c, Insets insets) {
Insets ins = super.getBorderInsets(c, insets);
InsetsUtil.addTo(borderInsets, ins);
return ins;
}
@Override
public boolean isBorderOpaque() {
return false;
}
}