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