package org.archstudio.bna.ui.utils;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.font.FontRenderContext;
import java.awt.font.LineMetrics;
import java.awt.geom.Rectangle2D;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import org.archstudio.bna.ui.IUIResources;
import org.archstudio.bna.utils.BNAUtils;
import org.archstudio.swtutils.constants.FontStyle;
import org.archstudio.sysutils.SystemUtils;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Lists;
public abstract class AbstractUIResources implements IUIResources {
protected static class FontMetrics implements IUIResources.FontMetrics {
private final float leading, ascent, descent;
public FontMetrics(float leading, float ascent, float descent) {
this.leading = leading;
this.ascent = ascent;
this.descent = descent;
}
@Override
public float getLeading() {
return leading;
}
@Override
public float getAscent() {
return ascent;
}
@Override
public float getDescent() {
return descent;
}
@Override
public String toString() {
return "FontMetrics [leading=" + leading + ", ascent=" + ascent + ", descent=" + descent + "]";
}
}
private final LoadingCache<List<? extends Object>, Font> fonts = CacheBuilder.newBuilder().build(
new CacheLoader<List<? extends Object>, Font>() {
@Override
public Font load(List<? extends Object> data) throws Exception {
return _getFont((String) data.get(0), (FontStyle) data.get(1), (Integer) data.get(2));
}
});
private final LoadingCache<Font, IUIResources.FontMetrics> fontMetrics = CacheBuilder.newBuilder().build(
new CacheLoader<Font, IUIResources.FontMetrics>() {
@Override
public IUIResources.FontMetrics load(Font font) throws Exception {
LineMetrics fontMetrics = font.getLineMetrics("", fontRenderContext);
Rectangle2D stdMetrics = font.createGlyphVector(fontRenderContext, "O")
.getOutline(0, fontMetrics.getAscent()).getBounds2D();
float leading = (float) stdMetrics.getY();
float ascent = (float) stdMetrics.getMaxY() - leading;
float descent = fontMetrics.getHeight() - (leading + ascent);
return new FontMetrics(leading, ascent, descent);
}
});
private boolean antialiasGraphics = true;
private boolean antialiasText = true;
private FontRenderContext fontRenderContext = new FontRenderContext(null, antialiasText, false);
private boolean decorativeGraphics = true;
private boolean displayShadows = true;
private Deque<Float> globalAlphaStack = new LinkedList<>();
private float globalAlpha = 1f;
public AbstractUIResources() {
}
@Override
public void dispose() {
fonts.invalidateAll();
fontMetrics.invalidateAll();
}
@Override
public boolean isAntialiasGraphics() {
return antialiasGraphics;
}
@Override
public void setAntialiasGraphics(boolean antialiasGraphics) {
this.antialiasGraphics = antialiasGraphics;
}
@Override
public boolean isAntialiasText() {
return antialiasText;
}
@Override
public void setAntialiasText(boolean antialiasText) {
if (this.antialiasText != antialiasText) {
this.antialiasText = antialiasText;
fontRenderContext = new FontRenderContext(null, antialiasText, false);
}
}
@Override
public boolean isDecorativeGraphics() {
return decorativeGraphics;
}
@Override
public void setDecorativeGraphics(boolean decorativeGraphics) {
this.decorativeGraphics = decorativeGraphics;
}
@Override
public boolean isDisplayShadows() {
return displayShadows;
}
@Override
public void setDisplayShadows(boolean displayShadows) {
this.displayShadows = displayShadows;
}
@Override
public double pushAlpha(double alpha) {
globalAlphaStack.push(globalAlpha);
globalAlpha *= alpha;
return globalAlpha;
}
@Override
public double popAlpha() {
return globalAlpha = globalAlphaStack.pop();
}
protected float getGlobalAlpha() {
return globalAlpha;
}
@Override
public Font getFont(String name, FontStyle style, int size) {
/*
* AWT fonts are noticeably smaller than SWT fonts. We scale them based on their ascent to make them
* approximately the same size.
*/
IUIResources.FontMetrics metrics = getFontMetrics(_getFont(name, style, size));
return fonts.getUnchecked(Lists.<Object> newArrayList(name, style,
SystemUtils.round(size * size / metrics.getAscent())));
}
protected Font _getFont(String name, FontStyle style, int size) {
return new Font(name, style.toAWT(), size);
}
@Override
public IUIResources.FontMetrics getFontMetrics(Font font) {
return fontMetrics.getUnchecked(font);
}
@Override
public Dimension getTextSize(Font font, String text) {
return BNAUtils.toDimension(font.getStringBounds(text, fontRenderContext));
}
}