package com.positive.charting;
import java.util.Iterator;
import java.util.LinkedList;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import com.positive.colorchecker.StaticColorChecker;
/**
* A SWT GUI component for displaying a {@link Chart} object.
* <P>
* The chart canvas panel registers with the chart to receive notification of
* changes to any component of the chart. The chart is redrawn automatically
* whenever this notification is received.
*/
public class ScrollingChartCanvas extends Canvas implements PaintListener,
ControlListener {
private final LinkedList series = new LinkedList();
private Image backBuffer;
private boolean disposeBackBufferNeeded = false;
private int pointsAdded;
public ScrollingChartCanvas(final Composite parent, final int style) {
super(parent, style);
this.addPaintListener(this);
this.series.add(new Double(0.5));
this.addControlListener(this);
}
public void addPoint(final double value) {
this.series.add(0, new Double(value));
this.pointsAdded++;
this.getDisplay().asyncExec(new Runnable() {
public void run() {
ScrollingChartCanvas.this.scrollChart();
}
});
}
private void allocateBackBuffer(final Rectangle clientArea) {
if ((this.backBuffer != null) && !this.backBuffer.isDisposed()
&& this.disposeBackBufferNeeded) {
this.backBuffer.dispose();
this.backBuffer = null;
this.disposeBackBufferNeeded = false;
}
if (this.backBuffer == null) {
this.backBuffer = new Image(this.getDisplay(), clientArea);
}
}
public void controlMoved(final ControlEvent e) {
}
public void controlResized(final ControlEvent e) {
this.disposeBackBufferNeeded = true;
}
private void drawSeriesLine(final PaintEvent e, final GC gc,
final Rectangle clientArea) {
int x = clientArea.width + 5;
int yPrev = (int) (0.5 * clientArea.height);
for (final Iterator iter = this.series.iterator(); iter.hasNext();) {
final Double value = (Double) iter.next();
final int y = (int) (value.doubleValue() * clientArea.height);
gc.drawLine(x, yPrev, x -= 5, y);
yPrev = y;
if (x < e.x) {
break;
}
}
}
private void fullRepaint(final PaintEvent e, final GC gc) {
if (!this.isVisible()) {
return;
}
final Rectangle clientArea = this.getClientArea();
gc.setForeground( StaticColorChecker.dublicateColor(SWT.COLOR_BLUE));// this.getDisplay().getSystemColor(SWT.COLOR_BLUE));
gc.setAntialias(SWT.OFF);
gc.setLineWidth(1);
this.drawSeriesLine(e, gc, clientArea);
}
public void paintControl(final PaintEvent e) {
final Rectangle clientArea = this.getClientArea();
this.allocateBackBuffer(clientArea);
final GC gc = new GC(this.backBuffer);
this.fullRepaint(e, gc);
e.gc.drawImage(this.backBuffer, 0, 0);
gc.dispose();
}
protected void scrollChart() {
if (this.pointsAdded <= 0) {
return;
}
final Rectangle clientArea = this.getClientArea();
this.allocateBackBuffer(clientArea);
final GC backBufferGc = new GC(this.backBuffer);
final GC frontGc = new GC(this);
final int repaintRectWidth = 5 * this.pointsAdded;
backBufferGc.copyArea(repaintRectWidth, 0, clientArea.width
- repaintRectWidth, clientArea.height, 0, 0, false);
backBufferGc.fillRectangle(clientArea.width - repaintRectWidth, 0,
repaintRectWidth, clientArea.height);
frontGc.drawImage(this.backBuffer, 0, 0);
backBufferGc.dispose();
this.redraw(clientArea.width - repaintRectWidth, 0, repaintRectWidth,
clientArea.height, false);
this.pointsAdded = 0;
}
}