/* * Copyright (c) 2006 Stiftung Deutsches Elektronen-Synchroton, * Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY. * * THIS SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "../AS IS" BASIS. * WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR PARTICULAR PURPOSE AND * NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * THE USE OR OTHER DEALINGS IN THE SOFTWARE. SHOULD THE SOFTWARE PROVE DEFECTIVE * IN ANY RESPECT, THE USER ASSUMES THE COST OF ANY NECESSARY SERVICING, REPAIR OR * CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. * NO USE OF ANY SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. * DESY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, * OR MODIFICATIONS. * THE FULL LICENSE SPECIFYING FOR THE SOFTWARE THE REDISTRIBUTION, MODIFICATION, * USAGE AND OTHER RIGHTS AND OBLIGATIONS IS INCLUDED WITH THE DISTRIBUTION OF THIS * PROJECT IN THE FILE LICENSE.HTML. IF THE LICENSE IS NOT INCLUDED YOU MAY FIND A COPY * AT HTTP://WWW.DESY.DE/LEGAL/LICENSE.HTM */ package org.csstudio.sds.components.model; import org.csstudio.sds.model.AbstractWidgetModel; import org.csstudio.sds.model.PropertyChangeAdapter; import org.csstudio.sds.model.WidgetPropertyCategory; import org.csstudio.sds.util.RotationUtil; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.PointList; import org.eclipse.draw2d.geometry.Rectangle; /** * * @author Sven Wende */ public abstract class AbstractPolyModel extends AbstractWidgetModel { /** * The ID of the points property. */ public static final String PROP_POINTS = "points"; //$NON-NLS-1$ /** * The ID of the fill level property. */ public static final String PROP_FILL = "fill"; //$NON-NLS-1$ /** * The default value of the height property. */ private static final int DEFAULT_HEIGHT = 10; /** * The default value of the width property. */ private static final int DEFAULT_WIDTH = 20; /** * The original Points without rotation. */ private PointList _originalPoints; /** * Constructor. */ public AbstractPolyModel() { super(true); setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); addPropertyChangeListener(PROP_ROTATION, new PropertyChangeAdapter() { @Override public void propertyValueChanged(final Object oldValue, final Object newValue) { setPoints(rotatePoints(_originalPoints.getCopy(), (Double) newValue), false); } }); } /** * {@inheritDoc} */ @Override protected void configureProperties() { addPointlistProperty(PROP_POINTS, "Points", WidgetPropertyCategory.POSITION, new PointList(), false); addDoubleProperty(PROP_FILL, "Value", WidgetPropertyCategory.DISPLAY, 100.0, 0.0, 100.0, true, PROP_TOOLTIP); } /** * Sets the specified _points for the polygon. * * @param points * the polygon points * @param rememberPoints * true if the zero relative points should be remembered, false * otherwise. */ public final void setPoints(final PointList points, final boolean rememberPoints) { if (points.size() > 0) { final PointList copy = points.getCopy(); if (rememberPoints) { this.rememberZeroDegreePoints(copy); } super.setPropertyValue(PROP_POINTS, copy); final Rectangle bounds = copy.getBounds(); super.setPropertyValue(PROP_POS_X, bounds.x); super.setPropertyValue(PROP_POS_Y, bounds.y); super.setPropertyValue(PROP_WIDTH, bounds.width); super.setPropertyValue(PROP_HEIGHT, bounds.height); } } /** * Gets the polygon _points. * * @return the polygon _points */ public final PointList getPoints() { return getPointlistProperty(PROP_POINTS); } /** * Returns the fill grade. * * @return the fill grade */ public final double getFill() { return getDoubleProperty(PROP_FILL); } /** * {@inheritDoc} */ @Override public final void setSize(final int width, final int height) { final int targetW = Math.max(1, width); final int targetH = Math.max(1, height); final PointList pointList = getPoints(); final double oldW = pointList.getBounds().width; final double oldH = pointList.getBounds().height; final double topLeftX = pointList.getBounds().x; final double topLeftY = pointList.getBounds().y; if (oldW != targetW || oldH != targetH) { final PointList newPoints = new PointList(); for (int i = 0; i < pointList.size(); i++) { final int x = pointList.getPoint(i).x; final int y = pointList.getPoint(i).y; Point newPoint = new Point(x, y); if (oldW > 0 && oldH > 0) { final double oldRelX = (x - topLeftX) / oldW; final double oldRelY = (y - topLeftY) / oldH; final double newX = topLeftX + oldRelX * targetW; final double newY = topLeftY + oldRelY * targetH; final long roundedX = Math.round(newX); final long roundedY = Math.round(newY); newPoint = new Point(roundedX, roundedY); } newPoints.addPoint(newPoint); } setPoints(newPoints, true); } } /** * {@inheritDoc} */ @Override public final void setLocation(final int x, final int y) { final PointList points = getPoints(); final int oldX = points.getBounds().x; final int oldY = points.getBounds().y; points.translate(x - oldX, y - oldY); setPoints(points, true); final int newX = points.getBounds().x; final int newY = points.getBounds().y; super.setLocation(newX, newY); } /** * Rotates all points. * * @param points * The PoinList, which points should be rotated * @param angle * The angle to rotate * @return The rotated PointList */ public final PointList rotatePoints(final PointList points, final double angle) { final Rectangle pointBounds = points.getBounds(); final Point rotationPoint = pointBounds.getCenter(); final PointList newPoints = new PointList(); for (int i = 0; i < points.size(); i++) { newPoints.addPoint(RotationUtil.rotate(points.getPoint(i), angle, rotationPoint)); } final Rectangle newPointBounds = newPoints.getBounds(); if (!rotationPoint.equals(newPointBounds.getCenter())) { final Dimension difference = rotationPoint.getCopy().getDifference(newPointBounds.getCenter()); newPoints.translate(difference.width, difference.height); } return newPoints; } /** * Rotates the given points to 0 degrees and sets them as * <code>_originalPoints</code>. * * @param points * The current {@link PointList} */ private void rememberZeroDegreePoints(final PointList points) { if (this.getRotationAngle() == 0) { _originalPoints = points.getCopy(); } else { _originalPoints = this.rotatePoints(points, -this.getRotationAngle()); } } /** * {@inheritDoc} */ @Override public synchronized void setPropertyValue(final String propertyID, final Object value) { if (propertyID.equals(AbstractPolyModel.PROP_POINTS)) { if (value instanceof PointList) { this.setPoints((PointList) value, true); } } else if (propertyID.equals(AbstractWidgetModel.PROP_POS_X) && (Integer) value != getPoints().getBounds().x) { setLocation((Integer) value, getY()); } else if (propertyID.equals(AbstractWidgetModel.PROP_POS_Y) && (Integer) value != getPoints().getBounds().y) { setLocation(getX(), (Integer) value); } else if (propertyID.equals(AbstractWidgetModel.PROP_WIDTH) && (Integer) value != getPoints().getBounds().width) { setSize((Integer) value, getHeight()); } else if (propertyID.equals(AbstractWidgetModel.PROP_HEIGHT) && (Integer) value != getPoints().getBounds().height) { setSize(getWidth(), (Integer) value); } else { super.setPropertyValue(propertyID, value); } } }