2015-01-21 21:58:35 +01:00
|
|
|
/*******************************************************************************
|
2015-10-22 00:25:12 +02:00
|
|
|
* Copyright (c) 2015 MINRES Technologies GmbH and others.
|
2015-01-21 21:58:35 +01:00
|
|
|
* 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
|
|
|
|
*
|
|
|
|
* Contributors:
|
|
|
|
* MINRES Technologies GmbH - initial API and implementation
|
|
|
|
*******************************************************************************/
|
2015-01-25 14:23:34 +01:00
|
|
|
package com.minres.scviewer.database.swt.internal;
|
2015-01-20 18:50:15 +01:00
|
|
|
|
2018-10-11 14:44:41 +02:00
|
|
|
import java.util.Collection;
|
2015-01-20 18:50:15 +01:00
|
|
|
import java.util.Map.Entry;
|
|
|
|
import java.util.NavigableMap;
|
|
|
|
|
2017-01-21 13:13:05 +01:00
|
|
|
import javax.swing.JPanel;
|
|
|
|
|
2015-01-20 18:50:15 +01:00
|
|
|
import org.eclipse.swt.SWT;
|
|
|
|
import org.eclipse.swt.graphics.Color;
|
2017-01-21 13:13:05 +01:00
|
|
|
import org.eclipse.swt.graphics.FontData;
|
2015-01-20 18:50:15 +01:00
|
|
|
import org.eclipse.swt.graphics.GC;
|
2017-01-21 13:13:05 +01:00
|
|
|
import org.eclipse.swt.graphics.Point;
|
2015-01-20 18:50:15 +01:00
|
|
|
import org.eclipse.swt.graphics.Rectangle;
|
|
|
|
|
2018-11-05 18:23:17 +01:00
|
|
|
import com.minres.scviewer.database.BitVector;
|
2015-01-20 18:50:15 +01:00
|
|
|
import com.minres.scviewer.database.ISignal;
|
2015-11-12 23:35:13 +01:00
|
|
|
import com.minres.scviewer.database.ui.TrackEntry;
|
|
|
|
import com.minres.scviewer.database.ui.WaveformColors;
|
2015-01-20 18:50:15 +01:00
|
|
|
|
2017-01-21 13:13:05 +01:00
|
|
|
public class SignalPainter extends TrackPainter {
|
|
|
|
private class SignalChange {
|
|
|
|
long time;
|
2018-11-05 18:23:17 +01:00
|
|
|
Object value;
|
2017-01-21 13:13:05 +01:00
|
|
|
boolean fromMap;
|
|
|
|
|
2018-11-05 18:23:17 +01:00
|
|
|
public SignalChange(Entry<Long, ?> entry) {
|
2017-01-21 13:13:05 +01:00
|
|
|
time = entry.getKey();
|
|
|
|
value = entry.getValue();
|
|
|
|
fromMap = true;
|
|
|
|
}
|
|
|
|
|
2018-11-05 18:23:17 +01:00
|
|
|
public void set(Entry<Long, ?> entry, Long actTime) {
|
2017-01-21 13:13:05 +01:00
|
|
|
if (entry != null) {
|
|
|
|
time = entry.getKey();
|
|
|
|
value = entry.getValue();
|
|
|
|
fromMap = true;
|
|
|
|
} else {
|
|
|
|
time = actTime;
|
|
|
|
fromMap = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void assign(SignalChange other) {
|
|
|
|
time = other.time;
|
|
|
|
value = other.value;
|
|
|
|
fromMap = other.fromMap;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-20 18:50:15 +01:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
2017-01-21 13:13:05 +01:00
|
|
|
private static final JPanel DUMMY_PANEL = new JPanel();
|
|
|
|
|
2015-01-20 18:50:15 +01:00
|
|
|
private final WaveformCanvas waveCanvas;
|
|
|
|
|
2017-01-21 13:13:05 +01:00
|
|
|
int yOffsetT;
|
|
|
|
int yOffsetM;
|
|
|
|
int yOffsetB;
|
2019-03-17 20:03:22 +01:00
|
|
|
/// maximum visible canvas position in canvas coordinates
|
|
|
|
int maxPosX;
|
|
|
|
/// maximum visible position in waveform coordinates
|
|
|
|
int maxValX;
|
2017-01-21 13:13:05 +01:00
|
|
|
|
2015-11-06 19:29:36 +01:00
|
|
|
public SignalPainter(WaveformCanvas txDisplay, boolean even, TrackEntry trackEntry) {
|
|
|
|
super(trackEntry, even);
|
2015-01-20 18:50:15 +01:00
|
|
|
this.waveCanvas = txDisplay;
|
2017-01-21 13:13:05 +01:00
|
|
|
}
|
|
|
|
|
2019-03-17 20:03:22 +01:00
|
|
|
private int getXValEnd(long time) {
|
2017-01-21 13:13:05 +01:00
|
|
|
long ltmp = time / this.waveCanvas.getScaleFactor();
|
2019-03-17 20:03:22 +01:00
|
|
|
return ltmp > maxValX ? maxValX : (int) ltmp;
|
2015-01-20 18:50:15 +01:00
|
|
|
}
|
|
|
|
|
2019-03-17 20:03:22 +01:00
|
|
|
private int getXPosEnd(long time) {
|
|
|
|
long ltmp = time / this.waveCanvas.getScaleFactor() - waveCanvas.getXOffset();
|
|
|
|
return ltmp > maxPosX ? maxPosX : (int) ltmp;
|
|
|
|
}
|
|
|
|
|
2017-01-21 13:13:05 +01:00
|
|
|
public void paintArea(GC gc, Rectangle area) {
|
2018-11-05 18:23:17 +01:00
|
|
|
ISignal<?> signal = trackEntry.getSignal();
|
2017-01-21 13:13:05 +01:00
|
|
|
if (trackEntry.selected)
|
2015-11-12 23:35:13 +01:00
|
|
|
gc.setBackground(this.waveCanvas.colors[WaveformColors.TRACK_BG_HIGHLITE.ordinal()]);
|
2015-01-21 21:58:35 +01:00
|
|
|
else
|
2017-01-21 13:13:05 +01:00
|
|
|
gc.setBackground(this.waveCanvas.colors[even ? WaveformColors.TRACK_BG_EVEN.ordinal() : WaveformColors.TRACK_BG_ODD.ordinal()]);
|
2015-01-20 18:50:15 +01:00
|
|
|
gc.setFillRule(SWT.FILL_EVEN_ODD);
|
|
|
|
gc.fillRectangle(area);
|
2019-03-17 20:03:22 +01:00
|
|
|
|
|
|
|
long scaleFactor = this.waveCanvas.getScaleFactor();
|
|
|
|
long beginPos = area.x;
|
|
|
|
long beginTime = (beginPos + waveCanvas.getXOffset())*scaleFactor;
|
|
|
|
long endPos = beginPos + area.width;
|
|
|
|
long endTime = beginTime + area.width*scaleFactor;
|
|
|
|
|
2018-11-05 18:23:17 +01:00
|
|
|
Entry<Long, ?> first = signal.getEvents().floorEntry(beginTime);
|
|
|
|
Entry<Long, ?> last = signal.getEvents().floorEntry(endTime);
|
2017-01-21 13:13:05 +01:00
|
|
|
if (first == null) {
|
|
|
|
if (last == null)
|
|
|
|
return;
|
|
|
|
first = signal.getEvents().firstEntry();
|
|
|
|
} else if (last == null) {
|
|
|
|
last = signal.getEvents().lastEntry();
|
2015-01-20 18:50:15 +01:00
|
|
|
}
|
2015-11-12 23:35:13 +01:00
|
|
|
gc.setForeground(this.waveCanvas.colors[WaveformColors.LINE.ordinal()]);
|
2015-01-20 18:50:15 +01:00
|
|
|
gc.setLineStyle(SWT.LINE_SOLID);
|
|
|
|
gc.setLineWidth(1);
|
2018-11-05 18:23:17 +01:00
|
|
|
NavigableMap<Long, ?> entries = signal.getEvents().subMap(first.getKey(), false, last.getKey(), true);
|
2017-01-21 13:13:05 +01:00
|
|
|
SignalChange left = new SignalChange(first);
|
|
|
|
SignalChange right = new SignalChange(entries.size() > 0 ? entries.firstEntry() : first);
|
2019-03-17 20:03:22 +01:00
|
|
|
maxPosX = area.x + area.width;
|
|
|
|
maxValX = maxPosX + (int)waveCanvas.getXOffset();
|
2017-01-21 13:13:05 +01:00
|
|
|
yOffsetT = this.waveCanvas.getTrackHeight() / 5 + area.y;
|
|
|
|
yOffsetM = this.waveCanvas.getTrackHeight() / 2 + area.y;
|
|
|
|
yOffsetB = 4 * this.waveCanvas.getTrackHeight() / 5 + area.y;
|
2019-03-17 20:03:22 +01:00
|
|
|
int xSigChangeBeginVal = Math.max(area.x + (int)waveCanvas.getXOffset(), (int) (left.time / this.waveCanvas.getScaleFactor()));
|
|
|
|
int xSigChangeBeginPos = area.x;
|
|
|
|
int xSigChangeEndVal = Math.max(area.x + (int)waveCanvas.getXOffset(), getXValEnd(right.time));
|
|
|
|
int xSigChangeEndPos = Math.max(area.x, getXPosEnd(right.time));
|
|
|
|
|
2017-01-21 13:13:05 +01:00
|
|
|
boolean multiple = false;
|
2019-03-17 20:03:22 +01:00
|
|
|
if (xSigChangeEndPos == xSigChangeBeginPos) {
|
2017-01-21 13:13:05 +01:00
|
|
|
// this can trigger if
|
|
|
|
// a) left == right
|
|
|
|
// b) left to close to right
|
|
|
|
if (left.time == right.time) {
|
|
|
|
right.time = endTime;
|
|
|
|
} else {
|
|
|
|
multiple = true;
|
2019-03-17 20:03:22 +01:00
|
|
|
long eTime = (xSigChangeBeginVal + 1) * this.waveCanvas.getScaleFactor();
|
2017-01-21 13:13:05 +01:00
|
|
|
right.set(entries.floorEntry(eTime), endTime);
|
|
|
|
right.time = eTime;
|
2015-01-20 18:50:15 +01:00
|
|
|
}
|
2019-03-17 20:03:22 +01:00
|
|
|
xSigChangeEndPos = getXPosEnd(right.time);
|
2017-01-21 13:13:05 +01:00
|
|
|
}
|
|
|
|
|
2019-03-17 20:03:22 +01:00
|
|
|
|
2018-10-11 14:44:41 +02:00
|
|
|
SignalStencil stencil = getStencil(gc, left, entries);
|
2017-01-21 13:13:05 +01:00
|
|
|
do {
|
2019-03-17 20:03:22 +01:00
|
|
|
stencil.draw(gc, area, left.value, right.value, xSigChangeBeginPos, xSigChangeEndPos, multiple);
|
2017-01-21 13:13:05 +01:00
|
|
|
if (right.time >= endTime)
|
|
|
|
break;
|
|
|
|
left.assign(right);
|
2019-03-17 20:03:22 +01:00
|
|
|
xSigChangeBeginPos = xSigChangeEndPos;
|
2017-01-21 13:13:05 +01:00
|
|
|
right.set(entries.higherEntry(left.time), endTime);
|
2019-03-17 20:03:22 +01:00
|
|
|
xSigChangeEndPos = getXPosEnd(right.time);
|
2017-01-21 13:13:05 +01:00
|
|
|
multiple = false;
|
2019-03-17 20:03:22 +01:00
|
|
|
if (xSigChangeEndPos == xSigChangeBeginPos) {
|
2017-01-21 13:13:05 +01:00
|
|
|
multiple = true;
|
2019-03-17 20:03:22 +01:00
|
|
|
long eTime = (xSigChangeBeginPos + 1) * this.waveCanvas.getScaleFactor();
|
2018-11-05 18:23:17 +01:00
|
|
|
Entry<Long, ?> entry = entries.floorEntry(eTime);
|
2018-08-27 16:27:11 +02:00
|
|
|
if(entry!=null && entry.getKey()> right.time)
|
|
|
|
right.set(entry, endTime);
|
2019-03-17 20:03:22 +01:00
|
|
|
xSigChangeEndPos = getXPosEnd(eTime);
|
2017-01-21 13:13:05 +01:00
|
|
|
}
|
|
|
|
} while (left.time < endTime);
|
|
|
|
}
|
|
|
|
|
2018-11-05 18:23:17 +01:00
|
|
|
private SignalStencil getStencil(GC gc, SignalChange left, NavigableMap<Long, ?> entries) {
|
|
|
|
Object val = left.value;
|
|
|
|
if(val instanceof BitVector) {
|
|
|
|
BitVector bv = (BitVector) val;
|
|
|
|
if(bv.getWidth()==1)
|
|
|
|
return new SingleBitStencil();
|
2018-10-14 08:59:17 +02:00
|
|
|
if(trackEntry.waveDisplay==TrackEntry.WaveDisplay.DEFAULT)
|
|
|
|
return new MultiBitStencil(gc);
|
|
|
|
else
|
|
|
|
return new MultiBitStencilAnalog(entries, left.value,
|
|
|
|
trackEntry.waveDisplay==TrackEntry.WaveDisplay.CONTINOUS,
|
|
|
|
trackEntry.valueDisplay==TrackEntry.ValueDisplay.SIGNED);
|
2018-11-05 18:23:17 +01:00
|
|
|
} else if (val instanceof Double)
|
2018-10-14 08:59:17 +02:00
|
|
|
return new RealStencil(entries, left.value, trackEntry.waveDisplay==TrackEntry.WaveDisplay.CONTINOUS);
|
2018-10-11 14:44:41 +02:00
|
|
|
else
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2017-01-21 13:13:05 +01:00
|
|
|
private interface SignalStencil {
|
|
|
|
|
2018-11-05 18:23:17 +01:00
|
|
|
public void draw(GC gc, Rectangle area, Object left, Object right, int xBegin, int xEnd, boolean multiple);
|
2017-01-21 13:13:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private class MultiBitStencil implements SignalStencil {
|
|
|
|
|
|
|
|
private java.awt.Font tmpAwtFont;
|
|
|
|
private int height;
|
|
|
|
|
|
|
|
public MultiBitStencil(GC gc) {
|
|
|
|
FontData fd = gc.getFont().getFontData()[0];
|
|
|
|
height = gc.getDevice().getDPI().y * fd.getHeight() / 72;
|
|
|
|
tmpAwtFont = new java.awt.Font(fd.getName(), fd.getStyle(), height);
|
|
|
|
}
|
|
|
|
|
2018-11-05 18:23:17 +01:00
|
|
|
public void draw(GC gc, Rectangle area, Object left, Object right, int xBegin, int xEnd, boolean multiple) {
|
2017-01-21 13:13:05 +01:00
|
|
|
Color colorBorder = waveCanvas.colors[WaveformColors.SIGNAL0.ordinal()];
|
2018-11-05 18:23:17 +01:00
|
|
|
BitVector last = (BitVector) left;
|
2017-01-21 13:13:05 +01:00
|
|
|
if (last.getValue().toString().contains("X")) {
|
|
|
|
colorBorder = waveCanvas.colors[WaveformColors.SIGNALX.ordinal()];
|
|
|
|
} else if (last.getValue().toString().contains("Z")) {
|
|
|
|
colorBorder = waveCanvas.colors[WaveformColors.SIGNALZ.ordinal()];
|
|
|
|
}
|
|
|
|
int width = xEnd - xBegin;
|
|
|
|
if (width > 1) {
|
|
|
|
int[] points = {
|
|
|
|
xBegin, yOffsetM,
|
|
|
|
xBegin + 1, yOffsetT,
|
|
|
|
xEnd - 1, yOffsetT,
|
|
|
|
xEnd, yOffsetM,
|
|
|
|
xEnd - 1, yOffsetB,
|
|
|
|
xBegin + 1, yOffsetB
|
2015-01-20 18:50:15 +01:00
|
|
|
};
|
|
|
|
gc.setForeground(colorBorder);
|
|
|
|
gc.drawPolygon(points);
|
2017-01-21 13:13:05 +01:00
|
|
|
gc.setForeground(waveCanvas.colors[WaveformColors.SIGNAL_TEXT.ordinal()]);
|
2018-10-14 08:59:17 +02:00
|
|
|
//TODO: this code should be provided from a central location
|
|
|
|
String label = null;
|
|
|
|
switch(trackEntry.valueDisplay) {
|
|
|
|
case SIGNED:
|
2018-11-05 18:23:17 +01:00
|
|
|
label=Long.toString(last.toSignedValue());
|
2018-10-14 08:59:17 +02:00
|
|
|
break;
|
|
|
|
case UNSIGNED:
|
2018-11-05 18:23:17 +01:00
|
|
|
label=Long.toString(last.toUnsignedValue());
|
2018-10-14 08:59:17 +02:00
|
|
|
break;
|
|
|
|
default:
|
2018-11-05 18:23:17 +01:00
|
|
|
label="h'"+last.toHexString();
|
2018-10-14 08:59:17 +02:00
|
|
|
}
|
2017-01-21 13:13:05 +01:00
|
|
|
Point bb = getBoxWidth(gc, label);
|
|
|
|
if (xBegin < area.x) {
|
|
|
|
xBegin = area.x;
|
|
|
|
width = xEnd - xBegin;
|
|
|
|
}
|
|
|
|
if (width > (bb.x+1)) {
|
2015-01-20 18:50:15 +01:00
|
|
|
Rectangle old = gc.getClipping();
|
2017-01-21 13:13:05 +01:00
|
|
|
gc.setClipping(xBegin + 3, yOffsetT, xEnd - xBegin - 5, yOffsetB - yOffsetT);
|
|
|
|
gc.drawText(label, xBegin + 3, yOffsetM - bb.y / 2 - 1);
|
2015-01-20 18:50:15 +01:00
|
|
|
gc.setClipping(old);
|
|
|
|
}
|
2017-01-21 13:13:05 +01:00
|
|
|
} else {
|
|
|
|
gc.setForeground(colorBorder);
|
|
|
|
gc.drawLine(xEnd, yOffsetT, xEnd, yOffsetB);
|
2015-01-20 18:50:15 +01:00
|
|
|
}
|
|
|
|
}
|
2017-01-21 13:13:05 +01:00
|
|
|
|
|
|
|
private Point getBoxWidth(GC gc, String label) {
|
|
|
|
return new Point(DUMMY_PANEL.getFontMetrics(tmpAwtFont).stringWidth(label), height);
|
|
|
|
}
|
|
|
|
|
2015-01-20 18:50:15 +01:00
|
|
|
}
|
|
|
|
|
2018-10-14 08:59:17 +02:00
|
|
|
private class MultiBitStencilAnalog implements SignalStencil {
|
|
|
|
|
|
|
|
final boolean continous;
|
|
|
|
private long minVal;
|
|
|
|
private long range;
|
|
|
|
|
2018-11-05 18:23:17 +01:00
|
|
|
public MultiBitStencilAnalog(NavigableMap<Long, ?> entries, Object left, boolean continous, boolean signed) {
|
2018-10-14 08:59:17 +02:00
|
|
|
this.continous=continous;
|
2018-11-05 18:23:17 +01:00
|
|
|
Collection<?> values = ((NavigableMap<Long, ?>) entries).values();
|
|
|
|
minVal=((BitVector) left).toUnsignedValue();
|
2018-10-14 08:59:17 +02:00
|
|
|
range=2;
|
|
|
|
if(!values.isEmpty()) {
|
|
|
|
long maxVal=minVal;
|
2018-11-05 18:23:17 +01:00
|
|
|
for (Object e : entries.values()) {
|
|
|
|
long v = ((BitVector)e).toUnsignedValue();
|
2018-10-14 08:59:17 +02:00
|
|
|
maxVal=Math.max(maxVal, v);
|
|
|
|
minVal=Math.min(minVal, v);
|
|
|
|
}
|
|
|
|
if(maxVal==minVal) {
|
|
|
|
maxVal--;
|
|
|
|
minVal++;
|
|
|
|
}
|
|
|
|
range = maxVal-minVal;
|
|
|
|
} else
|
|
|
|
minVal--;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-11-05 18:23:17 +01:00
|
|
|
public void draw(GC gc, Rectangle area, Object left, Object right, int xBegin, int xEnd, boolean multiple) {
|
|
|
|
long leftVal = ((BitVector) left).toUnsignedValue();
|
|
|
|
long rightVal= ((BitVector) right).toUnsignedValue();
|
2018-10-14 08:59:17 +02:00
|
|
|
gc.setForeground(waveCanvas.colors[WaveformColors.SIGNAL_REAL.ordinal()]);
|
|
|
|
int yOffsetLeft = (int) ((leftVal-minVal) / range * (yOffsetB-yOffsetT));
|
|
|
|
int yOffsetRight = (int) ((rightVal-minVal) / range * (yOffsetB-yOffsetT));
|
|
|
|
if(continous) {
|
2019-03-17 20:03:22 +01:00
|
|
|
if (xEnd > maxPosX) {
|
|
|
|
gc.drawLine(xBegin, yOffsetB-yOffsetLeft, maxPosX, yOffsetB-yOffsetRight);
|
2018-10-14 08:59:17 +02:00
|
|
|
} else {
|
|
|
|
gc.drawLine(xBegin, yOffsetB-yOffsetLeft, xEnd, yOffsetB-yOffsetRight);
|
|
|
|
}
|
|
|
|
} else {
|
2019-03-17 20:03:22 +01:00
|
|
|
if (xEnd > maxPosX) {
|
|
|
|
gc.drawLine(xBegin, yOffsetB-yOffsetLeft, maxPosX, yOffsetB-yOffsetLeft);
|
2018-10-14 08:59:17 +02:00
|
|
|
} else {
|
|
|
|
gc.drawLine(xBegin, yOffsetB-yOffsetLeft, xEnd, yOffsetB-yOffsetLeft);
|
|
|
|
if(yOffsetRight!=yOffsetLeft) {
|
|
|
|
gc.drawLine(xEnd, yOffsetB-yOffsetLeft, xEnd, yOffsetB-yOffsetRight);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-21 13:13:05 +01:00
|
|
|
private class SingleBitStencil implements SignalStencil {
|
2018-11-05 18:23:17 +01:00
|
|
|
public void draw(GC gc, Rectangle area, Object left, Object right, int xBegin, int xEnd, boolean multiple) {
|
2017-01-21 13:13:05 +01:00
|
|
|
if (multiple) {
|
|
|
|
gc.setForeground(waveCanvas.colors[WaveformColors.SIGNALU.ordinal()]);
|
|
|
|
gc.drawLine(xBegin, yOffsetT, xBegin, yOffsetB);
|
2018-10-11 14:44:41 +02:00
|
|
|
if(xEnd>xBegin)
|
|
|
|
gc.drawLine(xEnd, yOffsetT, xEnd, yOffsetB);
|
2017-01-21 13:13:05 +01:00
|
|
|
} else {
|
|
|
|
Color color = waveCanvas.colors[WaveformColors.SIGNALX.ordinal()];
|
|
|
|
int yOffset = yOffsetM;
|
2018-11-05 18:23:17 +01:00
|
|
|
switch (((BitVector) left).getValue()[0]) {
|
2017-01-21 13:13:05 +01:00
|
|
|
case '1':
|
|
|
|
color = waveCanvas.colors[WaveformColors.SIGNAL1.ordinal()];
|
|
|
|
yOffset = yOffsetT;
|
|
|
|
break;
|
|
|
|
case '0':
|
|
|
|
color = waveCanvas.colors[WaveformColors.SIGNAL0.ordinal()];
|
|
|
|
yOffset = yOffsetB;
|
|
|
|
break;
|
|
|
|
case 'Z':
|
|
|
|
color = waveCanvas.colors[WaveformColors.SIGNALZ.ordinal()];
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
gc.setForeground(color);
|
2019-03-17 20:03:22 +01:00
|
|
|
if (xEnd > maxPosX) {
|
|
|
|
gc.drawLine(xBegin, yOffset, maxPosX, yOffset);
|
2017-01-21 13:13:05 +01:00
|
|
|
} else {
|
|
|
|
gc.drawLine(xBegin, yOffset, xEnd, yOffset);
|
|
|
|
int yNext = yOffsetM;
|
2018-11-05 18:23:17 +01:00
|
|
|
switch (((BitVector) right).getValue()[0]) {
|
2017-01-21 13:13:05 +01:00
|
|
|
case '1':
|
|
|
|
yNext = yOffsetT;
|
|
|
|
break;
|
|
|
|
case '0':
|
|
|
|
yNext = yOffsetB;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
if (yOffset != yNext)
|
|
|
|
gc.drawLine(xEnd, yOffset, xEnd, yNext);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-01-20 18:50:15 +01:00
|
|
|
|
2018-10-11 14:44:41 +02:00
|
|
|
private class RealStencil implements SignalStencil {
|
|
|
|
|
|
|
|
double minVal, range;
|
|
|
|
|
|
|
|
final double scaleFactor = 1.05;
|
|
|
|
|
2018-10-14 08:59:17 +02:00
|
|
|
boolean continous=true;
|
2018-10-11 14:44:41 +02:00
|
|
|
|
2018-11-05 18:23:17 +01:00
|
|
|
public RealStencil(NavigableMap<Long, ?> entries, Object left, boolean continous) {
|
2018-10-14 08:59:17 +02:00
|
|
|
this.continous=continous;
|
2018-11-05 18:23:17 +01:00
|
|
|
Collection<?> values = ((NavigableMap<Long, ?>) entries).values();
|
|
|
|
minVal=(Double) left;
|
2018-10-11 14:44:41 +02:00
|
|
|
range=2.0;
|
|
|
|
if(!values.isEmpty()) {
|
|
|
|
double maxVal=minVal;
|
2018-11-05 18:23:17 +01:00
|
|
|
for (Object e : entries.values()) {
|
|
|
|
double v = ((Double)e);
|
2018-10-14 08:59:17 +02:00
|
|
|
if(Double.isNaN(maxVal))
|
|
|
|
maxVal=v;
|
|
|
|
else if(!Double.isNaN(v))
|
|
|
|
maxVal=Math.max(maxVal, v);
|
|
|
|
if(Double.isNaN(minVal))
|
|
|
|
minVal=v;
|
|
|
|
else if(!Double.isNaN(v))
|
|
|
|
minVal=Math.min(minVal, v);
|
|
|
|
}
|
|
|
|
if(Double.isNaN(maxVal)){
|
|
|
|
maxVal=minVal=0.0;
|
2018-10-11 14:44:41 +02:00
|
|
|
}
|
|
|
|
range = (maxVal-minVal)*scaleFactor;
|
|
|
|
double avg = (maxVal+minVal)/2.0;
|
|
|
|
minVal=avg-(avg-minVal)*scaleFactor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-05 18:23:17 +01:00
|
|
|
public void draw(GC gc, Rectangle area, Object left, Object right, int xBegin, int xEnd, boolean multiple) {
|
|
|
|
double leftVal = (Double) left;
|
|
|
|
double rightVal= (Double) right;
|
2018-10-14 08:59:17 +02:00
|
|
|
if(Double.isNaN(leftVal)) {
|
|
|
|
Color color = waveCanvas.colors[WaveformColors.SIGNAL_NAN.ordinal()];
|
|
|
|
int width = xEnd - xBegin;
|
|
|
|
if (width > 1) {
|
|
|
|
int[] points = {
|
|
|
|
xBegin, yOffsetT,
|
|
|
|
xEnd, yOffsetT,
|
|
|
|
xEnd, yOffsetB,
|
|
|
|
xBegin, yOffsetB
|
|
|
|
};
|
|
|
|
gc.setForeground(color);
|
|
|
|
gc.drawPolygon(points);
|
|
|
|
gc.setBackground(color);
|
|
|
|
gc.fillPolygon(points);
|
2018-10-11 14:44:41 +02:00
|
|
|
} else {
|
2018-10-14 08:59:17 +02:00
|
|
|
gc.setForeground(color);
|
|
|
|
gc.drawLine(xEnd, yOffsetT, xEnd, yOffsetB);
|
2018-10-11 14:44:41 +02:00
|
|
|
}
|
2018-10-14 08:59:17 +02:00
|
|
|
} else {
|
|
|
|
gc.setForeground(waveCanvas.colors[WaveformColors.SIGNAL_REAL.ordinal()]);
|
|
|
|
int yOffsetLeft = (int) ((leftVal-minVal) / range * (yOffsetB-yOffsetT));
|
|
|
|
int yOffsetRight = Double.isNaN(rightVal)?yOffsetLeft:(int) ((rightVal-minVal) / range * (yOffsetB-yOffsetT));
|
|
|
|
if(continous) {
|
2019-03-17 20:03:22 +01:00
|
|
|
if (xEnd > maxPosX) {
|
|
|
|
gc.drawLine(xBegin, yOffsetB-yOffsetLeft, maxPosX, yOffsetB-yOffsetRight);
|
2018-10-14 08:59:17 +02:00
|
|
|
} else {
|
|
|
|
gc.drawLine(xBegin, yOffsetB-yOffsetLeft, xEnd, yOffsetB-yOffsetRight);
|
|
|
|
}
|
2018-10-11 14:44:41 +02:00
|
|
|
} else {
|
2019-03-17 20:03:22 +01:00
|
|
|
if (xEnd > maxPosX) {
|
|
|
|
gc.drawLine(xBegin, yOffsetB-yOffsetLeft, maxPosX, yOffsetB-yOffsetLeft);
|
2018-10-14 08:59:17 +02:00
|
|
|
} else {
|
|
|
|
gc.drawLine(xBegin, yOffsetB-yOffsetLeft, xEnd, yOffsetB-yOffsetLeft);
|
|
|
|
if(yOffsetRight!=yOffsetLeft) {
|
|
|
|
gc.drawLine(xEnd, yOffsetB-yOffsetLeft, xEnd, yOffsetB-yOffsetRight);
|
|
|
|
}
|
|
|
|
}
|
2018-10-11 14:44:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|