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.Pin;
26 public abstract class SubmodelComponent extends GUIComponent
28 protected final ViewModelModifiable submodelModifiable;
29 public final ViewModel submodel;
30 private final Map<PinMovable, PinMovable> submodelPinsPerSupermodelPin;
31 private final Map<Pin, Pin> submodelPinsPerSupermodelPinUnmodifiable;
32 private final Map<PinMovable, PinMovable> supermodelPinsPerSubmodelPin;
33 private final Map<Pin, Pin> supermodelPinsPerSubmodelPinUnmodifiable;
34 private final SubmodelInterface submodelInterface;
36 private double submodelScale;
37 private double maxVisibleRegionFillRatioForAlpha0;
38 private double minVisibleRegionFillRatioForAlpha1;
39 private final LogicUIRenderer renderer;
41 public SubmodelComponent(ViewModelModifiable model)
44 this.submodelModifiable = new ViewModelModifiable();
45 this.submodel = submodelModifiable;
46 this.submodelPinsPerSupermodelPin = new HashMap<>();
47 this.submodelPinsPerSupermodelPinUnmodifiable = Collections.unmodifiableMap(submodelPinsPerSupermodelPin);
48 this.supermodelPinsPerSubmodelPin = new HashMap<>();
49 this.supermodelPinsPerSubmodelPinUnmodifiable = Collections.unmodifiableMap(supermodelPinsPerSubmodelPin);
50 this.submodelInterface = new SubmodelInterface(submodelModifiable);
52 this.submodelScale = 1;
53 this.maxVisibleRegionFillRatioForAlpha0 = 0.4;
54 this.minVisibleRegionFillRatioForAlpha1 = 0.8;
55 this.renderer = new LogicUIRenderer(submodelModifiable);
57 submodelModifiable.addRedrawListener(this::requestRedraw);
60 protected void setSubmodelScale(double submodelScale)
62 this.submodelScale = submodelScale;
64 for (Entry<PinMovable, PinMovable> e : supermodelPinsPerSubmodelPin.entrySet())
65 e.getKey().setRelPos(e.getValue().getRelX() * submodelScale, e.getValue().getRelY() * submodelScale);
67 requestRedraw();// needed if there is no submodel interface pin
70 protected double getSubmodelScale()
76 * Returns the submodel pin.
78 protected Pin addSubmodelInterface(int logicWidth, double relX, double relY)
80 PinMovable submodelPin = new PinMovable(submodelInterface, logicWidth, relX / submodelScale, relY / submodelScale);
81 submodelInterface.addPin(submodelPin);
83 PinMovable supermodelPin = new PinMovable(this, logicWidth, relX, relY);
84 addPin(supermodelPin);
86 submodelPinsPerSupermodelPin.put(supermodelPin, submodelPin);
87 supermodelPinsPerSubmodelPin.put(submodelPin, supermodelPin);
89 // no need to call requestRedraw() because addPin() will request a redraw
93 protected void moveSubmodelInterface(Pin supermodelPin, double relX, double relY)
95 PinMovable submodelPin = getSubmodelMovablePin(supermodelPin);
96 PinMovable supermodelPinMovable = getSupermodelMovablePin(submodelPin);
98 submodelPin.setRelPos(relX / submodelScale, relY / submodelScale);
99 supermodelPinMovable.setRelPos(relX, relY);
101 // no need to call requestRedraw() because setRelPos() will request a redraw
104 protected void removeSubmodelInterface(Pin supermodelPin)
106 removePin(supermodelPin);
107 Pin submodelPin = getSubmodelMovablePin(supermodelPin);
108 submodelInterface.removePin(submodelPin);
110 submodelPinsPerSupermodelPin.remove(supermodelPin);
111 supermodelPinsPerSubmodelPin.remove(submodelPin);
113 // no need to call requestRedraw() because removePin() will request a redraw
116 public Map<Pin, Pin> getSupermodelPinsPerSubmodelPin()
118 return supermodelPinsPerSubmodelPinUnmodifiable;
121 public Pin getSupermodelPin(Pin submodelPin)
123 return getSupermodelMovablePin(submodelPin);
126 protected PinMovable getSupermodelMovablePin(Pin submodelPin)
128 return supermodelPinsPerSubmodelPin.get(submodelPin);
131 public Map<Pin, Pin> getSubmodelPinsPerSupermodelPin()
133 return submodelPinsPerSupermodelPinUnmodifiable;
136 public Pin getSubmodelPin(Pin supermodelPin)
138 return getSubmodelMovablePin(supermodelPin);
141 protected PinMovable getSubmodelMovablePin(Pin supermodelPin)
143 return submodelPinsPerSupermodelPin.get(supermodelPin);
147 public void render(GeneralGC gc, Rectangle visibleRegion)
149 double posX = getBounds().x;
150 double posY = getBounds().y;
152 GCConfig conf = new GCConfig(gc);
153 TranslatedGC tgc = new TranslatedGC(gc, posX, posY, submodelScale, true);
155 double visibleRegionFillRatio = Math.max(getBounds().width / visibleRegion.width, getBounds().height / visibleRegion.height);
156 double alphaFactor = map(visibleRegionFillRatio, maxVisibleRegionFillRatioForAlpha0, minVisibleRegionFillRatioForAlpha1, 0, 1);
157 alphaFactor = Math.max(0, Math.min(1, alphaFactor));
158 // we need to take the old alpha into account to support nested submodules better.
159 int oldAlpha = gc.getAlpha();
160 int submodelAlpha = Math.max(0, Math.min(255, (int) (oldAlpha * alphaFactor)));
161 int labelAlpha = Math.max(0, Math.min(255, (int) (oldAlpha * (1 - alphaFactor))));
162 if (submodelAlpha != 0)
164 gc.setAlpha(submodelAlpha);
165 renderer.render(tgc, visibleRegion.translate(posX / submodelScale, posY / submodelScale, 1 / submodelScale));
169 gc.setAlpha(labelAlpha);
170 renderSymbol(gc, visibleRegion);
173 // draw the outline after all other operations to make interface pins look better
174 renderOutline(gc, visibleRegion);
177 protected abstract void renderOutline(GeneralGC gc, Rectangle visibleRegion);
179 protected abstract void renderSymbol(GeneralGC gc, Rectangle visibleRegion);
181 private static double map(double val, double valMin, double valMax, double mapMin, double mapMax)
183 return mapMin + (val - valMin) * (mapMax - mapMin) / (valMax - valMin);
187 public boolean clicked(double x, double y)
190 double scaledX = (x - getBounds().x) / submodelScale;
191 double scaledY = (y - getBounds().y) / submodelScale;
192 double roundedScaledX = Math.round(scaledX / 5 * 2) * 5 / 2.;
193 double roundedScaledY = Math.round(scaledY / 5 * 2) * 5 / 2.;
194 System.out.println(scaledX + "|" + scaledY + ", rounded " + roundedScaledX + "|" + roundedScaledY);
198 private static class PinMovable extends Pin
200 public PinMovable(GUIComponent component, int logicWidth, double relX, double relY)
202 super(component, logicWidth, relX, relY);
206 protected void setRelPos(double relX, double relY)
208 super.setRelPos(relX, relY);
213 * @return {@link SubmodelComponentParams}, which describe this {@link SubmodelComponent}.
215 public SubmodelComponentParams calculateParams()
217 SubmodelComponentParams params = new SubmodelComponentParams();
218 params.type = SubmodelComponent.class.getSimpleName();
219 params.composition = calculateCompositionParams();
221 Rectangle bounds = getBounds();
222 params.width = bounds.width;
223 params.height = bounds.height;
225 List<Pin> pinList = pinsUnmodifiable;
226 InterfacePinParams[] iPins = new InterfacePinParams[pinList.size()];
228 for (Pin p : pinList)
230 InterfacePinParams iPinParams = new InterfacePinParams();
231 iPins[i] = iPinParams;
232 iPinParams.location = p.getRelPos();
233 iPinParams.logicWidth = p.logicWidth;
236 params.interfacePins = iPins;
240 protected ComponentCompositionParams calculateCompositionParams()
242 ComponentCompositionParams params = new ComponentCompositionParams();
243 params.innerScale = getSubmodelScale();
245 List<GUIComponent> compList = submodelModifiable.getComponents();
246 Iterator<GUIComponent> componentIt = compList.iterator();
247 componentIt.next(); // Skip inner SubmodelInterface
248 InnerComponentParams[] comps = new InnerComponentParams[compList.size() - 1];
250 while (componentIt.hasNext())
252 GUIComponent component = componentIt.next();
253 InnerComponentParams inner = new InnerComponentParams();
255 inner.logicWidth = component.getPins().get(0).logicWidth; // This could be done a little more elegantly
256 Rectangle bounds = component.getBounds();
257 inner.pos = new Point(bounds.x, bounds.y);
258 inner.type = component.getIdentifier();
261 params.subComps = comps;
263 List<GUIWire> wireList = submodelModifiable.getWires();
264 InnerWireParams wires[] = new InnerWireParams[wireList.size()];
266 for (GUIWire wire : wireList)
268 InnerWireParams inner = new InnerWireParams();
270 InnerPinParams pin1Params = new InnerPinParams(), pin2Params = new InnerPinParams();
272 pin1Params.pinIndex = wire.getPin1().component.getPins().indexOf(wire.getPin1());
273 pin1Params.compId = compList.indexOf(wire.getPin1().component);
274 pin2Params.pinIndex = wire.getPin2().component.getPins().indexOf(wire.getPin2());
275 pin2Params.compId = compList.indexOf(wire.getPin2().component);
276 inner.pin1 = pin1Params;
277 inner.pin2 = pin2Params;
278 inner.path = wire.getPath();
281 params.innerWires = wires;