2015-01-20 18:50:15 +01:00
|
|
|
/*******************************************************************************
|
2015-01-21 21:58:35 +01:00
|
|
|
* Copyright (c) 2014, 2015 MINRES Technologies GmbH and others.
|
2015-01-20 18:50:15 +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
|
|
|
|
*******************************************************************************/
|
|
|
|
package com.minres.scviewer.ui.swt;
|
|
|
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.LinkedList;
|
|
|
|
import java.util.List;
|
2015-01-21 21:58:35 +01:00
|
|
|
import java.util.Map.Entry;
|
2015-01-20 18:50:15 +01:00
|
|
|
import java.util.TreeMap;
|
|
|
|
|
|
|
|
import org.eclipse.swt.SWT;
|
|
|
|
import org.eclipse.swt.events.ControlAdapter;
|
|
|
|
import org.eclipse.swt.events.ControlEvent;
|
|
|
|
import org.eclipse.swt.events.PaintEvent;
|
|
|
|
import org.eclipse.swt.events.PaintListener;
|
|
|
|
import org.eclipse.swt.events.SelectionAdapter;
|
|
|
|
import org.eclipse.swt.events.SelectionEvent;
|
|
|
|
import org.eclipse.swt.graphics.Color;
|
|
|
|
import org.eclipse.swt.graphics.GC;
|
|
|
|
import org.eclipse.swt.graphics.Point;
|
|
|
|
import org.eclipse.swt.graphics.RGB;
|
|
|
|
import org.eclipse.swt.graphics.Rectangle;
|
|
|
|
import org.eclipse.swt.graphics.Transform;
|
|
|
|
import org.eclipse.swt.widgets.Canvas;
|
|
|
|
import org.eclipse.swt.widgets.Composite;
|
|
|
|
import org.eclipse.swt.widgets.Display;
|
|
|
|
import org.eclipse.swt.widgets.ScrollBar;
|
|
|
|
import org.eclipse.wb.swt.SWTResourceManager;
|
|
|
|
|
2015-01-21 21:58:35 +01:00
|
|
|
import com.google.common.collect.Lists;
|
|
|
|
import com.minres.scviewer.database.ITx;
|
2015-01-20 18:50:15 +01:00
|
|
|
import com.minres.scviewer.database.IWaveform;
|
2015-01-21 21:58:35 +01:00
|
|
|
import com.minres.scviewer.database.IWaveformEvent;
|
2015-01-20 18:50:15 +01:00
|
|
|
|
|
|
|
public class WaveformCanvas extends Canvas {
|
|
|
|
public enum Colors {
|
|
|
|
LINE,
|
|
|
|
LINE_HIGHLITE,
|
|
|
|
TRACK_BG_EVEN,
|
|
|
|
TRACK_BG_HIGHLITE,
|
|
|
|
TRACK_BG_ODD,
|
|
|
|
TX_BG,
|
|
|
|
TX_BG_HIGHLITE,
|
|
|
|
TX_BORDER,
|
|
|
|
SIGNAL0,
|
|
|
|
SIGNAL1,
|
|
|
|
SIGNALZ,
|
|
|
|
SIGNALX,
|
2015-01-21 21:58:35 +01:00
|
|
|
SIGNAL_TEXT,
|
|
|
|
CURSOR
|
2015-01-20 18:50:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Color[] colors=new Color[Colors.values().length];
|
|
|
|
|
|
|
|
private int trackHeight = 50;
|
|
|
|
private long scaleFactor = 1000000L;
|
2015-01-21 21:58:35 +01:00
|
|
|
private int level=6;
|
2015-01-20 18:50:15 +01:00
|
|
|
private long maxTime;
|
|
|
|
protected Point origin; /* original size */
|
|
|
|
protected Transform transform;
|
2015-01-21 21:58:35 +01:00
|
|
|
protected Ruler ruler;
|
2015-01-20 18:50:15 +01:00
|
|
|
protected List<IPainter> painterList;
|
|
|
|
TreeMap<Integer, IWaveformPainter> trackVerticalOffset;
|
2015-01-21 21:58:35 +01:00
|
|
|
|
|
|
|
protected List<IWaveform<? extends IWaveformEvent>> streams;
|
|
|
|
|
|
|
|
ITx currentSelection;
|
|
|
|
IWaveform<? extends IWaveformEvent> currentWaveformSelection;
|
|
|
|
|
2015-01-20 18:50:15 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor for ScrollableCanvas.
|
|
|
|
* @param parent the parent of this control.
|
|
|
|
* @param style the style of this control.
|
|
|
|
*/
|
|
|
|
public WaveformCanvas(final Composite parent, int style) {
|
2015-01-22 13:59:30 +01:00
|
|
|
super( parent, style |SWT.DOUBLE_BUFFERED| SWT.NO_BACKGROUND|SWT.NO_REDRAW_RESIZE|SWT.V_SCROLL|SWT.H_SCROLL);
|
2015-01-20 18:50:15 +01:00
|
|
|
addControlListener(new ControlAdapter() { /* resize listener. */
|
|
|
|
public void controlResized(ControlEvent event) {
|
|
|
|
syncScrollBars();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
addPaintListener(new PaintListener() { /* paint listener. */
|
|
|
|
public void paintControl(final PaintEvent event) {
|
|
|
|
paint(event.gc);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
painterList=new LinkedList<IPainter>();
|
|
|
|
origin=new Point(0,0);
|
|
|
|
transform = new Transform(getDisplay());
|
|
|
|
trackVerticalOffset=new TreeMap<Integer, IWaveformPainter>();
|
|
|
|
initScrollBars();
|
|
|
|
initColors(null);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void initColors(HashMap<Colors, RGB> colourMap){
|
|
|
|
Display d = getDisplay();
|
|
|
|
if(colourMap!=null){
|
|
|
|
for(Colors c:Colors.values()){
|
|
|
|
if(colourMap.containsKey(c)){
|
|
|
|
colors[c.ordinal()].dispose();
|
|
|
|
colors[c.ordinal()]=new Color(d, colourMap.get(c));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
colors[Colors.LINE.ordinal()]=SWTResourceManager.getColor(SWT.COLOR_RED);
|
|
|
|
colors[Colors.LINE_HIGHLITE.ordinal()]=SWTResourceManager.getColor(SWT.COLOR_CYAN);
|
|
|
|
colors[Colors.TRACK_BG_EVEN.ordinal()]=SWTResourceManager.getColor(SWT.COLOR_BLACK);
|
2015-01-21 21:58:35 +01:00
|
|
|
colors[Colors.TRACK_BG_ODD.ordinal()]=SWTResourceManager.getColor(40,40,40);
|
|
|
|
colors[Colors.TRACK_BG_HIGHLITE.ordinal()]=SWTResourceManager.getColor(40,40,80);
|
2015-01-20 18:50:15 +01:00
|
|
|
colors[Colors.TX_BG.ordinal()]=SWTResourceManager.getColor(SWT.COLOR_GREEN);
|
|
|
|
colors[Colors.TX_BG_HIGHLITE.ordinal()]=SWTResourceManager.getColor(SWT.COLOR_DARK_GREEN);
|
|
|
|
colors[Colors.TX_BORDER.ordinal()]=SWTResourceManager.getColor(SWT.COLOR_RED);
|
|
|
|
colors[Colors.SIGNAL0.ordinal()]=SWTResourceManager.getColor(SWT.COLOR_DARK_GREEN);
|
|
|
|
colors[Colors.SIGNAL1.ordinal()]=SWTResourceManager.getColor(SWT.COLOR_DARK_GREEN);
|
|
|
|
colors[Colors.SIGNALZ.ordinal()]=SWTResourceManager.getColor(SWT.COLOR_GRAY);
|
|
|
|
colors[Colors.SIGNALX.ordinal()]=SWTResourceManager.getColor(SWT.COLOR_RED);
|
|
|
|
colors[Colors.SIGNAL_TEXT.ordinal()]=SWTResourceManager.getColor(SWT.COLOR_WHITE);
|
2015-01-22 13:59:30 +01:00
|
|
|
colors[Colors.CURSOR.ordinal()]=SWTResourceManager.getColor(SWT.COLOR_YELLOW);
|
2015-01-20 18:50:15 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-21 21:58:35 +01:00
|
|
|
public List<IWaveform<? extends IWaveformEvent>> getStreams() {
|
|
|
|
return streams;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setStreams(List<IWaveform<? extends IWaveformEvent>> streams) {
|
|
|
|
this.streams = streams;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Ruler getRuler(){
|
|
|
|
return ruler;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setRuler(Ruler ruler) {
|
|
|
|
this.ruler=ruler;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Object getOrigin() {
|
|
|
|
return origin;
|
|
|
|
}
|
|
|
|
|
2015-01-20 18:50:15 +01:00
|
|
|
public long getMaxTime() {
|
|
|
|
return maxTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setMaxTime(long maxTime){
|
|
|
|
this.maxTime=maxTime;
|
|
|
|
syncScrollBars();
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getTrackHeight() {
|
|
|
|
return trackHeight;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setTrackHeight(int trackHeight) {
|
|
|
|
this.trackHeight = trackHeight;
|
|
|
|
syncScrollBars();
|
|
|
|
}
|
|
|
|
|
2015-01-21 21:58:35 +01:00
|
|
|
public void setZoomLevel(int level) {
|
|
|
|
this.level=level;
|
|
|
|
this.scaleFactor = (long) Math.pow(10, level);
|
|
|
|
if(ruler!=null) ruler.setStartPoint(-origin.x*scaleFactor);
|
|
|
|
syncScrollBars();
|
2015-01-20 18:50:15 +01:00
|
|
|
}
|
|
|
|
|
2015-01-21 21:58:35 +01:00
|
|
|
public int getZoomLevel() {
|
|
|
|
return level;
|
|
|
|
}
|
|
|
|
|
|
|
|
public long getScaleFactor() {
|
|
|
|
return scaleFactor;
|
2015-01-20 18:50:15 +01:00
|
|
|
}
|
|
|
|
|
2015-01-21 21:58:35 +01:00
|
|
|
public void addPainter(IPainter painter) {
|
2015-01-20 18:50:15 +01:00
|
|
|
painterList.add(painter);
|
|
|
|
redraw();
|
|
|
|
}
|
|
|
|
|
2015-01-21 21:58:35 +01:00
|
|
|
public void removePainter(IPainter painter){
|
2015-01-20 18:50:15 +01:00
|
|
|
painterList.remove(painter);
|
|
|
|
redraw();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void clearAllWavefromPainter() {
|
|
|
|
trackVerticalOffset.clear();
|
|
|
|
syncScrollBars();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void addWavefromPainter(int yoffs, IWaveformPainter painter) {
|
|
|
|
trackVerticalOffset.put(yoffs, painter);
|
|
|
|
syncScrollBars();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Dispose the garbage here
|
|
|
|
*/
|
|
|
|
public void dispose() {
|
|
|
|
transform.dispose();
|
|
|
|
for(Colors c:Colors.values()) colors[c.ordinal()].dispose();
|
|
|
|
super.dispose();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void scrollToY(int y){
|
|
|
|
ScrollBar vBar = getVerticalBar();
|
|
|
|
vBar.setSelection(y);
|
|
|
|
scrollVertically(vBar);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void scrollToX(int x){
|
|
|
|
ScrollBar hBar = getHorizontalBar();
|
|
|
|
hBar.setSelection(x);
|
|
|
|
scrollHorizontally(hBar);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Scroll horizontally */
|
|
|
|
private void scrollHorizontally(ScrollBar scrollBar) {
|
|
|
|
if (painterList.size()==0) return;
|
|
|
|
origin.x= -scrollBar.getSelection();
|
2015-01-21 21:58:35 +01:00
|
|
|
if(ruler!=null) ruler.setStartPoint(-origin.x*scaleFactor);
|
2015-01-20 18:50:15 +01:00
|
|
|
syncScrollBars();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Scroll vertically */
|
|
|
|
private void scrollVertically(ScrollBar scrollBar) {
|
|
|
|
if (painterList.size()==0) return;
|
|
|
|
origin.y = -scrollBar.getSelection();
|
|
|
|
syncScrollBars();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initalize the scrollbar and register listeners. */
|
|
|
|
private void initScrollBars() {
|
|
|
|
ScrollBar horizontal = getHorizontalBar();
|
|
|
|
horizontal.setEnabled(false);
|
|
|
|
horizontal.setVisible(true);
|
|
|
|
horizontal.addSelectionListener(new SelectionAdapter() {
|
|
|
|
public void widgetSelected(SelectionEvent event) {
|
|
|
|
scrollHorizontally((ScrollBar) event.widget);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
ScrollBar vertical = getVerticalBar();
|
|
|
|
vertical.setEnabled(false);
|
|
|
|
vertical.setVisible(true);
|
|
|
|
vertical.addSelectionListener(new SelectionAdapter() {
|
|
|
|
public void widgetSelected(SelectionEvent event) {
|
|
|
|
scrollVertically((ScrollBar) event.widget);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Synchronize the scrollbar with the image. If the transform is out
|
|
|
|
* of range, it will correct it. This function considers only following
|
|
|
|
* factors :<b> transform, image size, client area</b>.
|
|
|
|
*/
|
|
|
|
private void syncScrollBars() {
|
|
|
|
if (painterList.size()==0) {
|
|
|
|
redraw();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int height=1;
|
|
|
|
if(trackVerticalOffset.size()>0)
|
|
|
|
height=trackVerticalOffset.lastKey()+trackVerticalOffset.lastEntry().getValue().getMinHeight();
|
|
|
|
|
|
|
|
int width = (int) (maxTime/scaleFactor);
|
|
|
|
ScrollBar horizontal = getHorizontalBar();
|
|
|
|
horizontal.setIncrement((int) (getClientArea().width / 100));
|
|
|
|
horizontal.setPageIncrement(getClientArea().width);
|
|
|
|
int cw = getClientArea().width;
|
|
|
|
if (width > cw) { /* image is wider than client area */
|
|
|
|
horizontal.setMaximum(width);
|
|
|
|
horizontal.setEnabled(true);
|
|
|
|
if (((int) - origin.x) > horizontal.getMaximum() - cw)
|
|
|
|
origin.x = -horizontal.getMaximum() + cw;
|
|
|
|
} else { /* image is narrower than client area */
|
|
|
|
horizontal.setEnabled(false);
|
|
|
|
}
|
|
|
|
horizontal.setSelection(-origin.x);
|
|
|
|
horizontal.setThumb(cw);
|
|
|
|
|
|
|
|
ScrollBar vertical = getVerticalBar();
|
|
|
|
vertical.setIncrement((int) (getClientArea().height / 100));
|
|
|
|
vertical.setPageIncrement((int) (getClientArea().height));
|
|
|
|
int ch = getClientArea().height;
|
|
|
|
if (height> ch) { /* image is higher than client area */
|
|
|
|
vertical.setMaximum(height);
|
|
|
|
vertical.setEnabled(true);
|
|
|
|
if (((int) - origin.y) > vertical.getMaximum() - ch)
|
|
|
|
origin.y = -vertical.getMaximum() + ch;
|
|
|
|
} else { /* image is less higher than client area */
|
|
|
|
vertical.setMaximum((int) (ch));
|
|
|
|
vertical.setEnabled(false);
|
|
|
|
}
|
|
|
|
vertical.setSelection(-origin.y);
|
|
|
|
vertical.setThumb(ch);
|
2015-01-21 21:58:35 +01:00
|
|
|
ruler.setScaleFactor(scaleFactor);
|
2015-01-20 18:50:15 +01:00
|
|
|
redraw();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Paint function */
|
|
|
|
private void paint(GC gc) {
|
|
|
|
Rectangle clientRect = getClientArea(); /* Canvas' painting area */
|
|
|
|
clientRect.x=-origin.x;
|
|
|
|
clientRect.y=-origin.y;
|
|
|
|
// reset the transform
|
|
|
|
transform.identity();
|
|
|
|
// shift the content
|
|
|
|
transform.translate(origin.x, origin.y);
|
|
|
|
gc.setTransform(transform);
|
|
|
|
gc.setClipping(clientRect);
|
|
|
|
if (painterList.size()>0 && trackVerticalOffset.size()>0) {
|
|
|
|
for(IPainter painter: painterList)
|
|
|
|
painter.paintArea(gc, clientRect);
|
|
|
|
} else {
|
|
|
|
gc.fillRectangle(clientRect);
|
|
|
|
initScrollBars();
|
|
|
|
}
|
|
|
|
}
|
2015-01-21 21:58:35 +01:00
|
|
|
|
|
|
|
public Object getClicked(Point point) {
|
|
|
|
for(IPainter p:Lists.reverse(painterList)){
|
|
|
|
if(p instanceof TrackPainter){
|
|
|
|
int y= point.y-origin.y;
|
|
|
|
int x=point.x-origin.x;
|
|
|
|
Entry<Integer, IWaveformPainter> entry = trackVerticalOffset.floorEntry(y);
|
|
|
|
if(entry!=null){
|
|
|
|
if(entry.getValue() instanceof StreamPainter){
|
|
|
|
return ((StreamPainter)entry.getValue()).getClicked(new Point(x,y-entry.getKey()));
|
|
|
|
}else if(entry.getValue() instanceof SignalPainter)
|
|
|
|
return ((SignalPainter)entry.getValue()).getSignal();
|
|
|
|
}
|
|
|
|
}else if(p instanceof CursorPainter){
|
|
|
|
if(Math.abs(point.x*scaleFactor-((CursorPainter)p).getTime())<2){
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setSelected(ITx currentSelection, IWaveform<? extends IWaveformEvent> currentWaveformSelection) {
|
|
|
|
this.currentSelection=currentSelection;
|
|
|
|
this.currentWaveformSelection=currentWaveformSelection;
|
|
|
|
if(currentSelection!=null) reveal(currentSelection.getBeginTime(), currentSelection.getEndTime());
|
|
|
|
redraw();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void reveal(Long beginTime, Long endTime) {
|
|
|
|
int lower = (int) (beginTime/scaleFactor);
|
|
|
|
int higher=(int) (endTime/scaleFactor);
|
|
|
|
Point size = getSize();
|
|
|
|
if(lower<-origin.x){
|
|
|
|
scrollToX(lower);
|
|
|
|
} else if(higher>(size.x-origin.x)){
|
|
|
|
scrollToX(higher-size.x);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-20 18:50:15 +01:00
|
|
|
}
|