mirror of https://github.com/lawrancej/logisim.git
Integrating a large number bug fixes, all of which (or most of which) are based on bug reports submitted through SourceForge:
Feature: The window's last-observed location is saved as a preference, and that location is used when the application starts later. Bug fix: The Probe's Radix attribute displayed the values as they are saved in the file, rather than the display strings based on the current translation being used. Appearance change: Rectangular XOR and XNOR gates are drawn with "=1" to conform to the ISO standard (previously it was simply "1"). However, if the "Multiple-Input Behavior" attribute is "When an odd number are on" and there are more than two inputs, the label is "2k+1" to reflect that it is actually doing an odd parity. (Previously it showed this label for odd parity even when there were just two inputs.) Bug fix: Edits to the Bit Extender's Extension Type attribute or the Comparator's did not have an immediate effect in the circuit. Bug fix: Under MacOS X, the title bar's close-window button would indicate that the file was changed after the first change, but the indicator would not disappear when the file was saved. Bug fix: When a rectangle, oval, or rounded rectangle in a circuit's appearance had a paint type of "Border & Fill" and it was filled with solid black, that information was not properly stored in the saved file. Bug fix: Libraries could not be unloaded. Bug fix: The XNOR gate incorrectly did even parity by default, rather than being off only when exactly one input is one. Bug fix: Most options were not loaded when a file was later reopened (all except the toolbar and mouse mappings). Bug fix: The Logisim version saved in the project file was not interpreted correctly when opening the project. One consequence: If you edited the toolbar to include the Select and Wiring tools, they would be replaced by the Edit tool when reloaded. Bug fix: When moving a selection so that one wire in the selection is moved exactly into the location of a wire being moved, the wire would sometimes disappear entirely rather than be moved. Bug fix: With the Edit Tool, pressing the backspace key deletes the current selection (just as it does when the delete key is pressed). Bug fix: Edits to the Bit Extender's Extension Type attribute or the Comparator's did not have an immediate effect in the circuit. Bug fix: Under MacOS X, the title bar's close-window button would indicate that the file was changed after the first change, but the indicator would not disappear when the file was saved. git-svn-id: https://circuit.svn.sourceforge.net/svnroot/circuit/trunk@164 70edf91d-0b9e-4248-82e7-2488d7716404
This commit is contained in:
parent
dcda046abb
commit
d4499774e5
|
@ -143,7 +143,9 @@ class SvgCreator {
|
|||
elt.setAttribute("fill", "none");
|
||||
} else {
|
||||
Color fill = shape.getValue(DrawAttr.FILL_COLOR);
|
||||
if (!colorMatches(fill, Color.BLACK)) {
|
||||
if (colorMatches(fill, Color.BLACK)) {
|
||||
elt.removeAttribute("fill");
|
||||
} else {
|
||||
elt.setAttribute("fill", getColorString(fill));
|
||||
}
|
||||
if (showOpacity(fill)) {
|
||||
|
|
|
@ -49,7 +49,7 @@ public class SvgReader {
|
|||
String fill = elt.getAttribute("fill");
|
||||
if (stroke.equals("") || stroke.equals("none")) {
|
||||
ret.setValue(DrawAttr.PAINT_TYPE, DrawAttr.PAINT_FILL);
|
||||
} else if (fill.equals("") || fill.equals("none")) {
|
||||
} else if (fill.equals("none")) {
|
||||
ret.setValue(DrawAttr.PAINT_TYPE, DrawAttr.PAINT_STROKE);
|
||||
} else {
|
||||
ret.setValue(DrawAttr.PAINT_TYPE, DrawAttr.PAINT_STROKE_FILL);
|
||||
|
@ -69,6 +69,7 @@ public class SvgReader {
|
|||
}
|
||||
if (attrs.contains(DrawAttr.FILL_COLOR)) {
|
||||
String color = elt.getAttribute("fill");
|
||||
if (color.equals("")) color = "#000000";
|
||||
String opacity = elt.getAttribute("fill-opacity");
|
||||
if (!color.equals("none")) {
|
||||
ret.setValue(DrawAttr.FILL_COLOR, getColor(color, opacity));
|
||||
|
|
|
@ -15,7 +15,7 @@ public class LogisimVersion {
|
|||
}
|
||||
|
||||
public static LogisimVersion parse(String versionString) {
|
||||
String[] parts = versionString.split(".");
|
||||
String[] parts = versionString.split("\\.");
|
||||
int major = 0;
|
||||
int minor = 0;
|
||||
int release = 0;
|
||||
|
|
|
@ -145,20 +145,28 @@ class CircuitChange {
|
|||
}
|
||||
}
|
||||
|
||||
void execute(CircuitMutator mutator) {
|
||||
void execute(CircuitMutator mutator, ReplacementMap prevReplacements) {
|
||||
switch (type) {
|
||||
case CLEAR: mutator.clear(circuit); break;
|
||||
case ADD: mutator.add(circuit, comp); break;
|
||||
case CLEAR: mutator.clear(circuit); prevReplacements.reset(); break;
|
||||
case ADD: prevReplacements.add(comp); break;
|
||||
case ADD_ALL:
|
||||
for (Component comp : comps) mutator.add(circuit, comp);
|
||||
for (Component comp : comps) prevReplacements.add(comp);
|
||||
break;
|
||||
case REMOVE: mutator.remove(circuit, comp); break;
|
||||
case REMOVE: prevReplacements.remove(comp); break;
|
||||
case REMOVE_ALL:
|
||||
for (Component comp : comps) mutator.remove(circuit, comp);
|
||||
for (Component comp : comps) prevReplacements.remove(comp);
|
||||
break;
|
||||
case REPLACE: prevReplacements.append((ReplacementMap) newValue); break;
|
||||
case SET:
|
||||
mutator.replace(circuit, prevReplacements);
|
||||
prevReplacements.reset();
|
||||
mutator.set(circuit, comp, attr, newValue);
|
||||
break;
|
||||
case SET_FOR_CIRCUIT:
|
||||
mutator.replace(circuit, prevReplacements);
|
||||
prevReplacements.reset();
|
||||
mutator.setForCircuit(circuit, attr, newValue);
|
||||
break;
|
||||
case REPLACE: mutator.replace(circuit, (ReplacementMap) newValue); break;
|
||||
case SET: mutator.set(circuit, comp, attr, newValue); break;
|
||||
case SET_FOR_CIRCUIT: mutator.setForCircuit(circuit, attr, newValue); break;
|
||||
default: throw new IllegalArgumentException("unknown change type " + type);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,8 +103,21 @@ public final class CircuitMutation extends CircuitTransaction {
|
|||
|
||||
@Override
|
||||
protected void run(CircuitMutator mutator) {
|
||||
Circuit curCircuit = null;
|
||||
ReplacementMap curReplacements = null;
|
||||
for (CircuitChange change : changes) {
|
||||
change.execute(mutator);
|
||||
Circuit circ = change.getCircuit();
|
||||
if (circ != curCircuit) {
|
||||
if (curCircuit != null) {
|
||||
mutator.replace(curCircuit, curReplacements);
|
||||
}
|
||||
curCircuit = circ;
|
||||
curReplacements = new ReplacementMap();
|
||||
}
|
||||
change.execute(mutator, curReplacements);
|
||||
}
|
||||
if (curCircuit != null) {
|
||||
mutator.replace(curCircuit, curReplacements);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,12 +4,13 @@
|
|||
package com.cburch.logisim.circuit;
|
||||
|
||||
import com.cburch.logisim.data.Attribute;
|
||||
import com.cburch.logisim.data.AttributeOption;
|
||||
import com.cburch.logisim.data.Attributes;
|
||||
import com.cburch.logisim.data.BitWidth;
|
||||
import com.cburch.logisim.data.Value;
|
||||
import com.cburch.logisim.util.StringGetter;
|
||||
|
||||
public abstract class RadixOption {
|
||||
public abstract class RadixOption extends AttributeOption {
|
||||
public static final RadixOption RADIX_2 = new Radix2();
|
||||
public static final RadixOption RADIX_8 = new Radix8();
|
||||
public static final RadixOption RADIX_10_UNSIGNED = new Radix10Unsigned();
|
||||
|
@ -35,6 +36,7 @@ public abstract class RadixOption {
|
|||
private StringGetter displayGetter;
|
||||
|
||||
private RadixOption(String saveName, StringGetter displayGetter) {
|
||||
super(saveName, displayGetter);
|
||||
this.saveName = saveName;
|
||||
this.displayGetter = displayGetter;
|
||||
}
|
||||
|
@ -47,6 +49,7 @@ public abstract class RadixOption {
|
|||
return saveName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toDisplayString() {
|
||||
return displayGetter.get();
|
||||
}
|
||||
|
|
|
@ -39,6 +39,11 @@ public class ReplacementMap {
|
|||
this.inverse = inverse;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
map.clear();
|
||||
inverse.clear();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return map.isEmpty() && inverse.isEmpty();
|
||||
}
|
||||
|
|
|
@ -28,6 +28,15 @@ class WireIterator implements Iterator<Location> {
|
|||
if (curY < destY) deltaY = 10;
|
||||
else if (curY > destY) deltaY = -10;
|
||||
else deltaY = 0;
|
||||
|
||||
int offX = (destX - curX) % 10;
|
||||
if (offX != 0) { // should not happen, but in case it does...
|
||||
destX = curX + deltaX * ((destX - curX) / 10);
|
||||
}
|
||||
int offY = (destY - curY) % 10;
|
||||
if (offY != 0) { // should not happen, but in case it does...
|
||||
destY = curY + deltaY * ((destY - curY) / 10);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
|
|
|
@ -270,8 +270,8 @@ public class LogisimFile extends Library implements LibraryEventSource {
|
|||
factories.add(((AddTool) tool).getFactory());
|
||||
}
|
||||
}
|
||||
for (AddTool tool : tools) {
|
||||
Circuit circuit = (Circuit) tool.getFactory();
|
||||
|
||||
for (Circuit circuit : getCircuits()) {
|
||||
for (Component comp : circuit.getNonWires()) {
|
||||
if (factories.contains(comp.getFactory())) {
|
||||
return StringUtil.format(Strings.get("unloadUsedError"),
|
||||
|
@ -300,10 +300,6 @@ public class LogisimFile extends Library implements LibraryEventSource {
|
|||
fireEvent(LibraryEvent.SET_MAIN, circuit);
|
||||
}
|
||||
|
||||
public void setOptions(Options options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
//
|
||||
// other methods
|
||||
//
|
||||
|
|
|
@ -32,11 +32,15 @@ public class Options {
|
|||
GATE_UNDEFINED_IGNORE, Integer.valueOf(1000), Integer.valueOf(0),
|
||||
};
|
||||
|
||||
private AttributeSet attrs = AttributeSets.fixedSet(ATTRIBUTES, DEFAULTS);
|
||||
private MouseMappings mmappings = new MouseMappings();
|
||||
private ToolbarData toolbar = new ToolbarData();
|
||||
private AttributeSet attrs;
|
||||
private MouseMappings mmappings;
|
||||
private ToolbarData toolbar;
|
||||
|
||||
public Options() { }
|
||||
public Options() {
|
||||
attrs = AttributeSets.fixedSet(ATTRIBUTES, DEFAULTS);
|
||||
mmappings = new MouseMappings();
|
||||
toolbar = new ToolbarData();
|
||||
}
|
||||
|
||||
public AttributeSet getAttributeSet() {
|
||||
return attrs;
|
||||
|
|
|
@ -94,7 +94,7 @@ class XmlReader {
|
|||
if (name.equals("circuit") || name.equals("lib")) {
|
||||
; // Nothing to do: Done earlier.
|
||||
} else if (name.equals("options")) {
|
||||
initAttributeSet(elt, file.getOptions().getAttributeSet(), null);
|
||||
initAttributeSet(sub_elt, file.getOptions().getAttributeSet(), null);
|
||||
} else if (name.equals("mappings")) {
|
||||
initMouseMappings(sub_elt);
|
||||
} else if (name.equals("toolbar")) {
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
/* 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.gui.generic;
|
||||
|
||||
import java.awt.Frame;
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
/* 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.gui.generic;
|
||||
|
||||
import java.awt.Image;
|
||||
|
|
|
@ -7,6 +7,12 @@ import java.awt.BorderLayout;
|
|||
import java.awt.Color;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.IllegalComponentStateException;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
|
@ -45,6 +51,7 @@ import com.cburch.logisim.proj.Project;
|
|||
import com.cburch.logisim.proj.ProjectActions;
|
||||
import com.cburch.logisim.proj.ProjectEvent;
|
||||
import com.cburch.logisim.proj.ProjectListener;
|
||||
import com.cburch.logisim.proj.Projects;
|
||||
import com.cburch.logisim.tools.SetAttributeAction;
|
||||
import com.cburch.logisim.tools.Tool;
|
||||
import com.cburch.logisim.util.HorizontalSplitPane;
|
||||
|
@ -65,12 +72,6 @@ public class Frame extends LFrame implements LocaleListener {
|
|||
public void projectChanged(ProjectEvent event) {
|
||||
int action = event.getAction();
|
||||
|
||||
if (action == ProjectEvent.ACTION_COMPLETE
|
||||
|| action == ProjectEvent.UNDO_COMPLETE
|
||||
|| action == ProjectEvent.ACTION_SET_FILE) {
|
||||
enableSave();
|
||||
}
|
||||
|
||||
if (action == ProjectEvent.ACTION_SET_FILE) {
|
||||
computeTitle();
|
||||
proj.setTool(proj.getOptions().getToolbarData().getFirstTool());
|
||||
|
@ -93,6 +94,8 @@ public class Frame extends LFrame implements LocaleListener {
|
|||
public void libraryChanged(LibraryEvent e) {
|
||||
if (e.getAction() == LibraryEvent.SET_NAME) {
|
||||
computeTitle();
|
||||
} else if (e.getAction() == LibraryEvent.DIRTY_STATE) {
|
||||
enableSave();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -259,6 +262,10 @@ public class Frame extends LFrame implements LocaleListener {
|
|||
|
||||
this.setSize(AppPreferences.WINDOW_WIDTH.get().intValue(),
|
||||
AppPreferences.WINDOW_HEIGHT.get().intValue());
|
||||
Point prefPoint = getInitialLocation();
|
||||
if (prefPoint != null) {
|
||||
this.setLocation(prefPoint);
|
||||
}
|
||||
this.setExtendedState(AppPreferences.WINDOW_STATE.get().intValue());
|
||||
|
||||
menuListener.register(mainPanel);
|
||||
|
@ -372,6 +379,7 @@ public class Frame extends LFrame implements LocaleListener {
|
|||
s = StringUtil.format(Strings.get("titleFileKnown"), name);
|
||||
}
|
||||
this.setTitle(s);
|
||||
myProjectListener.enableSave();
|
||||
}
|
||||
|
||||
void viewAttributes(Tool newTool) {
|
||||
|
@ -436,6 +444,15 @@ public class Frame extends LFrame implements LocaleListener {
|
|||
Dimension dim = getSize();
|
||||
AppPreferences.WINDOW_WIDTH.set(Integer.valueOf(dim.width));
|
||||
AppPreferences.WINDOW_HEIGHT.set(Integer.valueOf(dim.height));
|
||||
Point loc;
|
||||
try {
|
||||
loc = getLocationOnScreen();
|
||||
} catch (IllegalComponentStateException e) {
|
||||
loc = Projects.getLocation(this);
|
||||
}
|
||||
if (loc != null) {
|
||||
AppPreferences.WINDOW_LOCATION.set(loc.x + "," + loc.y);
|
||||
}
|
||||
AppPreferences.WINDOW_LEFT_SPLIT.set(Double.valueOf(leftRegion.getFraction()));
|
||||
AppPreferences.WINDOW_MAIN_SPLIT.set(Double.valueOf(mainRegion.getFraction()));
|
||||
}
|
||||
|
@ -468,4 +485,62 @@ public class Frame extends LFrame implements LocaleListener {
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static Point getInitialLocation() {
|
||||
String s = AppPreferences.WINDOW_LOCATION.get();
|
||||
if (s == null) return null;
|
||||
int comma = s.indexOf(',');
|
||||
if (comma < 0) return null;
|
||||
try {
|
||||
int x = Integer.parseInt(s.substring(0, comma));
|
||||
int y = Integer.parseInt(s.substring(comma + 1));
|
||||
while (isProjectFrameAt(x, y)) {
|
||||
x += 20;
|
||||
y += 20;
|
||||
}
|
||||
Rectangle desired = new Rectangle(x, y, 50, 50);
|
||||
|
||||
int gcBestSize = 0;
|
||||
Point gcBestPoint = null;
|
||||
GraphicsEnvironment ge;
|
||||
ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
for (GraphicsDevice gd : ge.getScreenDevices()) {
|
||||
for (GraphicsConfiguration gc : gd.getConfigurations()) {
|
||||
Rectangle gcBounds = gc.getBounds();
|
||||
if (gcBounds.intersects(desired)) {
|
||||
Rectangle inter = gcBounds.intersection(desired);
|
||||
int size = inter.width * inter.height;
|
||||
if (size > gcBestSize) {
|
||||
gcBestSize = size;
|
||||
int x2 = Math.max(gcBounds.x, Math.min(inter.x,
|
||||
inter.x + inter.width - 50));
|
||||
int y2 = Math.max(gcBounds.y, Math.min(inter.y,
|
||||
inter.y + inter.height - 50));
|
||||
gcBestPoint = new Point(x2, y2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (gcBestPoint != null) {
|
||||
if (isProjectFrameAt(gcBestPoint.x, gcBestPoint.y)) {
|
||||
gcBestPoint = null;
|
||||
}
|
||||
}
|
||||
return gcBestPoint;
|
||||
} catch (Throwable t) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isProjectFrameAt(int x, int y) {
|
||||
for (Project current : Projects.getOpenProjects()) {
|
||||
Frame frame = current.getFrame();
|
||||
if (frame != null) {
|
||||
Point loc = frame.getLocationOnScreen();
|
||||
int d = Math.abs(loc.x - x) + Math.abs(loc.y - y);
|
||||
if (d <= 3) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ class MenuHelp extends JMenu implements ActionListener {
|
|||
private JMenuItem library = new JMenuItem();
|
||||
private JMenuItem about = new JMenuItem();
|
||||
private HelpSet helpSet;
|
||||
private String helpSetUrl;
|
||||
private String helpSetUrl = "";
|
||||
private JHelp helpComponent;
|
||||
private LFrame helpFrame;
|
||||
|
||||
|
@ -77,11 +77,11 @@ class MenuHelp extends JMenu implements ActionListener {
|
|||
|
||||
private void loadBroker() {
|
||||
String helpUrl = Strings.get("helpsetUrl");
|
||||
if (helpUrl == null) helpUrl = "doc/en/doc.hs";
|
||||
if (helpUrl == null) helpUrl = "doc/doc_en.hs";
|
||||
if (helpSet == null || helpFrame == null || !helpUrl.equals(helpSetUrl)) {
|
||||
ClassLoader cl = MenuHelp.class.getClassLoader();
|
||||
ClassLoader loader = MenuHelp.class.getClassLoader();
|
||||
try {
|
||||
URL hsURL = HelpSet.findHelpSet(cl, helpUrl);
|
||||
URL hsURL = HelpSet.findHelpSet(loader, helpUrl);
|
||||
if (hsURL == null) {
|
||||
disableHelp();
|
||||
JOptionPane.showMessageDialog(menubar.getParentWindow(),
|
||||
|
@ -100,6 +100,7 @@ class MenuHelp extends JMenu implements ActionListener {
|
|||
} else {
|
||||
helpFrame.getContentPane().removeAll();
|
||||
helpFrame.getContentPane().add(helpComponent);
|
||||
helpComponent.revalidate();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
disableHelp();
|
||||
|
|
|
@ -400,7 +400,7 @@ public class Startup {
|
|||
System.err.println(); //OK
|
||||
System.err.println(Strings.get("argOptionHeader")); //OK
|
||||
System.err.println(" " + Strings.get("argAccentsOption")); //OK
|
||||
System.err.println(" " + Strings.get("argClearPropsOption")); //OK
|
||||
System.err.println(" " + Strings.get("argClearOption")); //OK
|
||||
System.err.println(" " + Strings.get("argEmptyOption")); //OK
|
||||
System.err.println(" " + Strings.get("argGatesOption")); //OK
|
||||
System.err.println(" " + Strings.get("argHelpOption")); //OK
|
||||
|
|
|
@ -144,6 +144,8 @@ public class AppPreferences {
|
|||
= create(new PrefMonitorInt("windowWidth", 640));
|
||||
public static final PrefMonitor<Integer> WINDOW_HEIGHT
|
||||
= create(new PrefMonitorInt("windowHeight", 480));
|
||||
public static final PrefMonitor<String> WINDOW_LOCATION
|
||||
= create(new PrefMonitorString("windowLocation", "0,0"));
|
||||
public static final PrefMonitor<Double> WINDOW_MAIN_SPLIT
|
||||
= create(new PrefMonitorDouble("windowMainSplit", 0.25));
|
||||
public static final PrefMonitor<Double> WINDOW_LEFT_SPLIT
|
||||
|
|
|
@ -5,6 +5,7 @@ package com.cburch.logisim.proj;
|
|||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Point;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
|
@ -12,6 +13,7 @@ import java.io.File;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import com.cburch.logisim.file.Loader;
|
||||
import com.cburch.logisim.gui.main.Frame;
|
||||
|
@ -21,6 +23,9 @@ import com.cburch.logisim.util.PropertyChangeWeakSupport;
|
|||
public class Projects {
|
||||
public static final String projectListProperty = "projectList";
|
||||
|
||||
private static final WeakHashMap<Window, Point> frameLocations
|
||||
= new WeakHashMap<Window, Point>();
|
||||
|
||||
private static void projectRemoved(Project proj, Frame frame,
|
||||
MyListener listener) {
|
||||
frame.removeWindowListener(listener);
|
||||
|
@ -40,6 +45,9 @@ public class Projects {
|
|||
Frame frame = (Frame) event.getSource();
|
||||
if ((frame.getExtendedState() & Frame.ICONIFIED) == 0) {
|
||||
mostRecentFrame = frame;
|
||||
try {
|
||||
frameLocations.put(frame, frame.getLocationOnScreen());
|
||||
} catch (Throwable t) { }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,4 +167,9 @@ public class Projects {
|
|||
public static void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
|
||||
propertySupport.removePropertyChangeListener(propertyName, listener);
|
||||
}
|
||||
|
||||
public static Point getLocation(Window win) {
|
||||
Point ret = frameLocations.get(win);
|
||||
return ret == null ? null : (Point) ret.clone();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import com.cburch.logisim.data.BitWidth;
|
|||
import com.cburch.logisim.data.Bounds;
|
||||
import com.cburch.logisim.data.Direction;
|
||||
import com.cburch.logisim.data.Value;
|
||||
import com.cburch.logisim.instance.Instance;
|
||||
import com.cburch.logisim.instance.InstanceFactory;
|
||||
import com.cburch.logisim.instance.InstancePainter;
|
||||
import com.cburch.logisim.instance.InstanceState;
|
||||
|
@ -115,4 +116,18 @@ public class Comparator extends InstanceFactory {
|
|||
painter.drawPort(EQ, "=", Direction.WEST);
|
||||
painter.drawPort(LT, "<", Direction.WEST);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// methods for instances
|
||||
//
|
||||
@Override
|
||||
protected void configureNewInstance(Instance instance) {
|
||||
instance.addAttributeListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void instanceAttributeChanged(Instance instance, Attribute<?> attr) {
|
||||
instance.fireInvalidated();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,6 +103,9 @@ public class BitExtender extends InstanceFactory {
|
|||
protected void instanceAttributeChanged(Instance instance, Attribute<?> attr) {
|
||||
if (attr == ATTR_TYPE) {
|
||||
configurePorts(instance);
|
||||
instance.fireInvalidated();
|
||||
} else {
|
||||
instance.fireInvalidated();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,12 @@ class XnorGate extends AbstractGate {
|
|||
|
||||
@Override
|
||||
protected Value computeOutput(Value[] inputs, int numInputs, InstanceState state) {
|
||||
return GateFunctions.computeOddParity(inputs, numInputs).not();
|
||||
Object behavior = state.getAttributeValue(GateAttributes.ATTR_XOR);
|
||||
if (behavior == GateAttributes.XOR_ODD) {
|
||||
return GateFunctions.computeOddParity(inputs, numInputs).not();
|
||||
} else {
|
||||
return GateFunctions.computeExactlyOne(inputs, numInputs).not();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -28,8 +28,15 @@ class XorGate extends AbstractGate {
|
|||
@Override
|
||||
public String getRectangularLabel(AttributeSet attrs) {
|
||||
if (attrs == null) return "";
|
||||
boolean isOdd = false;
|
||||
Object behavior = attrs.getValue(GateAttributes.ATTR_XOR);
|
||||
return behavior == GateAttributes.XOR_ODD ? "2k+1" : "1";
|
||||
if (behavior == GateAttributes.XOR_ODD) {
|
||||
Object inputs = attrs.getValue(GateAttributes.ATTR_INPUTS);
|
||||
if (inputs == null || ((Integer) inputs).intValue() != 2) {
|
||||
isOdd = true;
|
||||
}
|
||||
}
|
||||
return isOdd ? "2k+1" : "=1";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -380,7 +380,18 @@ public class SelectTool extends Tool {
|
|||
if (state == MOVING && e.getKeyCode() == KeyEvent.VK_SHIFT) {
|
||||
handleMoveDrag(canvas, curDx, curDy, e.getModifiersEx());
|
||||
} else {
|
||||
processKeyEvent(canvas, e, KeyConfigurationEvent.KEY_PRESSED);
|
||||
switch (e.getKeyCode()) {
|
||||
case KeyEvent.VK_BACK_SPACE:
|
||||
case KeyEvent.VK_DELETE:
|
||||
if (!canvas.getSelection().isEmpty()) {
|
||||
Action act = SelectionActions.clear(canvas.getSelection());
|
||||
canvas.getProject().doAction(act);
|
||||
e.consume();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
processKeyEvent(canvas, e, KeyConfigurationEvent.KEY_PRESSED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -68,11 +68,25 @@ public class MoveResult {
|
|||
}
|
||||
|
||||
public void print(PrintStream out) {
|
||||
boolean printed = false;
|
||||
for (Component w : replacements.getAdditions()) {
|
||||
printed = true;
|
||||
out.println("add " + w);
|
||||
}
|
||||
for (Component w : replacements.getRemovals()) {
|
||||
printed = true;
|
||||
out.println("del " + w);
|
||||
}
|
||||
for (Component w : replacements.getReplacedComponents()) {
|
||||
printed = true;
|
||||
out.print("repl " + w + " by");
|
||||
for (Component w2 : replacements.getComponentsReplacing(w)) {
|
||||
out.print(" " + w2);
|
||||
}
|
||||
out.println();
|
||||
}
|
||||
if (!printed) {
|
||||
out.println("no replacements");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue