/*******************************************************************************
* 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.deidentifier.arx.gui.view.impl.common;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import org.deidentifier.arx.gui.view.SWTUtil;
import org.eclipse.draw2d.AbstractLayout;
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.nebula.visualization.internal.widgets.introspection.MeterIntrospector;
import org.eclipse.nebula.visualization.widgets.figureparts.RoundScale;
import org.eclipse.nebula.visualization.widgets.figureparts.RoundScaledRamp;
import org.eclipse.nebula.visualization.widgets.figures.AbstractRoundRampedFigure;
import org.eclipse.nebula.visualization.widgets.util.PointsUtil;
import org.eclipse.nebula.visualization.xygraph.util.XYGraphMediaFactory;
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. Adapted for ARX by fabian.prasser@gmail.com
*
* @author Xihui Chen
* @author Fabian Prasser
*/
public class ComponentMeterFigure extends AbstractRoundRampedFigure {
static class Needle extends Polygon {
public Needle() {
setBackgroundColor(XYGraphMediaFactory.getInstance().getColor(XYGraphMediaFactory.COLOR_RED));
}
@Override
protected void fillShape(Graphics g) {
g.setAntialias(SWT.ON);
super.fillShape(g);
}
}
class XMeterLayout extends AbstractLayout {
private static final int GAP_BTW_NEEDLE_SCALE = -5;
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 value label*/
public static final String VALUE_LABEL = "valueLabel"; //$NON-NLS-1$
private RoundScale scale;
private RoundScaledRamp ramp;
private Polygon needle;
private Label valueLabel;
private PointList needlePoints = new PointList(new int[] {0,0,0,0,0,0});
public void layout(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().getUpper()), scale.getFont()))/2;
}
int h = area.height;
int w = area.width;
int offsetY = 0;
int offsetX = 0;
if(h > HW_RATIO * (w - 2*M)) {
h = (int) (HW_RATIO * (w - 2*M));
offsetY = (area.height - h) / 2;
if (offsetY > 10) {
offsetY -= 10;
} else {
offsetY = 0;
}
} else {
offsetX = ((int) (HW_RATIO * (w - 2*M)) - h);
}
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 + offsetX, y + offsetY, (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();
int lY1 = area.y + area.height/2 -(scale.getInnerRadius() - area.height/5)/2 - labelSize.height/2;
int lY2 = container.getClientArea().height - labelSize.height - 3;
valueLabel.setBounds(new Rectangle(area.x + area.width/2 - labelSize.width/2,
Math.min(lY1, lY2),
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(getCoercedValue(), false);
if(maximum > minimum){
if(value > maximum)
valuePosition += 8;
else if(value < minimum)
valuePosition -=8;
}else{
if(value > minimum)
valuePosition -= 8;
else if(value < maximum)
valuePosition +=8;
}
needlePoints.setPoint(PointsUtil.rotate(needlePoints.getPoint(0), valuePosition, center), 0);
needlePoints.setPoint(PointsUtil.rotate(needlePoints.getPoint(1), valuePosition, center), 1);
needlePoints.setPoint(PointsUtil.rotate(needlePoints.getPoint(2), valuePosition, center),2);
needle.setPoints(needlePoints);
}
}
@Override
public void setConstraint(IFigure child, 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(VALUE_LABEL))
valueLabel = (Label)child;
}
@Override
protected Dimension calculatePreferredSize(IFigure container, int w,
int h) {
Insets insets = container.getInsets();
Dimension d = new Dimension(container.getClientArea().width, container.getClientArea().height);
d.expand(insets.getWidth(), insets.getHeight());
return d;
}
}
private final static Font DEFAULT_LABEL_FONT = XYGraphMediaFactory.getInstance().getFont(
new FontData("Arial", 10, SWT.BOLD));
private Needle needle;
private Label valueLabel;
private final static double SPACE_ANGLE = 45;
public static final int NEEDLE_WIDTH = 16;
public final static double ALPHA = SPACE_ANGLE * Math.PI/180;
public final static double HW_RATIO = (1- Math.sin(ALPHA)/2)/(2*Math.cos(ALPHA));
public ComponentMeterFigure() {
super();
setTransparent(false);
scale.setScaleLineVisible(false);
((RoundScale)scale).setStartAngle(180-SPACE_ANGLE);
((RoundScale)scale).setEndAngle(SPACE_ANGLE);
ramp.setRampWidth(12);
setLoColor(XYGraphMediaFactory.getInstance().getColor(XYGraphMediaFactory.COLOR_YELLOW));
setHiColor(XYGraphMediaFactory.getInstance().getColor(XYGraphMediaFactory.COLOR_YELLOW));
valueLabel = new Label();
valueLabel.setFont(DEFAULT_LABEL_FONT);
needle = new Needle();
needle.setFill(true);
needle.setOutline(false);
setLayoutManager(new XMeterLayout());
add(ramp, XMeterLayout.RAMP);
add(scale, XMeterLayout.SCALE);
add(needle, XMeterLayout.NEEDLE);
add(valueLabel, XMeterLayout.VALUE_LABEL);
addFigureListener(new FigureListener() {
public void figureMoved(IFigure source) {
ramp.setDirty(true);
revalidate();
}
});
}
@Override
public BeanInfo getBeanInfo() throws IntrospectionException {
return new MeterIntrospector().getBeanInfo(this.getClass());
}
/**
* @return color of the needle.
*/
public Color getNeedleColor(){
return needle.getBackgroundColor();
}
@Override
public void setBounds(Rectangle rect) {
super.setBounds(rect);
}
/**
* @param needleColor the needleColor to set
*/
public void setNeedleColor(Color needleColor) {
needle.setBackgroundColor(needleColor);
}
@Override
public void setShowMarkers(boolean showMarkers) {
super.setShowMarkers(showMarkers);
ramp.setVisible(showMarkers);
}
@Override
public void setValue(double value) {
super.setValue(value);
valueLabel.setText(SWTUtil.getPrettyString(value) + "%");
}
public void setValueLabelVisibility(boolean visible) {
valueLabel.setVisible(visible);
}
}