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.RoundScaleTickMarks; import org.csstudio.sds.components.ui.internal.figureparts.RoundScaledRamp; import org.csstudio.sds.util.RotationUtil; import org.csstudio.swt.xygraph.linearscale.AbstractScale.LabelSide; 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.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; import org.eclipse.swt.graphics.Pattern; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.Display; /** * The figure of gauge * @author Xihui Chen * */ public class RefreshableGaugeFigure extends AbstractRoundRampedFigure { private final static Color WHITE_COLOR = CustomMediaFactory.getInstance().getColor( CustomMediaFactory.COLOR_WHITE); private final static Color BORDER_COLOR = CustomMediaFactory.getInstance().getColor( new RGB(100, 100, 100)); private final static Color GRAY_COLOR = CustomMediaFactory.getInstance().getColor( CustomMediaFactory.COLOR_GRAY); private final static Font DEFAULT_LABEL_FONT = CustomMediaFactory.getInstance().getFont( new FontData("Arial", 12, SWT.BOLD)); private final static int BORDER_WIDTH = 2; private boolean effect3D = true; private final NeedleCenter needleCenter; private final Needle needle; private final Label valueLabel; public RefreshableGaugeFigure() { super(); transparent = true; scale.setScaleLineVisible(false); scale.setTickLabelSide(LabelSide.Secondary); ramp.setRampWidth(10); valueLabel = new Label(); valueLabel.setText("20.00"); valueLabel.setFont(DEFAULT_LABEL_FONT); needle = new Needle(); needle.setFill(true); needle.setOutline(false); needleCenter = new NeedleCenter(); needleCenter.setOutline(false); setLayoutManager(new GaugeLayout()); add(ramp, GaugeLayout.RAMP); add(scale, GaugeLayout.SCALE); add(valueLabel, GaugeLayout.VALUE_LABEL); add(needle, GaugeLayout.NEEDLE); add(needleCenter, GaugeLayout.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)); } @Override protected void paintClientArea(final Graphics graphics) { graphics.setAntialias(SWT.ON); Rectangle area = getClientArea(); area.width = Math.min(area.width, area.height); area.height = area.width; Pattern pattern = null; graphics.pushState(); graphics.setBackgroundColor(GRAY_COLOR); if(effect3D) { pattern = new Pattern(Display.getCurrent(), area.x, area.y, area.x+area.width, area.y + area.height, BORDER_COLOR, WHITE_COLOR); graphics.setBackgroundPattern(pattern); } graphics.fillOval(area); graphics.popState(); if(effect3D){ pattern.dispose(); area.shrink(BORDER_WIDTH, BORDER_WIDTH); } else { area.shrink(1, 1); } graphics.fillOval(area); super.paintClientArea(graphics); //glossy effect if(effect3D) { graphics.pushState(); graphics.setAntialias(SWT.ON); final double R = area.width/2; final double UD_FILL_PART = 9.5d/10d; final double UP_DOWN_RATIO = 1d/2d; final double LR_FILL_PART = 8.5d/10d; final double UP_ANGLE = 0d * Math.PI/180d; final double DOWN_ANGLE = 35d * Math.PI/180d; Pattern glossyPattern = new Pattern(Display.getCurrent(), area.x + area.width/2, (float)(area.y + area.height/2 - R * UD_FILL_PART), area.x + area.width/2, (float) (area.y + area.height/2 + R * UP_DOWN_RATIO), WHITE_COLOR, 90, WHITE_COLOR, 0); graphics.setBackgroundPattern(glossyPattern); Rectangle rectangle = new Rectangle( (int)(area.x + area.width/2 - R * LR_FILL_PART *Math.cos(UP_ANGLE)), (int)(area.y + area.height/2 - R * UD_FILL_PART), (int)(2*R* LR_FILL_PART*Math.cos(UP_ANGLE)), (int)(R*UD_FILL_PART + R*UP_DOWN_RATIO)); graphics.fillOval(rectangle); glossyPattern.dispose(); glossyPattern = new Pattern(Display.getCurrent(), area.x + area.width/2, (float)(area.y + area.height/2 + R * UP_DOWN_RATIO -1), area.x + area.width/2, (float) (area.y + area.height/2 + R * UD_FILL_PART + 1), WHITE_COLOR, 0, WHITE_COLOR, 40); graphics.setBackgroundPattern(glossyPattern); rectangle = new Rectangle( (int)(area.x + area.width/2 - R*LR_FILL_PART*Math.sin(DOWN_ANGLE)), (int)Math.ceil(area.y + area.height/2 + R * UP_DOWN_RATIO), (int)(2*R*LR_FILL_PART*Math.sin(DOWN_ANGLE)), (int)Math.ceil(R*UD_FILL_PART - R*UP_DOWN_RATIO)); graphics.fillOval(rectangle); glossyPattern.dispose(); graphics.popState(); } } public void setNeedleColor(final Color color) { needle.setBackgroundColor(color); } /** * @param effect3D the effect3D to set */ public void setEffect3D(final boolean effect3D) { this.effect3D = effect3D; } class Needle extends Polygon { @Override protected void fillShape(final Graphics g) { g.setAntialias(SWT.ON); super.fillShape(g); } } class NeedleCenter extends Ellipse { public static final int DIAMETER = 16; @Override protected void fillShape(final Graphics graphics) { graphics.setAntialias(SWT.ON); Pattern pattern = null; graphics.setBackgroundColor(GRAY_COLOR); if(effect3D){ pattern = new Pattern(Display.getCurrent(), bounds.x, bounds.y, bounds.x + bounds.width, bounds.y + bounds.height, WHITE_COLOR, BORDER_COLOR); graphics.setBackgroundPattern(pattern); } super.fillShape(graphics); if(effect3D) { pattern.dispose(); } } } class GaugeLayout extends AbstractLayout { private static final int GAP_BTW_NEEDLE_SCALE = -1; /** 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 NeedleCenter 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 = (NeedleCenter) 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(); area.width = Math.min(area.width, area.height); area.height = area.width; area.shrink(BORDER_WIDTH, BORDER_WIDTH); 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, area.height/4)); } if(valueLabel != null) { Dimension labelSize = valueLabel.getPreferredSize(); valueLabel.setBounds(new Rectangle(area.x + area.width/2 - labelSize.width/2, area.y + area.height * 7/8 - labelSize.height/2, labelSize.width, labelSize.height)); } if((needle != null) && (scale != null)) { needlePoints.setPoint ( new Point(center.x, center.y - NeedleCenter.DIAMETER/2 + 3), 0); scale.getScaleTickMarks(); needlePoints.setPoint( new Point(center.x + area.width/2 - RoundScaleTickMarks.MAJOR_TICK_LENGTH - GAP_BTW_NEEDLE_SCALE, center.y), 1); needlePoints.setPoint( new Point(center.x, center.y + NeedleCenter.DIAMETER/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 - NeedleCenter.DIAMETER/2, center.y - NeedleCenter.DIAMETER/2, NeedleCenter.DIAMETER, NeedleCenter.DIAMETER)); } } } }