/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenFlexo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.fge.graphics; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Image; import java.awt.Paint; import java.awt.Rectangle; import java.awt.TexturePaint; import java.awt.Toolkit; import java.awt.image.BufferedImage; import java.awt.image.FilteredImageSource; import java.awt.image.ImageProducer; import java.awt.image.RGBImageFilter; import java.io.File; import java.util.Observable; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.ImageIcon; import org.openflexo.fge.GraphicalRepresentation; import org.openflexo.fge.GraphicalRepresentation.GRParameter; import org.openflexo.fge.notifications.FGENotification; import org.openflexo.inspector.HasIcon; import org.openflexo.toolbox.ImageIconResource; import org.openflexo.xmlcode.XMLSerializable; import sun.awt.image.ImageRepresentation; import sun.awt.image.ToolkitImage; public abstract class BackgroundStyle extends Observable implements XMLSerializable, Cloneable { private static final Logger logger = Logger.getLogger(BackgroundStyle.class.getPackage().getName()); private transient GraphicalRepresentation graphicalRepresentation; private boolean useTransparency = false; private float transparencyLevel = 0.5f; // Between 0.0 and 1.0 public static enum Parameters implements GRParameter { color, color1, color2, direction, textureType, imageFile, deltaX, deltaY, imageBackgroundType, scaleX, scaleY, fitToShape, imageBackgroundColor, transparencyLevel, useTransparency; } public static BackgroundStyle makeEmptyBackground() { return new None(); } public static BackgroundStyle makeColoredBackground(java.awt.Color aColor) { return new Color(aColor); } public static BackgroundStyle makeColorGradientBackground(java.awt.Color color1, java.awt.Color color2, ColorGradient.ColorGradientDirection direction) { return new ColorGradient(color1, color2, direction); } public static BackgroundStyle makeTexturedBackground(Texture.TextureType type, java.awt.Color aColor1, java.awt.Color aColor2) { return new Texture(type, aColor1, aColor2); } public static BackgroundImage makeImageBackground(File imageFile) { return new BackgroundImage(imageFile); } public static BackgroundImage makeImageBackground(ImageIcon image) { return new BackgroundImage(image); } public static BackgroundStyle makeBackground(BackgroundStyleType type) { if (type == BackgroundStyleType.NONE) { return makeEmptyBackground(); } else if (type == BackgroundStyleType.COLOR) { return makeColoredBackground(java.awt.Color.WHITE); } else if (type == BackgroundStyleType.COLOR_GRADIENT) { return makeColorGradientBackground(java.awt.Color.WHITE, java.awt.Color.BLACK, org.openflexo.fge.graphics.BackgroundStyle.ColorGradient.ColorGradientDirection.SOUTH_EAST_NORTH_WEST); } else if (type == BackgroundStyleType.TEXTURE) { return makeTexturedBackground(org.openflexo.fge.graphics.BackgroundStyle.Texture.TextureType.TEXTURE1, java.awt.Color.RED, java.awt.Color.WHITE); } else if (type == BackgroundStyleType.IMAGE) { return makeImageBackground((File) null); } return null; } public abstract Paint getPaint(GraphicalRepresentation gr, double scale); public abstract BackgroundStyleType getBackgroundStyleType(); /*public GraphicalRepresentation getGraphicalRepresentation() { return graphicalRepresentation; } public void setGraphicalRepresentation( GraphicalRepresentation graphicalRepresentation) { this.graphicalRepresentation = graphicalRepresentation; }*/ @Override public abstract String toString(); public static enum BackgroundStyleType { NONE, COLOR, COLOR_GRADIENT, TEXTURE, IMAGE } public static class None extends BackgroundStyle { @Override public Paint getPaint(GraphicalRepresentation gr, double scale) { return null; } @Override public BackgroundStyleType getBackgroundStyleType() { return BackgroundStyleType.NONE; } @Override public String toString() { return "BackgroundStyle.NONE"; } } public static class Color extends BackgroundStyle { private java.awt.Color color; public Color() { color = java.awt.Color.WHITE; } public Color(java.awt.Color aColor) { color = aColor; } @Override public Paint getPaint(GraphicalRepresentation gr, double scale) { return color; } public java.awt.Color getColor() { return color; } @Override public BackgroundStyleType getBackgroundStyleType() { return BackgroundStyleType.COLOR; } public void setColor(java.awt.Color aColor) { if (requireChange(this.color, aColor)) { java.awt.Color oldColor = color; this.color = aColor; setChanged(); notifyObservers(new FGENotification(Parameters.color, oldColor, aColor)); } } @Override public String toString() { return "BackgroundStyle.COLOR(" + getColor() + ")"; } private boolean requireChange(Object oldObject, Object newObject) { if (oldObject == null) { if (newObject == null) { return false; } else { return true; } } return !oldObject.equals(newObject); } } public static class ColorGradient extends BackgroundStyle { private java.awt.Color color1; private java.awt.Color color2; private ColorGradientDirection direction; public ColorGradient() { this(java.awt.Color.WHITE, java.awt.Color.BLACK, org.openflexo.fge.graphics.BackgroundStyle.ColorGradient.ColorGradientDirection.SOUTH_EAST_NORTH_WEST); } public ColorGradient(java.awt.Color aColor1, java.awt.Color aColor2, ColorGradientDirection aDirection) { super(); this.color1 = aColor1; this.color2 = aColor2; this.direction = aDirection; } public static enum ColorGradientDirection { NORTH_SOUTH, WEST_EAST, SOUTH_EAST_NORTH_WEST, SOUTH_WEST_NORTH_EAST } @Override public Paint getPaint(GraphicalRepresentation gr, double scale) { switch (direction) { case SOUTH_EAST_NORTH_WEST: return new GradientPaint(0, 0, color1, gr.getViewWidth(scale), gr.getViewHeight(scale), color2); case SOUTH_WEST_NORTH_EAST: return new GradientPaint(0, gr.getViewHeight(scale), color1, gr.getViewWidth(scale), 0, color2); case WEST_EAST: return new GradientPaint(0, 0.5f * gr.getViewHeight(scale), color1, gr.getViewWidth(scale), 0.5f * gr.getViewHeight(scale), color2); case NORTH_SOUTH: return new GradientPaint(0.5f * gr.getViewWidth(scale), 0, color1, 0.5f * gr.getViewWidth(scale), gr.getViewHeight(scale), color2); default: return new GradientPaint(0, 0, color1, gr.getViewWidth(scale), gr.getViewHeight(scale), color2); } } @Override public BackgroundStyleType getBackgroundStyleType() { return BackgroundStyleType.COLOR_GRADIENT; } public java.awt.Color getColor1() { return color1; } public void setColor1(java.awt.Color aColor) { if (requireChange(this.color1, aColor)) { java.awt.Color oldColor = color1; this.color1 = aColor; setChanged(); notifyObservers(new FGENotification(Parameters.color1, oldColor, aColor)); } } public java.awt.Color getColor2() { return color2; } public void setColor2(java.awt.Color aColor) { if (requireChange(this.color2, aColor)) { java.awt.Color oldColor = color2; this.color2 = aColor; setChanged(); notifyObservers(new FGENotification(Parameters.color2, oldColor, aColor)); } } public ColorGradientDirection getDirection() { return direction; } public void setDirection(ColorGradientDirection aDirection) { if (requireChange(this.direction, aDirection)) { ColorGradientDirection oldTexture = direction; this.direction = aDirection; setChanged(); notifyObservers(new FGENotification(Parameters.direction, oldTexture, aDirection)); } } @Override public String toString() { return "BackgroundStyle.COLOR_GRADIENT(" + getColor1() + "," + getColor2() + "," + getDirection() + ")"; } private boolean requireChange(Object oldObject, Object newObject) { if (oldObject == null) { if (newObject == null) { return false; } else { return true; } } return !oldObject.equals(newObject); } } public static class Texture extends BackgroundStyle { private TextureType textureType; private java.awt.Color color1; private java.awt.Color color2; private BufferedImage coloredTexture; private ToolkitImage coloredImage; public Texture() { this(TextureType.TEXTURE1, java.awt.Color.WHITE, java.awt.Color.BLACK); } public Texture(TextureType aTextureType, java.awt.Color aColor1, java.awt.Color aColor2) { super(); textureType = aTextureType; this.color1 = aColor1; this.color2 = aColor2; rebuildColoredTexture(); } private void rebuildColoredTexture() { if (textureType == null) { return; } final Image initialImage = textureType.getImageIcon().getImage(); ColorSwapFilter imgfilter = new ColorSwapFilter(java.awt.Color.BLACK, color1, java.awt.Color.WHITE, color2) { @Override public void imageComplete(int status) { super.imageComplete(status); coloredTexture = new BufferedImage(initialImage.getWidth(null), initialImage.getHeight(null), BufferedImage.TYPE_INT_ARGB); Graphics gi = coloredTexture.getGraphics(); gi.drawImage(coloredImage, 0, 0, null); } }; ImageProducer producer = new FilteredImageSource(initialImage.getSource(), imgfilter); coloredImage = (ToolkitImage) Toolkit.getDefaultToolkit().createImage(producer); ImageRepresentation consumer = new ImageRepresentation(coloredImage, null, true); producer.addConsumer(consumer); try { producer.startProduction(consumer); } catch (RuntimeException e) { logger.warning("Unexpected exception: " + e); } } private BufferedImage getColoredTexture() { if (coloredTexture == null) { rebuildColoredTexture(); /*int tests = 10; // Time-out = 1s while (coloredTexture == null && tests>=0) { try { tests--; Thread.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (coloredTexture == null) { logger.warning("Could not compute colored texture"); Image initialImage = textureType.getImageIcon().getImage(); System.out.println("initialImage="+initialImage+" initialImage.getWidth(null)="+initialImage.getWidth(null)); coloredTexture = new BufferedImage( initialImage.getWidth(null), initialImage.getHeight(null), BufferedImage.TYPE_INT_ARGB); Graphics gi = coloredTexture.getGraphics(); gi.drawImage(initialImage, 0, 0, null); }*/ } return coloredTexture; } static class ColorSwapFilter extends RGBImageFilter { private int target1; private int replacement1; private int target2; private int replacement2; public ColorSwapFilter(java.awt.Color target1, java.awt.Color replacement1, java.awt.Color target2, java.awt.Color replacement2) { this.target1 = target1.getRGB(); this.replacement1 = replacement1.getRGB(); this.target2 = target2.getRGB(); this.replacement2 = replacement2.getRGB(); } @Override public int filterRGB(int x, int y, int rgb) { // if (x==0 && y==0) logger.info("Starting convert image"); // if (x==15 && y==15) logger.info("Finished convert image"); if (rgb == target1) { return replacement1; } else if (rgb == target2) { return replacement2; } return rgb; } @Override public void imageComplete(int status) { super.imageComplete(status); if (logger.isLoggable(Level.FINE)) { logger.fine("imageComplete status=" + status); } } } public static enum TextureType implements HasIcon { TEXTURE1, TEXTURE2, TEXTURE3, TEXTURE4, TEXTURE5, TEXTURE6, TEXTURE7, TEXTURE8, TEXTURE9, TEXTURE10, TEXTURE11, TEXTURE12, TEXTURE13, TEXTURE14, TEXTURE15, TEXTURE16; public ImageIcon getImageIcon() { return new ImageIconResource("Motifs/Motif" + (ordinal() + 1) + ".gif"); } @Override public ImageIcon getIcon() { return getImageIcon(); } } @Override public Paint getPaint(GraphicalRepresentation gr, double scale) { return new TexturePaint(getColoredTexture(), new Rectangle(0, 0, getColoredTexture().getWidth(), getColoredTexture() .getHeight())); } @Override public BackgroundStyleType getBackgroundStyleType() { return BackgroundStyleType.TEXTURE; } public TextureType getTextureType() { return textureType; } public void setTextureType(TextureType aTextureType) { if (requireChange(this.textureType, aTextureType)) { TextureType oldTexture = textureType; this.textureType = aTextureType; rebuildColoredTexture(); setChanged(); notifyObservers(new FGENotification(Parameters.textureType, oldTexture, aTextureType)); } } public java.awt.Color getColor1() { return color1; } public void setColor1(java.awt.Color aColor) { if (requireChange(this.color1, aColor)) { java.awt.Color oldColor = color1; this.color1 = aColor; rebuildColoredTexture(); setChanged(); notifyObservers(new FGENotification(Parameters.color1, oldColor, aColor)); } } public java.awt.Color getColor2() { return color2; } public void setColor2(java.awt.Color aColor) { if (requireChange(this.color2, aColor)) { java.awt.Color oldColor = color2; this.color2 = aColor; rebuildColoredTexture(); setChanged(); notifyObservers(new FGENotification(Parameters.color2, oldColor, aColor)); } } @Override public String toString() { return "BackgroundStyle.TEXTURE(" + getColor1() + "," + getColor2() + "," + getTextureType() + ")"; } private boolean requireChange(Object oldObject, Object newObject) { if (oldObject == null) { if (newObject == null) { return false; } else { return true; } } return !oldObject.equals(newObject); } } public static class BackgroundImage extends BackgroundStyle { private File imageFile; private Image image; public BackgroundImage() { this((File) null); } public BackgroundImage(File imageFile) { super(); setImageFile(imageFile); } public BackgroundImage(ImageIcon image) { super(); this.image = image.getImage(); } @Override public Paint getPaint(GraphicalRepresentation gr, double scale) { return java.awt.Color.WHITE; } @Override public BackgroundStyleType getBackgroundStyleType() { return BackgroundStyleType.IMAGE; } public File getImageFile() { return imageFile; } public void setImageFile(File anImageFile) { if (requireChange(this.imageFile, anImageFile)) { File oldFile = imageFile; imageFile = anImageFile; if (anImageFile != null && anImageFile.exists()) { image = new ImageIcon(anImageFile.getAbsolutePath()).getImage(); } else { image = null; } setChanged(); notifyObservers(new FGENotification(Parameters.imageFile, oldFile, anImageFile)); } } public Image getImage() { return image; } private ImageBackgroundType imageBackgroundType = ImageBackgroundType.TRANSPARENT; private double scaleX = 1.0; private double scaleY = 1.0; private double deltaX = 0.0; private double deltaY = 0.0; private java.awt.Color imageBackgroundColor = java.awt.Color.WHITE; private boolean fitToShape = false; public static enum ImageBackgroundType { OPAQUE, TRANSPARENT } public java.awt.Color getImageBackgroundColor() { return imageBackgroundColor; } public void setImageBackgroundColor(java.awt.Color aColor) { if (requireChange(this.imageBackgroundColor, aColor)) { java.awt.Color oldColor = imageBackgroundColor; this.imageBackgroundColor = aColor; setChanged(); notifyObservers(new FGENotification(Parameters.imageBackgroundColor, oldColor, aColor)); } } public double getDeltaX() { return deltaX; } public void setDeltaX(double aDeltaX) { if (requireChange(this.deltaX, aDeltaX)) { double oldDeltaX = this.deltaX; this.deltaX = aDeltaX; setChanged(); notifyObservers(new FGENotification(Parameters.deltaX, oldDeltaX, deltaX)); } } public double getDeltaY() { return deltaY; } public void setDeltaY(double aDeltaY) { if (requireChange(this.deltaY, aDeltaY)) { double oldDeltaY = this.deltaY; this.deltaY = aDeltaY; setChanged(); notifyObservers(new FGENotification(Parameters.deltaY, oldDeltaY, deltaY)); } } public ImageBackgroundType getImageBackgroundType() { return imageBackgroundType; } public void setImageBackgroundType(ImageBackgroundType anImageBackgroundType) { if (requireChange(this.imageBackgroundType, anImageBackgroundType)) { ImageBackgroundType oldImageBackgroundType = this.imageBackgroundType; this.imageBackgroundType = anImageBackgroundType; setChanged(); notifyObservers(new FGENotification(Parameters.imageBackgroundType, oldImageBackgroundType, anImageBackgroundType)); } } public double getScaleX() { return scaleX; } public void setScaleX(double aScaleX) { if (requireChange(this.scaleX, aScaleX)) { double oldScaleX = this.scaleX; // logger.info(toString()+": Sets scaleX from "+oldScaleX+" to "+aScaleX); this.scaleX = aScaleX; setChanged(); notifyObservers(new FGENotification(Parameters.scaleX, oldScaleX, scaleX)); } } public void setScaleXNoNotification(double aScaleX) { if (requireChange(this.scaleX, aScaleX)) { this.scaleX = aScaleX; } } public double getScaleY() { return scaleY; } public void setScaleY(double aScaleY) { if (requireChange(this.scaleY, aScaleY)) { double oldScaleY = this.scaleY; // logger.info(toString()+": Sets scaleY from "+oldScaleY+" to "+aScaleY); this.scaleY = aScaleY; setChanged(); notifyObservers(new FGENotification(Parameters.scaleY, oldScaleY, scaleY)); } } public void setScaleYNoNotification(double aScaleY) { if (requireChange(this.scaleY, aScaleY)) { this.scaleY = aScaleY; } } public boolean getFitToShape() { return fitToShape; } public void setFitToShape(boolean aFlag) { if (requireChange(this.fitToShape, aFlag)) { boolean oldValue = fitToShape; this.fitToShape = aFlag; setChanged(); notifyObservers(new FGENotification(Parameters.fitToShape, oldValue, aFlag)); } } @Override public String toString() { return "BackgroundStyle.IMAGE(" + getImageFile() + ")"; } private boolean requireChange(Object oldObject, Object newObject) { if (oldObject == null) { if (newObject == null) { return false; } else { return true; } } return !oldObject.equals(newObject); } } public float getTransparencyLevel() { return transparencyLevel; } public void setTransparencyLevel(float aLevel) { if (requireChange(this.transparencyLevel, aLevel)) { float oldValue = transparencyLevel; this.transparencyLevel = aLevel; setChanged(); notifyObservers(new FGENotification(Parameters.transparencyLevel, oldValue, aLevel)); } } public boolean getUseTransparency() { return useTransparency; } public void setUseTransparency(boolean aFlag) { if (requireChange(this.useTransparency, aFlag)) { boolean oldValue = useTransparency; this.useTransparency = aFlag; setChanged(); notifyObservers(new FGENotification(Parameters.useTransparency, oldValue, aFlag)); } } @Override public BackgroundStyle clone() { try { BackgroundStyle returned = (BackgroundStyle) super.clone(); returned.graphicalRepresentation = null; return returned; } catch (CloneNotSupportedException e) { // cannot happen since we are clonable e.printStackTrace(); return null; } } private boolean requireChange(Object oldObject, Object newObject) { if (oldObject == null) { if (newObject == null) { return false; } else { return true; } } return !oldObject.equals(newObject); } }