/* Copyright (c) 2010, Carl Burch. License information is located in the * com.cburch.logisim.Main source code and at www.cburch.com/logisim/. */ package com.cburch.logisim.tools; import java.awt.Color; import java.awt.Cursor; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import javax.swing.Icon; import com.cburch.logisim.circuit.Circuit; import com.cburch.logisim.circuit.CircuitEvent; import com.cburch.logisim.circuit.CircuitListener; import com.cburch.logisim.circuit.RadixOption; import com.cburch.logisim.circuit.Wire; import com.cburch.logisim.circuit.WireSet; import com.cburch.logisim.comp.Component; import com.cburch.logisim.comp.ComponentDrawContext; import com.cburch.logisim.comp.ComponentUserEvent; import com.cburch.logisim.data.AttributeSet; import com.cburch.logisim.data.Location; import com.cburch.logisim.data.Value; import com.cburch.logisim.gui.main.Canvas; import com.cburch.logisim.gui.main.SelectionActions; import com.cburch.logisim.prefs.AppPreferences; import com.cburch.logisim.proj.Project; import com.cburch.logisim.util.Icons; public class PokeTool extends Tool { private class Listener implements CircuitListener { @Override public void circuitChanged(CircuitEvent event) { Circuit circ = pokedCircuit; if (event.getCircuit() == circ && circ != null && (event.getAction() == CircuitEvent.ACTION_REMOVE || event.getAction() == CircuitEvent.ACTION_CLEAR) && !circ.contains(pokedComponent)) { removeCaret(false); } } } private static class WireCaret extends AbstractCaret { Canvas canvas; Wire wire; int x; int y; WireCaret(Canvas c, Wire w, int x, int y, AttributeSet opts) { canvas = c; wire = w; this.x = x; this.y = y; } @Override public void draw(Graphics g) { Value v = canvas.getCircuitState().getValue(wire.getEnd0()); RadixOption radix1 = RadixOption.decode(AppPreferences.POKE_WIRE_RADIX1.get()); RadixOption radix2 = RadixOption.decode(AppPreferences.POKE_WIRE_RADIX2.get()); if (radix1 == null) radix1 = RadixOption.RADIX_2; String vStr = radix1.toString(v); if (radix2 != null && v.getWidth() > 1) { vStr += " / " + radix2.toString(v); } FontMetrics fm = g.getFontMetrics(); Rectangle r = canvas.getViewableRectangle(); g.fillOval(x - 2, y - 2, 4, 4); g.setColor(Color.WHITE); boolean left = x < r.x + r.width / 2; boolean up = y < r.y + r.height / 2; if (left) { // left oriented int[] xPoints = { x, x, x + 4 + fm.stringWidth(vStr), x + 4 + fm.stringWidth(vStr), x + 3 }; if (up) { // number above the mouse int[] yPoints = { y, y + 8 + fm.getAscent() + fm.getDescent(), y + 8 + fm.getAscent() + fm.getDescent(), y + 6, y + 6 }; g.fillPolygon(xPoints, yPoints, 5); g.setColor(Color.BLACK); g.drawPolygon(xPoints, yPoints, 5); g.drawString(vStr, x + 2, y + 7 + fm.getAscent()); } else { // number below the mouse int[] yPoints = { y, y - 8 - fm.getAscent() - fm.getDescent(), y - 8 - fm.getAscent() - fm.getDescent(), y - 6, y - 6 }; g.fillPolygon(xPoints, yPoints, 5); g.setColor(Color.BLACK); g.drawPolygon(xPoints, yPoints, 5); g.drawString(vStr, x + 2, y - 7 - fm.getDescent()); } } else { // right oriented int[] xPoints = { x, x, x - 4 - fm.stringWidth(vStr), x - 4 - fm.stringWidth(vStr), x - 3 }; if (up) { // number above the mouse int[] yPoints = { y, y + 8 + fm.getAscent() + fm.getDescent(), y + 8 + fm.getAscent() + fm.getDescent(), y + 6, y + 6 }; g.fillPolygon(xPoints, yPoints, 5); g.setColor(Color.BLACK); g.drawPolygon(xPoints, yPoints, 5); g.drawString(vStr, x - 2 - fm.stringWidth(vStr), y + 7 + fm.getAscent()); } else { // number below the mouse int[] yPoints = { y, y - 8 - fm.getAscent() - fm.getDescent(), y - 8 - fm.getAscent() - fm.getDescent(), y - 6, y - 6 }; g.fillPolygon(xPoints, yPoints, 5); g.setColor(Color.BLACK); g.drawPolygon(xPoints, yPoints, 5); g.drawString(vStr, x - 2 - fm.stringWidth(vStr), y - 7 - fm.getDescent()); } } } } private static final Icon toolIcon = Icons.getIcon("poke.gif"); private static final Cursor cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); private static final Cursor move = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR); private Listener listener; private Circuit pokedCircuit; private Component pokedComponent; private Caret pokeCaret; private int x = 0, y = 0, x0 = 0, y0 = 0, ScrollBarX = 0, ScrollBarY = 0; public PokeTool() { this.listener = new Listener(); } @Override public void deselect(Canvas canvas) { removeCaret(true); canvas.setHighlightedWires(WireSet.EMPTY); } @Override public void draw(Canvas canvas, ComponentDrawContext context) { if (pokeCaret != null) pokeCaret.draw(context.getGraphics()); } @Override public boolean equals(Object other) { return other instanceof PokeTool; } @Override public Cursor getCursor() { return cursor; } @Override public String getDescription() { return Strings.get("pokeToolDesc"); } @Override public String getDisplayName() { return Strings.get("pokeTool"); } @Override public String getName() { return "Poke Tool"; } @Override public int hashCode() { return PokeTool.class.hashCode(); } @Override public void keyPressed(Canvas canvas, KeyEvent e) { if (pokeCaret != null) { pokeCaret.keyPressed(e); canvas.getProject().repaintCanvas(); } } @Override public void keyReleased(Canvas canvas, KeyEvent e) { if (pokeCaret != null) { pokeCaret.keyReleased(e); canvas.getProject().repaintCanvas(); } } @Override public void keyTyped(Canvas canvas, KeyEvent e) { if (pokeCaret != null) { pokeCaret.keyTyped(e); canvas.getProject().repaintCanvas(); } } @Override public void mouseDragged(Canvas canvas, Graphics g, MouseEvent e) { if (pokeCaret != null) { pokeCaret.mouseDragged(e); canvas.getProject().repaintCanvas(); } else { // move scrollpane dragging hand Point m = canvas.getMousePosition(); if (m == null) { // if mouse exited and continue dragging this.x0 = -1; this.y0 = -1; this.ScrollBarX = -1; this.ScrollBarY = -1; return; } else if (this.x0 == -1 || this.y0 == -1 || this.ScrollBarX == -1 || this.ScrollBarY == -1) { // if mouse re-entered after it exited without releasing the button this.x0 = (int) m.getX(); this.y0 = (int) m.getY(); this.ScrollBarX = canvas.getHorizzontalScrollBar(); this.ScrollBarY = canvas.getVerticalScrollBar(); } int x = (int) (this.x0 - m.getX()); int y = (int) (this.y0 - m.getY()); canvas.setCursor(move); canvas.setScrollBar(this.ScrollBarX + x, this.ScrollBarY + y); canvas.setArrows(); } } @Override public void mousePressed(Canvas canvas, Graphics g, MouseEvent e) { this.x0 = (int) canvas.getMousePosition().getX(); this.y0 = (int) canvas.getMousePosition().getY(); this.x = e.getX(); this.y = e.getY(); this.ScrollBarX = canvas.getHorizzontalScrollBar(); this.ScrollBarY = canvas.getVerticalScrollBar(); canvas.setCursor(cursor); Location loc = Location.create(x, y); boolean dirty = false; canvas.setHighlightedWires(WireSet.EMPTY); if (pokeCaret != null && !pokeCaret.getBounds(g).contains(loc)) { dirty = true; removeCaret(true); } if (pokeCaret == null) { ComponentUserEvent event = new ComponentUserEvent(canvas, x, y); Circuit circ = canvas.getCircuit(); for (Component c : circ.getAllContaining(loc, g)) { if (pokeCaret != null) break; if (c instanceof Wire) { Caret caret = new WireCaret(canvas, (Wire) c, x, y, canvas.getProject().getOptions().getAttributeSet()); setPokedComponent(circ, c, caret); canvas.setHighlightedWires(circ.getWireSet((Wire) c)); } else { Pokable p = (Pokable) c.getFeature(Pokable.class); if (p != null) { Caret caret = p.getPokeCaret(event); setPokedComponent(circ, c, caret); AttributeSet attrs = c.getAttributeSet(); if (attrs != null && attrs.getAttributes().size() > 0) { SelectionActions.dropAll(canvas.getSelection()); Project proj = canvas.getProject(); proj.getFrame().viewComponentAttributes(circ, c); } } } } } if (pokeCaret != null) { dirty = true; pokeCaret.mousePressed(e); } if (dirty) canvas.getProject().repaintCanvas(); } @Override public void mouseReleased(Canvas canvas, Graphics g, MouseEvent e) { if (pokeCaret != null) { pokeCaret.mouseReleased(e); canvas.getProject().repaintCanvas(); } } @Override public void paintIcon(ComponentDrawContext c, int x, int y) { Graphics g = c.getGraphics(); if (toolIcon != null) { toolIcon.paintIcon(c.getDestination(), g, x + 2, y + 2); } else { g.setColor(java.awt.Color.black); g.drawLine(x + 4, y + 2, x + 4, y + 17); g.drawLine(x + 4, y + 17, x + 1, y + 11); g.drawLine(x + 4, y + 17, x + 7, y + 11); g.drawLine(x + 15, y + 2, x + 15, y + 17); g.drawLine(x + 15, y + 2, x + 12, y + 8); g.drawLine(x + 15, y + 2, x + 18, y + 8); } } private void removeCaret(boolean normal) { Circuit circ = pokedCircuit; Caret caret = pokeCaret; if (caret != null) { if (normal) caret.stopEditing(); else caret.cancelEditing(); circ.removeCircuitListener(listener); pokedCircuit = null; pokedComponent = null; pokeCaret = null; } } private void setPokedComponent(Circuit circ, Component comp, Caret caret) { removeCaret(true); pokedCircuit = circ; pokedComponent = comp; pokeCaret = caret; if (caret != null) { circ.addCircuitListener(listener); } } }