Added SubmodelComponent
[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.GCDefaultConfig;
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 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 final LogicUIRenderer renderer;
29
30         public SubmodelComponent(ViewModelModifiable model)
31         {
32                 super(model);
33                 this.submodelModifiable = new ViewModelModifiable();
34                 this.submodel = submodelModifiable;
35                 this.submodelPinsPerSupermodelPin = new HashMap<>();
36                 this.submodelPinsPerSupermodelPinUnmodifiable = Collections.unmodifiableMap(submodelPinsPerSupermodelPin);
37                 this.supermodelPinsPerSubmodelPin = new HashMap<>();
38                 this.supermodelPinsPerSubmodelPinUnmodifiable = Collections.unmodifiableMap(supermodelPinsPerSubmodelPin);
39                 this.submodelInterface = new SubmodelInterface(submodelModifiable);
40
41                 this.submodelScale = 1;
42                 this.renderer = new LogicUIRenderer(submodelModifiable);
43
44                 submodelModifiable.addRedrawListener(this::requestRedraw);
45         }
46
47         protected void setSubmodelScale(double submodelScale)
48         {
49                 this.submodelScale = submodelScale;
50
51                 for (Entry<PinMovable, PinMovable> e : supermodelPinsPerSubmodelPin.entrySet())
52                         e.getKey().setRelPos(e.getValue().getRelX() * submodelScale, e.getValue().getRelY() * submodelScale);
53
54                 requestRedraw();// needed if there is no submodel interface pin
55         }
56
57         /**
58          * Returns the submodel pin.
59          */
60         protected Pin addSubmodelInterface(int logicWidth, double relX, double relY)
61         {
62                 PinMovable submodelPin = new PinMovable(submodelInterface, logicWidth, relX / submodelScale, relY / submodelScale);
63                 submodelInterface.addPin(submodelPin);
64
65                 PinMovable supermodelPin = new PinMovable(this, logicWidth, relX, relY);
66                 addPin(supermodelPin);
67
68                 submodelPinsPerSupermodelPin.put(supermodelPin, submodelPin);
69                 supermodelPinsPerSubmodelPin.put(submodelPin, supermodelPin);
70
71                 // no need to call requestRedraw() because addPin() will request a redraw
72                 return submodelPin;
73         }
74
75         protected void moveSubmodelInterface(Pin supermodelPin, double relX, double relY)
76         {
77                 PinMovable submodelPin = getSubmodelMovablePin(supermodelPin);
78                 PinMovable supermodelPinMovable = getSupermodelMovablePin(submodelPin);
79
80                 submodelPin.setRelPos(relX / submodelScale, relY / submodelScale);
81                 supermodelPinMovable.setRelPos(relX, relY);
82
83                 // no need to call requestRedraw() because setRelPos() will request a redraw
84         }
85
86         protected void removeSubmodelInterface(Pin supermodelPin)
87         {
88                 removePin(supermodelPin);
89                 Pin submodelPin = getSubmodelMovablePin(supermodelPin);
90                 submodelInterface.removePin(submodelPin);
91
92                 submodelPinsPerSupermodelPin.remove(supermodelPin);
93                 supermodelPinsPerSubmodelPin.remove(submodelPin);
94
95                 // no need to call requestRedraw() because removePin() will request a redraw
96         }
97
98         public Map<Pin, Pin> getSupermodelPinsPerSubmodelPin()
99         {
100                 return supermodelPinsPerSubmodelPinUnmodifiable;
101         }
102
103         public Pin getSupermodelPin(Pin submodelPin)
104         {
105                 return getSupermodelMovablePin(submodelPin);
106         }
107
108         protected PinMovable getSupermodelMovablePin(Pin submodelPin)
109         {
110                 return supermodelPinsPerSubmodelPin.get(submodelPin);
111         }
112
113         public Map<Pin, Pin> getSubmodelPinsPerSupermodelPin()
114         {
115                 return submodelPinsPerSupermodelPinUnmodifiable;
116         }
117
118         public Pin getSubmodelPin(Pin supermodelPin)
119         {
120                 return getSubmodelMovablePin(supermodelPin);
121         }
122
123         protected PinMovable getSubmodelMovablePin(Pin supermodelPin)
124         {
125                 return submodelPinsPerSupermodelPin.get(supermodelPin);
126         }
127
128         @Override
129         public void render(GeneralGC gc, Rectangle visibleRegion)
130         {
131                 double posX = getBounds().x;
132                 double posY = getBounds().y;
133
134                 GCDefaultConfig conf = new GCDefaultConfig(gc);
135                 TranslatedGC tgc = new TranslatedGC(gc, posX, posY, submodelScale, true);
136                 conf.reset(tgc);
137                 renderer.render(tgc, visibleRegion.translate(posX, posY, submodelScale));
138                 conf.reset(gc);
139                 // draw the "bounding box" after all other operations to make interface pins look better
140                 gc.drawRectangle(getBounds());
141         }
142
143         private static class PinMovable extends Pin
144         {
145                 public PinMovable(GUIComponent component, int logicWidth, double relX, double relY)
146                 {
147                         super(component, logicWidth, relX, relY);
148                 }
149
150                 @Override
151                 protected void setRelPos(double relX, double relY)
152                 {
153                         super.setRelPos(relX, relY);
154                 }
155         }
156 }