/*
* Copyright (c) 2009 Kathryn Huxtable and Kenneth Orr.
*
* This file is part of the SeaGlass Pluggable Look and Feel.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* $Id: SeaGlassIcon.java 1595 2011-08-09 20:33:48Z rosstauscher@gmx.de $
*/
package com.seaglasslookandfeel.component;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.JComponent;
import javax.swing.JToolBar;
import javax.swing.UIManager;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.synth.SynthContext;
import com.seaglasslookandfeel.SeaGlassLookAndFeel;
import com.seaglasslookandfeel.SeaGlassStyle;
import com.seaglasslookandfeel.painter.SeaGlassPainter;
import sun.swing.plaf.synth.SynthIcon;
/**
* An icon that delegates to a painter.
*
* <p>Based on NimbusIcon by Richard Bair. Reimplemented because too much is
* package local.</p>
*
*/
public class SeaGlassIcon extends SynthIcon {
private int width;
private int height;
private String prefix;
private String key;
/**
* Creates a new SeaGlassIcon object.
*
* @param prefix the prefix to use to get the painter.
* @param key the key to use to get the painter.
* @param w the icon width.
* @param h the icon height.
*/
public SeaGlassIcon(String prefix, String key, int w, int h) {
this.width = w;
this.height = h;
this.prefix = prefix;
this.key = key;
}
/**
* Paints the icon at the specified location.
*
* @param context Identifies hosting region, may be null.
* @param g the Graphics context to paint with.
* @param x x location to paint to.
* @param y y location to paint to.
* @param w Width of the region to paint to, may be 0.
* @param h Height of the region to paint to, may be 0.
*/
@SuppressWarnings("unchecked")
@Override
public void paintIcon(SynthContext context, Graphics g, int x, int y, int w, int h) {
SeaGlassPainter painter = null;
if (context != null) {
painter = (SeaGlassPainter) context.getStyle().get(context, key);
}
if (painter == null) {
painter = (SeaGlassPainter) UIManager.get(prefix + "[Enabled]." + key);
}
if (painter == null) {
painter = (SeaGlassPainter) UIManager.get(prefix + "." + key);
}
if (painter != null && context != null) {
JComponent c = context.getComponent();
boolean rotate = false;
boolean flip = false;
// translatex and translatey are additional translations that
// must occur on the graphics context when rendering a toolbar
// icon
int translatex = 0;
int translatey = 0;
if (c instanceof JToolBar) {
JToolBar toolbar = (JToolBar) c;
rotate = toolbar.getOrientation() == JToolBar.VERTICAL;
flip = !toolbar.getComponentOrientation().isLeftToRight();
Object o = SeaGlassLookAndFeel.resolveToolbarConstraint(toolbar);
// we only do the +1 hack for UIResource borders, assuming
// that the border is probably going to be our border
if (toolbar.getBorder() instanceof UIResource) {
if (o == BorderLayout.SOUTH) {
translatey = 1;
} else if (o == BorderLayout.EAST) {
translatex = 1;
}
}
}
if (g instanceof Graphics2D) {
Graphics2D gfx = (Graphics2D) g;
gfx.translate(x, y);
gfx.translate(translatex, translatey);
if (rotate) {
gfx.rotate(Math.toRadians(90));
gfx.translate(0, -w);
painter.paint(gfx, context.getComponent(), h, w);
gfx.translate(0, w);
gfx.rotate(Math.toRadians(-90));
} else if (flip) {
gfx.scale(-1, 1);
gfx.translate(-w, 0);
painter.paint(gfx, context.getComponent(), w, h);
gfx.translate(w, 0);
gfx.scale(-1, 1);
} else {
painter.paint(gfx, context.getComponent(), w, h);
}
gfx.translate(-translatex, -translatey);
gfx.translate(-x, -y);
} else {
// use image if we are printing to a Java 1.1 PrintGraphics as
// it is not a instance of Graphics2D
BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D gfx = img.createGraphics();
if (rotate) {
gfx.rotate(Math.toRadians(90));
gfx.translate(0, -w);
painter.paint(gfx, context.getComponent(), h, w);
} else if (flip) {
gfx.scale(-1, 1);
gfx.translate(-w, 0);
painter.paint(gfx, context.getComponent(), w, h);
} else {
painter.paint(gfx, context.getComponent(), w, h);
}
gfx.dispose();
g.drawImage(img, x, y, null);
img = null;
}
}
}
/**
* Implements the standard Icon interface's paintIcon method as the standard
* synth stub passes null for the context and this will cause us to not
* paint any thing, so we override here so that we can paint the enabled
* state if no synth context is available
*
* @param c the component to paint.
* @param g the Graphics context to paint with.
* @param x the x coordinate of the upper-left corner of the icon.
* @param y the y coordinate of the upper-left corner of the icon.
*/
@SuppressWarnings("unchecked")
@Override
public void paintIcon(Component c, Graphics g, int x, int y) {
SeaGlassPainter painter = (SeaGlassPainter) UIManager.get(prefix + "[Enabled]." + key);
if (painter != null) {
JComponent jc = (c instanceof JComponent) ? (JComponent) c : null;
Graphics2D gfx = (Graphics2D) g;
gfx.translate(x, y);
painter.paint(gfx, jc, width, height);
gfx.translate(-x, -y);
}
}
/**
* Returns the icon's width. This is a cover methods for <code>
* getIconWidth(null)</code>.
*
* @param context the SynthContext describing the component/region, the
* style, and the state.
*
* @return an int specifying the fixed width of the icon.
*/
@Override
public int getIconWidth(SynthContext context) {
if (context == null) {
return width;
}
JComponent c = context.getComponent();
if (c instanceof JToolBar && ((JToolBar) c).getOrientation() == JToolBar.VERTICAL) {
// we only do the -1 hack for UIResource borders, assuming
// that the border is probably going to be our border
if (c.getBorder() instanceof UIResource) {
return c.getWidth() - 1;
} else {
return c.getWidth();
}
} else {
return scale(context, width);
}
}
/**
* Returns the icon's height. This is a cover method for <code>
* getIconHeight(null)</code>.
*
* @param context the SynthContext describing the component/region, the
* style, and the state.
*
* @return an int specifying the fixed height of the icon.
*/
@Override
public int getIconHeight(SynthContext context) {
if (context == null) {
return height;
}
JComponent c = context.getComponent();
if (c instanceof JToolBar) {
JToolBar toolbar = (JToolBar) c;
if (toolbar.getOrientation() == JToolBar.HORIZONTAL) {
// we only do the -1 hack for UIResource borders, assuming
// that the border is probably going to be our border
if (toolbar.getBorder() instanceof UIResource) {
return c.getHeight() - 1;
} else {
return c.getHeight();
}
} else {
return scale(context, width);
}
} else {
return scale(context, height);
}
}
/**
* Scale a size based on the "JComponent.sizeVariant" client property of the
* component that is using this icon
*
* @param context The synthContext to get the component from
* @param size The size to scale
*
* @return The scaled size or original if "JComponent.sizeVariant" is not
* set
*/
private int scale(SynthContext context, int size) {
if (context == null || context.getComponent() == null) {
return size;
}
// The key "JComponent.sizeVariant" is used to match Apple's LAF
String scaleKey = SeaGlassStyle.getSizeVariant(context.getComponent());
if (scaleKey != null) {
if (SeaGlassStyle.LARGE_KEY.equals(scaleKey)) {
size *= SeaGlassStyle.LARGE_SCALE;
} else if (SeaGlassStyle.SMALL_KEY.equals(scaleKey)) {
size *= SeaGlassStyle.SMALL_SCALE;
} else if (SeaGlassStyle.MINI_KEY.equals(scaleKey)) {
// mini is not quite as small for icons as full mini is
// just too tiny
size *= SeaGlassStyle.MINI_SCALE + 0.07;
}
}
return size;
}
}