1 package net.mograsim.logic.ui.model.components;
3 import java.util.Collections;
4 import java.util.HashMap;
5 import java.util.Iterator;
8 import java.util.Map.Entry;
10 import net.haspamelodica.swt.helper.gcs.GCConfig;
11 import net.haspamelodica.swt.helper.gcs.GeneralGC;
12 import net.haspamelodica.swt.helper.gcs.TranslatedGC;
13 import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
14 import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
15 import net.mograsim.logic.ui.LogicUIRenderer;
16 import net.mograsim.logic.ui.model.ViewModel;
17 import net.mograsim.logic.ui.model.ViewModelModifiable;
18 import net.mograsim.logic.ui.model.components.SubmodelComponentParams.ComponentCompositionParams;
19 import net.mograsim.logic.ui.model.components.SubmodelComponentParams.ComponentCompositionParams.InnerComponentParams;
20 import net.mograsim.logic.ui.model.components.SubmodelComponentParams.InnerPinParams;
21 import net.mograsim.logic.ui.model.components.SubmodelComponentParams.InnerWireParams;
22 import net.mograsim.logic.ui.model.components.SubmodelComponentParams.InterfacePinParams;
23 import net.mograsim.logic.ui.model.wires.GUIWire;
24 import net.mograsim.logic.ui.model.wires.MovablePin;
25 import net.mograsim.logic.ui.model.wires.Pin;
27 public abstract class SubmodelComponent extends GUIComponent
29 protected final ViewModelModifiable submodelModifiable;
30 public final ViewModel submodel;
31 private final Map<MovablePin, MovablePin> submodelPinsPerSupermodelPin;
32 private final Map<Pin, Pin> submodelPinsPerSupermodelPinUnmodifiable;
33 private final Map<MovablePin, MovablePin> supermodelPinsPerSubmodelPin;
34 private final Map<Pin, Pin> supermodelPinsPerSubmodelPinUnmodifiable;
35 private final SubmodelInterface submodelInterface;
37 private double submodelScale;
38 private double maxVisibleRegionFillRatioForAlpha0;
39 private double minVisibleRegionFillRatioForAlpha1;
40 private final LogicUIRenderer renderer;
42 public SubmodelComponent(ViewModelModifiable model)
45 this.submodelModifiable = new ViewModelModifiable();
46 this.submodel = submodelModifiable;
47 this.submodelPinsPerSupermodelPin = new HashMap<>();
48 this.submodelPinsPerSupermodelPinUnmodifiable = Collections.unmodifiableMap(submodelPinsPerSupermodelPin);
49 this.supermodelPinsPerSubmodelPin = new HashMap<>();
50 this.supermodelPinsPerSubmodelPinUnmodifiable = Collections.unmodifiableMap(supermodelPinsPerSubmodelPin);
51 this.submodelInterface = new SubmodelInterface(submodelModifiable);
53 this.submodelScale = 1;
54 this.maxVisibleRegionFillRatioForAlpha0 = 0.4;
55 this.minVisibleRegionFillRatioForAlpha1 = 0.8;
56 this.renderer = new LogicUIRenderer(submodelModifiable);
58 submodelModifiable.addRedrawListener(this::requestRedraw);
61 protected void setSubmodelScale(double submodelScale)
63 this.submodelScale = submodelScale;
65 for (Entry<MovablePin, MovablePin> e : supermodelPinsPerSubmodelPin.entrySet())
66 e.getKey().setRelPos(e.getValue().getRelX() * submodelScale, e.getValue().getRelY() * submodelScale);
68 requestRedraw();// needed if there is no submodel interface pin
71 protected double getSubmodelScale()
77 * Returns the submodel pin.
79 protected Pin addSubmodelInterface(String name, int logicWidth, double relX, double relY)
81 MovablePin submodelPin = new MovablePin(submodelInterface, name, logicWidth, relX / submodelScale, relY / submodelScale);
82 submodelInterface.addPin(submodelPin);
84 MovablePin supermodelPin = new MovablePin(this, name, logicWidth, relX, relY);
85 super.addPin(supermodelPin);
87 submodelPinsPerSupermodelPin.put(supermodelPin, submodelPin);
88 supermodelPinsPerSubmodelPin.put(submodelPin, supermodelPin);
90 // no need to call requestRedraw() because addPin() will request a redraw
94 protected void moveSubmodelInterface(Pin supermodelPin, double relX, double relY)
96 MovablePin submodelPin = getSubmodelMovablePin(supermodelPin);
97 MovablePin supermodelPinMovable = getSupermodelMovablePin(submodelPin);
99 submodelPin.setRelPos(relX / submodelScale, relY / submodelScale);
100 supermodelPinMovable.setRelPos(relX, relY);
102 // no need to call requestRedraw() because setRelPos() will request a redraw
105 protected void removeSubmodelInterface(Pin supermodelPin)
107 super.removePin(supermodelPin);
108 Pin submodelPin = getSubmodelMovablePin(supermodelPin);
109 submodelInterface.removePin(submodelPin);
111 submodelPinsPerSupermodelPin.remove(supermodelPin);
112 supermodelPinsPerSubmodelPin.remove(submodelPin);
114 // no need to call requestRedraw() because removePin() will request a redraw
117 public Map<Pin, Pin> getSupermodelPinsPerSubmodelPin()
119 return supermodelPinsPerSubmodelPinUnmodifiable;
122 public Pin getSupermodelPin(Pin submodelPin)
124 return getSupermodelMovablePin(submodelPin);
127 protected MovablePin getSupermodelMovablePin(Pin submodelPin)
129 return supermodelPinsPerSubmodelPin.get(submodelPin);
132 public Map<Pin, Pin> getSubmodelPinsPerSupermodelPin()
134 return submodelPinsPerSupermodelPinUnmodifiable;
137 public Pin getSubmodelPin(Pin supermodelPin)
139 return getSubmodelMovablePin(supermodelPin);
142 protected MovablePin getSubmodelMovablePin(Pin supermodelPin)
144 return submodelPinsPerSupermodelPin.get(supermodelPin);
148 public void render(GeneralGC gc, Rectangle visibleRegion)
150 double posX = getBounds().x;
151 double posY = getBounds().y;
153 GCConfig conf = new GCConfig(gc);
154 TranslatedGC tgc = new TranslatedGC(gc, posX, posY, submodelScale, true);
156 double visibleRegionFillRatio = Math.max(getBounds().width / visibleRegion.width, getBounds().height / visibleRegion.height);
157 double alphaFactor = map(visibleRegionFillRatio, maxVisibleRegionFillRatioForAlpha0, minVisibleRegionFillRatioForAlpha1, 0, 1);
158 alphaFactor = Math.max(0, Math.min(1, alphaFactor));
159 // we need to take the old alpha into account to support nested submodules better.
160 int oldAlpha = gc.getAlpha();
161 int submodelAlpha = Math.max(0, Math.min(255, (int) (oldAlpha * alphaFactor)));
162 int labelAlpha = Math.max(0, Math.min(255, (int) (oldAlpha * (1 - alphaFactor))));
163 if (submodelAlpha != 0)
165 gc.setAlpha(submodelAlpha);
166 renderer.render(tgc, visibleRegion.translate(posX / submodelScale, posY / submodelScale, 1 / submodelScale));
170 gc.setAlpha(labelAlpha);
171 renderSymbol(gc, visibleRegion);
174 // draw the outline after all other operations to make interface pins look better
175 renderOutline(gc, visibleRegion);
178 protected abstract void renderOutline(GeneralGC gc, Rectangle visibleRegion);
180 protected abstract void renderSymbol(GeneralGC gc, Rectangle visibleRegion);
182 private static double map(double val, double valMin, double valMax, double mapMin, double mapMax)
184 return mapMin + (val - valMin) * (mapMax - mapMin) / (valMax - valMin);
188 public boolean clicked(double x, double y)
191 double scaledX = (x - getBounds().x) / submodelScale;
192 double scaledY = (y - getBounds().y) / submodelScale;
193 double roundedScaledX = Math.round(scaledX / 5 * 2) * 5 / 2.;
194 double roundedScaledY = Math.round(scaledY / 5 * 2) * 5 / 2.;
195 System.out.println(scaledX + "|" + scaledY + ", rounded " + roundedScaledX + "|" + roundedScaledY);
200 * @return {@link SubmodelComponentParams}, which describe this {@link SubmodelComponent}.
202 public SubmodelComponentParams calculateParams()
204 SubmodelComponentParams params = new SubmodelComponentParams();
205 params.type = SubmodelComponent.class.getSimpleName();
206 params.composition = calculateCompositionParams();
208 Rectangle bounds = getBounds();
209 params.width = bounds.width;
210 params.height = bounds.height;
212 List<Pin> pinList = pinsUnmodifiable;
213 InterfacePinParams[] iPins = new InterfacePinParams[pinList.size()];
215 for (Pin p : pinList)
217 InterfacePinParams iPinParams = new InterfacePinParams();
218 iPins[i] = iPinParams;
219 iPinParams.location = p.getRelPos();
220 iPinParams.name = p.name;
221 iPinParams.logicWidth = p.logicWidth;
224 params.interfacePins = iPins;
228 protected ComponentCompositionParams calculateCompositionParams()
230 ComponentCompositionParams params = new ComponentCompositionParams();
231 params.innerScale = getSubmodelScale();
233 List<GUIComponent> compList = submodelModifiable.getComponents();
234 Iterator<GUIComponent> componentIt = compList.iterator();
235 componentIt.next(); // Skip inner SubmodelInterface
236 InnerComponentParams[] comps = new InnerComponentParams[compList.size() - 1];
238 while (componentIt.hasNext())
240 GUIComponent component = componentIt.next();
241 InnerComponentParams inner = new InnerComponentParams();
243 inner.logicWidth = component.getPins().get(0).logicWidth; // This could be done a little more elegantly
244 Rectangle bounds = component.getBounds();
245 inner.pos = new Point(bounds.x, bounds.y);
246 inner.type = component.getIdentifier();
249 params.subComps = comps;
251 List<GUIWire> wireList = submodelModifiable.getWires();
252 InnerWireParams wires[] = new InnerWireParams[wireList.size()];
254 for (GUIWire wire : wireList)
256 InnerWireParams inner = new InnerWireParams();
258 InnerPinParams pin1Params = new InnerPinParams(), pin2Params = new InnerPinParams();
260 pin1Params.pinIndex = wire.getPin1().component.getPins().indexOf(wire.getPin1());
261 pin1Params.compId = compList.indexOf(wire.getPin1().component);
262 pin2Params.pinIndex = wire.getPin2().component.getPins().indexOf(wire.getPin2());
263 pin2Params.compId = compList.indexOf(wire.getPin2().component);
264 inner.pin1 = pin1Params;
265 inner.pin2 = pin2Params;
266 inner.path = wire.getPath();
269 params.innerWires = wires;
274 protected void addPin(Pin pin)
276 throw new UnsupportedOperationException("Can't add pins to a SubmodelComponent directly, call addSubmodelInterface instead");
280 protected void removePin(Pin pin)
282 throw new UnsupportedOperationException("Can't remove pins of a SubmodelComponent directly, call removeSubmodelInterface instead");