Skip to content
This repository was archived by the owner on Mar 25, 2019. It is now read-only.

Commit 7dc5577

Browse files
committed
Zoom by Mouse implemented
1 parent 839baad commit 7dc5577

File tree

5 files changed

+189
-12
lines changed

5 files changed

+189
-12
lines changed

src/xyz/elmot/clion/charttool/ChartsPanel.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@
1010
import javafx.scene.chart.NumberAxis;
1111
import javafx.scene.chart.XYChart;
1212
import javafx.scene.control.Button;
13+
import javafx.scene.layout.HBox;
1314
import javafx.scene.layout.Priority;
1415
import javafx.scene.layout.VBox;
1516
import org.jetbrains.annotations.NotNull;
1617
import xyz.elmot.clion.charttool.state.ChartExpr;
1718
import xyz.elmot.clion.charttool.state.ExpressionState;
19+
import xyz.elmot.clion.charttool.ui.Zoomer;
1820

1921
import java.util.*;
2022
import java.util.concurrent.ConcurrentHashMap;
@@ -26,29 +28,31 @@ public class ChartsPanel extends JFXPanel {
2628
private boolean initialized = false;
2729
public static final int MAX_SERIES = 50;
2830

29-
private Button reset;
3031
private LineChart<Number, Number> lineChart;
3132
private Map<String, ChartExpressionData> seriesByName = new ConcurrentHashMap<>();
3233

3334
public ChartsPanel() {
3435
Platform.runLater(() -> {
3536

36-
reset = new Button("Clear");
37+
Button reset = new Button("Clear");
3738
reset.setOnAction(e -> clear());
39+
Button noZoom = new Button("Reset Zoom");
3840
//defining the axes
3941
final NumberAxis xAxis = new NumberAxis();
4042
final NumberAxis yAxis = new NumberAxis();
4143
//creating the chart
4244
lineChart = new LineChart<>(xAxis, yAxis);
4345
lineChart.setCreateSymbols(false);
4446

45-
VBox vBox = new VBox(10, lineChart, reset);
47+
Zoomer zoomer = new Zoomer(lineChart);
48+
noZoom.setOnAction(e -> zoomer.resetZoom());
49+
VBox vBox = new VBox(10, zoomer, new HBox(10,reset,noZoom));
4650
vBox.setPadding(new Insets(10));
4751
Scene scene = new Scene(vBox);
4852

4953
lineChart.setAnimated(false);
5054
vBox.setFillWidth(true);
51-
VBox.setVgrow(lineChart, Priority.ALWAYS);
55+
VBox.setVgrow(zoomer, Priority.ALWAYS);
5256
lineChart.setScaleShape(true);
5357
setScene(scene);
5458
invalidate();

src/xyz/elmot/clion/charttool/DebugListener.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
import com.intellij.openapi.application.ApplicationManager;
44
import com.intellij.openapi.project.Project;
5+
import com.intellij.openapi.ui.MessageType;
6+
import com.intellij.openapi.wm.ToolWindowId;
7+
import com.intellij.openapi.wm.ToolWindowManager;
58
import com.intellij.xdebugger.XDebugSession;
69
import com.intellij.xdebugger.XDebugSessionListener;
710
import com.intellij.xdebugger.XDebuggerManager;
@@ -15,11 +18,14 @@
1518
import xyz.elmot.clion.charttool.state.ChartExpr;
1619
import xyz.elmot.clion.charttool.state.ExpressionState;
1720
import xyz.elmot.clion.charttool.state.LineState;
21+
import xyz.elmot.clion.openocd.Informational;
22+
import xyz.elmot.clion.openocd.OpenOcdConfigurationType;
1823
import xyz.elmot.clion.openocd.OpenOcdLauncher;
1924

2025
import java.util.ArrayList;
2126
import java.util.List;
2227
import java.util.StringTokenizer;
28+
import java.util.concurrent.ExecutionException;
2329
import java.util.concurrent.TimeUnit;
2430
import java.util.regex.Pattern;
2531

@@ -99,11 +105,28 @@ private void sampleChart(@NotNull CidrDebugProcess debugProcess) {
99105
.requestValue("p/r " + expressionTrim))
100106
);
101107
try {
102-
String evalResult = sinDataPromise.onError(e -> showError(e, expressionTrim))
108+
String evalResult = sinDataPromise
103109
.blockingGet(20, TimeUnit.SECONDS);
104110
processGdbOutput(evalResult, chartExpr);
111+
} catch (ExecutionException e) {
112+
ApplicationManager.getApplication().invokeLater(() ->
113+
{
114+
ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project);
115+
if (toolWindowManager.canShowNotification(ToolWindowId.RUN)) {
116+
Throwable t = e;
117+
while (t.getCause() != null) {
118+
t = t.getCause();
119+
}
120+
String localizedMessage = t.getLocalizedMessage();
121+
toolWindowManager.notifyByBalloon(ToolWindowId.DEBUG, MessageType.WARNING,
122+
expressionTrim + ": " + localizedMessage,
123+
OpenOcdConfigurationType.getPluginIcon(), null
124+
);
125+
}
126+
}
127+
);
105128
} catch (Throwable e) {
106-
showError(e, expressionTrim);//todo do not show the dialog
129+
showError(e, expressionTrim);
107130
}
108131

109132
}

src/xyz/elmot/clion/charttool/SignalSources.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public class SignalSources extends JBSplitter implements XDebuggerManagerListene
3030

3131
public SignalSources(Project project, DebugListener debugListener, ChartToolPersistence persistence,
3232
ChartsPanel chartsPanel) {
33-
super(false, 0.5f, 0.1f, 0.9f);
33+
super(true, 0.5f, 0.1f, 0.9f);
3434
setBorder(JBUI.Borders.empty(15));
3535
this.project = project;
3636
this.debugListener = debugListener;

src/xyz/elmot/clion/charttool/ui/ExpressionList.java

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package xyz.elmot.clion.charttool.ui;
22

33
import com.intellij.openapi.ui.DialogBuilder;
4+
import com.intellij.openapi.ui.DialogWrapper;
45
import com.intellij.ui.AddEditRemovePanel;
6+
import com.intellij.ui.DocumentAdapter;
57
import com.intellij.ui.components.JBLabel;
68
import com.intellij.ui.components.JBPanel;
79
import com.intellij.ui.components.JBTextField;
@@ -11,7 +13,13 @@
1113
import xyz.elmot.clion.charttool.state.ChartExpr;
1214
import xyz.elmot.clion.charttool.state.ExpressionState;
1315

16+
import javax.swing.*;
17+
import javax.swing.event.DocumentEvent;
18+
import javax.swing.text.JTextComponent;
1419
import java.awt.*;
20+
import java.awt.event.ActionEvent;
21+
import java.beans.PropertyChangeListener;
22+
import java.util.function.Consumer;
1523
import java.util.stream.Stream;
1624

1725
public class ExpressionList extends AddEditRemovePanel<ChartExpr> {
@@ -84,7 +92,6 @@ protected ChartExpr editItem(ChartExpr chartExpr) {
8492
@Nullable
8593
private ChartExpr doEdit(ChartExpr chartExpr) {
8694
JBTextField expressionField = new JBTextField();
87-
// expressionField.getDocument().addDocumentListener(e->);//todo enable/disable OK
8895
JBTextField nameField = new JBTextField();
8996
JBTextField baseXField = new JBTextField();
9097
JBTextField baseYField = new JBTextField();
@@ -120,7 +127,24 @@ private ChartExpr doEdit(ChartExpr chartExpr) {
120127
.centerPanel(dataPanel)
121128
.title("Edit expression");
122129
dialogBuilder.addOkAction();
130+
expressionField.getDocument().addDocumentListener(new DocumentAdapter() {
131+
@Override
132+
protected void textChanged(DocumentEvent e) {
133+
dialogBuilder.setOkActionEnabled(!expressionField.getText().trim().isEmpty());
134+
}
135+
});
136+
123137
dialogBuilder.addCancelAction();
138+
dialogBuilder.addAction(new AbstractAction("Reset") {
139+
@Override
140+
public void actionPerformed(ActionEvent e) {
141+
baseXField.setText("" + 0.0);
142+
baseYField.setText("" + 0.0);
143+
scaleXField.setText("" + 1.0);
144+
scaleYField.setText("" + 1.0);
145+
146+
}
147+
});
124148

125149
expressionField.setText(chartExpr.getExpression());
126150
nameField.setText(chartExpr.getName());
@@ -136,16 +160,23 @@ private ChartExpr doEdit(ChartExpr chartExpr) {
136160
chartExpr.setName(nameField.getText().trim());
137161
chartExpr.setState(stateGroup.getSelectedValue());
138162

139-
chartExpr.setXBase(Double.parseDouble(baseXField.getText()));
140-
chartExpr.setYBase(Double.parseDouble(baseYField.getText()));
163+
setDouble(baseXField, chartExpr::setXBase);
164+
setDouble(baseYField, chartExpr::setYBase);
141165

142-
chartExpr.setXScale(Double.parseDouble(scaleXField.getText()));
143-
chartExpr.setYScale(Double.parseDouble(scaleYField.getText()));
166+
setDouble(scaleXField, chartExpr::setXScale);
167+
setDouble(scaleYField, chartExpr::setYScale);
144168

145169
persistence.registerChange();
146170
updateRunner.run();
147171
return chartExpr;
148172
}
149173
return null;
150174
}
175+
176+
private void setDouble(JTextComponent field, Consumer<Double> target) {
177+
try {
178+
target.accept(Double.parseDouble(field.getText()));
179+
} catch (NumberFormatException ignore) {
180+
}
181+
}
151182
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package xyz.elmot.clion.charttool.ui;
2+
3+
import javafx.geometry.Bounds;
4+
import javafx.scene.Node;
5+
import javafx.scene.chart.ValueAxis;
6+
import javafx.scene.chart.XYChart;
7+
import javafx.scene.input.MouseButton;
8+
import javafx.scene.input.MouseEvent;
9+
import javafx.scene.layout.StackPane;
10+
import javafx.scene.paint.Color;
11+
import javafx.scene.shape.Rectangle;
12+
13+
import java.util.LinkedList;
14+
15+
public class Zoomer extends StackPane {
16+
17+
public static final int ZOOM_GO_BACK_DEPTH = 5;
18+
private final XYChart<Number, Number> chart;
19+
20+
private double zoomStartX = -1;
21+
private double zoomStartY = -1;
22+
private final Rectangle zoomRectangle;
23+
private final Node chartBackground;
24+
private final ValueAxis<Number> xAxis;
25+
private final ValueAxis<Number> yAxis;
26+
private final LinkedList<double[]> zoomStack = new LinkedList<>();
27+
28+
public Zoomer(XYChart<Number, Number> chart) {
29+
super(chart);
30+
this.chart = chart;
31+
zoomRectangle = new Rectangle(0, 0, new Color(0, 0.5, 1, 0.2));
32+
zoomRectangle.setManaged(false);
33+
getChildren().add(zoomRectangle);
34+
chartBackground = chart.lookup(".chart-plot-background");
35+
chartBackground.setOnMouseDragged(this::mouseEventDrag);
36+
chartBackground.setOnMousePressed(this::mouseEventPress);
37+
chartBackground.setOnMouseReleased(this::mouseEventRelease);
38+
chartBackground.setOnMouseClicked(this::mouseEventClick);
39+
xAxis = (ValueAxis<Number>) chart.getXAxis();
40+
yAxis = (ValueAxis<Number>) chart.getYAxis();
41+
}
42+
43+
44+
private void mouseEventClick(MouseEvent mouseEvent) {
45+
if (mouseEvent.getButton() == MouseButton.SECONDARY) {
46+
if (zoomStack.isEmpty()) {
47+
resetZoom();
48+
} else {
49+
double[] zoom = zoomStack.pop();
50+
xAxis.setLowerBound(zoom[0]);
51+
xAxis.setUpperBound(zoom[1]);
52+
yAxis.setLowerBound(zoom[2]);
53+
yAxis.setUpperBound(zoom[3]);
54+
55+
}
56+
}
57+
}
58+
59+
private void mouseEventDrag(MouseEvent mouseEvent) {
60+
if (zoomStartX >= 0) {
61+
Bounds bounds = chartBackground.localToScene(chartBackground.getBoundsInLocal());
62+
double sceneX = mouseEvent.getSceneX();
63+
if (zoomStartX > sceneX) {
64+
zoomRectangle.setX(Math.max(bounds.getMinX(), sceneX));
65+
zoomRectangle.setWidth(Math.min(bounds.getMaxX(), zoomStartX) - zoomRectangle.getX());
66+
} else {
67+
zoomRectangle.setX(zoomStartX);
68+
zoomRectangle.setWidth(Math.min(bounds.getMaxX(), sceneX) - zoomRectangle.getX());
69+
}
70+
double sceneY = mouseEvent.getSceneY();
71+
if (zoomStartY > sceneY) {
72+
zoomRectangle.setY(Math.max(bounds.getMinX(), sceneY));
73+
zoomRectangle.setHeight(Math.min(bounds.getMaxY(), zoomStartY) - zoomRectangle.getY());
74+
} else {
75+
zoomRectangle.setY(zoomStartY);
76+
zoomRectangle.setHeight(Math.min(bounds.getMaxY(), sceneY) - zoomRectangle.getY());
77+
}
78+
79+
zoomRectangle.setVisible(true);
80+
}
81+
}
82+
83+
private void mouseEventPress(MouseEvent event) {
84+
if (zoomStartX < 0 && event.getButton() == MouseButton.PRIMARY) {
85+
zoomStartX = event.getSceneX();
86+
zoomStartY = event.getSceneY();
87+
}
88+
}
89+
90+
private void mouseEventRelease(MouseEvent mouseEvent) {
91+
if (zoomStartX >= 0 && mouseEvent.getButton() == MouseButton.PRIMARY) {
92+
Bounds bounds = xAxis.localToScene(xAxis.getLayoutBounds());
93+
Number minZoomX = xAxis.getValueForDisplay(zoomRectangle.getX() - bounds.getMinX());
94+
Number maxZoomX = xAxis.getValueForDisplay(zoomRectangle.getX() + zoomRectangle.getWidth() - bounds.getMinX());
95+
bounds = yAxis.localToScene(yAxis.getLayoutBounds());
96+
Number maxZoomY = yAxis.getValueForDisplay(zoomRectangle.getY() - bounds.getMinY());
97+
Number minZoomY = yAxis.getValueForDisplay(zoomRectangle.getY() + zoomRectangle.getWidth() - bounds.getMinY());
98+
if (!xAxis.isAutoRanging()) {
99+
zoomStack.push(new double[]{xAxis.getLowerBound(), xAxis.getUpperBound(), yAxis.getLowerBound(), yAxis.getUpperBound()});
100+
}
101+
xAxis.setAutoRanging(false);
102+
xAxis.setLowerBound(minZoomX.doubleValue());
103+
xAxis.setUpperBound(maxZoomX.doubleValue());
104+
yAxis.setAutoRanging(false);
105+
yAxis.setLowerBound(minZoomY.doubleValue());
106+
yAxis.setUpperBound(maxZoomY.doubleValue());
107+
while (zoomStack.size() > ZOOM_GO_BACK_DEPTH) {
108+
zoomStack.removeLast();
109+
}
110+
zoomStartX = zoomStartY = -1;
111+
zoomRectangle.setVisible(false);
112+
}
113+
}
114+
public void resetZoom() {
115+
xAxis.setAutoRanging(true);
116+
yAxis.setAutoRanging(true);
117+
zoomStack.clear();
118+
}
119+
}

0 commit comments

Comments
 (0)