/* ******************************************************************************
* Copyright (c) 2014 - 2015 Fabian Prasser.
* 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:
* Fabian Prasser - initial API and implementation
******************************************************************************/
package de.linearbits.swt.widgets;
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.RadialGradientPaint;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.awt.image.DirectColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.WritableRaster;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Display;
/**
* This class renders an oval with 3d effects. It mostly consists of code borrowed from the TimingFramework and JFreeChart.
*
* @author Fabian Prasser
* @author Romain Guy
* @author Henry Proudhon
* @author Rainer Blessing
* @author David Gilbert
* @author Christoph Beck
*/
class KnobRenderer {
/**
* Converts the byte to a float between 0 and 1
* @param value
* @return
*/
private float byteToFloat(int value){
return (float)Math.round((double)value / 255d);
}
/**
* JFreeChart : a free chart library for the Java(tm) platform
* (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jfreechart/index.html
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at
* your option) any later version.
*
* This library 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 Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Original Author: Henry Proudhon (henry.proudhon AT ensmp.fr);
* Contributor(s): Rainer Blessing; David Gilbert
* (david.gilbert@object-refinery.com); Christoph Beck.
*
*/
private ImageData convertToSWT(BufferedImage bufferedImage) {
if (bufferedImage.getColorModel() instanceof DirectColorModel) {
DirectColorModel colorModel = (DirectColorModel) bufferedImage.getColorModel();
PaletteData palette = new PaletteData(colorModel.getRedMask(),
colorModel.getGreenMask(),
colorModel.getBlueMask());
ImageData data = new ImageData(bufferedImage.getWidth(),
bufferedImage.getHeight(),
colorModel.getPixelSize(),
palette);
WritableRaster raster = bufferedImage.getRaster();
int[] pixelArray = new int[3];
for (int y = 0; y < data.height; y++) {
for (int x = 0; x < data.width; x++) {
raster.getPixel(x, y, pixelArray);
int pixel = palette.getPixel(new RGB(pixelArray[0],
pixelArray[1],
pixelArray[2]));
data.setPixel(data.width - x - 1, data.height - y - 1, pixel);
}
}
return data;
} else if (bufferedImage.getColorModel() instanceof IndexColorModel) {
IndexColorModel colorModel = (IndexColorModel) bufferedImage.getColorModel();
int size = colorModel.getMapSize();
byte[] reds = new byte[size];
byte[] greens = new byte[size];
byte[] blues = new byte[size];
colorModel.getReds(reds);
colorModel.getGreens(greens);
colorModel.getBlues(blues);
RGB[] rgbs = new RGB[size];
for (int i = 0; i < rgbs.length; i++) {
rgbs[i] = new RGB(reds[i] & 0xFF, greens[i] & 0xFF, blues[i] & 0xFF);
}
PaletteData palette = new PaletteData(rgbs);
ImageData data = new ImageData(bufferedImage.getWidth(),
bufferedImage.getHeight(),
colorModel.getPixelSize(),
palette);
data.transparentPixel = colorModel.getTransparentPixel();
WritableRaster raster = bufferedImage.getRaster();
int[] pixelArray = new int[1];
for (int y = 0; y < data.height; y++) {
for (int x = 0; x < data.width; x++) {
raster.getPixel(x, y, pixelArray);
data.setPixel(data.width - x - 1, data.height - y - 1, pixelArray[0]);
}
}
return data;
}
return null;
}
/**
* Copyright (c) 2007, Romain Guy All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * Redistributions
* in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. * Neither the name of the
* TimingFramework project nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* @param profile
*/
private void render(Graphics g, Color background, KnobColorProfile profile, int width, int height) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// Retains the previous state
Paint oldPaint = g2.getPaint();
g2.setColor(background);
g2.fillRect(0, 0, width, height);
// Fills the circle with solid blue color
Color c = new Color(profile.getBackground().getRed(),
profile.getBackground().getGreen(),
profile.getBackground().getBlue());
g2.setColor(c);
g2.fillOval(0, 0, width - 1, height - 1);
// Adds shadows at the top
Paint p;
Color c1 = new Color(byteToFloat(profile.getShadow().getRed()),
byteToFloat(profile.getShadow().getGreen()),
byteToFloat(profile.getShadow().getBlue()), 0.4f);
Color c2 = new Color(byteToFloat(profile.getShadow().getRed()),
byteToFloat(profile.getShadow().getGreen()),
byteToFloat(profile.getShadow().getBlue()), 0.0f);
p = new GradientPaint(0, 0, c1, 0, height, c2);
g2.setPaint(p);
g2.fillOval(0, 0, width - 1, height - 1);
// Adds highlights at the bottom
c1 = new Color(byteToFloat(profile.getHighlightBottom().getRed()),
byteToFloat(profile.getHighlightBottom().getGreen()),
byteToFloat(profile.getHighlightBottom().getBlue()), 0.0f);
c2 = new Color(byteToFloat(profile.getHighlightBottom().getRed()),
byteToFloat(profile.getHighlightBottom().getGreen()),
byteToFloat(profile.getHighlightBottom().getBlue()), 0.4f);
p = new GradientPaint(0, 0, c1, 0, height, c2);
g2.setPaint(p);
g2.fillOval(0, 0, width - 1, height - 1);
// Creates dark edges for 3D effect
c1 = new Color(profile.getEdgeFrom().getRed(),
profile.getEdgeFrom().getGreen(),
profile.getEdgeFrom().getBlue(), 127);
c2 = new Color(byteToFloat(profile.getEdgeTo().getRed()),
byteToFloat(profile.getEdgeTo().getGreen()),
byteToFloat(profile.getEdgeTo().getBlue()), 0.8f);
p = new RadialGradientPaint(new Point2D.Double(width / 2.0, height / 2.0),
width / 2.0f,
new float[] { 0.0f, 1.0f },
new Color[] { c1, c2});
g2.setPaint(p);
g2.fillOval(0, 0, width - 1, height - 1);
// Adds oval inner highlight at the bottom
c1 = new Color(profile.getHighlightInnerFrom().getRed(),
profile.getHighlightInnerFrom().getGreen(),
profile.getHighlightInnerFrom().getBlue(), 255);
c2 = new Color(profile.getHighlightInnerTo().getRed(),
profile.getHighlightInnerTo().getGreen(),
profile.getHighlightInnerTo().getBlue(), 0);
p = new RadialGradientPaint(new Point2D.Double(width / 2.0, height * 1.5),
width / 2.3f,
new Point2D.Double(width / 2.0, height * 1.75 + 6),
new float[] { 0.0f, 0.8f },
new Color[] { c1, c2 },
RadialGradientPaint.CycleMethod.NO_CYCLE,
RadialGradientPaint.ColorSpaceType.SRGB,
AffineTransform.getScaleInstance(1.0, 0.5));
g2.setPaint(p);
g2.fillOval(0, 0, width - 1, height - 1);
// Adds oval specular highlight at the top left
c1 = new Color(byteToFloat(profile.getHighlightSpecular().getRed()),
byteToFloat(profile.getHighlightSpecular().getGreen()),
byteToFloat(profile.getHighlightSpecular().getBlue()), 0.4f);
c2 = new Color(byteToFloat(profile.getHighlightSpecular().getRed()),
byteToFloat(profile.getHighlightSpecular().getGreen()),
byteToFloat(profile.getHighlightSpecular().getBlue()), 0.0f);
p = new RadialGradientPaint(new Point2D.Double(width / 2.0, height / 2.0),
width / 1.4f,
new Point2D.Double(45.0, 25.0),
new float[] { 0.0f, 0.5f },
new Color[] { c1, c2},
RadialGradientPaint.CycleMethod.NO_CYCLE);
g2.setPaint(p);
g2.fillOval(0, 0, width - 1, height - 1);
// Restores the previous state
g2.setPaint(oldPaint);
}
/**
* Renders a knob with the given width and height
*
* @param transparent
* @param width
* @param height
* @return
*/
Image render(Display display, org.eclipse.swt.graphics.Color transparent, KnobColorProfile profile, int width, int height) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
render(g, new Color(transparent.getRed(), transparent.getGreen(), transparent.getBlue()), profile, width, height);
g.dispose();
ImageData data = convertToSWT(image);
data.transparentPixel = data.palette.getPixel(transparent.getRGB());
return new Image(display, data);
}
}