package org.csstudio.sds.components.ui.internal.figures; import java.text.NumberFormat; 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.ui.util.CustomMediaFactory; 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 RefreshableThermoFigure extends AbstractLinearMarkedFigure { private Color fillColor; private Color fillBackgroundColor; private Color contrastFillColor; private Color outlineColor; private final Pipe pipe; private final Bulb bulb; private final Label unit; private boolean effect3D = true; /** * the value be set before coerced, which is used for displaying on bulb */ private double rawValue = 50; private final static Color WHITE_COLOR = CustomMediaFactory.getInstance().getColor( CustomMediaFactory.COLOR_WHITE); public RefreshableThermoFigure() { super(); ((LinearScale) scale).setOrientation(Orientation.VERTICAL); scale.setScaleLineVisible(false); scale.setForegroundColor(outlineColor); pipe = new Pipe(); bulb = new Bulb(); unit = new Label(); unit.setForegroundColor(outlineColor); setLayoutManager(new ThermoLayout()); add(scale, ThermoLayout.SCALE); add(marker, ThermoLayout.MARKERS); add(pipe, ThermoLayout.PIPE); add(unit, ThermoLayout.UNIT); add(bulb, ThermoLayout.BULB); } @Override public void paint(final Graphics graphics) { super.paint(graphics); Rectangle figureBounds = getBounds().getCopy(); paintAdapter(graphics); } @Override public boolean isOpaque() { return false; } @Override public void setForegroundColor(final Color fg) { super.setForegroundColor(fg); outlineColor = fg; } /** * @param fillColor the fillColor to set */ public void setFillColor(final Color fillColor) { this.fillColor = fillColor; int red = fillColor.getRed(); int green = 255 - fillColor.getGreen(); int blue = 255 - fillColor.getBlue(); this.contrastFillColor = CustomMediaFactory.getInstance().getColor( new RGB(red, green, blue)); } /** * @param showBulb the showBulb to set */ public void setShowBulb(final boolean showBulb) { bulb.setVisible(showBulb); revalidate(); } /** * @param fahrenheit the fahrenheit to set */ public void setFahrenheit(final boolean fahrenheit) { if(fahrenheit) { unit.setText("\u2109"); } else { unit.setText("\u2103"); } } public void setFillBackgroundColor(final Color fillBackgroundColor) { this.fillBackgroundColor = fillBackgroundColor; } /** * @param effect3D the effect3D to set */ public void setEffect3D(final boolean effect3D) { this.effect3D = effect3D; } @Override public void setValue(final double value) { super.setValue(value); rawValue = value; } class Pipe extends RoundedRectangle { public final static int FILL_CORNER = 3; public final static int PIPE_WIDTH = 15; private final Color EFFECT3D_PIPE_COLOR = CustomMediaFactory.getInstance().getColor( new RGB(160, 160, 160)); public Pipe() { super(); setOutline(true); } @Override protected void fillShape(final Graphics graphics) { corner.height =PIPE_WIDTH/2; corner.width = PIPE_WIDTH/2; graphics.setForegroundColor(outlineColor); graphics.setBackgroundColor(fillBackgroundColor); int valuePosition = ((LinearScale) scale).getValuePosition(value, false); if(effect3D){ 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); } } @Override public Dimension getPreferredSize(final int wHint, final int hHint) { return new Dimension(PIPE_WIDTH , hHint+2*corner.height); } public Dimension getCorner() { return corner; } } class Bulb extends Ellipse { public final static int MAX_DIAMETER = 40; private final Color EFFECT3D_BULB_COLOR = CustomMediaFactory.getInstance().getColor( new RGB(140, 140, 140)); public Bulb() { super(); setOutline(true); } @Override protected void fillShape(final Graphics graphics) { graphics.setAntialias(SWT.ON); if(effect3D){ graphics.setBackgroundColor(fillColor); super.fillShape(graphics); int l = (int) ((bounds.width - lineWidth)*0.293/2); Pattern backPattern = new Pattern(Display.getCurrent(), bounds.x + lineWidth, bounds.y + lineWidth, bounds.x+bounds.width - l, bounds.y+bounds.height- l, WHITE_COLOR,255, fillColor, 0); graphics.setBackgroundPattern(backPattern); super.fillShape(graphics); backPattern.dispose(); }else{ graphics.setBackgroundColor(fillColor); super.fillShape(graphics); } NumberFormat format = NumberFormat.getInstance(); format.setMaximumFractionDigits(2); String valueString = format.format(rawValue); 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(final Graphics graphics) { if(effect3D) { graphics.setForegroundColor(EFFECT3D_BULB_COLOR); } else { graphics.setForegroundColor(outlineColor); } super.outlineShape(graphics); //draw a small rectangle to hide the joint if(effect3D) { 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 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 public void setConstraint(final IFigure child, final 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; } } @Override protected Dimension calculatePreferredSize(final IFigure container, final int w, final 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(final 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 = new Dimension(0, 0); Dimension markerSize = new Dimension(0, 0); Dimension pipeSize = new Dimension(0, 0); 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)); } } } }