blob: 7a3d25c12a60bca325e2aca64887e4f057b5b658 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2014 Dirk Fauth, Edwin Park.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Dirk Fauth <dirk.fauth@googlemail.com> - initial API and implementation
* Edwin Park <esp1@cornell.edu> - initial API and implementation
******************************************************************************/
package org.eclipse.nebula.widgets.nattable.ui.swt;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.nebula.widgets.nattable.core.geometry.PixelRectangle;
import org.eclipse.nebula.widgets.nattable.core.ui.rendering.Color;
import org.eclipse.nebula.widgets.nattable.core.ui.rendering.Font;
import org.eclipse.nebula.widgets.nattable.core.ui.rendering.Font.FontStyle;
import org.eclipse.nebula.widgets.nattable.core.ui.rendering.GraphicsContext;
import org.eclipse.nebula.widgets.nattable.core.ui.rendering.Image;
import org.eclipse.nebula.widgets.nattable.core.ui.rendering.Transform;
import org.eclipse.nebula.widgets.nattable.style.IStyle;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;
/**
* Proxy implementation of {@link GraphicsContext} to provide the drawing
* capabilities by SWT {@link GC} so the NatTable can be painted using this.
*/
public class SWTGraphicsContext implements GraphicsContext {
private static final String KEY_PREFIX = SWTGraphicsContext.class.getCanonicalName() + "."; //$NON-NLS-1$
enum GraphicsProperties {
FOREGROUND_COLOR,
BACKGROUND_COLOR,
ALPHA,
CLIP_BOUNDS,
TRANSFORM,
LINE_STYLE,
LINE_DASH,
LINE_WIDTH
}
private Stack<Map<GraphicsProperties, Object>> stateStack = new Stack<Map<GraphicsProperties, Object>>();
/**
* The SWT {@link GC} which is proxied by this implementation.
*/
private GC gc;
/**
*
* @param gc
* The SWT {@link GC} that should be proxied by this
* implementation.
*/
public SWTGraphicsContext(GC gc) {
this.gc = gc;
}
@Override
public void initStyle(IStyle style) {
// TODO Auto-generated method stub
}
@Override
public void drawText(String text, double x, double y) {
this.gc.drawText(text, (int) x, (int) y, SWT.DRAW_TRANSPARENT | SWT.DRAW_DELIMITER);
}
@Override
public void drawLine(double x1, double y1, double x2, double y2) {
this.gc.drawLine((int) x1, (int) y1, (int) x2, (int) y2);
}
@Override
public void drawRectangle(PixelRectangle rect) {
this.gc.drawRectangle((int) rect.x, (int) rect.y, (int) rect.width, (int) rect.height);
}
@Override
public void fillRectangle(PixelRectangle rect) {
this.gc.fillRectangle((int) rect.x, (int) rect.y, (int) rect.width, (int) rect.height);
}
@Override
public double calculateTextWidth(String text) {
return this.gc.textExtent(text).x;
}
@Override
public double getFontHeight() {
return this.gc.getFontMetrics().getHeight();
}
@Override
public void pushState() {
Map<GraphicsProperties, Object> props = new HashMap<GraphicsProperties, Object>();
props.put(GraphicsProperties.FOREGROUND_COLOR, this.gc.getForeground());
props.put(GraphicsProperties.BACKGROUND_COLOR, this.gc.getBackground());
props.put(GraphicsProperties.ALPHA, this.gc.getAlpha());
props.put(GraphicsProperties.CLIP_BOUNDS, this.gc.getClipping());
// TODO remember the transform wrapper if any is active
// props.put(GraphicsProperties.TRANSFORM, null);
this.stateStack.push(props);
}
@Override
public void popState() {
Map<GraphicsProperties, Object> props = this.stateStack.pop();
this.gc.setForeground((org.eclipse.swt.graphics.Color) props.get(GraphicsProperties.FOREGROUND_COLOR));
this.gc.setBackground((org.eclipse.swt.graphics.Color) props.get(GraphicsProperties.BACKGROUND_COLOR));
this.gc.setAlpha((Integer) props.get(GraphicsProperties.ALPHA));
this.gc.setClipping((Rectangle) props.get(GraphicsProperties.CLIP_BOUNDS));
}
@Override
public PixelRectangle getClipping() {
return getPixelRectangle(this.gc.getClipping());
}
@Override
public void setClipping(PixelRectangle clipBounds) {
this.gc.setClipping(getUiRectangle(clipBounds));
}
@Override
public void setForeground(Color foregroundColor) {
this.gc.setForeground(getUiColor(foregroundColor));
// TODO set alpha
}
@Override
public void setBackground(Color backgroundColor) {
this.gc.setBackground(getUiColor(backgroundColor));
// TODO set alpha
}
@Override
public org.eclipse.swt.graphics.Color getUiColor(Color color) {
if (color.getNativeColor() == null) {
String key = KEY_PREFIX + "_COLOR_" + color.red + "_" + color.green + "_" + color.blue; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
if (!JFaceResources.getColorRegistry().hasValueFor(key)) {
JFaceResources.getColorRegistry().put(key, new RGB(color.red, color.green, color.blue));
}
color.setNativeColor(JFaceResources.getColorRegistry().get(key));
}
if (color.getNativeColor() == null || !(color.getNativeColor() instanceof org.eclipse.swt.graphics.Color)) {
throw new IllegalStateException("native color instance in color wrapper is invalid");
}
return (org.eclipse.swt.graphics.Color) color.getNativeColor();
}
@Override
public void setFont(Font font) {
this.gc.setFont(getUiFont(font));
}
@Override
public org.eclipse.swt.graphics.Font getUiFont(Font font) {
if (font.getNativeFont() == null) {
// if all attributes are not set, use the default font
if (font.name == null && font.height == -1 && font.style == null) {
font.setNativeFont(Display.getDefault().getSystemFont());
}
else {
FontData defaultFontData = Display.getDefault().getSystemFont().getFontData()[0];
String fontName = (font.name == null) ? defaultFontData.getName() : font.name;
int height = (font.height == -1) ? defaultFontData.getHeight() : Double.valueOf(font.height).intValue();
int fontStyle = SWT.NORMAL;
// calculate font style
if (font.style != null) {
for (FontStyle style : font.style) {
if (FontStyle.ITALIC.equals(style)) {
fontStyle = fontStyle | SWT.ITALIC;
}
else if (FontStyle.BOLD.equals(style)
|| FontStyle.EXTRA_BOLD.equals(style)
|| FontStyle.SEMI_BOLD.equals(style)) {
fontStyle = fontStyle | SWT.BOLD;
}
}
}
FontData data = new FontData(fontName, height, fontStyle);
String key = data.toString();
if (!JFaceResources.getFontRegistry().hasValueFor(key)) {
JFaceResources.getFontRegistry().put(key, new FontData[] { data });
}
font.setNativeFont(JFaceResources.getFontRegistry().get(key));
}
}
if (!(font.getNativeFont() instanceof org.eclipse.swt.graphics.Font)) {
throw new IllegalStateException("native font instance in font wrapper is invalid");
}
return (org.eclipse.swt.graphics.Font) font.getNativeFont();
}
@Override
public void drawImage(Image image, double x, double y) {
this.gc.drawImage(getUiImage(image), Double.valueOf(x).intValue(), Double.valueOf(y).intValue());
}
@Override
public org.eclipse.swt.graphics.Image getUiImage(Image image) {
if (image.getNativeImage() == null) {
// key = filename
String key = image.url.toString();
key = key.substring(key.lastIndexOf('/') + 1, key.lastIndexOf('.'));
ImageDescriptor descriptor = JFaceResources.getImageRegistry().getDescriptor(key);
if (descriptor == null) {
URL url = image.url;
// TODO check if scaling is necessary
// if (GUIHelper.needScaling())
descriptor = ImageDescriptor.createFromURL(url);
// TODO or upscale
JFaceResources.getImageRegistry().put(key, ImageDescriptor.createFromURL(url));
}
image.setNativeImage(JFaceResources.getImage(key));
}
if (image.getNativeImage() == null || !(image.getNativeImage() instanceof org.eclipse.swt.graphics.Image)) {
throw new IllegalStateException("native image instance in image wrapper is invalid");
}
return (org.eclipse.swt.graphics.Image) image.getNativeImage();
}
private Rectangle getUiRectangle(PixelRectangle rectangle) {
return new Rectangle(
(int) rectangle.x,
(int) rectangle.y,
(int) rectangle.width,
(int) rectangle.height);
}
private PixelRectangle getPixelRectangle(Rectangle rectangle) {
return new PixelRectangle(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
}
@Override
public void setTransform(Transform transform) {
if (transform == null) {
this.gc.setTransform(null);
}
else {
org.eclipse.swt.graphics.Transform uiTransform =
new org.eclipse.swt.graphics.Transform(this.gc.getDevice());
if (transform.hasRotation()) {
uiTransform.rotate(transform.getAngle());
}
if (transform.hasScaling()) {
uiTransform.scale(transform.getScaleX(), transform.getScaleY());
}
if (transform.hasTranslation()) {
uiTransform.translate(transform.getOffsetX(), transform.getOffsetY());
}
this.gc.setTransform(uiTransform);
}
}
}