package plots.views;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Sash;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.part.ViewPart;
public class PlotView extends ViewPart {
private static final String PLOT_VIEW_KEY = "plotView";
private static final int SASH_HEIGHT = 6;
private Action actionImportData;
private Composite parent;
private List<PlotViewer> viewers = new ArrayList<>();
// the global domain range, i.e. the portion of data
// to display
private int[] xrange = new int[] {0, 0};
private float xscale = 1;
private Action actionZoomIn;
/**
* The constructor.
*/
public PlotView() {
}
/**
* This is a callback that will allow us
* to create the viewer and initialize it.
*/
public void createPartControl(Composite parent) {
this.parent = parent;
GridLayoutFactory.fillDefaults().spacing(0, 0).applyTo(parent);
parent.setData(PLOT_VIEW_KEY, this);
// TODO: this is some initial data just for testing
addPlotViewer(parent, demoData());
addPlotViewer(parent, demoData());
parent.addMouseWheelListener(PlotView::mouseWheelMoved);
// view actions
makeActions();
contributeToActionBars();
}
// just for testing purposes
private int[] demoData() {
int[] vals;
vals = new int[1000];
int v = 37;
for (int i = 0; i < vals.length; i++) {
vals[i] = v;
v = (int) (v + (Math.random() - 0.5) * 10) % 100;
}
return vals;
}
private void addPlotViewer(Composite parent, int[] data) {
Sash sash = null;
PlotViewer plotViewer = new PlotViewer(parent);
plotViewer.addPlot(data);
sash = new Sash(parent, SWT.HORIZONTAL);
GridDataFactory.fillDefaults().grab(true, false).hint(SWT.DEFAULT, SASH_HEIGHT).applyTo(sash);
sash.addListener(SWT.Selection, PlotView::onSashMoved);
sash.setData(plotViewer);
plotViewer.colors.add(new Color(Display.getDefault(), 0, 0, 0));
plotViewer.colors.add(new Color(Display.getDefault(), 255, 0, 0));
plotViewer.sash = sash;
viewers.add(plotViewer);
plotViewer.canvas.addDisposeListener(e -> {
boolean removed = viewers.remove(e.widget.getData());
System.out.println("removed viewer :" + removed);
});
plotViewer.onRectChange(r -> {setAllRects(r); });
updateXRange(data);
parent.redraw();
parent.layout();
}
private void updateXRange(int[] data) {
// TODO: this should actually look in the domain array...
if (xrange[1] < data.length) {
xrange[1] = data.length;
}
updateDomainRangeAll();
}
private void updateDomainRangeAll() {
// notify all viewers about the new range
for (PlotViewer plotViewer : viewers) {
plotViewer.setDomainRange((int)(xrange[0] * xscale), (int)(xrange[1] * xscale));
}
}
private void setAllRects(Rectangle r) {
for (PlotViewer plotViewer : viewers)
plotViewer.setPlotRect(r);
}
private static void onSashMoved(Event e) {
Sash s = (Sash) e.widget;
PlotViewer pv = (PlotViewer) s.getData();
Rectangle sashBounds = e.getBounds();
System.out.println("Sash moved to:" + sashBounds);
Rectangle bounds = pv.canvas.getBounds();
int newh = sashBounds.y - bounds.y;
if (newh > 5) {
GridData gd = (GridData) pv.canvas.getLayoutData();
gd.heightHint = newh;
pv.canvas.getParent().layout();
pv.canvas.getParent().redraw();
}
}
private static void mouseWheelMoved(MouseEvent e) {
// check if CTRL/CMD is pressed
if ((e.stateMask & SWT.MOD1) == 0)
return;
Composite parent = (Composite) e.widget;
PlotView plotView = (PlotView) parent.getData(PLOT_VIEW_KEY);
if (plotView != null) {
if (e.count > 0)
plotView.xscale *= 1.2; // UP -> zoom in
else
plotView.xscale /= 1.2; // DOWN -> zoom out
System.out.printf("Update domain to plots: [%d,%d]x%f\n",
plotView.xrange[0],
plotView.xrange[1], plotView.xscale);
plotView.updateDomainRangeAll();
plotView.parent.redraw();
}
// find the plot view under the cursor
// PlotViewer pv = null;
// int x = 0;
// for (Control c : parent.getChildren()) {
// Rectangle bounds = c.getBounds();
// if (bounds.contains(e.x, e.y)) {
// if (c instanceof Canvas) {
// Canvas canvas = (Canvas) c;
// pv = (PlotViewer) canvas.getData();
// x = e.x - bounds.x;
// }
// break;
// }
// }
// if (pv == null)
// return;
//
// if (e.count > 0)
// pv.zoomIn(x); // UP -> zoom in
// else
// pv.zoomOut(x); // DOWN -> zoom out
}
private void contributeToActionBars() {
IActionBars bars = getViewSite().getActionBars();
bars.getMenuManager().add(actionImportData);
bars.getToolBarManager().add(actionImportData);
bars.getToolBarManager().add(actionZoomIn);
}
private void makeActions() {
actionImportData = new LambdaAction("+", "Add plot",
e -> {
ImportDataFromTextDialog dialog = new ImportDataFromTextDialog(getSite().getShell());
dialog.listOpenEditors(getSite().getWorkbenchWindow());
if (dialog.open() == Dialog.OK) {
int[] data = dialog.getData();
// TODO: option to import into an existing plot
addPlotViewer(parent, data);
parent.redraw();
}
});
actionZoomIn = new LambdaAction("><", "Zoom In",
e -> {
xscale *= 1.2; // UP -> zoom in
System.out.printf("Update domain to plots: [%d,%d]x%f\n",
xrange[0],
xrange[1], xscale);
updateDomainRangeAll();
parent.redraw();
Control[] children = parent.getChildren();
for (Control c : children) {
c.redraw();
}
});
}
/**
* Passing the focus request to the viewer's control.
*/
public void setFocus() {
parent.setFocus();
// getCanvas().setFocus();
}
}