/*******************************************************************************
* Copyright (c) 2010 Oak Ridge National Laboratory.
* 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
******************************************************************************/
package org.csstudio.swt.widgets.figures;
import org.csstudio.swt.widgets.util.GraphicsUtil;
import org.csstudio.swt.xygraph.linearscale.LinearScale;
import org.csstudio.swt.xygraph.linearscale.LinearScale.Orientation;
import org.csstudio.swt.xygraph.linearscale.LinearScaledMarker;
import org.csstudio.swt.xygraph.util.XYGraphMediaFactory;
import org.eclipse.draw2d.AbstractLayout;
import org.eclipse.draw2d.Ellipse;
import org.eclipse.draw2d.FigureUtilities;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.RoundedRectangle;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Insets;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Pattern;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Display;
/**
* A Thermometer figure
* @author Xihui Chen
*
*/
public class ThermometerFigure extends AbstractLinearMarkedFigure {
/**Temperature Unit Enum
* @author Xihui Chen
*
*/
public enum TemperatureUnit {
CELSIUS("Celsius", "\u2103"), //$NON-NLS-2$
FAHRENHEIT("Fahrenheit", "\u2109"), //$NON-NLS-2$
KELVIN("Kelvin", "K"),
NONE("None", ""); //$NON-NLS-2$
public static String[] stringValues(){
String[] result = new String[values().length];
int i=0;
for(TemperatureUnit t : values()){
result[i++] = t.toString();
}
return result;
}
private String name, unitString;
private TemperatureUnit(String name, String unitString) {
this.name = name;
this.unitString = unitString;
}
public String getUnitString(){
return unitString;
}
@Override
public String toString() {
return name;
}
}
private Color fillColor;
private Color contrastFillColor;
private TemperatureUnit temperatureUnit;
private Pipe pipe;
private Bulb bulb;
private Label unit;
private boolean effect3D = true;
private final Color RED_COLOR = XYGraphMediaFactory.getInstance().getColor(
XYGraphMediaFactory.COLOR_RED);
private final Color GRAY_COLOR = XYGraphMediaFactory.getInstance().getColor(
XYGraphMediaFactory.COLOR_GRAY);
private final Color WHITE_COLOR = XYGraphMediaFactory.getInstance().getColor(
XYGraphMediaFactory.COLOR_WHITE);
private final Color BLACK_COLOR = XYGraphMediaFactory.getInstance().getColor(
XYGraphMediaFactory.COLOR_BLACK);
private Color fillBackgroundColor = GRAY_COLOR;
public ThermometerFigure() {
super();
((LinearScale) scale).setOrientation(Orientation.VERTICAL);
scale.setScaleLineVisible(false);
pipe = new Pipe();
bulb = new Bulb();
unit = new Label();
setLayoutManager(new ThermoLayout());
add(scale, ThermoLayout.SCALE);
add(marker, ThermoLayout.MARKERS);
add(pipe, ThermoLayout.PIPE);
add(unit, ThermoLayout.UNIT);
add(bulb, ThermoLayout.BULB);
setFillColor(RED_COLOR);
setTemperatureUnit(TemperatureUnit.CELSIUS);
}
/**
* @return the fillBackgroundColor
*/
public Color getFillBackgroundColor() {
return fillBackgroundColor;
}
/**
* @return the fillColor
*/
public Color getFillColor() {
return fillColor;
}
/**
* @return the temperatureUnit
*/
public TemperatureUnit getTemperatureUnit() {
return temperatureUnit;
}
/**
* @return the effect3D
*/
public boolean isEffect3D() {
return effect3D;
}
@Override
public boolean isOpaque() {
return false;
}
/**
* @param effect3D the effect3D to set
*/
public void setEffect3D(boolean effect3D) {
if(this.effect3D == effect3D)
return;
this.effect3D = effect3D;
repaint();
}
/**
* @param fillBackgroundColor the fillBackgroundColor to set
*/
public void setFillBackgroundColor(Color fillBackgroundColor) {
if(this.fillBackgroundColor != null && this.fillBackgroundColor.equals(fillBackgroundColor))
return;
this.fillBackgroundColor = fillBackgroundColor;
repaint();
}
/**
* @param fillColor the fillColor to set
*/
public void setFillColor(Color fillColor) {
if(this.fillColor != null && this.fillColor.equals(fillColor))
return;
this.fillColor = fillColor;
int blue = 255 - fillColor.getBlue();
int green = 255 - fillColor.getGreen();
int red = fillColor.getRed();
this.contrastFillColor = XYGraphMediaFactory.getInstance().getColor(
new RGB(red, green, blue));
repaint();
}
@Override
public void setForegroundColor(Color fg) {
super.setForegroundColor(fg);
}
/**
* @param showBulb the showBulb to set
*/
public void setShowBulb(boolean showBulb) {
bulb.setVisible(showBulb);
revalidate();
}
/**
* @param temperatureUnit the unit to set.
*/
public void setTemperatureUnit(TemperatureUnit temperatureUnit) {
if(this.temperatureUnit == temperatureUnit)
return;
this.temperatureUnit = temperatureUnit;
unit.setText(temperatureUnit.getUnitString());
}
@Override
public void setValue(double value) {
super.setValue(value);
}
class Bulb extends Ellipse {
public final static int MAX_DIAMETER = 40;
private final Color EFFECT3D_BULB_COLOR = XYGraphMediaFactory.getInstance().getColor(
new RGB(140, 140, 140));
public Bulb() {
super();
setOutline(true);
}
@Override
protected void fillShape(Graphics graphics) {
graphics.setAntialias(SWT.ON);
boolean support3D = false;
if(effect3D)
support3D = GraphicsUtil.testPatternSupported(graphics);
if(effect3D && support3D){
graphics.setBackgroundColor(fillColor);
super.fillShape(graphics);
//int l = (int) ((bounds.width - lineWidth)*0.293/2);
Pattern backPattern = null;
backPattern = new Pattern(Display.getCurrent(),
bounds.x + lineWidth, bounds.y + lineWidth,
bounds.x+bounds.width-lineWidth, bounds.y+bounds.height-lineWidth,
WHITE_COLOR,255, fillColor, 0);
graphics.setBackgroundPattern(backPattern);
super.fillShape(graphics);
backPattern.dispose();
}else{
graphics.setBackgroundColor(fillColor);
super.fillShape(graphics);
}
String valueString = getValueText();
Dimension valueSize =
FigureUtilities.getTextExtents(valueString, getFont());
if(valueSize.width < bounds.width) {
graphics.setForegroundColor(contrastFillColor);
graphics.drawText(valueString, new Point(
bounds.x + bounds.width/2 - valueSize.width/2,
bounds.y + bounds.height/2 - valueSize.height/2));
}
}
@Override
protected void outlineShape(Graphics graphics) {
boolean support3D = false;
if(effect3D)
support3D = GraphicsUtil.testPatternSupported(graphics);
if(effect3D && support3D)
graphics.setForegroundColor(EFFECT3D_BULB_COLOR);
else
graphics.setForegroundColor(BLACK_COLOR);
super.outlineShape(graphics);
//draw a small rectangle to hide the joint
if(effect3D && support3D) {
graphics.setBackgroundColor(fillColor);
graphics.fillRectangle(new Rectangle(pipe.getBounds().x + pipe.getLineWidth(),
((LinearScale) scale).getValuePosition(scale.getRange().getLower(), false),
Pipe.PIPE_WIDTH- pipe.getLineWidth() *2, 2));
Pattern backPattern = new Pattern(Display.getCurrent(),
pipe.getBounds().x, ((LinearScale) scale).getValuePosition(scale.getRange().getLower(), false),
pipe.getBounds().x + Pipe.PIPE_WIDTH,
((LinearScale) scale).getValuePosition(scale.getRange().getLower(), false),
WHITE_COLOR,255, fillColor, 0);
graphics.setBackgroundPattern(backPattern);
graphics.fillRectangle(new Rectangle(pipe.getBounds().x + pipe.getLineWidth(),
((LinearScale) scale).getValuePosition(scale.getRange().getLower(), false),
Pipe.PIPE_WIDTH- pipe.getLineWidth() *2, 2));
backPattern.dispose();
}else{
graphics.setBackgroundColor(fillColor);
graphics.fillRoundRectangle(new Rectangle(pipe.getBounds().x + pipe.getLineWidth(),
((LinearScale) scale).getValuePosition(scale.getRange().getLower(), false),
Pipe.PIPE_WIDTH- pipe.getLineWidth() *2, ((LinearScale) scale).getMargin()),
Pipe.FILL_CORNER, Pipe.FILL_CORNER);
}
}
}
class Pipe extends RoundedRectangle {
public final static int FILL_CORNER = 3;
public final static int PIPE_WIDTH = 15;
private final Color EFFECT3D_PIPE_COLOR = XYGraphMediaFactory.getInstance().getColor(
new RGB(160, 160, 160));
public Pipe() {
super();
setOutline(true);
}
@Override
protected void fillShape(Graphics graphics) {
corner.height =PIPE_WIDTH/2;
corner.width = PIPE_WIDTH/2;
graphics.setBackgroundColor(fillBackgroundColor);
int valuePosition = ((LinearScale) scale).getValuePosition(getCoercedValue(), false);
if(maximum > minimum){
if(value > maximum)
valuePosition -= 10;
else if(value < minimum)
valuePosition +=10;
}else{
if(value > minimum)
valuePosition += 10;
else if(value < maximum)
valuePosition -=10;
}
boolean support3D = false;
if(effect3D)
support3D = GraphicsUtil.testPatternSupported(graphics);
if(effect3D && support3D){
graphics.setForegroundColor(EFFECT3D_PIPE_COLOR);
//fill back
super.fillShape(graphics);
Pattern backPattern = new Pattern(Display.getCurrent(),
bounds.x, bounds.y, bounds.x+bounds.width, bounds.y,
WHITE_COLOR,255, fillBackgroundColor, 0);
graphics.setBackgroundPattern(backPattern);
super.fillShape(graphics);
backPattern.dispose();
//fill value
graphics.setBackgroundColor(fillColor);
graphics.fillRoundRectangle(new Rectangle(bounds.x + lineWidth,
valuePosition,
bounds.width - 2* lineWidth,
bounds.height - (valuePosition - bounds.y)),
FILL_CORNER, FILL_CORNER);
backPattern = new Pattern(Display.getCurrent(),
bounds.x, bounds.y, bounds.x+bounds.width, bounds.y,
WHITE_COLOR,255, fillColor, 0);
graphics.setBackgroundPattern(backPattern);
graphics.fillRoundRectangle(new Rectangle(bounds.x + lineWidth,
valuePosition,
bounds.width - 2* lineWidth,
bounds.height - (valuePosition - bounds.y)),
FILL_CORNER, FILL_CORNER);
backPattern.dispose();
} else {
super.fillShape(graphics);
graphics.setBackgroundColor(fillColor);
graphics.fillRoundRectangle(new Rectangle(bounds.x + lineWidth,
valuePosition,
bounds.width - 2* lineWidth,
bounds.height - (valuePosition - bounds.y)),
FILL_CORNER, FILL_CORNER);
}
}
public Dimension getCorner() {
return corner;
}
@Override
public Dimension getPreferredSize(int wHint, int hHint) {
return new Dimension(PIPE_WIDTH , hHint+2*corner.height);
}
}
static class ThermoLayout extends AbstractLayout {
/** Used as a constraint for the scale. */
public static final String SCALE = "scale"; //$NON-NLS-1$
/** Used as a constraint for the pipe indicator. */
public static final String PIPE = "pipe"; //$NON-NLS-1$
/** Used as a constraint for the alarm ticks */
public static final String MARKERS = "markers"; //$NON-NLS-1$
/** Used as a constraint for the bulb in the below of pipe. */
public static final String BULB = "bulb"; //$NON-NLS-1$
/** Used as a constraint for the unit label*/
public static final String UNIT = "unit"; //$NON-NLS-1$
private LinearScale scale;
private LinearScaledMarker marker;
private Pipe pipe;
private IFigure bulb, unit;
@Override
protected Dimension calculatePreferredSize(IFigure container, int w,
int h) {
Insets insets = container.getInsets();
Dimension d = new Dimension(64, 4*64);
d.expand(insets.getWidth(), insets.getHeight());
return d;
}
@Override
public void layout(IFigure container) {
Rectangle area = container.getClientArea();
if(bulb != null && bulb.isVisible()) {
int diameter = area.width/2;
if(diameter > Bulb.MAX_DIAMETER)
diameter = Bulb.MAX_DIAMETER;
int x = area.x + area.width/2 - diameter /2;
int spareHeight = (area.height < diameter)? 0: (area.height - diameter);
int y = area.y + spareHeight;
bulb.setBounds(new Rectangle(x, y, diameter, diameter));
area.height = spareHeight + scale.getMargin();
}
Dimension unitSize = new Dimension(0, 0);
Dimension scaleSize;
Dimension markerSize;
Dimension pipeSize;
if(unit != null && unit.isVisible()) {
unitSize = unit.getPreferredSize();
unit.setBounds(new Rectangle(
area.x + area.width/2 - Pipe.PIPE_WIDTH/2 - unitSize.width,
area.y, unitSize.width, unitSize.height));
}
if(scale != null) {
scaleSize = scale.getPreferredSize(-1, area.height-unitSize.height);
scale.setBounds(new Rectangle(area.x + area.width/2 - Pipe.PIPE_WIDTH/2 - scaleSize.width,
area.y+unitSize.height,
scaleSize.width, scaleSize.height));
}
if(marker != null && marker.isVisible()) {
markerSize = marker.getPreferredSize();
marker.setBounds(new Rectangle(area.x + area.width/2 + Pipe.PIPE_WIDTH/2,
marker.getScale().getBounds().y, markerSize.width, markerSize.height));
}
if(pipe != null) {
pipeSize = pipe.getPreferredSize(-1, scale.getTickLength());
pipe.setBounds(new Rectangle(
area.x + area.width/2 - Pipe.PIPE_WIDTH/2,
scale.getValuePosition(scale.getRange().getUpper(), false) - pipe.getCorner().height,
pipeSize.width,
pipeSize.height));
}
}
@Override
public void setConstraint(IFigure child, Object constraint) {
if(constraint.equals(SCALE))
scale = (LinearScale)child;
else if (constraint.equals(MARKERS))
marker = (LinearScaledMarker) child;
else if (constraint.equals(PIPE))
pipe = (Pipe) child;
else if (constraint.equals(BULB))
bulb = child;
else if (constraint.equals(UNIT))
unit = child;
}
}
}