43ec22b02fb9c866f2e7fbbb4a9c7d9f8b0329d5
[Mograsim.git] / net.mograsim.logic.ui / src / net / mograsim / logic / ui / model / components / SubmodelComponent.java
1 package net.mograsim.logic.ui.model.components;
2
3 import java.util.Collections;
4 import java.util.HashMap;
5 import java.util.Map;
6 import java.util.Map.Entry;
7
8 import net.haspamelodica.swt.helper.gcs.GCConfig;
9 import net.haspamelodica.swt.helper.gcs.GeneralGC;
10 import net.haspamelodica.swt.helper.gcs.TranslatedGC;
11 import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
12 import net.mograsim.logic.ui.LogicUIRenderer;
13 import net.mograsim.logic.ui.model.ViewModel;
14 import net.mograsim.logic.ui.model.ViewModelModifiable;
15 import net.mograsim.logic.ui.model.wires.Pin;
16
17 public abstract class SubmodelComponent extends GUIComponent
18 {
19         protected final ViewModelModifiable submodelModifiable;
20         public final ViewModel submodel;
21         private final Map<PinMovable, PinMovable> submodelPinsPerSupermodelPin;
22         private final Map<Pin, Pin> submodelPinsPerSupermodelPinUnmodifiable;
23         private final Map<PinMovable, PinMovable> supermodelPinsPerSubmodelPin;
24         private final Map<Pin, Pin> supermodelPinsPerSubmodelPinUnmodifiable;
25         private final SubmodelInterface submodelInterface;
26
27         private double submodelScale;
28         private double maxVisibleRegionFillRatioForAlpha0;
29         private double minVisibleRegionFillRatioForAlpha1;
30         private final LogicUIRenderer renderer;
31
32         public SubmodelComponent(ViewModelModifiable model)
33         {
34                 super(model);
35                 this.submodelModifiable = new ViewModelModifiable();
36                 this.submodel = submodelModifiable;
37                 this.submodelPinsPerSupermodelPin = new HashMap<>();
38                 this.submodelPinsPerSupermodelPinUnmodifiable = Collections.unmodifiableMap(submodelPinsPerSupermodelPin);
39                 this.supermodelPinsPerSubmodelPin = new HashMap<>();
40                 this.supermodelPinsPerSubmodelPinUnmodifiable = Collections.unmodifiableMap(supermodelPinsPerSubmodelPin);
41                 this.submodelInterface = new SubmodelInterface(submodelModifiable);
42
43                 this.submodelScale = 1;
44                 this.maxVisibleRegionFillRatioForAlpha0 = 0.4;
45                 this.minVisibleRegionFillRatioForAlpha1 = 0.8;
46                 this.renderer = new LogicUIRenderer(submodelModifiable);
47
48                 submodelModifiable.addRedrawListener(this::requestRedraw);
49         }
50
51         protected void setSubmodelScale(double submodelScale)
52         {
53                 this.submodelScale = submodelScale;
54
55                 for (Entry<PinMovable, PinMovable> e : supermodelPinsPerSubmodelPin.entrySet())
56                         e.getKey().setRelPos(e.getValue().getRelX() * submodelScale, e.getValue().getRelY() * submodelScale);
57
58                 requestRedraw();// needed if there is no submodel interface pin
59         }
60
61         protected double getSubmodelScale()
62         {
63                 return submodelScale;
64         }
65
66         /**
67          * Returns the submodel pin.
68          */
69         protected Pin addSubmodelInterface(int logicWidth, double relX, double relY)
70         {
71                 PinMovable submodelPin = new PinMovable(submodelInterface, logicWidth, relX / submodelScale, relY / submodelScale);
72                 submodelInterface.addPin(submodelPin);
73
74                 PinMovable supermodelPin = new PinMovable(this, logicWidth, relX, relY);
75                 addPin(supermodelPin);
76
77                 submodelPinsPerSupermodelPin.put(supermodelPin, submodelPin);
78                 supermodelPinsPerSubmodelPin.put(submodelPin, supermodelPin);
79
80                 // no need to call requestRedraw() because addPin() will request a redraw
81                 return submodelPin;
82         }
83
84         protected void moveSubmodelInterface(Pin supermodelPin, double relX, double relY)
85         {
86                 PinMovable submodelPin = getSubmodelMovablePin(supermodelPin);
87                 PinMovable supermodelPinMovable = getSupermodelMovablePin(submodelPin);
88
89                 submodelPin.setRelPos(relX / submodelScale, relY / submodelScale);
90                 supermodelPinMovable.setRelPos(relX, relY);
91
92                 // no need to call requestRedraw() because setRelPos() will request a redraw
93         }
94
95         protected void removeSubmodelInterface(Pin supermodelPin)
96         {
97                 removePin(supermodelPin);
98                 Pin submodelPin = getSubmodelMovablePin(supermodelPin);
99                 submodelInterface.removePin(submodelPin);
100
101                 submodelPinsPerSupermodelPin.remove(supermodelPin);
102                 supermodelPinsPerSubmodelPin.remove(submodelPin);
103
104                 // no need to call requestRedraw() because removePin() will request a redraw
105         }
106
107         public Map<Pin, Pin> getSupermodelPinsPerSubmodelPin()
108         {
109                 return supermodelPinsPerSubmodelPinUnmodifiable;
110         }
111
112         public Pin getSupermodelPin(Pin submodelPin)
113         {
114                 return getSupermodelMovablePin(submodelPin);
115         }
116
117         protected PinMovable getSupermodelMovablePin(Pin submodelPin)
118         {
119                 return supermodelPinsPerSubmodelPin.get(submodelPin);
120         }
121
122         public Map<Pin, Pin> getSubmodelPinsPerSupermodelPin()
123         {
124                 return submodelPinsPerSupermodelPinUnmodifiable;
125         }
126
127         public Pin getSubmodelPin(Pin supermodelPin)
128         {
129                 return getSubmodelMovablePin(supermodelPin);
130         }
131
132         protected PinMovable getSubmodelMovablePin(Pin supermodelPin)
133         {
134                 return submodelPinsPerSupermodelPin.get(supermodelPin);
135         }
136
137         @Override
138         public void render(GeneralGC gc, Rectangle visibleRegion)
139         {
140                 double posX = getBounds().x;
141                 double posY = getBounds().y;
142
143                 GCConfig conf = new GCConfig(gc);
144                 TranslatedGC tgc = new TranslatedGC(gc, posX, posY, submodelScale, true);
145                 conf.reset(tgc);
146                 double visibleRegionFillRatio = Math.max(getBounds().width / visibleRegion.width, getBounds().height / visibleRegion.height);
147                 double alphaFactor = map(visibleRegionFillRatio, maxVisibleRegionFillRatioForAlpha0, minVisibleRegionFillRatioForAlpha1, 0, 1);
148                 alphaFactor = Math.max(0, Math.min(1, alphaFactor));
149                 // we need to take the old alpha into account to support nested submodules better.
150                 int oldAlpha = gc.getAlpha();
151                 int submodelAlpha = Math.max(0, Math.min(255, (int) (oldAlpha * alphaFactor)));
152                 int labelAlpha = Math.max(0, Math.min(255, (int) (oldAlpha * (1 - alphaFactor))));
153                 if (submodelAlpha != 0)
154                 {
155                         gc.setAlpha(submodelAlpha);
156                         renderer.render(tgc, visibleRegion.translate(posX / submodelScale, posY / submodelScale, 1 / submodelScale));
157                 }
158                 if (labelAlpha != 0)
159                 {
160                         gc.setAlpha(labelAlpha);
161                         renderSymbol(gc, visibleRegion);
162                 }
163                 conf.reset(gc);
164                 // draw the outline after all other operations to make interface pins look better
165                 renderOutline(gc, visibleRegion);
166         }
167
168         protected abstract void renderOutline(GeneralGC gc, Rectangle visibleRegion);
169
170         protected abstract void renderSymbol(GeneralGC gc, Rectangle visibleRegion);
171
172         private static double map(double val, double valMin, double valMax, double mapMin, double mapMax)
173         {
174                 return mapMin + (val - valMin) * (mapMax - mapMin) / (valMax - valMin);
175         }
176
177         @Override
178         public boolean clicked(double x, double y)
179         {
180                 // TODO
181                 double scaledX = (x - getBounds().x) / submodelScale;
182                 double scaledY = (y - getBounds().y) / submodelScale;
183                 double roundedScaledX = Math.round(scaledX / 5 * 2) * 5 / 2.;
184                 double roundedScaledY = Math.round(scaledY / 5 * 2) * 5 / 2.;
185                 System.out.println(scaledX + "|" + scaledY + ", rounded " + roundedScaledX + "|" + roundedScaledY);
186                 return true;
187         }
188
189         private static class PinMovable extends Pin
190         {
191                 public PinMovable(GUIComponent component, int logicWidth, double relX, double relY)
192                 {
193                         super(component, logicWidth, relX, relY);
194                 }
195
196                 @Override
197                 protected void setRelPos(double relX, double relY)
198                 {
199                         super.setRelPos(relX, relY);
200                 }
201         }
202 }