diff --git a/src/main/java/de/neemann/digital/gui/components/data/DataSet.java b/src/main/java/de/neemann/digital/gui/components/data/DataSet.java index 297e98167..3715916ad 100644 --- a/src/main/java/de/neemann/digital/gui/components/data/DataSet.java +++ b/src/main/java/de/neemann/digital/gui/components/data/DataSet.java @@ -24,6 +24,7 @@ public class DataSet implements Iterable, Drawable { private final int maxTextLength; private DataSample min; private DataSample max; + private double size = SIZE; /** * Creates a simple dummy DataSet used for creating the DataShape @@ -138,6 +139,25 @@ public class DataSet implements Iterable, Drawable { private static final int SEP2 = 5; private static final int SEP = SEP2 * 2; + /** + * Fits the data in the visible area + * + * @param width width of the frame + */ + public void fitInside(int width) { + size = ((double) (width - getTextBorder())) / size(); + } + + /** + * Apply a scaling factor + * + * @param f the factor + */ + public void scale(double f) { + size *= f; + if (size < Style.NORMAL.getThickness()) size = Style.NORMAL.getThickness(); + if (size > SIZE * 4) size = SIZE * 4; + } @Override synchronized public void drawTo(Graphic g, Style highLight) { @@ -148,32 +168,33 @@ public class DataSet implements Iterable, Drawable { for (int i = 0; i < signalSize(); i++) { String text = getSignal(i).getName(); g.drawText(new Vector(x - 2, y + yOffs), new Vector(x + 1, y + yOffs), text, Orientation.RIGHTCENTER, Style.NORMAL); - g.drawLine(new Vector(x, y - SEP2), new Vector(x + SIZE * size(), y - SEP2), Style.DASH); + g.drawLine(new Vector(x, y - SEP2), new Vector(x + (int) (size * size()), y - SEP2), Style.DASH); y += SIZE + SEP; } - g.drawLine(new Vector(x, y - SEP2), new Vector(x + SIZE * size(), y - SEP2), Style.DASH); + g.drawLine(new Vector(x, y - SEP2), new Vector(x + (int) (size * size()), y - SEP2), Style.DASH); int[] lastRy = new int[signalSize()]; boolean first = true; + double pos = 0; for (DataSample s : this) { - g.drawLine(new Vector(x, BORDER - SEP2), new Vector(x, (SIZE + SEP) * signalSize() + BORDER - SEP2), Style.DASH); + int xx = (int) (pos + x); + g.drawLine(new Vector(xx, BORDER - SEP2), new Vector(xx, (SIZE + SEP) * signalSize() + BORDER - SEP2), Style.DASH); y = BORDER; for (int i = 0; i < signalSize(); i++) { long width = getWidth(i); if (width == 0) width = 1; - //int ry = (int) (SIZE-(SIZE*(s.getValue(i)-dataSet.getMin().getValue(i)))/ width); int ry = (int) (SIZE - (SIZE * s.getValue(i)) / width); - g.drawLine(new Vector(x, y + ry), new Vector(x + SIZE, y + ry), Style.NORMAL); + g.drawLine(new Vector(xx, y + ry), new Vector((int) (xx + size), y + ry), Style.NORMAL); if (!first && ry != lastRy[i]) - g.drawLine(new Vector(x, y + lastRy[i]), new Vector(x, y + ry), Style.NORMAL); + g.drawLine(new Vector(xx, y + lastRy[i]), new Vector(xx, y + ry), Style.NORMAL); lastRy[i] = ry; y += SIZE + SEP; } first = false; - x += SIZE; + pos += size; } g.drawLine(new Vector(x, BORDER - SEP2), new Vector(x, (SIZE + SEP) * signalSize() + BORDER - SEP2), Style.DASH); } @@ -196,6 +217,13 @@ public class DataSet implements Iterable, Drawable { return signalSize() * (SIZE + SEP) + 2 * BORDER; } + /** + * @return the current width of the graphical representation + */ + public int getCurrentGraphicWidth() { + return getTextBorder() + (int) (size() * size); + } + /** * @return the signals stored */ diff --git a/src/main/java/de/neemann/digital/gui/components/data/DataSetComponent.java b/src/main/java/de/neemann/digital/gui/components/data/DataSetComponent.java index b30230055..669ce92fc 100644 --- a/src/main/java/de/neemann/digital/gui/components/data/DataSetComponent.java +++ b/src/main/java/de/neemann/digital/gui/components/data/DataSetComponent.java @@ -21,6 +21,10 @@ public class DataSetComponent extends JComponent { */ public DataSetComponent(DataSet dataSet) { this.dataSet = dataSet; + addMouseWheelListener(e -> { + double f = Math.pow(0.9, e.getWheelRotation()); + scale(f); // ToDo keep relative mouse position + }); } @Override @@ -34,8 +38,30 @@ public class DataSetComponent extends JComponent { @Override public Dimension getPreferredSize() { - int w = dataSet.getGraphicWidth(); + int w = dataSet.getCurrentGraphicWidth(); if (w < 600) w = 600; return new Dimension(w, dataSet.getGraphicHeight()); } + + /** + * Apply a scaling factor + * + * @param f the factor + */ + public void scale(double f) { + revalidate(); + repaint(); + dataSet.scale(f); + } + + /** + * Fits the data to the visible area + * + * @param width the clients width + */ + public void fitData(int width) { + dataSet.fitInside(width); + revalidate(); + repaint(); + } } diff --git a/src/main/java/de/neemann/digital/gui/components/data/DataSetDialog.java b/src/main/java/de/neemann/digital/gui/components/data/DataSetDialog.java index e3096b131..3cb3e3dbc 100644 --- a/src/main/java/de/neemann/digital/gui/components/data/DataSetDialog.java +++ b/src/main/java/de/neemann/digital/gui/components/data/DataSetDialog.java @@ -8,6 +8,7 @@ import de.neemann.digital.gui.SaveAsHelper; import de.neemann.digital.gui.components.OrderMerger; import de.neemann.digital.gui.sync.Sync; import de.neemann.digital.lang.Lang; +import de.neemann.gui.IconCreator; import de.neemann.gui.MyFileChooser; import de.neemann.gui.ToolTipAction; @@ -33,6 +34,10 @@ public class DataSetDialog extends JDialog implements ModelStateObserver { private DataSet dataSet; private DataSetObserver dataSetObserver; + private static final Icon ICON_EXPAND = IconCreator.create("View-zoom-fit.png"); + private static final Icon ICON_ZOOM_IN = IconCreator.create("View-zoom-in.png"); + private static final Icon ICON_ZOOM_OUT = IconCreator.create("View-zoom-out.png"); + /** * Creates a new instance * @@ -64,6 +69,33 @@ public class DataSetDialog extends JDialog implements ModelStateObserver { scrollPane = new JScrollPane(dsc); getContentPane().add(scrollPane); + JToolBar toolBar = new JToolBar(); + ToolTipAction maximize = new ToolTipAction(Lang.get("menu_maximize"), ICON_EXPAND) { + @Override + public void actionPerformed(ActionEvent e) { + dsc.fitData(scrollPane.getWidth() - scrollPane.getInsets().left - scrollPane.getInsets().right); + } + }.setAccelerator("F1"); + ToolTipAction zoomIn = new ToolTipAction(Lang.get("menu_zoomIn"), ICON_ZOOM_IN) { + @Override + public void actionPerformed(ActionEvent e) { + dsc.scale(1.25f); + } + }.setAccelerator("control PLUS"); + ToolTipAction zoomOut = new ToolTipAction(Lang.get("menu_zoomOut"), ICON_ZOOM_OUT) { + @Override + public void actionPerformed(ActionEvent e) { + dsc.scale(0.8f); + } + }.setAccelerator("control MINUS"); + + toolBar.add(zoomIn.createJButtonNoText()); + toolBar.add(zoomOut.createJButtonNoText()); + toolBar.add(maximize.createJButtonNoText()); + + getContentPane().add(toolBar, BorderLayout.NORTH); + pack(); + addWindowListener(new WindowAdapter() { @Override public void windowOpened(WindowEvent e) { @@ -90,8 +122,14 @@ public class DataSetDialog extends JDialog implements ModelStateObserver { .checkOverwrite(file -> dataSet.saveCSV(file)); } }.setToolTip(Lang.get("menu_saveData_tt")).createJMenuItem()); - setJMenuBar(bar); + JMenu view = new JMenu(Lang.get("menu_view")); + bar.add(view); + view.add(maximize.createJMenuItem()); + view.add(zoomOut.createJMenuItem()); + view.add(zoomIn.createJMenuItem()); + + setJMenuBar(bar); pack(); setLocationRelativeTo(owner); } @@ -112,8 +150,10 @@ public class DataSetDialog extends JDialog implements ModelStateObserver { SwingUtilities.invokeLater(() -> { dsc.revalidate(); dsc.repaint(); - JScrollBar bar = scrollPane.getHorizontalScrollBar(); - bar.setValue(bar.getMaximum()); + SwingUtilities.invokeLater(() -> { + JScrollBar bar = scrollPane.getHorizontalScrollBar(); + bar.setValue(bar.getMaximum()); + }); }); } }