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.params.GeneralComponentParams;
19 import net.mograsim.logic.ui.model.components.params.GeneralComponentParams.InnerComponentParams;
20 import net.mograsim.logic.ui.model.components.params.SubComponentParams;
21 import net.mograsim.logic.ui.model.components.params.SubComponentParams.InterfacePinParams;
22 import net.mograsim.logic.ui.model.wires.GUIWire;
23 import net.mograsim.logic.ui.model.wires.Pin;
24 import net.mograsim.logic.ui.model.components.params.SubComponentParams.InnerPinParams;
25 import net.mograsim.logic.ui.model.components.params.SubComponentParams.InnerWireParams;
27 public abstract class SubmodelComponent extends GUIComponent
29 protected final ViewModelModifiable submodelModifiable;
30 public final ViewModel submodel;
31 private final Map<PinMovable, PinMovable> submodelPinsPerSupermodelPin;
32 private final Map<Pin, Pin> submodelPinsPerSupermodelPinUnmodifiable;
33 private final Map<PinMovable, PinMovable> 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<PinMovable, PinMovable> 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(int logicWidth, double relX, double relY)
81 PinMovable submodelPin = new PinMovable(submodelInterface, logicWidth, relX / submodelScale, relY / submodelScale);
82 submodelInterface.addPin(submodelPin);
84 PinMovable supermodelPin = new PinMovable(this, logicWidth, relX, relY);
85 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 PinMovable submodelPin = getSubmodelMovablePin(supermodelPin);
97 PinMovable 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 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 PinMovable 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 PinMovable 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);
199 private static class PinMovable extends Pin
201 public PinMovable(GUIComponent component, int logicWidth, double relX, double relY)
203 super(component, logicWidth, relX, relY);
207 protected void setRelPos(double relX, double relY)
209 super.setRelPos(relX, relY);
213 public SubComponentParams calculateParams()
215 SubComponentParams params = new SubComponentParams();
216 params.type = SubmodelComponent.class.getSimpleName();
217 params.composition = calculateCompositionParams();
219 Rectangle bounds = getBounds();
220 params.width = bounds.width;
221 params.height = bounds.height;
223 List<Pin> pinList = pinsUnmodifiable;
224 InterfacePinParams[] iPins = new InterfacePinParams[pinList.size()];
226 for (Pin p : pinList)
228 InterfacePinParams iPinParams = new InterfacePinParams();
229 iPins[i] = iPinParams;
230 iPinParams.location = p.getRelPos();
231 iPinParams.logicWidth = p.logicWidth;
234 params.interfacePins = iPins;
238 protected GeneralComponentParams calculateCompositionParams()
240 GeneralComponentParams params = new GeneralComponentParams();
241 params.innerScale = getSubmodelScale();
243 List<GUIComponent> compList = submodelModifiable.getComponents();
244 Iterator<GUIComponent> componentIt = compList.iterator();
245 componentIt.next(); // Skip inner SubmodelInterface
246 InnerComponentParams[] comps = new InnerComponentParams[compList.size() - 1];
248 while (componentIt.hasNext())
250 GUIComponent component = componentIt.next();
251 InnerComponentParams inner = new InnerComponentParams();
253 inner.logicWidth = component.getPins().get(0).logicWidth; // This could be done a little more elegantly
254 Rectangle bounds = component.getBounds();
255 inner.pos = new Point(bounds.x, bounds.y);
256 inner.type = component.getIdentifier();
259 params.subComps = comps;
261 List<GUIWire> wireList = submodelModifiable.getWires();
262 InnerWireParams wires[] = new InnerWireParams[wireList.size()];
264 for (GUIWire wire : wireList)
266 InnerWireParams inner = new InnerWireParams();
268 InnerPinParams pin1Params = new InnerPinParams(), pin2Params = new InnerPinParams();
270 pin1Params.pinIndex = wire.getPin1().component.getPins().indexOf(wire.getPin1());
271 pin1Params.compId = compList.indexOf(wire.getPin1().component);
272 pin2Params.pinIndex = wire.getPin2().component.getPins().indexOf(wire.getPin2());
273 pin2Params.compId = compList.indexOf(wire.getPin2().component);
274 inner.pin1 = pin1Params;
275 inner.pin2 = pin2Params;
276 inner.path = wire.getPath();
279 params.innerWires = wires;