X-Git-Url: https://mograsim.net/gitweb/?a=blobdiff_plain;f=net.mograsim.logic.ui%2Fsrc%2Fnet%2Fmograsim%2Flogic%2Fui%2Fmodel%2Fcomponents%2FSubmodelComponent.java;h=bb6cca1796f36cd5b1bf176f6af1d833fa3ec3a3;hb=f14ea37d69488dd51518a36413af7176916b8bd7;hp=9fa933bdb00630a3aa147678b109c0940985d908;hpb=a93901091c018edc992828e3a23817e97a98e4ca;p=Mograsim.git diff --git a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/SubmodelComponent.java b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/SubmodelComponent.java index 9fa933bd..bb6cca17 100644 --- a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/SubmodelComponent.java +++ b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/SubmodelComponent.java @@ -24,30 +24,81 @@ import net.mograsim.logic.ui.model.wires.GUIWire; import net.mograsim.logic.ui.model.wires.MovablePin; import net.mograsim.logic.ui.model.wires.Pin; +/** + * A {@link GUIComponent} consisting of another model. A SubmodelComponent can have so-called "interface pins" connecting the + * inner and outer models. + */ public abstract class SubmodelComponent extends GUIComponent { + /** + * A modifiable view of {@link #submodel}. + */ protected final ViewModelModifiable submodelModifiable; + /** + * The model this {@link SubmodelComponent} consists of. + */ public final ViewModel submodel; - private final Map submodelPinsPerSupermodelPin; - private final Map submodelPinsPerSupermodelPinUnmodifiable; - private final Map supermodelPinsPerSubmodelPin; - private final Map supermodelPinsPerSubmodelPinUnmodifiable; + /** + * The list of all submodel interface pins of this {@link SubmodelComponent} on the submodel side. + */ + private final Map submodelPins; + /** + * An unmodifiable view of {@link #submodelPins}. + */ + private final Map submodelMovablePinsUnmodifiable; + /** + * An unmodifiable view of {@link #submodelPins} where pins are not movable. + */ + private final Map submodelUnmovablePinsUnmodifiable; + /** + * The list of all submodel interface pins of this {@link SubmodelComponent} on the supermodel side. + */ + private final Map supermodelPins; + /** + * An unmodifiable view of {@link #supermodelPins}. + */ + private final Map supermodelMovablePinsUnmodifiable; + /** + * An unmodifiable view of {@link #supermodelPins} where pins are not movable. + */ + private final Map supermodelUnmovablePinsUnmodifiable; + /** + * A pseudo-component containing all submodel interface pins on the submodel side. + */ private final SubmodelInterface submodelInterface; + /** + * The factor by which the submodel is scaled when rendering. + */ private double submodelScale; + /** + * If this {@link SubmodelComponent} fills at least this amount of the visible region vertically or horizontally, the submodel starts to + * be visible. + */ private double maxVisibleRegionFillRatioForAlpha0; + /** + * If this {@link SubmodelComponent} fills at least this amount of the visible region vertically or horizontally, the submodel is fully + * visible. + */ private double minVisibleRegionFillRatioForAlpha1; + /** + * The renderer used for rendering the submodel. + */ private final LogicUIRenderer renderer; + // creation and destruction + public SubmodelComponent(ViewModelModifiable model) { super(model); this.submodelModifiable = new ViewModelModifiable(); this.submodel = submodelModifiable; - this.submodelPinsPerSupermodelPin = new HashMap<>(); - this.submodelPinsPerSupermodelPinUnmodifiable = Collections.unmodifiableMap(submodelPinsPerSupermodelPin); - this.supermodelPinsPerSubmodelPin = new HashMap<>(); - this.supermodelPinsPerSubmodelPinUnmodifiable = Collections.unmodifiableMap(supermodelPinsPerSubmodelPin); + this.submodelPins = new HashMap<>(); + this.submodelMovablePinsUnmodifiable = Collections.unmodifiableMap(submodelPins); + this.submodelUnmovablePinsUnmodifiable = Collections.unmodifiableMap(submodelPins); + this.supermodelPins = new HashMap<>(); + this.supermodelMovablePinsUnmodifiable = Collections.unmodifiableMap(supermodelPins); + this.supermodelUnmovablePinsUnmodifiable = Collections.unmodifiableMap(supermodelPins); this.submodelInterface = new SubmodelInterface(submodelModifiable); this.submodelScale = 1; @@ -58,102 +109,179 @@ public abstract class SubmodelComponent extends GUIComponent submodelModifiable.addRedrawListener(this::requestRedraw); } - protected void setSubmodelScale(double submodelScale) - { - this.submodelScale = submodelScale; - - for (Entry e : supermodelPinsPerSubmodelPin.entrySet()) - e.getKey().setRelPos(e.getValue().getRelX() * submodelScale, e.getValue().getRelY() * submodelScale); - - requestRedraw();// needed if there is no submodel interface pin - } - - protected double getSubmodelScale() - { - return submodelScale; - } + // pins /** - * Returns the submodel pin. + * Adds a new submodel interface pin. + * + * @param supermodelPin the submodel interface pin on the supermodel side + * + * @return the submodel interface pin on the submodel side + * + * @author Daniel Kirschten */ - protected Pin addSubmodelInterface(String name, int logicWidth, double relX, double relY) + protected Pin addSubmodelInterface(MovablePin supermodelPin) { - MovablePin submodelPin = new MovablePin(submodelInterface, name, logicWidth, relX / submodelScale, relY / submodelScale); - submodelInterface.addPin(submodelPin); + super.addPin(supermodelPin);// do this first to be fail-fast if the supermodel does not belong to this component + + String name = supermodelPin.name; + MovablePin submodelPin = new MovablePin(submodelInterface, name, supermodelPin.logicWidth, supermodelPin.getRelX() / submodelScale, + supermodelPin.getRelY() / submodelScale); + + submodelPin.addPinMovedListener(p -> + { + double newRelX = p.getRelX() * submodelScale; + double newRelY = p.getRelY() * submodelScale; + if (supermodelPin.getRelX() != newRelX || supermodelPin.getRelY() != newRelY) + supermodelPin.setRelPos(newRelX, newRelY); + }); + supermodelPin.addPinMovedListener(p -> + { + double newRelX = p.getRelX() / submodelScale; + double newRelY = p.getRelY() / submodelScale; + if (submodelPin.getRelX() != newRelX || submodelPin.getRelY() != newRelY) + submodelPin.setRelPos(newRelX, newRelY); + }); - MovablePin supermodelPin = new MovablePin(this, name, logicWidth, relX, relY); - addPin(supermodelPin); + submodelInterface.addPin(submodelPin); - submodelPinsPerSupermodelPin.put(supermodelPin, submodelPin); - supermodelPinsPerSubmodelPin.put(submodelPin, supermodelPin); + submodelPins.put(name, submodelPin); + supermodelPins.put(name, supermodelPin); // no need to call requestRedraw() because addPin() will request a redraw return submodelPin; } - protected void moveSubmodelInterface(Pin supermodelPin, double relX, double relY) + /** + * Removes a submodel interface pin. + * + * @author Daniel Kirschten + */ + protected void removeSubmodelInterface(String name) { - MovablePin submodelPin = getSubmodelMovablePin(supermodelPin); - MovablePin supermodelPinMovable = getSupermodelMovablePin(submodelPin); + super.removePin(name);// do this first to be fail-fast if this component doesn't have a pin with the given name + Pin submodelPin = submodelPins.remove(name); + submodelInterface.removePin(submodelPin.name); + supermodelPins.remove(name); - submodelPin.setRelPos(relX / submodelScale, relY / submodelScale); - supermodelPinMovable.setRelPos(relX, relY); + // no need to call requestRedraw() because removePin() will request a redraw + } - // no need to call requestRedraw() because setRelPos() will request a redraw + /** + * Returns a collection of submodel interface pins on the submodel side of this component. + * + * @author Daniel Kirschten + */ + public Map getSubmodelPins() + { + return submodelUnmovablePinsUnmodifiable; } - protected void removeSubmodelInterface(Pin supermodelPin) + /** + * Returns the submodel interface pin with the given name on the submodel side of this component. + * + * @author Daniel Kirschten + */ + public Pin getSubmodelPin(String name) { - removePin(supermodelPin); - Pin submodelPin = getSubmodelMovablePin(supermodelPin); - submodelInterface.removePin(submodelPin); + return getSubmodelMovablePin(name); + } - submodelPinsPerSupermodelPin.remove(supermodelPin); - supermodelPinsPerSubmodelPin.remove(submodelPin); + /** + * Returns a collection of movable submodel interface pins on the submodel side of this component. + * + * @author Daniel Kirschten + */ + protected Map getSubmodelMovablePins() + { + return submodelMovablePinsUnmodifiable; + } - // no need to call requestRedraw() because removePin() will request a redraw + /** + * Returns the movable submodel interface pin with the given name on the submodel side of this component. + * + * @author Daniel Kirschten + */ + protected MovablePin getSubmodelMovablePin(String name) + { + return submodelPins.get(name); } - public Map getSupermodelPinsPerSubmodelPin() + /** + * Returns a collection of submodel interface pins on the supermodel side of this component. + * + * @author Daniel Kirschten + */ + public Map getSupermodelPins() { - return supermodelPinsPerSubmodelPinUnmodifiable; + return supermodelUnmovablePinsUnmodifiable; } - public Pin getSupermodelPin(Pin submodelPin) + /** + * Returns the submodel interface pin with the given name on the supermodel side of this component. + * + * @author Daniel Kirschten + */ + public Pin getSupermodelPin(String name) { - return getSupermodelMovablePin(submodelPin); + return getSupermodelMovablePin(name); } - protected MovablePin getSupermodelMovablePin(Pin submodelPin) + /** + * Returns a collection of movable submodel interface pins on the supermodel side of this component. + * + * @author Daniel Kirschten + */ + protected Map getSupermodelMovablePins() { - return supermodelPinsPerSubmodelPin.get(submodelPin); + return supermodelMovablePinsUnmodifiable; } - public Map getSubmodelPinsPerSupermodelPin() + /** + * Returns the movable submodel interface pin with the given name on the supermodel side of this component. + * + * @author Daniel Kirschten + */ + protected MovablePin getSupermodelMovablePin(String name) { - return submodelPinsPerSupermodelPinUnmodifiable; + return supermodelPins.get(name); } - public Pin getSubmodelPin(Pin supermodelPin) + // "graphical" operations + + /** + * Sets the factor by which the submodel is scaled when rendering and calls redrawListeners. Note that the submodel interface pins will + * stay at their position relative to the supermodel, which means they will move relative to the submodel. + * + * @author Daniel Kirschten + */ + protected void setSubmodelScale(double submodelScale) { - return getSubmodelMovablePin(supermodelPin); + this.submodelScale = submodelScale; + + for (Entry e : supermodelPins.entrySet()) + getSubmodelMovablePin(e.getKey()).setRelPos(e.getValue().getRelX() * submodelScale, e.getValue().getRelY() * submodelScale); + + requestRedraw();// needed if there is no submodel interface pin } - protected MovablePin getSubmodelMovablePin(Pin supermodelPin) + /** + * Returns the current factor by which the submodel is scaled when rendering. + * + * @author Daniel Kirschten + */ + protected double getSubmodelScale() { - return submodelPinsPerSupermodelPin.get(supermodelPin); + return submodelScale; } @Override public void render(GeneralGC gc, Rectangle visibleRegion) { - double posX = getBounds().x; - double posY = getBounds().y; - GCConfig conf = new GCConfig(gc); - TranslatedGC tgc = new TranslatedGC(gc, posX, posY, submodelScale, true); + TranslatedGC tgc = new TranslatedGC(gc, getPosX(), getPosY(), submodelScale, true); conf.reset(tgc); - double visibleRegionFillRatio = Math.max(getBounds().width / visibleRegion.width, getBounds().height / visibleRegion.height); + double visibleRegionFillRatio = Math.max(getWidth() / visibleRegion.width, getHeight() / visibleRegion.height); double alphaFactor = map(visibleRegionFillRatio, maxVisibleRegionFillRatioForAlpha0, minVisibleRegionFillRatioForAlpha1, 0, 1); alphaFactor = Math.max(0, Math.min(1, alphaFactor)); // we need to take the old alpha into account to support nested submodules better. @@ -163,7 +291,7 @@ public abstract class SubmodelComponent extends GUIComponent if (submodelAlpha != 0) { gc.setAlpha(submodelAlpha); - renderer.render(tgc, visibleRegion.translate(posX / submodelScale, posY / submodelScale, 1 / submodelScale)); + renderer.render(tgc, visibleRegion.translate(getPosX() / submodelScale, getPosY() / submodelScale, 1 / submodelScale)); } if (labelAlpha != 0) { @@ -187,15 +315,16 @@ public abstract class SubmodelComponent extends GUIComponent @Override public boolean clicked(double x, double y) { - // TODO - double scaledX = (x - getBounds().x) / submodelScale; - double scaledY = (y - getBounds().y) / submodelScale; - double roundedScaledX = Math.round(scaledX / 5 * 2) * 5 / 2.; - double roundedScaledY = Math.round(scaledY / 5 * 2) * 5 / 2.; - System.out.println(scaledX + "|" + scaledY + ", rounded " + roundedScaledX + "|" + roundedScaledY); - return true; + double scaledX = (x - getPosX()) / submodelScale; + double scaledY = (y - getPosY()) / submodelScale; + for (GUIComponent component : submodel.getComponents()) + if (component.getBounds().contains(scaledX, scaledY) && component.clicked(scaledX, scaledY)) + return true; + return false; } + // serializing + /** * @return {@link SubmodelComponentParams}, which describe this {@link SubmodelComponent}. */ @@ -205,14 +334,12 @@ public abstract class SubmodelComponent extends GUIComponent params.type = SubmodelComponent.class.getSimpleName(); params.composition = calculateCompositionParams(); - Rectangle bounds = getBounds(); - params.width = bounds.width; - params.height = bounds.height; + params.width = getWidth(); + params.height = getHeight(); - List pinList = pinsUnmodifiable; - InterfacePinParams[] iPins = new InterfacePinParams[pinList.size()]; + InterfacePinParams[] iPins = new InterfacePinParams[getPins().size()]; int i = 0; - for (Pin p : pinList) + for (Pin p : getPins().values()) { InterfacePinParams iPinParams = new InterfacePinParams(); iPins[i] = iPinParams; @@ -240,9 +367,8 @@ public abstract class SubmodelComponent extends GUIComponent GUIComponent component = componentIt.next(); InnerComponentParams inner = new InnerComponentParams(); comps[i] = inner; - inner.logicWidth = component.getPins().get(0).logicWidth; // This could be done a little more elegantly - Rectangle bounds = component.getBounds(); - inner.pos = new Point(bounds.x, bounds.y); + inner.params = component.getInstantiationParameters(); + inner.pos = new Point(getPosX(), getPosY()); inner.type = component.getIdentifier(); i++; } @@ -257,9 +383,9 @@ public abstract class SubmodelComponent extends GUIComponent wires[i] = inner; InnerPinParams pin1Params = new InnerPinParams(), pin2Params = new InnerPinParams(); - pin1Params.pinIndex = wire.getPin1().component.getPins().indexOf(wire.getPin1()); + pin1Params.pinName = wire.getPin1().name; pin1Params.compId = compList.indexOf(wire.getPin1().component); - pin2Params.pinIndex = wire.getPin2().component.getPins().indexOf(wire.getPin2()); + pin2Params.pinName = wire.getPin2().name; pin2Params.compId = compList.indexOf(wire.getPin2().component); inner.pin1 = pin1Params; inner.pin2 = pin2Params; @@ -269,4 +395,28 @@ public abstract class SubmodelComponent extends GUIComponent params.innerWires = wires; return params; } + + public List getComponents() + { + return submodel.getComponents(); + } + + public List getWires() + { + return submodel.getWires(); + } + + // operations no longer supported + + @Override + protected void addPin(Pin pin) + { + throw new UnsupportedOperationException("Can't add pins to a SubmodelComponent directly, call addSubmodelInterface instead"); + } + + @Override + protected void removePin(String name) + { + throw new UnsupportedOperationException("Can't remove pins of a SubmodelComponent directly, call removeSubmodelInterface instead"); + } } \ No newline at end of file