package org.csstudio.sds.components.ui.internal.figures;
import org.csstudio.sds.components.ui.internal.figureparts.RoundScale;
import org.csstudio.sds.components.ui.internal.figureparts.RoundScaledRamp;
import org.csstudio.sds.util.RotationUtil;
import org.csstudio.ui.util.CustomMediaFactory;
import org.eclipse.draw2d.AbstractLayout;
import org.eclipse.draw2d.Ellipse;
import org.eclipse.draw2d.FigureListener;
import org.eclipse.draw2d.FigureUtilities;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.Polygon;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Insets;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PointList;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
/**
* The figure of Express Meter
* @author Xihui Chen
*
*/
public class RefreshableXMeterFigure extends AbstractRoundRampedFigure {
private final static Font DEFAULT_LABEL_FONT = CustomMediaFactory.getInstance().getFont(
new FontData("Arial", 12, SWT.BOLD));
private final Ellipse needleCenter;
private final Needle needle;
private final Label valueLabel;
private final static double SPACE_ANGLE = 45;
public static final int NEEDLE_WIDTH = 16;
public RefreshableXMeterFigure() {
super();
transparent = true;
scale.setScaleLineVisible(false);
((RoundScale)scale).setStartAngle(180-SPACE_ANGLE);
((RoundScale)scale).setEndAngle(SPACE_ANGLE);
ramp.setRampWidth(12);
setLoColor(CustomMediaFactory.getInstance().getColor(CustomMediaFactory.COLOR_YELLOW));
setHiColor(CustomMediaFactory.getInstance().getColor(CustomMediaFactory.COLOR_YELLOW));
valueLabel = new Label();
valueLabel.setText("20.00");
valueLabel.setFont(DEFAULT_LABEL_FONT);
needle = new Needle();
needle.setFill(true);
needle.setOutline(false);
needleCenter = new Ellipse();
needleCenter.setOutline(false);
setLayoutManager(new XMeterLayout());
add(ramp, XMeterLayout.RAMP);
add(scale, XMeterLayout.SCALE);
add(valueLabel, XMeterLayout.VALUE_LABEL);
add(needle, XMeterLayout.NEEDLE);
add(needleCenter, XMeterLayout.NEEDLE_CENTER);
addFigureListener(new FigureListener() {
@Override
public void figureMoved(final IFigure source) {
ramp.setDirty(true);
revalidate();
}
});
}
@Override
public void paint(final Graphics graphics) {
super.paint(graphics);
Rectangle figureBounds = getBounds().getCopy();
paintAdapter(graphics);
}
@Override
public void setBounds(final Rectangle rect) {
super.setBounds(rect);
}
@Override
public void setValue(final double value) {
super.setValue(value);
valueLabel.setText(scale.format(value));
}
/**
* @param needleColor the needleColor to set
*/
public void setNeedleColor(final Color needleColor) {
needle.setBackgroundColor(needleColor);
}
class Needle extends Polygon {
@Override
protected void fillShape(final Graphics g) {
g.setAntialias(SWT.ON);
super.fillShape(g);
}
}
class XMeterLayout extends AbstractLayout {
private static final int GAP_BTW_NEEDLE_SCALE = -5;
private final double ALPHA = SPACE_ANGLE * Math.PI/180;
private final double HW_RATIO = (1- Math.sin(ALPHA)/2)/(2*Math.cos(ALPHA));
int M = 0;
/** Used as a constraint for the scale. */
public static final String SCALE = "scale"; //$NON-NLS-1$
/** Used as a constraint for the Needle. */
public static final String NEEDLE = "needle"; //$NON-NLS-1$
/** Used as a constraint for the Ramp */
public static final String RAMP = "ramp"; //$NON-NLS-1$
/** Used as a constraint for the needleCenter */
public static final String NEEDLE_CENTER = "needleCenter"; //$NON-NLS-1$
/** Used as a constraint for the value label*/
public static final String VALUE_LABEL = "valueLabel"; //$NON-NLS-1$
private RoundScale scale;
private RoundScaledRamp ramp;
private Polygon needle;
private Ellipse needleCenter;
private Label valueLabel;
private final PointList needlePoints = new PointList(new int[] {0,0,0,0,0,0});
@Override
public void setConstraint(final IFigure child, final Object constraint) {
if(constraint.equals(SCALE)) {
scale = (RoundScale)child;
} else if (constraint.equals(RAMP)) {
ramp = (RoundScaledRamp) child;
} else if (constraint.equals(NEEDLE)) {
needle = (Polygon) child;
} else if (constraint.equals(NEEDLE_CENTER)) {
needleCenter = (Ellipse) child;
} else if (constraint.equals(VALUE_LABEL)) {
valueLabel = (Label)child;
}
}
@Override
protected Dimension calculatePreferredSize(final IFigure container, final int w,
final int h) {
Insets insets = container.getInsets();
Dimension d = new Dimension(256, 256);
d.expand(insets.getWidth(), insets.getHeight());
return d;
}
@Override
public void layout(final IFigure container) {
Rectangle area = container.getClientArea();
// calculate a virtual area
if((scale != null) && scale.isDirty()) {
M = Math.max(FigureUtilities.getTextWidth(
scale.format(scale.getRange().getLower()), scale.getFont()),
FigureUtilities.getTextWidth(
scale.format(scale.getRange().getLower()), scale.getFont()))/2;
}
int h = area.height;
int w = area.width;
if(h > HW_RATIO * (w - 2*M)) {
h = (int) (HW_RATIO * (w - 2*M));
} else if (w > h/HW_RATIO + 2*M) {
w = (int) (h/HW_RATIO + 2*M);
}
double r = h/(1- Math.sin(ALPHA)/2);
int x = (int) (area.x - r * (1.0 - Math.cos(ALPHA)) + M);
int y = area.y;
area = new Rectangle(x, y, (int)(2*r), (int)(2*r));
Point center = area.getCenter();
if(scale != null) {
scale.setBounds(area);
}
if((ramp != null) && ramp.isVisible()) {
Rectangle rampBounds = area.getCopy();
ramp.setBounds(rampBounds.shrink(area.width/4 -ramp.getRampWidth(),
area.height/4 - ramp.getRampWidth()));
}
if(valueLabel != null) {
Dimension labelSize = valueLabel.getPreferredSize();
valueLabel.setBounds(new Rectangle(area.x + area.width/2 - labelSize.width/2,
area.y + area.height/2 - area.height/4
-(scale.getInnerRadius() - area.height/4)/2 - labelSize.height/2,
labelSize.width, labelSize.height));
}
if((needle != null) && (scale != null)) {
needlePoints.setPoint (
new Point(center.x + area.width/4, center.y - NEEDLE_WIDTH/2 + 3), 0);
scale.getScaleTickMarks();
needlePoints.setPoint(
new Point(center.x + scale.getInnerRadius() - GAP_BTW_NEEDLE_SCALE, center.y), 1);
needlePoints.setPoint(
new Point(center.x + area.width/4, center.y + NEEDLE_WIDTH/2 - 3), 2);
double valuePosition = 360 - scale.getValuePosition(value, false);
needlePoints.setPoint(
RotationUtil.rotate(needlePoints.getPoint(0), valuePosition, center), 0);
needlePoints.setPoint(
RotationUtil.rotate(needlePoints.getPoint(1), valuePosition, center), 1);
needlePoints.setPoint(
RotationUtil.rotate(needlePoints.getPoint(2), valuePosition, center),2);
needle.setPoints(needlePoints);
}
if(needleCenter == null){
needleCenter.setBounds(new Rectangle(center.x - area.width/4,
center.y - area.height/4,
area.width/2, area.height/2));
}
}
}
}