/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: Panel.java * * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. * * Electric(tm) is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Electric(tm) is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Electric(tm); see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, Mass 02111-1307, USA. */ package com.sun.electric.tool.user.waveform; import com.sun.electric.Main; import com.sun.electric.database.geometry.Poly; import com.sun.electric.database.geometry.PolyBase; import com.sun.electric.database.variable.TextDescriptor; import com.sun.electric.technology.technologies.Artwork; import com.sun.electric.tool.simulation.BusSample; import com.sun.electric.tool.simulation.DigitalSample; import com.sun.electric.tool.simulation.RangeSample; import com.sun.electric.tool.simulation.Sample; import com.sun.electric.tool.simulation.ScalarSample; import com.sun.electric.tool.simulation.Signal; import com.sun.electric.tool.simulation.SweptSample; import com.sun.electric.tool.user.Highlight; import com.sun.electric.tool.user.Resources; import com.sun.electric.tool.user.User; import com.sun.electric.tool.user.dialogs.WaveformZoom; import com.sun.electric.tool.user.ui.ClickZoomWireListener; import com.sun.electric.tool.user.ui.ToolBar; import com.sun.electric.tool.user.ui.ZoomAndPanListener; import com.sun.electric.util.TextUtils; import com.sun.electric.util.math.GenMath; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Cursor; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Frame; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Image; import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTarget; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.awt.font.GlyphVector; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.awt.image.VolatileImage; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Set; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.ScrollPaneConstants; /** * This class defines a single panel of WaveSignals with an associated list of signal names. */ public class Panel extends JPanel implements MouseMotionListener, MouseListener, MouseWheelListener, KeyListener { /** Use VolatileImage for offscreen buffer */ private static final boolean USE_VOLATILE_IMAGE = false; /** Use anti-aliasing for lines */ private static final boolean USE_ANTIALIASING = false; /** Spacing above and below each panel */ private static final int PANELGAP = 2; /** the main waveform window this is part of */ private WaveformWindow waveWindow; /** the size of the window (in pixels) */ private Dimension sz; /** true if the size field is valid */ private boolean szValid; /** the signal on the X axis (null for time) */ private Signal<?> xAxisSignal; /** maps signal button panels to the actual Signal */ private LinkedHashMap<JComponent,WaveSignal> waveSignals = new LinkedHashMap<JComponent,WaveSignal>(); /** the list of signal name buttons on the left */ private JPanel signalButtons; /** the highest index of new signal buttons */ private int signalButtonsHighIndex; /** the JScrollPane with of signal name buttons */ private JScrollPane signalButtonsPane; /** the left side: with signal names etc. */ private JPanel leftHalf; /** the right side: with signal traces */ private JPanel rightHalf; /** the title of the panel */ private DragButton panelTitle; /** the button to close this panel. */ private JButton close; /** the button to hide this panel. */ private JButton hide; /** the button to delete selected signal. */ private JButton deleteSignal; /** the button to delete all signals. */ private JButton deleteAllSignals; /** displayed range along horizontal axis */ private double minXPosition, maxXPosition; /** low value displayed in this panel (analog) */ private double analogLowValue; /** high value displayed in this panel (analog) */ private double analogHighValue; /** vertical range displayed in this panel (analog) */ private double analogRange; /** true if an X axis cursor is being dragged */ private boolean draggingMain, draggingExt, draggingVertAxis; /** true if an area is being dragged */ private boolean draggingArea; /** list of measurements being displayed */ private List<Rectangle2D> measurementList; /** current measurement being displayed */ private Rectangle2D curMeasurement; /** true if this waveform panel is selected */ private boolean selected; /** true if this waveform panel is hidden */ private boolean hidden; /** the horizontal ruler at the top of this panel. */ private HorizRuler horizRulerPanel; /** true if the horizontal ruler is logarithmic */ private boolean horizRulerPanelLogarithmic; /** true if this panel is logarithmic in Y */ private boolean vertPanelLogarithmic; /** the number of this panel. */ private int panelNumber; /** extent of area dragged-out by cursor */ private double dragStartXD, dragStartYD; /** extent of area dragged-out by cursor */ private double dragEndXD, dragEndYD; /** the location of the Y axis vertical line */ private int vertAxisPos; /** the smallest nonzero X value (for log drawing) */ private double smallestXValue; /** the smallest nonzero Y value (for log drawing) */ private double smallestYValue; /** the background color of a button */ private Color background = null; /** for determining double-clicks */ private long lastClick = 0; // /** current panel */ private static Panel curPanel; // /** current X coordinate in the panel */ private static int curXPos; /** The color of the grid (a gray) */ private static final Color gridColor = new Color(0x808080); /** for drawing far-dotted lines */ private static final BasicStroke farDottedLine = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[] {4,12}, 0); /** the size of control point squares */ private static final int CONTROLPOINTSIZE = 6; /** the width of the panel label on the left */ private static final int VERTLABELWIDTH = 60; private static final ImageIcon iconHidePanel = Resources.getResource(WaveformWindow.class, "ButtonSimHide.gif"); private static final ImageIcon iconClosePanel = Resources.getResource(WaveformWindow.class, "ButtonSimClose.gif"); private static final ImageIcon iconDeleteSignal = Resources.getResource(WaveformWindow.class, "ButtonSimDelete.gif"); private static final ImageIcon iconDeleteAllSignals = Resources.getResource(WaveformWindow.class, "ButtonSimDeleteAll.gif"); private static final Cursor dragXPositionCursor = ToolBar.readCursor("CursorDragTime.gif", 8, 8); /** * Constructor creates a panel in a WaveformWindow. * @param waveWindow the WaveformWindow in which to place this Panel. */ public Panel(WaveformWindow waveWindow, int height) { // remember state this.waveWindow = waveWindow; selected = false; panelNumber = waveWindow.getNewPanelNumber(); vertAxisPos = VERTLABELWIDTH; horizRulerPanelLogarithmic = false; vertPanelLogarithmic = false; xAxisSignal = null; measurementList = new ArrayList<Rectangle2D>(); curMeasurement = null; // setup this panel window sz = new Dimension(50, height); szValid = false; setSize(sz.width, sz.height); setPreferredSize(sz); setLayout(new FlowLayout()); // add listeners --> BE SURE to remove listeners in finished() addKeyListener(this); addMouseListener(this); addMouseMotionListener(this); addMouseWheelListener(this); setXAxisRange(waveWindow.getLowDefaultHorizontalRange(), waveWindow.getHighDefaultHorizontalRange()); // the left side with signal names leftHalf = new WaveformWindow.OnePanel(this, waveWindow); leftHalf.setLayout(new GridBagLayout()); leftHalf.setPreferredSize(new Dimension(100, height)); // a drop target for the signal panel new DropTarget(leftHalf, DnDConstants.ACTION_LINK, waveWindow.waveformDropTarget, true); // // a separator at the top // JSeparator sep = new JSeparator(SwingConstants.HORIZONTAL); // GridBagConstraints gbc = new GridBagConstraints(); // gbc.gridx = 0; gbc.gridy = 0; // gbc.gridwidth = 5; gbc.gridheight = 1; // gbc.weightx = 1; gbc.weighty = 0; // gbc.anchor = GridBagConstraints.NORTH; // gbc.fill = GridBagConstraints.HORIZONTAL; // gbc.insets = new Insets(4, 0, 4, 0); // leftHalf.add(sep, gbc); // the name of this panel panelTitle = new DragButton("" + Integer.toString(panelNumber), panelNumber); panelTitle.setToolTipText("Identification number of this waveform panel (drag the number to rearrange panels)"); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 1; gbc.weightx = 1; gbc.weighty = 0; gbc.anchor = GridBagConstraints.WEST; gbc.insets = new Insets(2, 4, 2, 1); panelTitle.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { panelTitleClicked(evt); } }); leftHalf.add(panelTitle, gbc); // the close button for this panel close = new JButton(iconClosePanel); close.setBorderPainted(false); close.setDefaultCapable(false); close.setToolTipText("Close this waveform panel"); Dimension minWid = new Dimension(iconClosePanel.getIconWidth()+4, iconClosePanel.getIconHeight()+4); close.setMinimumSize(minWid); close.setPreferredSize(minWid); gbc = new GridBagConstraints(); gbc.gridx = 1; gbc.gridy = 1; gbc.fill = GridBagConstraints.NONE; gbc.insets = new Insets(0, 1, 0, 2); leftHalf.add(close, gbc); close.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { closePanel(); } }); // the hide button for this panel hide = new JButton(iconHidePanel); hide.setBorderPainted(false); hide.setDefaultCapable(false); hide.setToolTipText("Hide this waveform panel"); minWid = new Dimension(iconHidePanel.getIconWidth()+4, iconHidePanel.getIconHeight()+4); hide.setMinimumSize(minWid); hide.setPreferredSize(minWid); gbc = new GridBagConstraints(); gbc.gridx = 2; gbc.gridy = 1; gbc.fill = GridBagConstraints.NONE; gbc.insets = new Insets(0, 2, 0, 2); leftHalf.add(hide, gbc); hide.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { hidePanel(); } }); // the "delete signal" button for this panel deleteSignal = new JButton(iconDeleteSignal); deleteSignal.setBorderPainted(false); deleteSignal.setDefaultCapable(false); deleteSignal.setToolTipText("Remove selected signals from this panel"); minWid = new Dimension(iconDeleteSignal.getIconWidth()+4, iconDeleteSignal.getIconHeight()+4); deleteSignal.setMinimumSize(minWid); deleteSignal.setPreferredSize(minWid); gbc = new GridBagConstraints(); gbc.gridx = 3; gbc.gridy = 1; gbc.fill = GridBagConstraints.NONE; gbc.insets = new Insets(0, 2, 0, 2); leftHalf.add(deleteSignal, gbc); deleteSignal.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { deleteSignalFromPanel(); } }); // the "delete all signal" button for this panel deleteAllSignals = new JButton(iconDeleteAllSignals); deleteAllSignals.setBorderPainted(false); deleteAllSignals.setDefaultCapable(false); deleteAllSignals.setToolTipText("Remove all signals from this panel"); minWid = new Dimension(iconDeleteAllSignals.getIconWidth()+4, iconDeleteAllSignals.getIconHeight()+4); deleteAllSignals.setMinimumSize(minWid); deleteAllSignals.setPreferredSize(minWid); gbc = new GridBagConstraints(); gbc.gridx = 4; gbc.gridy = 1; gbc.fill = GridBagConstraints.NONE; gbc.insets = new Insets(0, 2, 0, 4); leftHalf.add(deleteAllSignals, gbc); deleteAllSignals.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { deleteAllSignalsFromPanel(); } }); // the list of signals in this panel signalButtonsHighIndex = 0; signalButtons = new JPanel(); signalButtons.setLayout(new GridBagLayout()); signalButtonsPane = new JScrollPane(signalButtons); signalButtonsPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 3; gbc.gridwidth = 5; gbc.gridheight = 1; gbc.weightx = 1; gbc.weighty = 1; gbc.anchor = GridBagConstraints.CENTER; gbc.fill = GridBagConstraints.BOTH; leftHalf.add(signalButtonsPane, gbc); // the right side with signal traces rightHalf = new JPanel(); rightHalf.setLayout(new GridBagLayout()); rightHalf.setPreferredSize(new Dimension(100, height)); // a drop target for the signal panel new DropTarget(this, DnDConstants.ACTION_LINK, waveWindow.waveformDropTarget, true); // // a separator at the top // sep = new JSeparator(SwingConstants.HORIZONTAL); // gbc = new GridBagConstraints(); // gbc.gridx = 0; gbc.gridy = 0; // gbc.weightx = 1; gbc.weighty = 0; // gbc.anchor = GridBagConstraints.NORTH; // gbc.fill = GridBagConstraints.HORIZONTAL; // gbc.insets = new Insets(4, 0, 4, 0); // rightHalf.add(sep, gbc); // the horizontal ruler (if separate rulers in each panel) if (!waveWindow.isXAxisLocked()) addHorizRulerPanel(); // the waveform display for this panel gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 2; gbc.weightx = 1; gbc.weighty = 1; gbc.anchor = GridBagConstraints.CENTER; gbc.fill = GridBagConstraints.BOTH; gbc.insets = new Insets(PANELGAP, 0, PANELGAP, 0); rightHalf.add(this, gbc); // add to list of wave panels waveWindow.addPanel(this); // put the left and right sides into the window waveWindow.getWaveformTable().repaint(); waveWindow.getWaveformTable().doLayout(); waveWindow.getWaveformTable().updateUI(); // rebuild list of panels waveWindow.rebuildPanelList(); waveWindow.redrawAllPanels(); } // ************************************* MISCELLANEOUS ************************************* public WaveformWindow getWaveWindow() { return waveWindow; } /** * Method to get rid of this Panel. */ public void finished() { // remove myself from listener list removeKeyListener(this); removeMouseListener(this); removeMouseMotionListener(this); removeMouseWheelListener(this); } public JPanel getLeftHalf() { return leftHalf; } public JPanel getRightHalf() { return rightHalf; } /** * Make this panel show a linear Y axis. */ private void makeLinear() { setPanelLogarithmicVertically(false); } /** * Make this panel show a logarithmic Y axis. */ private void makeLogarithmic() { setPanelLogarithmicVertically(true); } public void setPanelLogarithmicVertically(boolean logarithmic) { vertPanelLogarithmic = logarithmic; repaintContents(); } public boolean isAnalog() { for(JComponent comp : waveSignals.keySet()) { WaveSignal ws = waveSignals.get(comp); Signal<?> sig = ws.getSignal(); if (!sig.isDigital()) return true; } return false; } public JPanel getSignalButtons() { return signalButtons; }; public JScrollPane getSignalButtonsPane() { return signalButtonsPane; }; public int getPanelNumber() { return panelNumber; } public void setPanelLogarithmicHorizontally(boolean logarithmic) { horizRulerPanelLogarithmic = logarithmic; horizRulerPanel.repaint(); } public boolean isPanelLogarithmicHorizontally() { if (waveWindow.isXAxisLocked()) return waveWindow.isWaveWindowLogarithmic(); return horizRulerPanelLogarithmic; } public boolean isPanelLogarithmicVertically() { return vertPanelLogarithmic; } public int getVertAxisPos() { return vertAxisPos; } public void setVertAxisPos(int x) { vertAxisPos = x; } // public static Panel getCurrentPanel() { return curPanel; } // public static int getCurrentXPos() { return curXPos; } public Dimension getSz() { return sz; } // ************************************* SIGNALS IN THE PANEL ************************************* public void addSignal(WaveSignal sig, JComponent comp) { waveSignals.put(comp, sig); updatePanelTitle(); } /** * Method to change the title of the panel depending on the contents and size. */ public void updatePanelTitle() { String panelTitleName = "" + panelNumber; if (waveSignals.size() != 1) { if (waveSignals.size() != 0) panelTitleName += ": (" + waveSignals.size() + " SIGNALS)"; else panelTitleName += ": (NO SIGNALS)"; } else { boolean signalsVisible = false; JTable table = waveWindow.getWaveformTable(); for(int i=0; i<table.getRowCount(); i++) { if (this == waveWindow.getPanel(i)) { int rowHeight = table.getRowHeight(i); if (rowHeight >= 55) signalsVisible = true; } } if (!signalsVisible) { Collection<WaveSignal> justOneWS = waveSignals.values(); WaveSignal ws = justOneWS.iterator().next(); Signal<?> sig = ws.getSignal(); panelTitleName += ": " + sig.getSignalName(); } } panelTitle.setText(panelTitleName); } public void removeSignal(JComponent panel) { if (signalButtons != null) signalButtons.remove(panel); waveSignals.remove(panel); updatePanelTitle(); } public void removeAllSignals() { waveSignals.clear(); updatePanelTitle(); } /** * Method to return a List of WaveSignals in this panel. * @return a List of WaveSignals in this panel. */ public List<WaveSignal> getSignals() { List<WaveSignal> signals = new ArrayList<WaveSignal>(); for(JComponent comp : waveSignals.keySet()) { WaveSignal ws = waveSignals.get(comp); signals.add(ws); } return signals; } public int getNumSignals() { return waveSignals.size(); } public int getNewSignalButtonIndex() { return signalButtonsHighIndex++; } public WaveSignal findWaveSignal(Signal<?> sig) { for(JComponent comp : waveSignals.keySet()) { WaveSignal ws = waveSignals.get(comp); if (ws.getSignal() == sig) return ws; } return null; } public WaveSignal findWaveSignal(JComponent comp) { WaveSignal sig = waveSignals.get(comp); return sig; } public JComponent findButton(WaveSignal ws) { for(JComponent comp : waveSignals.keySet()) { WaveSignal oWs = waveSignals.get(comp); if (oWs == ws) return comp; } return null; } private void deleteSignalFromPanel() { waveWindow.deleteSignalFromPanel(this); } private void deleteAllSignalsFromPanel() { waveWindow.deleteAllSignalsFromPanel(this); } // ************************************* THE HORIZONTAL RULER ************************************* public void addHorizRulerPanel() { horizRulerPanel = new HorizRuler(this, waveWindow); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 1; gbc.gridwidth = 1; gbc.gridheight = 1; gbc.weightx = 1; gbc.weighty = 0; gbc.anchor = GridBagConstraints.CENTER; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.insets = new Insets(0, 0, 0, 0); rightHalf.add(horizRulerPanel, gbc); } public void removeHorizRulerPanel() { rightHalf.remove(horizRulerPanel); horizRulerPanel = null; } public HorizRuler getHorizRuler() { return horizRulerPanel; } public Signal<?> getXAxisSignal() { return xAxisSignal; } public void setXAxisSignal(Signal<?> sig) { xAxisSignal = sig; } // ************************************* PANEL DISPLAY CONTROL ************************************* public void hidePanel() { waveWindow.hidePanel(this); } public void closePanel() { waveWindow.closePanel(this); waveWindow.saveSignalOrder(); } public void toggleBusContents() { // this panel must have one signal Collection<WaveSignal> theSignals = waveSignals.values(); if (theSignals.size() != 1) return; // the only signal must be digital WaveSignal ws = theSignals.iterator().next(); if (!(ws.getSignal().isDigital())) return; // the digital signal must be a bus Signal<DigitalSample> sDSig = (Signal<DigitalSample>)ws.getSignal(); Signal<?>[] bussedSignals = sDSig.getBusMembers(); if (bussedSignals == null) return; // see if any of the bussed signals are displayed boolean opened = false; for(Signal<?> subSig : bussedSignals) { WaveSignal subWs = waveWindow.findDisplayedSignal(subSig); if (subWs != null) { opened = true; break; } } // now open or close the bus if (opened) { // opened: remove all entries on the bus List<Panel> allPanels = new ArrayList<Panel>(); for(Iterator<Panel> it = waveWindow.getPanels(); it.hasNext(); ) allPanels.add(it.next()); for(Signal<?> subSig : bussedSignals) { WaveSignal subWs = waveWindow.findDisplayedSignal(subSig); if (subWs != null) { Panel wp = subWs.getPanel(); waveWindow.closePanel(wp); allPanels.remove(wp); } } } else { // closed: add all entries on the bus int increment = 1; waveWindow.stopEditing(); for(Signal<?> subSig : bussedSignals) { Panel wp = waveWindow.makeNewPanel(-1); WaveSignal wsig = new WaveSignal(wp, subSig); // remove the panels and put them in the right place waveWindow.removePanel(wsig.getPanel()); int destIndex = waveWindow.getPanelIndex(this); waveWindow.addPanel(wsig.getPanel(), destIndex+increment); increment++; } waveWindow.reloadTable(); } waveWindow.validatePanel(); waveWindow.saveSignalOrder(); } // ************************************* X AND Y AXIS CONTROL ************************************* /** * Method to set the X axis range in this panel. * Since the panel may go backwards in time, these values aren't * guaranteed to run from left to right. * @param leftEdge the X axis value on the left side of the panel. * @param rightEdge the X axis value on the right side of the panel. */ public void setXAxisRange(double leftEdge, double rightEdge) { this.minXPosition = leftEdge; this.maxXPosition = rightEdge; } /** * Method to return the low X axis value shown in this panel. * @return the low X axis value shown in this panel. */ public double getMinXAxis() { return minXPosition; } /** * Method to return the high X axis value shown in this panel. * @return the high X axis value shown in this panel. */ public double getMaxXAxis() { return maxXPosition; } /** * Method to make this Panel show a signal fully. * @param sSig the signal to show or null to fit to all signals */ public void fitToSignal(Signal<?> sig) { double lowValue = Double.MAX_VALUE; double highValue = -Double.MAX_VALUE; for(WaveSignal wSig : getSignals()) { Signal<Sample> sSig = (Signal<Sample>)wSig.getSignal(); if (sig != null && sig != sSig) continue; lowValue = Math.min(lowValue, sSig.getMinValue()); highValue = Math.max(highValue, sSig.getMaxValue()); // if (sSig.isDigital()) // { // lowValue = Math.min(lowValue, 0); // highValue = Math.max(highValue, 1); // } else // { // Signal.View<RangeSample<Sample>> view = sSig.getRasterView(sSig.getMinTime(), sSig.getMaxTime(), 2); // for(int i=0; i<view.getNumEvents(); i++) // { // RangeSample<?> rs = view.getSample(i); // if (rs==null) continue; // Sample min = rs.getMin(); // if (min != null) // { // if (min instanceof ScalarSample) lowValue = Math.min(lowValue, ((ScalarSample)min).getValue()); else // if (min instanceof SweptSample<?>) lowValue = Math.min(lowValue, ((SweptSample<ScalarSample>)min).getMin()); // } // Sample max = rs.getMax(); // if (max != null) // { // if (max instanceof ScalarSample) highValue = Math.max(highValue, ((ScalarSample)max).getValue()); else // if (max instanceof SweptSample<?>) highValue = Math.max(highValue, ((SweptSample<ScalarSample>)max).getMax()); // } // } // } } double range = highValue - lowValue; if (range == 0) range = 2; double rangeExtra = range / 10; setYAxisRange(lowValue - rangeExtra, highValue + rangeExtra); makeSelectedPanel(-1, -1); repaintWithRulers(); } /** * Method to set the Y axis range in this panel. * @param low the low Y axis value. * @param high the high Y axis value. */ public void setYAxisRange(double low, double high) { if (low == high) { low -= 0.5; high += 0.5; } analogLowValue = low; analogHighValue = high; analogRange = analogHighValue - analogLowValue; } public double getYAxisRange() { return analogRange; } public double getYAxisLowValue() { return analogLowValue; } public double getYAxisHighValue() { return analogHighValue; } /** * Method to scale a simulation X value to the X coordinate in this window. * @param value the simulation X value. * @return the X coordinate of that simulation value on the screen. */ public int convertXDataToScreen(double value) { // see if doing logarithmic axes boolean log = waveWindow.isWaveWindowLogarithmic(); if (!waveWindow.isXAxisLocked()) log = horizRulerPanelLogarithmic; if (log) { // logarithmic axes if (value <= smallestXValue) value = smallestXValue; double logValue = Math.log10(value); double winMinX = minXPosition; if (winMinX <= 0) winMinX = smallestXValue; double logWinMinX = Math.log10(winMinX); double winMaxX = maxXPosition; if (winMaxX <= 0) winMaxX = smallestXValue; double logWinMaxX = Math.log10(winMaxX); double x = (logValue - logWinMinX) / (logWinMaxX - logWinMinX) * (sz.width - vertAxisPos) + vertAxisPos; return (int)x; } // linear axes double x = (value - minXPosition) / (maxXPosition - minXPosition) * (sz.width - vertAxisPos) + vertAxisPos; return (int)x; } /** * Method to scale an X coordinate from screen space to data space. * @param x the X coordinate on the screen. * @return the X value in the simulation corresponding to that screen coordinate. */ public double convertXScreenToData(int x) { // see if doing logarithmic axes boolean log = waveWindow.isWaveWindowLogarithmic(); if (!waveWindow.isXAxisLocked()) log = horizRulerPanelLogarithmic; if (log) { // logarithmic axes double winMinX = minXPosition; if (winMinX <= 0) winMinX = smallestXValue; double logWinMinX = Math.log10(winMinX); double winMaxX = maxXPosition; if (winMaxX <= 0) winMaxX = smallestXValue; double logWinMaxX = Math.log10(winMaxX); double xValue = Math.pow(10, ((double)(x - vertAxisPos)) / (sz.width - vertAxisPos) * (logWinMaxX - logWinMinX) + logWinMinX); return xValue; } // linear axes double xValue = ((double)(x - vertAxisPos)) / (sz.width - vertAxisPos) * (maxXPosition - minXPosition) + minXPosition; return xValue; } /** * Method to scale a simulation Y value to the Y coordinate in this window. * @param value the simulation Y value. * @return the Y coordinate of that simulation value on the screen */ public int convertYDataToScreen(double value) { if (vertPanelLogarithmic) { // logarithmic axes if (value <= smallestYValue) value = smallestYValue; double logValue = Math.log10(value); double winMinY = analogLowValue; if (winMinY <= 0) winMinY = smallestYValue; double logWinMinY = Math.log10(winMinY); double winMaxY = analogHighValue; if (winMaxY <= 0) winMaxY = smallestYValue; double logWinMaxY = Math.log10(winMaxY); double y = sz.height - 1 - (logValue - logWinMinY) / (logWinMaxY - logWinMinY) * (sz.height-1); return (int)y; } // linear axes double y = sz.height - 1 - (value - analogLowValue) / analogRange * (sz.height-1); return (int)y; } /** * Method to scale a Y coordinate from screen space to data space. * @param y the Y coordinate on the screen. * @return the Y value in the simulation corresponding to that screen coordinate. */ public double convertYScreenToData(int y) { if (vertPanelLogarithmic) { // logarithmic axes double winMinY = analogLowValue; if (winMinY <= 0) winMinY = smallestYValue; double logWinMinY = Math.log10(winMinY); double winMaxY = analogHighValue; if (winMaxY <= 0) winMaxY = smallestYValue; double logWinMaxY = Math.log10(winMaxY); double yValue = Math.pow(10, logWinMinY - (y - sz.height + 1) * (logWinMaxY - logWinMinY) / (sz.height-1)); return yValue; } // linear axes double value = 0; if (sz.height > 1) value = analogLowValue - (y - sz.height + 1) * analogRange / (sz.height-1); return value; } // ************************************* DISPLAY CONTROL ************************************* /** * Method to repaint this window and its associated ruler panel. */ public void repaintWithRulers() { if (horizRulerPanel != null) horizRulerPanel.repaint(); else { waveWindow.getMainHorizRuler().repaint(); } repaintContents(); } /** * Method to repaint the panel. * Rebuilds the offscreen image and schedules a repaint. */ public void repaintContents() { needRepaintOffscreenImage = true; waveWindow.getWaveformTable().repaint(); } private boolean needRepaintOffscreenImage; private Image offscreen; public Image getWaveImage() { return offscreen; } /** * Method to repaint this Panel. */ public void paint(Graphics g) { // requestFocus moved to mousePressed(). // to enable keys to be received //if (waveWindow.getWindowFrame() == WindowFrame.getCurrentWindowFrame()) // requestFocus(); sz = getSize(); szValid = true; int wid = sz.width; int hei = sz.height; if (USE_VOLATILE_IMAGE) { VolatileImage offscreen = (VolatileImage)this.offscreen; do { int returnCode = VolatileImage.IMAGE_INCOMPATIBLE; if (offscreen != null && offscreen.getWidth() == wid && offscreen.getHeight() == hei) returnCode = offscreen.validate(getGraphicsConfiguration()); if (returnCode == VolatileImage.IMAGE_INCOMPATIBLE) { // old offscreen doesn't work with new GraphicsConfig; re-create it if (offscreen != null) offscreen.flush(); this.offscreen = offscreen = createVolatileImage(wid, hei); needRepaintOffscreenImage = true; } if (returnCode != VolatileImage.IMAGE_OK || needRepaintOffscreenImage) { // Contents need to be restored repaintOffscreenImage(wid, hei); } if (offscreen.contentsLost()) continue; g.drawImage(offscreen, 0, 0, null); } while (offscreen.contentsLost()); } else { BufferedImage offscreen = (BufferedImage)this.offscreen; if (offscreen == null || offscreen.getWidth() != wid || offscreen.getHeight() != hei) { this.offscreen = offscreen = new BufferedImage(wid, hei, BufferedImage.TYPE_INT_RGB); needRepaintOffscreenImage = true; } if (needRepaintOffscreenImage) { repaintOffscreenImage(wid, hei); } g.drawImage(offscreen, 0, 0, null); } Dimension tableSz = waveWindow.getWaveformTable().getSize(); Point screenLoc = waveWindow.getWaveformTable().getLocationOnScreen(); waveWindow.setScreenXSize(screenLoc.x + tableSz.width - wid, screenLoc.x + tableSz.width); paintDragging((Graphics2D)g, wid, hei); } private void repaintOffscreenImage(int wid, int hei) { needRepaintOffscreenImage = false; Graphics2D offscreenGraphics = (Graphics2D)offscreen.getGraphics(); // clear the buffer offscreenGraphics.setColor(new Color(User.getColor(User.ColorPrefType.WAVE_BACKGROUND))); offscreenGraphics.fillRect(0, 0, wid, hei); drawPanelContents(wid, hei, offscreenGraphics, null, null); offscreenGraphics.dispose(); } private void paintDragging(Graphics2D g, int wid, int hei) { g.setColor(new Color(User.getColor(User.ColorPrefType.WAVE_FOREGROUND))); // draw the X position cursors g.setStroke(Highlight.dashedLine); int x = convertXDataToScreen(waveWindow.getMainXPositionCursor()); if (x >= vertAxisPos) g.drawLine(x, 0, x, hei); g.setStroke(farDottedLine); x = convertXDataToScreen(waveWindow.getExtensionXPositionCursor()); if (x >= vertAxisPos) g.drawLine(x, 0, x, hei); g.setStroke(Highlight.solidLine); // show dragged area if there if (draggingArea) { int lowX = Math.min(convertXDataToScreen(dragStartXD), convertXDataToScreen(dragEndXD)); int highX = Math.max(convertXDataToScreen(dragStartXD), convertXDataToScreen(dragEndXD)); int lowY = Math.min(convertYDataToScreen(dragStartYD), convertYDataToScreen(dragEndYD)); int highY = Math.max(convertYDataToScreen(dragStartYD), convertYDataToScreen(dragEndYD)); g.drawLine(lowX, lowY, lowX, highY); g.drawLine(lowX, highY, highX, highY); g.drawLine(highX, highY, highX, lowY); g.drawLine(highX, lowY, lowX, lowY); } for(Rectangle2D meas : measurementList) { int lowX = Math.min(convertXDataToScreen(meas.getMinX()), convertXDataToScreen(meas.getMaxX())); int highX = Math.max(convertXDataToScreen(meas.getMinX()), convertXDataToScreen(meas.getMaxX())); int lowY = Math.min(convertYDataToScreen(meas.getMinY()), convertYDataToScreen(meas.getMaxY())); int highY = Math.max(convertYDataToScreen(meas.getMinY()), convertYDataToScreen(meas.getMaxY())); g.drawLine(lowX, lowY, lowX, highY); g.drawLine(lowX, highY, highX, highY); g.drawLine(highX, highY, highX, lowY); g.drawLine(highX, lowY, lowX, lowY); // show dimensions while dragging double lowXValue = convertXScreenToData(lowX); double highXValue = convertXScreenToData(highX); double lowValue = convertYScreenToData(highY); double highValue = convertYScreenToData(lowY); g.setFont(waveWindow.getFont()); // show the low X value and arrow String lowXValueString = TextUtils.convertToEngineeringNotation(lowXValue, "s"); GlyphVector gv = waveWindow.getFont().createGlyphVector(waveWindow.getFontRenderContext(), lowXValueString); Rectangle2D glyphBounds = gv.getLogicalBounds(); int textWid = (int)glyphBounds.getWidth(); int textHei = (int)glyphBounds.getHeight(); int textY = (lowY+highY)/2; g.drawString(lowXValueString, lowX-textWid-6, textY+textHei/2-10); g.drawLine(lowX-1, textY, lowX-textWid, textY); g.drawLine(lowX-1, textY, lowX-6, textY+4); g.drawLine(lowX-1, textY, lowX-6, textY-4); // show the high X value and arrow String highXValueString = TextUtils.convertToEngineeringNotation(highXValue, "s"); gv = waveWindow.getFont().createGlyphVector(waveWindow.getFontRenderContext(), highXValueString); glyphBounds = gv.getLogicalBounds(); textWid = (int)glyphBounds.getWidth(); textHei = (int)glyphBounds.getHeight(); int highXValueTextWid = textWid; g.drawString(highXValueString, highX+6, textY+textHei/2-10); g.drawLine(highX+1, textY, highX+textWid, textY); g.drawLine(highX+1, textY, highX+6, textY+4); g.drawLine(highX+1, textY, highX+6, textY-4); // show the difference X value String xDiffString = TextUtils.convertToEngineeringNotation(highXValue-lowXValue, "s"); gv = waveWindow.getFont().createGlyphVector(waveWindow.getFontRenderContext(), xDiffString); glyphBounds = gv.getLogicalBounds(); textWid = (int)glyphBounds.getWidth(); textHei = (int)glyphBounds.getHeight(); if (textWid + 24 < highX - lowX) { // fits inside: draw arrows around text int yPosText = highY + textHei*5; int yPos = yPosText - textHei/2; int xCtr = (highX+lowX)/2; g.drawString(xDiffString, xCtr - textWid/2, yPosText); g.drawLine(lowX, yPos, xCtr - textWid/2 - 2, yPos); g.drawLine(highX, yPos, xCtr + textWid/2 + 2, yPos); g.drawLine(lowX, yPos, lowX+5, yPos+4); g.drawLine(lowX, yPos, lowX+5, yPos-4); g.drawLine(highX, yPos, highX-5, yPos+4); g.drawLine(highX, yPos, highX-5, yPos-4); } else { // does not fit inside: draw outside of arrows int yPosText = highY + textHei*5; int yPos = yPosText - textHei/2; g.drawString(xDiffString, highX + 12, yPosText); g.drawLine(lowX, yPos, lowX-10, yPos); g.drawLine(highX, yPos, highX+10, yPos); g.drawLine(lowX, yPos, lowX-5, yPos+4); g.drawLine(lowX, yPos, lowX-5, yPos-4); g.drawLine(highX, yPos, highX+5, yPos+4); g.drawLine(highX, yPos, highX+5, yPos-4); } if (isAnalog()) { // show the low value String lowValueString = TextUtils.convertToEngineeringNotation(highValue, null); gv = waveWindow.getFont().createGlyphVector(waveWindow.getFontRenderContext(), lowValueString); glyphBounds = gv.getLogicalBounds(); textWid = (int)glyphBounds.getWidth(); textHei = (int)glyphBounds.getHeight(); int xP = (lowX+highX)/2; int yText = lowY - 10 - textHei; g.drawString(lowValueString, xP, yText - 2); g.drawLine(xP, lowY-1, xP, yText); g.drawLine(xP, lowY-1, xP+4, lowY-5); g.drawLine(xP, lowY-1, xP-4, lowY-5); // show the high value String highValueString = TextUtils.convertToEngineeringNotation(lowValue, null); gv = waveWindow.getFont().createGlyphVector(waveWindow.getFontRenderContext(), highValueString); glyphBounds = gv.getLogicalBounds(); textWid = (int)glyphBounds.getWidth(); textHei = (int)glyphBounds.getHeight(); yText = highY + 10 + textHei; g.drawString(highValueString, xP, yText + textHei + 2); g.drawLine(xP, highY+1, xP, yText); g.drawLine(xP, highY+1, xP+4, highY+5); g.drawLine(xP, highY+1, xP-4, highY+5); // show the value difference String valueDiffString = TextUtils.convertToEngineeringNotation(highValue - lowValue, null); gv = waveWindow.getFont().createGlyphVector(waveWindow.getFontRenderContext(), valueDiffString); glyphBounds = gv.getLogicalBounds(); textWid = (int)glyphBounds.getWidth(); textHei = (int)glyphBounds.getHeight(); if (textHei + 12 < highY - lowY) { // fits inside: draw arrows around text int xPos = highX + highXValueTextWid + 30; int yCtr = (highY+lowY)/2; g.drawString(valueDiffString, xPos+2, yCtr + textHei/2); g.drawLine(xPos, lowY, xPos, highY); g.drawLine(xPos, lowY, xPos+4, lowY+5); g.drawLine(xPos, lowY, xPos-4, lowY+5); g.drawLine(xPos, highY, xPos+4, highY-5); g.drawLine(xPos, highY, xPos-4, highY-5); } else { // does not fit inside: draw outside of arrows int xPos = highX + highXValueTextWid + 30; g.drawString(valueDiffString, xPos+4, lowY - textHei/2 - 4); g.drawLine(xPos, lowY, xPos, lowY-10); g.drawLine(xPos, highY, xPos, highY+10); g.drawLine(xPos, lowY, xPos+4, lowY-5); g.drawLine(xPos, lowY, xPos-4, lowY-5); g.drawLine(xPos, highY, xPos+4, highY+5); g.drawLine(xPos, highY, xPos-4, highY+5); } } } } private void drawPanelContents(int wid, int hei, Graphics2D localGraphics, Rectangle2D bounds, List<PolyBase> polys) { // draw the grid first (behind the signals) if (waveWindow.isShowGrid()) { if (localGraphics != null) { localGraphics.setStroke(Highlight.dottedLine); localGraphics.setColor(gridColor); } // draw the vertical grid lines double displayedXLow = convertXScreenToData(vertAxisPos); double displayedXHigh = convertXScreenToData(wid); StepSize ss = new StepSize(displayedXHigh, displayedXLow, 10); if (ss.getSeparation() != 0.0) { double value = ss.getLowValue(); for(;;) { if (value >= displayedXLow) { if (value > ss.getHighValue()) break; int x = convertXDataToScreen(value); if (polys != null) { polys.add(new Poly(new Point2D[] { new Point2D.Double(x, 0), new Point2D.Double(x, hei)})); } else { localGraphics.drawLine(x, 0, x, hei); } } value += ss.getSeparation(); } } ss = new StepSize(analogHighValue, analogLowValue, 5); if (ss.getSeparation() != 0.0) { double value = ss.getLowValue(); for(;;) { if (value >= analogLowValue) { if (value > analogHighValue || value > ss.getHighValue()) break; int y = convertYDataToScreen(value); if (polys != null) { polys.add(new Poly(new Point2D[] { new Point2D.Double(vertAxisPos, y), new Point2D.Double(wid, y)})); } else { localGraphics.drawLine(vertAxisPos, y, wid, y); } } value += ss.getSeparation(); } } if (localGraphics != null) { localGraphics.setStroke(Highlight.solidLine); } } // draw all of the signals if (USE_ANTIALIASING && localGraphics != null) { Object oldAntialiasing = localGraphics.getRenderingHint(RenderingHints.KEY_ANTIALIASING); localGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); processSignals(localGraphics, bounds, polys); localGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, oldAntialiasing); } else { processSignals(localGraphics, bounds, polys); } // draw all of the control points if (localGraphics != null) processControlPoints(localGraphics, bounds); // draw the vertical label if (polys != null) { polys.add(new Poly(new Point2D[] { new Point2D.Double(vertAxisPos, 0), new Point2D.Double(vertAxisPos, hei)})); } else { localGraphics.setColor(new Color(User.getColor(User.ColorPrefType.WAVE_FOREGROUND))); localGraphics.drawLine(vertAxisPos, 0, vertAxisPos, hei); if (selected) { localGraphics.drawLine(vertAxisPos-1, 0, vertAxisPos-1, hei); localGraphics.drawLine(vertAxisPos-2, 0, vertAxisPos-2, hei-1); localGraphics.drawLine(vertAxisPos-3, 0, vertAxisPos-3, hei-2); } } if (isAnalog()) { double displayedLow = convertYScreenToData(hei); double displayedHigh = convertYScreenToData(0); StepSize ss = new StepSize(displayedHigh, displayedLow, 5); if (ss.getSeparation() != 0.0) { double value = ss.getLowValue(); if (localGraphics != null) localGraphics.setFont(waveWindow.getFont()); int lastY = -1; int ySeparation = convertYDataToScreen(value) - convertYDataToScreen(value+ss.getSeparation()); int textSkip = 100; if (ySeparation > 0) textSkip = 20 / ySeparation; int textSkipPos = 0; for(int i=0; ; i++) { if (value > displayedHigh) break; if (value >= displayedLow) { int y = convertYDataToScreen(value); if (lastY >= 0) { // add extra tick marks int addedTicks = (lastY - y) / 20; for(int j=1; j<addedTicks; j++) { int intY = (lastY - y) / addedTicks * j + y; if (polys != null) { polys.add(new Poly(new Point2D[] { new Point2D.Double(vertAxisPos-5, intY), new Point2D.Double(vertAxisPos, intY)})); } else { localGraphics.drawLine(vertAxisPos-5, intY, vertAxisPos, intY); } } } if (polys != null) { polys.add(new Poly(new Point2D[] { new Point2D.Double(vertAxisPos-10, y), new Point2D.Double(vertAxisPos, y)})); } else { localGraphics.drawLine(vertAxisPos-10, y, vertAxisPos, y); } // skip text if spaced too closely textSkipPos--; if (textSkipPos <= 0) { textSkipPos = textSkip; String yValue = TextUtils.convertToEngineeringNotation(value, null, ss.getStepScale()+3); if (polys != null) { Poly poly = new Poly(new Point2D[] { new Point2D.Double(vertAxisPos-12, y) }); poly.setStyle(Poly.Type.TEXTRIGHT); poly.setTextDescriptor(TextDescriptor.EMPTY.withAbsSize(6)); poly.setString(yValue); polys.add(poly); } else { GlyphVector gv = waveWindow.getFont().createGlyphVector(waveWindow.getFontRenderContext(), yValue); Rectangle2D glyphBounds = gv.getLogicalBounds(); int height = (int)glyphBounds.getHeight(); int yPos = y + height / 2; if (yPos-height <= 0) yPos = height+1; if (yPos >= hei) yPos = hei; int xPos = vertAxisPos-10-(int)glyphBounds.getWidth()-2; if (xPos < 0) xPos = 0; localGraphics.drawString(yValue, xPos, yPos); } } lastY = y; } value += ss.getSeparation(); } } } } public void dumpDataCSV(PrintWriter pw) { for(WaveSignal ws : waveSignals.values()) { Signal<?> as = ws.getSignal(); Signal.View<?> waveform = ((Signal<?>)as).getExactView(); int numEvents = waveform.getNumEvents(); for(int i=0; i<numEvents; i++) { Sample samp = waveform.getSample(i); double time = waveform.getTime(i); if (samp instanceof SweptSample<?>) { SweptSample<?> sws = (SweptSample<?>)samp; for(int s=0; s<sws.getWidth(); s++) { Sample ss = sws.getSweep(s); pw.println("\"" + time + "\",\"" + s + "\",\"" + ((ScalarSample)ss).getValue() + "\""); } } else if (samp instanceof DigitalSample) { DigitalSample ds = (DigitalSample)samp; String value; if (ds.isLogic0()) value = "0"; else if (ds.isLogic1()) value = "1"; else if (ds.isLogicX()) value = "X"; else if (ds.isLogicZ()) value = "Z"; else value = "?"; pw.println("\"" + time + "\",\"" + value + "\""); } else if (samp instanceof BusSample<?>) { BusSample<?> bs = (BusSample<?>)samp; boolean isX = false, isZ = false; StringBuffer sb = new StringBuffer(); for(int j=0; j<bs.getWidth(); j++) { DigitalSample ds = (DigitalSample)bs.getTrace(j); if (ds.isLogicX()) { isX = true; break; } if (ds.isLogicZ()) { isZ = true; break; } if (ds.isLogic0()) sb.append("0"); else if (ds.isLogic1()) sb.append("1"); else sb.append("?"); } String number = sb.toString(); if (isX) number = "X"; else if (isZ) number = "Z"; pw.println("\"" + time + "\",\"" + number + "\""); } else { ScalarSample ss = (ScalarSample)samp; pw.println("\"" + time + "\",\"" + ss.getValue() + "\""); } } pw.println(); } } private static String pad2(String s) { return s.length()>=2 ? s : pad2("0"+s); } void dumpDataForGnuplot(PrintWriter pw) { dumpDataForGnuplot(pw, -Double.MAX_VALUE, Double.MAX_VALUE, ""); } void dumpDataForGnuplot(PrintWriter pw, double min, double max, String sep) { boolean first = true; int linetype = 1; for(WaveSignal ws : waveSignals.values()) { boolean used = false; String [] sweepNames = ws.getSignal().getSignalCollection().getSweepNames(); int numSweeps = (sweepNames == null) ? 1 : sweepNames.length; for (int s = 0; s < numSweeps; s++) { if (!first) pw.print(sep); pw.print(" \'-\' with lines "); Color c = ws.getColor(); pw.print(" lt "+linetype+" "); pw.print("lc rgb \"#"+ pad2(Integer.toString(c.getRed() & 0xff, 16))+ pad2(Integer.toString(c.getGreen() & 0xff, 16))+ pad2(Integer.toString(c.getBlue() & 0xff, 16))+ "\" "); pw.print(" title \""+ws.getSignal().getFullName()+"\" "); first = false; used = true; } if (used) linetype++; } for(WaveSignal ws : waveSignals.values()) { Signal<?> as = ws.getSignal(); String [] sweepNames = ws.getSignal().getSignalCollection().getSweepNames(); int numSweeps = (sweepNames == null) ? 1 : sweepNames.length; Signal.View<?> waveform = ((Signal<?>)as).getExactView(); int numEvents = waveform.getNumEvents(); for (int s = 0; s < numSweeps; s++) { pw.println(); for(int i=0; i<numEvents; i++) { Sample samp = waveform.getSample(i); double time = waveform.getTime(i); if (time < min || time > max) continue; if (samp instanceof SweptSample<?>) { SweptSample<?> sws = (SweptSample<?>)samp; Sample ss = sws.getSweep(s); pw.println(time + " " + ss); } else { pw.println(time + " " + samp); } } pw.println("e"); pw.println(); } } } private List<WaveSelection> processSignals(Graphics g, Rectangle2D bounds, List<PolyBase> forPs) { List<WaveSelection> selectedObjects = null; if (bounds != null) selectedObjects = new ArrayList<WaveSelection>(); Signal<?> xSignal = xAxisSignal; if (waveWindow.isXAxisLocked()) xSignal = waveWindow.getXAxisSignalAll(); Collection<WaveSignal> sigs = waveSignals.values(); int sigIndex = 0; Color light = null; for(WaveSignal ws : sigs) { if (g != null) { if (waveWindow.getPrintingMode() == 2) g.setColor(Color.BLACK); else g.setColor(ws.getColor()); Color c = ws.getColor(); light = new Color(c.getRed(), c.getGreen(), c.getBlue(), 0x55); } if (forPs != null) { int hei = sz.height; double yPos = hei / 2; Poly.Type style = Poly.Type.TEXTRIGHT; if (sigs.size() > 1) { if (sigIndex == sigs.size()-1) style = Poly.Type.TEXTBOTRIGHT; else if (sigIndex == 0) style = Poly.Type.TEXTTOPRIGHT; yPos = ((double)(hei * sigIndex)) / (sigs.size()-1); } Poly poly = new Poly(new Point2D[] {new Point2D.Double(0, yPos)}); poly.setStyle(style); poly.setTextDescriptor(TextDescriptor.EMPTY.withAbsSize(12)); poly.setString(ws.getSignal().getFullName()); forPs.add(poly); } sigIndex++; ws.getSignal().plot(this, g, ws, light, forPs, bounds, selectedObjects, xSignal); } return selectedObjects; } private List<WaveSelection> processControlPoints(Graphics g, Rectangle2D bounds) { List<WaveSelection> selectedObjects = null; if (bounds != null) selectedObjects = new ArrayList<WaveSelection>(); // show control points for(WaveSignal ws : waveSignals.values()) { if (g != null) g.setColor(ws.getColor()); Double [] points = ws.getSignal().getControlPoints(); if (points == null) continue; if (g != null) g.setColor(ws.getColor()); for(int i=0; i<points.length; i++) { double xValue = points[i].doubleValue(); int x = convertXDataToScreen(xValue); if (processABox(g, x-CONTROLPOINTSIZE, sz.height-CONTROLPOINTSIZE*2, x+CONTROLPOINTSIZE, sz.height, bounds, null, selectedObjects, ws, true, xValue)) break; // see if the control point is selected boolean found = false; if (bounds == null && ws.getSelectedControlPoints() != null) { for(int j=0; j<ws.getSelectedControlPoints().length; j++) if (ws.getSelectedControlPoints()[j] == xValue) { found = true; break; } } if (found) { g.setColor(Color.GREEN); if (processABox(g, x-CONTROLPOINTSIZE+2, sz.height-CONTROLPOINTSIZE*2+2, x+CONTROLPOINTSIZE-2, sz.height-2, bounds, null, selectedObjects, ws, true, xValue)) break; g.setColor(ws.getColor()); } } } return selectedObjects; } public boolean processABox(Graphics g, int lX, int lY, int hX, int hY, Rectangle2D bounds, List<PolyBase> forPs, List<WaveSelection> result, WaveSignal ws, boolean controlPoint, double controlXValue) { // bounds is non-null if doing hit-testing if (bounds != null) { // do bounds checking for hit testing if (hX > bounds.getMinX() && lX < bounds.getMaxX() && hY > bounds.getMinY() && lY < bounds.getMaxY()) { if (forPs != null) { PolyBase poly = new PolyBase((lX+hX)/2, (lY+hY)/2, hX-lX, hY-lY); poly.setStyle(Poly.Type.FILLED); poly.setLayer(Artwork.tech().defaultLayer); forPs.add(poly); return false; } WaveSelection wSel = new WaveSelection(); wSel.ws = ws; wSel.controlPoint = controlPoint; wSel.controlXValue = controlXValue; result.add(wSel); return true; } return false; } // clip to left edge if (hX <= vertAxisPos) return false; if (lX < vertAxisPos) lX = vertAxisPos; // not doing hit-testing, just doing drawing g.fillRect(lX, lY, hX-lX, hY-lY); return false; } public boolean processALine(Graphics g, int fX, int fY, int tX, int tY, Rectangle2D bounds, List<PolyBase> forPs, List<WaveSelection> result, WaveSignal ws, int sweepNum) { if (bounds != null) { // do bounds checking for hit testing Point2D from = new Point2D.Double(fX, fY); Point2D to = new Point2D.Double(tX, tY); if (!GenMath.clipLine(from, to, bounds.getMinX(), bounds.getMaxX(), bounds.getMinY(), bounds.getMaxY())) { if (forPs != null) { forPs.add(new PolyBase(new Point2D[] {from, to})); return false; } WaveSelection wSel = new WaveSelection(); wSel.ws = ws; wSel.controlPoint = false; result.add(wSel); return true; } return false; } // clip to left edge if (fX < vertAxisPos || tX < vertAxisPos) { Point2D from = new Point2D.Double(fX, fY); Point2D to = new Point2D.Double(tX, tY); if (GenMath.clipLine(from, to, vertAxisPos, sz.width, 0, sz.height)) return false; fX = (int)from.getX(); fY = (int)from.getY(); tX = (int)to.getX(); tY = (int)to.getY(); } // draw the line g.drawLine(fX, fY, tX, tY); // highlight the line if requested boolean highlighted = ws.isHighlighted(); if (ws.getPanel().waveWindow.getHighlightedSweep() >= 0) { highlighted = ws.getPanel().waveWindow.getHighlightedSweep() == sweepNum; } if (highlighted) { if (fX == tX) { // vertical line g.drawLine(fX-1, fY, tX-1, tY); g.drawLine(fX+1, fY, tX+1, tY); } else if (fY == tY) { // horizontal line g.drawLine(fX, fY+1, tX, tY+1); g.drawLine(fX, fY-1, tX, tY-1); } else { int xDelta = 0, yDelta = 1; if (Math.abs(fX-tX) < Math.abs(fY-tY)) { xDelta = 1; yDelta = 0; } g.drawLine(tX+xDelta, tY+yDelta, fX+xDelta, fY+yDelta); g.drawLine(tX-xDelta, tY-yDelta, fX-xDelta, fY-yDelta); } } return false; } // ************************************* SIGNAL SELECTION ************************************* /** * the MouseListener events */ public void mousePressed(MouseEvent evt) { requestFocus(); waveWindow.vcrClickStop(); // set this to be the selected panel makeSelectedPanel(evt.getX(), evt.getY()); // reset dragging from last time for(Iterator<Panel> it = waveWindow.getPanels(); it.hasNext(); ) { Panel wp = it.next(); if (wp.draggingArea) wp.repaintContents(); wp.draggingArea = false; } if (evt.getClickCount() == 2 && evt.getX() < vertAxisPos) { new WaveformZoom((Frame) Main.getCurrentJFrame(), analogLowValue, analogHighValue, minXPosition, maxXPosition, waveWindow, this); return; } ToolBar.CursorMode mode = ToolBar.getCursorMode(); if (ClickZoomWireListener.isRightMouse(evt)) { if ((evt.getModifiersEx()&MouseEvent.SHIFT_DOWN_MASK) != 0) mode = ToolBar.CursorMode.ZOOM; else { if (evt.getX() < vertAxisPos) { // right click in ruler area: show popup of choices JPopupMenu menu = new JPopupMenu(); JMenuItem item = new JMenuItem("Linear"); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { makeLinear(); } }); menu.add(item); item = new JMenuItem("Logarithmic"); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { makeLogarithmic(); } }); menu.add(item); menu.show(this, evt.getX(), evt.getY()); return; } } } for(Iterator<Panel> it = waveWindow.getPanels(); it.hasNext(); ) it.next().curMeasurement = null; if (mode == ToolBar.CursorMode.ZOOM) mousePressedZoom(evt); else if (mode == ToolBar.CursorMode.PAN) mousePressedPan(evt); else mousePressedSelect(evt); } public void mouseReleased(MouseEvent evt) { ToolBar.CursorMode mode = ToolBar.getCursorMode(); if (ClickZoomWireListener.isRightMouse(evt) && (evt.getModifiersEx()&MouseEvent.SHIFT_DOWN_MASK) != 0) mode = ToolBar.CursorMode.ZOOM; if (mode == ToolBar.CursorMode.ZOOM) mouseReleasedZoom(evt); else if (mode == ToolBar.CursorMode.PAN) mouseReleasedPan(evt); else mouseReleasedSelect(evt); for(Iterator<Panel> it = waveWindow.getPanels(); it.hasNext(); ) { Panel panel = it.next(); panel.curMeasurement = null; if (mode == ToolBar.CursorMode.MEASURE) panel.draggingArea = false; } } public void mouseClicked(MouseEvent evt) {} public void mouseEntered(MouseEvent evt) { /*curPanel = this; curXPos = evt.getX();*/ } public void mouseExited(MouseEvent evt) { /*curPanel = null;*/ } /** * the MouseMotionListener events */ public void mouseMoved(MouseEvent evt) { // curXPos = evt.getX(); ToolBar.CursorMode mode = ToolBar.getCursorMode(); if (mode == ToolBar.CursorMode.ZOOM) mouseMovedZoom(evt); else if (mode == ToolBar.CursorMode.PAN) mouseMovedPan(evt); else mouseMovedSelect(evt); } public void mouseDragged(MouseEvent evt) { // curXPos = evt.getX(); ToolBar.CursorMode mode = ToolBar.getCursorMode(); if (ClickZoomWireListener.isRightMouse(evt) && (evt.getModifiersEx()&MouseEvent.SHIFT_DOWN_MASK) != 0) mode = ToolBar.CursorMode.ZOOM; if (mode == ToolBar.CursorMode.ZOOM) mouseDraggedZoom(evt); else if (mode == ToolBar.CursorMode.PAN) mouseDraggedPan(evt); else mouseDraggedSelect(evt); } /** * the MouseWheelListener events */ public void mouseWheelMoved(MouseWheelEvent evt) {} /** * the KeyListener events */ public void keyPressed(KeyEvent evt) { waveWindow.vcrClickStop(); } public void keyReleased(KeyEvent evt) {} public void keyTyped(KeyEvent evt) {} private void panelTitleClicked(ActionEvent evt) { long delay = evt.getWhen() - lastClick; lastClick = evt.getWhen(); if (delay < Main.getDoubleClickSpeed()) { toggleBusContents(); return; } Set<JComponent> set = waveSignals.keySet(); if (set.size() != 1) return; JComponent comp = set.iterator().next(); WaveSignal ws = waveSignals.get(comp); if ((evt.getModifiers()&MouseEvent.SHIFT_MASK) == 0) { // standard click: add this as the only trace for(Iterator<Panel> it = waveWindow.getPanels(); it.hasNext(); ) { Panel wp = it.next(); wp.clearHighlightedSignals(); } addHighlightedSignal(ws, true); makeSelectedPanel(-1, -1); } else { // TODO: this never gets called // shift click: add or remove to list of highlighted traces if (ws.isHighlighted()) removeHighlightedSignal(ws, true); else addHighlightedSignal(ws, true); } // show it in the schematic waveWindow.crossProbeWaveformToEditWindow(); } /** * Method to find the Signals in an area. * @param lX the low X coordinate of the area. * @param hX the high X coordinate of the area. * @param lY the low Y coordinate of the area. * @param hY the high Y coordinate of the area. * @return a list of WaveSelection objects. */ private List<WaveSelection> findSignalsInArea(int lX, int hX, int lY, int hY) { double lXd = Math.min(lX, hX)-2; double hXd = Math.max(lX, hX)+2; double hYd = Math.min(lY, hY)-2; double lYd = Math.max(lY, hY)+2; if (lXd > hXd) { double swap = lXd; lXd = hXd; hXd = swap; } if (lYd > hYd) { double swap = lYd; lYd = hYd; hYd = swap; } Rectangle2D bounds = new Rectangle2D.Double(lXd, lYd, hXd-lXd, hYd-lYd); List<WaveSelection> sigs = processSignals(null, bounds, null); List<WaveSelection> cps = processControlPoints(null, bounds); for(WaveSelection ws : sigs) cps.add(ws); return cps; } /** * Method to find a list of PolyBase objects that describe Signals in this panel. * @return a list of PolyBase objects. */ public List<PolyBase> getPolysForPrinting() { if (!szValid) { for(Iterator<Panel> it = this.waveWindow.getPanels(); it.hasNext(); ) { Panel wp = it.next(); if (wp.szValid) { sz = wp.sz; szValid = true; break; } } } sz = getSize(); List<PolyBase> polys = new ArrayList<PolyBase>(); drawPanelContents(sz.width, sz.height, null, new Rectangle2D.Double(vertAxisPos, 0, sz.width, sz.height), polys); return polys; } public static class WaveSelection { /** Selected signal in Waveform Window */ WaveSignal ws; /** true if this is a control point */ boolean controlPoint; /** X value of the control point (if a CP) */ double controlXValue; } /** * Method to remove all displayed measurements from the panel */ public void clearMeasurements() { measurementList.clear(); curMeasurement = null; repaintContents(); } /** * Method to implement the Mouse Pressed event for selection. */ public void mousePressedSelect(MouseEvent evt) { // see if the horizontal cursors are selected draggingMain = draggingExt = draggingVertAxis = false; int mainX = convertXDataToScreen(waveWindow.getMainXPositionCursor()); if (Math.abs(mainX - evt.getX()) < 5) { draggingMain = true; return; } int extX = convertXDataToScreen(waveWindow.getExtensionXPositionCursor()); if (Math.abs(extX - evt.getX()) < 5) { draggingExt = true; return; } if (Math.abs(vertAxisPos - evt.getX()) < 5) { draggingVertAxis = true; return; } // drag area Point pt = new Point(evt.getX(), evt.getY()); if (ToolBar.getCursorMode() == ToolBar.CursorMode.MEASURE) { pt = snapPoint(pt); } double xV = convertXScreenToData(pt.x); double yV = convertYScreenToData(pt.y); if (ToolBar.getCursorMode() == ToolBar.CursorMode.MEASURE) { if (ClickZoomWireListener.isRightMouse(evt)) { measurementList.clear(); curMeasurement = null; return; } curMeasurement = new Rectangle2D.Double(xV, yV, 0, 0); measurementList.add(curMeasurement); } dragEndXD = dragStartXD = xV; dragEndYD = dragStartYD = yV; draggingArea = true; } private Point getPointIfClose(int x, int y, Point pt) { if (Math.abs(x - pt.x) < 8 && Math.abs(y - pt.y) < 8) { pt.x = x; pt.y = y; return pt; } return null; } private Point getPointIfCloseToLine(Point2D lstPt, Point2D thisPt, Point2D snap) { Point2D closest = GenMath.closestPointToSegment(lstPt, thisPt, snap); if (closest.distance(snap) < 5) { Point pt = new Point((int)Math.round(closest.getX()), (int)Math.round(closest.getY())); return pt; } return null; } private Point snapPoint(Point pt) { // get list of views in this panel List<Signal.View<RangeSample<Sample>>> allViews = new ArrayList<Signal.View<RangeSample<Sample>>>(); for(WaveSignal ws : waveSignals.values()) { Signal<Sample> sig = (Signal<Sample>)ws.getSignal(); if (sig.isDigital()) continue; allViews.add(sig.getRasterView(sig.getMinTime(), sig.getMaxTime(), sz.width)); } // snap to any waveform points for(Signal.View<RangeSample<Sample>> view : allViews) { for(int i=0; i<view.getNumEvents(); i++) { RangeSample<?> rs = view.getSample(i); if (rs == null) continue; int x = convertXDataToScreen(view.getTime(i)); // see if point on minimum is close Sample min = rs.getMin(); if (min instanceof SweptSample<?>) { SweptSample<?> ss = (SweptSample<?>)min; for(int s=0; s<ss.getWidth(); s++) { Sample sweepSample = ss.getSweep(s); int y = convertYDataToScreen(((ScalarSample)sweepSample).getValue()); Point closePoint = getPointIfClose(x, y, pt); if (closePoint != null) return closePoint; } } else { int y = convertYDataToScreen(((ScalarSample)min).getValue()); Point closePoint = getPointIfClose(x, y, pt); if (closePoint != null) return closePoint; } // see if point on maximum is close Sample max = rs.getMax(); if (max instanceof SweptSample<?>) { SweptSample<?> ss = (SweptSample<?>)max; for(int s=0; s<ss.getWidth(); s++) { Sample sweepSample = ss.getSweep(s); int y = convertYDataToScreen(((ScalarSample)sweepSample).getValue()); Point closePoint = getPointIfClose(x, y, pt); if (closePoint != null) return closePoint; } } else { int y = convertYDataToScreen(((ScalarSample)max).getValue()); Point closePoint = getPointIfClose(x, y, pt); if (closePoint != null) return closePoint; } } } // snap to any waveform lines Point2D snap = new Point2D.Double(pt.x, pt.y); for(Signal.View<RangeSample<Sample>> view : allViews) { Point2D lastPt = null; List<Point2D> lastSweepMinPts = new ArrayList<Point2D>(); List<Point2D> lastSweepMaxPts = new ArrayList<Point2D>(); for(int i=0; i<view.getNumEvents(); i++) { RangeSample<?> rs = view.getSample(i); if (rs == null) continue; int x = convertXDataToScreen(view.getTime(i)); // see if point on minimum is close Sample min = rs.getMin(); if (min instanceof SweptSample<?>) { SweptSample<?> ss = (SweptSample<?>)min; for(int s=0; s<ss.getWidth(); s++) { Sample sweepSample = ss.getSweep(s); int y = convertYDataToScreen(((ScalarSample)sweepSample).getValue()); Point2D thisPt = new Point2D.Double(x, y); if (s < lastSweepMinPts.size()) { Point2D lstPt = lastSweepMinPts.get(s); Point close = getPointIfCloseToLine(lstPt, thisPt, snap); if (close != null) return close; } while (lastSweepMinPts.size() <= s) lastSweepMinPts.add(null); lastSweepMinPts.set(s, thisPt); } } else { int y = convertYDataToScreen(((ScalarSample)min).getValue()); Point2D thisPt = new Point2D.Double(x, y); if (lastPt != null) { Point close = getPointIfCloseToLine(lastPt, thisPt, snap); if (close != null) return close; } lastPt = thisPt; } // see if point on maximum is close Sample max = rs.getMax(); if (max instanceof SweptSample<?>) { SweptSample<?> ss = (SweptSample<?>)max; for(int s=0; s<ss.getWidth(); s++) { Sample sweepSample = ss.getSweep(s); int y = convertYDataToScreen(((ScalarSample)sweepSample).getValue()); Point2D thisPt = new Point2D.Double(x, y); if (s < lastSweepMaxPts.size()) { Point2D lstPt = lastSweepMaxPts.get(s); Point close = getPointIfCloseToLine(lstPt, thisPt, snap); if (close != null) return close; } while (lastSweepMaxPts.size() <= s) lastSweepMaxPts.add(null); lastSweepMaxPts.set(s, thisPt); } } else { int y = convertYDataToScreen(((ScalarSample)max).getValue()); Point2D thisPt = new Point2D.Double(x, y); if (lastPt != null) { Point close = getPointIfCloseToLine(lastPt, thisPt, snap); if (close != null) return close; } lastPt = thisPt; } } } // no snapping: return the original point return pt; } /** * Method to implement the Mouse Released event for selection. */ public void mouseReleasedSelect(MouseEvent evt) { if (draggingArea) { draggingArea = false; Panel wp = (Panel)evt.getSource(); if (ToolBar.getCursorMode() != ToolBar.CursorMode.MEASURE && ToolBar.getSelectMode() == ToolBar.SelectMode.OBJECTS) { List<WaveSelection> selectedObjects = wp.findSignalsInArea(convertXDataToScreen(dragStartXD), convertXDataToScreen(dragEndXD), convertYDataToScreen(dragStartYD), convertYDataToScreen(dragEndYD)); if ((evt.getModifiers()&MouseEvent.SHIFT_MASK) == 0) { // standard click: add this as the only trace clearHighlightedSignals(); for(WaveSelection wSel : selectedObjects) { if (wSel.controlPoint) { wSel.ws.addSelectedControlPoint(wSel.controlXValue); } wp.addHighlightedSignal(wSel.ws, false); } } else { // shift click: add or remove to list of highlighted traces for(WaveSelection wSel : selectedObjects) { WaveSignal ws = wSel.ws; if (ws.isHighlighted()) { if (wSel.controlPoint) ws.removeSelectedControlPoint(wSel.controlXValue); removeHighlightedSignal(ws, false); } else { if (wSel.controlPoint) ws.addSelectedControlPoint(wSel.controlXValue); wp.addHighlightedSignal(ws, false); } } } // show it in the schematic wp.waveWindow.crossProbeWaveformToEditWindow(); } else { // just leave this highlight and show dimensions } } repaintContents(); } /** * Method to implement the Mouse Dragged event for selection. */ public void mouseDraggedSelect(MouseEvent evt) { if (draggingMain) { if (evt.getX() <= 0) return; double value = convertXScreenToData(evt.getX()); waveWindow.setMainXPositionCursor(value); waveWindow.repaintAllPanels(); } else if (draggingExt) { if (evt.getX() <= 0) return; double value = convertXScreenToData(evt.getX()); waveWindow.setExtensionXPositionCursor(value); waveWindow.repaintAllPanels(); } else if (draggingVertAxis) { if (evt.getX() <= 0) return; if (waveWindow.isXAxisLocked()) { for(Iterator<Panel> it = waveWindow.getPanels(); it.hasNext(); ) { Panel wp = it.next(); wp.vertAxisPos = evt.getX(); } waveWindow.redrawAllPanels(); waveWindow.getMainHorizRuler().repaint(); } else { vertAxisPos = evt.getX(); repaintWithRulers(); } } else if (draggingArea) { Set<Panel> measureWindows = new HashSet<Panel>(); Point cPt = new Point(); Panel curPanel = this; measureWindows.add(curPanel); JTable table = waveWindow.getWaveformTable(); // find the current Panel int startPanel = 0; for(int i=0; i<table.getRowCount(); i++) { if (this == waveWindow.getPanel(i)) { startPanel = i; break; } } // find the panel with the coordinates int yp = evt.getY(); Rectangle bou = evt.getComponent().getBounds(); if (yp >= bou.y && yp < bou.y+bou.height) { cPt.setLocation(evt.getX(), evt.getY()); } else { int curPanelNum = startPanel; if (yp < bou.y) { while (yp < bou.y) { // negative coordinate: try a previous panel if (curPanelNum <= 0) break; curPanelNum--; measureWindows.add(waveWindow.getPanel(curPanelNum)); yp += table.getRowHeight(curPanelNum); } } else if (yp >= bou.y+bou.height) { while (yp >= bou.y+bou.height) { // coordinate too large: try a subsequent panel if (curPanelNum+1 >= table.getRowCount()) break; yp -= table.getRowHeight(curPanelNum); curPanelNum++; measureWindows.add(waveWindow.getPanel(curPanelNum)); } } curPanel = waveWindow.getPanel(curPanelNum); cPt.setLocation(evt.getX(), yp); } // snap to waveform point cPt = curPanel.snapPoint(cPt); dragEndXD = curPanel.convertXScreenToData(cPt.x); dragEndYD = curPanel.convertYScreenToData(cPt.y); if (ToolBar.getCursorMode() == ToolBar.CursorMode.MEASURE && !ClickZoomWireListener.isRightMouse(evt)) { // reset all panels for(Iterator<Panel> it = waveWindow.getPanels(); it.hasNext(); ) it.next().draggingArea = false; // update all windows the measurement may have crossed over for(Panel wp : measureWindows) { if (wp.curMeasurement == null) { wp.curMeasurement = new Rectangle2D.Double(); wp.measurementList.add(wp.curMeasurement); } wp.curMeasurement.setRect(dragStartXD, dragStartYD, dragEndXD-dragStartXD, dragEndYD-dragStartYD); wp.dragStartXD = dragStartXD; wp.dragStartYD = dragStartYD; wp.dragEndXD = dragEndXD; wp.dragEndYD = dragEndYD; wp.draggingArea = true; wp.repaint(); } } repaint(); } } public void mouseMovedSelect(MouseEvent evt) { // see if over horizontal cursors int mainX = convertXDataToScreen(waveWindow.getMainXPositionCursor()); int extX = convertXDataToScreen(waveWindow.getExtensionXPositionCursor()); if (Math.abs(mainX - evt.getX()) < 5 || Math.abs(extX - evt.getX()) < 5 || Math.abs(vertAxisPos - evt.getX()) < 5) { setCursor(dragXPositionCursor); } else { setCursor(Cursor.getDefaultCursor()); } } // ************************************* HIGHLIGHTING ************************************* public void clearHighlightedSignals() { for(WaveSignal ws : waveSignals.values()) { if (!ws.isHighlighted()) continue; ws.setHighlighted(false); ws.clearSelectedControlPoints(); if (ws.getButton() != null) ws.getButton().setBackground(background); } waveWindow.setHighlightedSweep(-1); repaintContents(); } public void addHighlightedSignal(WaveSignal ws, boolean repaintContents) { if (ws.getButton() != null) { if (background == null) background = ws.getButton().getBackground(); ws.getButton().setBackground(new Color(User.getColor(User.ColorPrefType.WAVE_BACKGROUND))); } ws.setHighlighted(true); waveWindow.setHighlightedSweep(-1); if (repaintContents) repaintContents(); } public void removeHighlightedSignal(WaveSignal ws, boolean repaintContents) { ws.setHighlighted(false); if (ws.getButton() != null) ws.getButton().setBackground(background); waveWindow.setHighlightedSweep(-1); if (repaintContents) repaintContents(); } public boolean isHidden() { return hidden; } public void setHidden(boolean hidden) { this.hidden = hidden; } /** * Method to make this the highlighted Panel. */ public void makeSelectedPanel(int x, int y) { for(Iterator<Panel> it = waveWindow.getPanels(); it.hasNext(); ) { Panel wp = it.next(); if (wp.selected && wp != this) { wp.selected = false; wp.repaintContents(); } } if (!selected) { selected = true; repaintContents(); } // curPanel = this; // curXPos = x; } public boolean isSelected() { return selected; } // ****************************** ZOOMING AND PANNING ****************************** /** * Method to implement the Mouse Pressed event for zooming. */ public void mousePressedZoom(MouseEvent evt) { dragStartXD = convertXScreenToData(evt.getX()); dragStartYD = convertYScreenToData(evt.getY()); ZoomAndPanListener.setProperCursor(evt); draggingArea = true; } /** * Method to implement the Mouse Released event for zooming. */ public void mouseReleasedZoom(MouseEvent evt) { ZoomAndPanListener.setProperCursor(evt); draggingArea = false; double lowXValue = Math.min(dragEndXD, dragStartXD); double highXValue = Math.max(dragEndXD, dragStartXD); double xRange = highXValue - lowXValue; lowXValue -= xRange / 8; highXValue += xRange / 8; double lowValue = Math.min(dragEndYD, dragStartYD); double highValue = Math.max(dragEndYD, dragStartYD); double valueRange = highValue - lowValue; lowValue -= valueRange / 8; highValue += valueRange / 8; for(Iterator<Panel> it = waveWindow.getPanels(); it.hasNext(); ) { Panel wp = it.next(); if (!waveWindow.isXAxisLocked() && wp != this) continue; if ((evt.getModifiers()&MouseEvent.SHIFT_MASK) == 0 || ClickZoomWireListener.isRightMouse(evt)) { // standard click: zoom in if (wp.getMinXAxis() > wp.getMaxXAxis()) wp.setXAxisRange(highXValue, lowXValue); else wp.setXAxisRange(lowXValue, highXValue); if (wp == this) wp.setYAxisRange(lowValue, highValue); } else { // shift-click: zoom out double oldRange = wp.maxXPosition - wp.minXPosition; double min = (lowXValue + highXValue) / 2 - oldRange; double max = (lowXValue + highXValue) / 2 + oldRange; if (wp.getMinXAxis() > wp.getMaxXAxis()) wp.setXAxisRange(max, min); else wp.setXAxisRange(min, max); if (wp == this) wp.setYAxisRange((lowValue + highValue) / 2 - wp.analogRange, (lowValue + highValue) / 2 + wp.analogRange); } wp.repaintWithRulers(); } } /** * Method to implement the Mouse Dragged event for zooming. */ public void mouseDraggedZoom(MouseEvent evt) { // ZoomAndPanListener.setProperCursor(evt); if (draggingArea) { dragEndXD = convertXScreenToData(evt.getX()); dragEndYD = convertYScreenToData(evt.getY()); repaint(); // repaintContents(); } } public void mouseMovedZoom(MouseEvent evt) { // ZoomAndPanListener.setProperCursor(evt); } /** * Method to implement the Mouse Pressed event for panning. */ public void mousePressedPan(MouseEvent evt) { dragStartXD = convertXScreenToData(evt.getX()); dragStartYD = convertYScreenToData(evt.getY()); } /** * Method to implement the Mouse Released event for panning. */ public void mouseReleasedPan(MouseEvent evt) { } /** * Method to implement the Mouse Dragged event for panning. */ public void mouseDraggedPan(MouseEvent evt) { dragEndXD = convertXScreenToData(evt.getX()); double dXValue = dragEndXD - dragStartXD; dragEndYD = convertYScreenToData(evt.getY()); double dYValue = dragEndYD - dragStartYD; for(Iterator<Panel> it = waveWindow.getPanels(); it.hasNext(); ) { Panel wp = it.next(); if (!waveWindow.isXAxisLocked() && wp != this) continue; wp.setXAxisRange(wp.minXPosition - dXValue, wp.maxXPosition - dXValue); if (wp == this) setYAxisRange(analogLowValue - dYValue, analogHighValue - dYValue); wp.repaintWithRulers(); } dragStartXD = dragEndXD; dragStartYD = dragEndYD; } public void mouseMovedPan(MouseEvent evt) {} }