/******************************************************************************* * This file is part of logisim-evolution. * * logisim-evolution 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. * * logisim-evolution 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 logisim-evolution. If not, see <http://www.gnu.org/licenses/>. * * Original code by Carl Burch (http://www.cburch.com), 2011. * Subsequent modifications by : * + Haute École Spécialisée Bernoise * http://www.bfh.ch * + Haute École du paysage, d'ingénierie et d'architecture de Genève * http://hepia.hesge.ch/ * + Haute École d'Ingénierie et de Gestion du Canton de Vaud * http://www.heig-vd.ch/ * The project is currently maintained by : * + REDS Institute - HEIG-VD * Yverdon-les-Bains, Switzerland * http://reds.heig-vd.ch *******************************************************************************/ package com.hepia.logisim.chronogui; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; 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.image.BufferedImage; import javax.swing.JPanel; import com.hepia.logisim.chronodata.SignalData; import com.hepia.logisim.chronodata.SignalDataBus; /** * Draw a single signal or bus in the chronogram right area */ public class SignalDraw extends JPanel { private class MyListener implements MouseListener, MouseMotionListener, MouseWheelListener { @Override public void mouseClicked(MouseEvent e) { } @Override public void mouseDragged(MouseEvent e) { int posX = e.getX(); if (posX < 0) posX = 0; if (posX > getWidth()) posX = getWidth() - 1; mDrawAreaEventManager.fireMouseDragged(mSignalData, posX); } @Override public void mouseEntered(MouseEvent e) { mDrawAreaEventManager.fireMouseEntered(mSignalData); } @Override public void mouseExited(MouseEvent e) { mDrawAreaEventManager.fireMouseExited(mSignalData); } @Override public void mouseMoved(MouseEvent e) { } @Override public void mousePressed(MouseEvent e) { int posX = e.getX() >= 0 ? e.getX() : 0; mDrawAreaEventManager.fireMousePressed(mSignalData, posX); } @Override public void mouseReleased(MouseEvent e) { } @Override public void mouseWheelMoved(MouseWheelEvent e) { if (e.getWheelRotation() > 0) mDrawAreaEventManager.fireZoom(mSignalData, -1, e.getPoint().x); else mDrawAreaEventManager.fireZoom(mSignalData, 1, e.getPoint().x); } } private static final long serialVersionUID = 1L; private int tickWidth; private int busCrossingPosition; private Color lightGray = new Color(180, 180, 180, 100); private int lineTickness = 1; private int lowPos; private int highPos; private int width = 10; private int height; private BufferedImage signalDrawBuffered; private boolean isBufferObsolete = true; private SignalData mSignalData; private DrawAreaEventManager mDrawAreaEventManager; private RightPanel mRightPanel; private MyListener myListener = new MyListener(); public SignalDraw(RightPanel rightPanel, DrawAreaEventManager drawAreaEventManager, SignalData signalData, int height) { this.mRightPanel = rightPanel; this.mDrawAreaEventManager = drawAreaEventManager; this.mSignalData = signalData; this.tickWidth = rightPanel.getTickWidth(); this.width = tickWidth * signalData.getSignalValues().size(); if (this.width < 10) this.width = 10; this.height = height; this.busCrossingPosition = computeBusCrossingPosition(tickWidth); this.lowPos = height - 6; this.highPos = 6; this.setBackground(Color.white); this.setMaximumSize(new Dimension(width, height)); this.setPreferredSize(new Dimension(width, height)); this.setDoubleBuffered(true); this.addMouseListener(myListener); this.addMouseMotionListener(myListener); this.addMouseWheelListener(myListener); this.addMouseListener(new PopupMenu(drawAreaEventManager, signalData)); } /** * Compute the size of the cross (when a bus value change) */ private int computeBusCrossingPosition(int tickWidth) { return tickWidth - 5 < 1 ? 0 : 5; } /** * Draw the signals and buses */ private void drawSignal(Graphics g) { Graphics2D g2 = (Graphics2D) g; g2.setStroke(new BasicStroke(lineTickness)); int middleHeight = getHeight() / 2; int posX = 0; String prec, suiv; // get the index of data in SignalData that correspond to the display float posPercent = (float) mRightPanel.getDisplayOffsetX() / (float) mRightPanel.getSignalWidth(); int i = Math.round(mSignalData.getSignalValues().size() * posPercent); // drawing prec = mSignalData.getSignalValues().get(i++); while (posX < mRightPanel.getDisplayOffsetX() + getVisibleRect().width + (10 * tickWidth) && i < mSignalData.getSignalValues().size()) { suiv = mSignalData.getSignalValues().get(i++); String transi = prec + suiv; if (suiv.contains("E")) { g.setColor(Color.red); g.drawLine(posX, highPos, posX + tickWidth, middleHeight); g.drawLine(posX, middleHeight, posX + tickWidth, highPos); g.drawLine(posX, middleHeight, posX + tickWidth, lowPos); g.drawLine(posX, lowPos, posX + tickWidth, middleHeight); g.setColor(Color.black); } else if (suiv.contains("x")) { g.setColor(Color.blue); g.drawLine(posX, highPos, posX + tickWidth, middleHeight); g.drawLine(posX, middleHeight, posX + tickWidth, highPos); g.drawLine(posX, middleHeight, posX + tickWidth, lowPos); g.drawLine(posX, lowPos, posX + tickWidth, middleHeight); g.setColor(Color.black); } else if (suiv.equals("0")) { g.drawLine(posX, lowPos, posX + tickWidth, lowPos); } else if (suiv.equals("1")) { g.setColor(lightGray); g.fillRect(posX + 1, highPos, tickWidth, lowPos - highPos); g.setColor(Color.black); g.drawLine(posX, highPos, posX + tickWidth, highPos); } else { if (mSignalData instanceof SignalDataBus) { SignalDataBus sdb = (SignalDataBus) mSignalData; // first value if (i == 2) g.drawString(sdb.getValueInFormat(suiv), posX + 2, getHeight() / 2); // bus transition if (!suiv.contains("x") && !suiv.contains("E") && !suiv.equals(prec)) { g.drawLine(posX, lowPos, posX + busCrossingPosition, highPos); g.drawLine(posX, highPos, posX + busCrossingPosition, lowPos); g.drawLine(posX + busCrossingPosition, highPos, posX + tickWidth, highPos); g.drawLine(posX + busCrossingPosition, lowPos, posX + tickWidth, lowPos); g.drawString(sdb.getValueInFormat(suiv), posX + tickWidth, getHeight() / 2); } else { g.drawLine(posX, lowPos, posX + tickWidth, lowPos); g.drawLine(posX, highPos, posX + tickWidth, highPos); } } } // transition if (transi.equals("10")) { g.drawLine(posX, highPos, posX, lowPos); } else if (transi.equals("01")) { g.drawLine(posX, lowPos, posX, highPos); } prec = suiv; posX += tickWidth; } } public SignalData getSignalData() { return mSignalData; } /** * if on, the signal is displayed thicker */ public void highlight(boolean on) { if (lineTickness == 2) { if (!on) { isBufferObsolete = true; lineTickness = 1; this.repaint(); } } else { if (on) { isBufferObsolete = true; lineTickness = 2; this.repaint(); } } } public void paintComponent(Graphics g) { super.paintComponent(g); if (mSignalData.getSignalValues().size() > 1) { Graphics2D g2 = (Graphics2D) g; // if scroll or zoom, redraw everything into buffer if (isBufferObsolete) { signalDrawBuffered = (BufferedImage) (this.createImage( mRightPanel.getVisibleWidth() * 2, height)); Graphics2D g2a = signalDrawBuffered.createGraphics(); g2a.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_DEFAULT); drawSignal(g2a); isBufferObsolete = false; } g2.drawImage(signalDrawBuffered, null, mRightPanel.getDisplayOffsetX(), 0); } } /** * Call this function when the drawed signal is outdated ex: after zoom or * scroll. */ public void setBufferObsolete() { isBufferObsolete = true; } public void setSignalDrawSize(int width, int height) { this.width = width; this.height = height; this.setMaximumSize(new Dimension(width, height)); this.setPreferredSize(new Dimension(width, height)); } public void setTickWidth(int tickWidth) { isBufferObsolete = true; this.tickWidth = tickWidth; this.busCrossingPosition = computeBusCrossingPosition(tickWidth); int width = tickWidth * mSignalData.getSignalValues().size(); setSignalDrawSize(width, height); } }