/******************************************************************************* * 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.csstudio.swt.xygraph.linearscale; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.csstudio.swt.xygraph.linearscale.AbstractScale.LabelSide; import org.csstudio.swt.xygraph.util.XYGraphMediaFactory; import org.eclipse.draw2d.Figure; import org.eclipse.draw2d.FigureUtilities; import org.eclipse.draw2d.Graphics; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.RGB; /** * A linear scale related marker, whose orientation, range, mark position etc. are * determined by the scale. It must have the same length and bounds.x(for horizontal) * or bounds.y(for vertical) with the scale. * * @author Xihui Chen */ public class LinearScaledMarker extends Figure { private Map<String, MarkerProperties> markersMap= new LinkedHashMap<String, MarkerProperties>(); private static final RGB DEFAULT_MARKER_COLOR = XYGraphMediaFactory.COLOR_RED; private String[] labels; private double[] markerValues; private Dimension[] markerLabelDimensions; private List<Color> markerColorsList = new ArrayList<Color>(); private LinearScale scale; private LabelSide makerLablesPosition = LabelSide.Secondary; private boolean markerLineVisible = false; private boolean markerLableVisible = true; private int tickLabelMaxLength; private boolean dirty = true; private int[] markerPositions; private final static int TICK_LENGTH = 10; private final static int TICK_LINE_WIDTH = 2; private final static int GAP_BTW_MARK_LABEL = 3; public LinearScaledMarker(LinearScale scale) { this.scale = scale; setFont(XYGraphMediaFactory.getInstance().getFont(XYGraphMediaFactory.FONT_TAHOMA)); } /** * @param dirty the dirty to set */ public void setDirty(boolean dirty) { this.dirty = dirty; } /** * If the marker exists, set its value. * @param label the label of the marker element, it must be unique. * @param value the value to be set */ public void setMarkerElementValue(String label, double value) { if(markersMap.containsKey(label)) { markersMap.get(label).value = value; dirty =true; } } /** * If the marker exists, set its color. * @param label the label of the marker element, it must be unique. * @param color the color to be set */ public void setMarkerElementColor(String label, RGB color) { if(markersMap.containsKey(label)) { markersMap.get(label).color = color; dirty =true; } } /** * Add (if the marker does not exist) or change a marker element. * @param label the label of the marker element, it must be unique. * @param value the value of the marker element * @param color the color of the marker element */ public void addMarkerElement(String label, double value, RGB color) { if(markersMap.containsKey(label)) { markersMap.get(label).value = value; markersMap.get(label).color = color; }else markersMap.put(label, new MarkerProperties(value, color)); dirty =true; } /** * Add (if the marker does not exist) or change a marker element. * @param label the label of the marker element, it must be unique. * @param value the value of the marker element */ public void addMarkerElement(String label, double value) { if(markersMap.containsKey(label)) markersMap.get(label).value = value; else markersMap.put(label, new MarkerProperties(value, DEFAULT_MARKER_COLOR)); dirty =true; } public void removeMarkerElement(String label) { markersMap.remove(label); dirty =true; } @Override protected void paintClientArea(Graphics graphics) { //use relative coordinate graphics.translate(bounds.x, bounds.y); updateTick(); drawMarkerTick(graphics); super.paintClientArea(graphics); } private void drawMarkerTick(Graphics graphics) { graphics.setLineWidth(TICK_LINE_WIDTH); if(scale.isHorizontal()) { if(makerLablesPosition == LabelSide.Primary) { int i = 0; for(int markerPos : markerPositions) { graphics.setForegroundColor(markerColorsList.get(i)); graphics.drawLine(markerPos, 0, markerPos, TICK_LENGTH); //draw labels if(isMarkerLableVisible()) { graphics.drawText(labels[i], markerPos-markerLabelDimensions[i].width/2, TICK_LENGTH + GAP_BTW_MARK_LABEL); } i++; } } else { int i = 0; for(int markerPos : markerPositions) { graphics.setForegroundColor(markerColorsList.get(i)); graphics.drawLine(markerPos, bounds.height, markerPos, bounds.height - TICK_LENGTH); //draw labels if(isMarkerLableVisible()) { graphics.drawText(labels[i], markerPos-markerLabelDimensions[i].width/2, bounds.height - TICK_LENGTH - GAP_BTW_MARK_LABEL - markerLabelDimensions[i].height); } i++; } } } else { if(makerLablesPosition == LabelSide.Primary) { for(int i = 0; i < markerPositions.length; i++) { graphics.setForegroundColor(markerColorsList.get(i)); graphics.drawLine(bounds.width, markerPositions[i], bounds.width - TICK_LENGTH, markerPositions[i]); //draw labels if(isMarkerLableVisible()) { graphics.drawText(labels[i], bounds.width - TICK_LENGTH - GAP_BTW_MARK_LABEL - markerLabelDimensions[i].width, markerPositions[i] - markerLabelDimensions[i].height/2); } } } else { int i = 0; for(int markerPos : markerPositions) { graphics.setForegroundColor(markerColorsList.get(i)); graphics.drawLine(0, markerPos, TICK_LENGTH, markerPos); //draw labels if(isMarkerLableVisible()) { graphics.drawText(labels[i], TICK_LENGTH + GAP_BTW_MARK_LABEL, markerPos-markerLabelDimensions[i].height/2 ); } i++; } } } } @Override public void setBounds(Rectangle rect) { if(!bounds.equals(rect)) dirty = true; super.setBounds(rect); } /** * Updates the tick, recalculate all inner parameters */ public void updateTick() { if(dirty == true) { updateMarkerElments(); updateTickLabelMaxLength(); } dirty = false; } /** * Gets max length of tick label. */ private void updateTickLabelMaxLength() { int maxLength = 0; for (int i = 0; i < labels.length; i++) { Dimension p = FigureUtilities.getTextExtents(labels[i], scale.getFont()); if (p.width > maxLength) { maxLength = p.width; } } tickLabelMaxLength = maxLength; } /** * @return the labels */ public String[] getLabels() { String[] labels = new String[markersMap.size()]; int i=0; for(String label : markersMap.keySet()) { labels[i] = label; i++; } return labels; } /** * @return the markerValues */ public void updateMarkerElments() { labels = new String[markersMap.size()]; markerColorsList.clear(); markerValues = new double[markersMap.size()]; markerLabelDimensions = new Dimension[markersMap.size()]; markerPositions = new int[markerValues.length]; int i = 0; for(String label : markersMap.keySet()) { labels[i] = label; markerValues[i] = markersMap.get(label).value; markerPositions[i] = scale.getValuePosition(markerValues[i], true); markerLabelDimensions[i] = FigureUtilities.getTextExtents(label, getFont()); markerColorsList.add( XYGraphMediaFactory.getInstance().getColor(markersMap.get(label).color)); i++; } } /** * @param scale the scale to set */ public void setScale(LinearScale scale) { this.scale = scale; dirty =true; } /** * @return the scale */ public LinearScale getScale() { return scale; } /** * @param labelSide the makerLablesPosition to set */ public void setLabelSide(LabelSide labelSide) { this.makerLablesPosition = labelSide; dirty =true; } /** * @return the makerLablesPosition */ public LabelSide getMakerLablesPosition() { return makerLablesPosition; } /** * @param markerLineVisible the markerLineVisible to set */ public void setMarkerLineVisible(boolean markerLineVisible) { this.markerLineVisible = markerLineVisible; dirty = true; } /** * @return the markerLineVisible */ public boolean isMarkerLineVisible() { return markerLineVisible; } /** * @param markerLableVisible the markerLableVisible to set */ public void setMarkerLableVisible(boolean markerLableVisible) { this.markerLableVisible = markerLableVisible; dirty =true; } /** * @return the markerLableVisible */ public boolean isMarkerLableVisible() { return markerLableVisible; } @Override public Dimension getPreferredSize(int wHint, int hHint) { updateTick(); Dimension size = new Dimension(wHint, hHint); if(scale.isHorizontal()) { size.width = scale.getSize().width; size.height = FigureUtilities.getTextExtents("dummy", getFont()).height + GAP_BTW_MARK_LABEL + TICK_LENGTH; } else { updateTickLabelMaxLength(); size.width = (int)tickLabelMaxLength + GAP_BTW_MARK_LABEL + TICK_LENGTH; size.height = scale.getSize().height; } return size; } private static class MarkerProperties { private double value; private RGB color; /** * @param value * @param color */ public MarkerProperties(double value, RGB color) { this.value = value; this.color = color; } } }