0c0bf301e61bf408666f2ae326e31a87bf2f533b
[Mograsim.git] / net.mograsim.logic.ui / src / net / mograsim / logic / ui / model / components / SimpleRectangularSubmodelComponent.java
1 package net.mograsim.logic.ui.model.components;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.Collections;
6 import java.util.HashSet;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.TreeMap;
10
11 import net.haspamelodica.swt.helper.gcs.GeneralGC;
12 import net.haspamelodica.swt.helper.swtobjectwrappers.Font;
13 import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
14 import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
15 import net.mograsim.logic.ui.model.ViewModelModifiable;
16 import net.mograsim.logic.ui.model.wires.Pin;
17
18 public class SimpleRectangularSubmodelComponent extends SubmodelComponent
19 {
20         public static String kLabel = "label", kInCount = "input_count", kOutCount = "output_count", kLogicWidth = "logic_width";
21
22         private static final double width = 35;
23         private static final double pinDistance = 10;
24         private static final double pinNameMargin = .5;
25         private static final double labelFontHeight = 5;
26         private static final double pinNameFontHeight = 3.5;
27
28         private final String label;
29         protected final int logicWidth;
30
31         private final List<String> inputPinNames;
32         private final List<String> inputPinNamesUnmodifiable;
33         private final List<String> outputPinNames;
34         private final List<String> outputPinNamesUnmodifiable;
35
36         protected SimpleRectangularSubmodelComponent(ViewModelModifiable model, int logicWidth, String label)
37         {
38                 super(model);
39                 this.label = label;
40                 this.logicWidth = logicWidth;
41                 this.inputPinNames = new ArrayList<>();
42                 this.inputPinNamesUnmodifiable = Collections.unmodifiableList(inputPinNames);
43                 this.outputPinNames = new ArrayList<>();
44                 this.outputPinNamesUnmodifiable = Collections.unmodifiableList(outputPinNames);
45         }
46
47         protected void setInputPins(String... pinNames)
48         {
49                 setIOPins(0, inputPinNames, outputPinNames, pinNames);
50         }
51
52         protected void setOutputPins(String... pinNames)
53         {
54                 setIOPins(width, outputPinNames, inputPinNames, pinNames);
55         }
56
57         private void setIOPins(double relX, List<String> pinNamesListThisSide, List<String> pinNamesListOtherSide, String... newPinNames)
58         {
59                 int inputCount = newPinNames.length;
60                 List<String> newPinNamesList = Arrays.asList(newPinNames);
61                 if (new HashSet<>(newPinNamesList).size() != inputCount)
62                         throw new IllegalArgumentException("Pin names contain duplicates");
63                 for (String pinName : newPinNamesList)
64                         if (pinNamesListOtherSide.contains(pinName))
65                                 throw new IllegalArgumentException("Can't add pin. There is a pin on the other side with the same name: " + pinName);
66                 super.setSize(width, Math.max(inputCount, pinNamesListOtherSide.size()) * pinDistance);
67                 for (int i = 0; i < inputCount; i++)
68                 {
69                         String pinName = newPinNames[i];
70                         int oldPinIndex = pinNamesListThisSide.indexOf(pinName);
71                         if (oldPinIndex == -1)
72                                 super.addSubmodelInterface(pinName, logicWidth, relX, pinDistance / 2 + i * pinDistance);
73                         else
74                                 getSupermodelMovablePin(pinName).setRelPos(relX, pinDistance / 2 + i * pinDistance);
75                 }
76                 for (String pinName : pinNamesListThisSide)
77                         if (!newPinNamesList.contains(pinName))
78                                 super.removeSubmodelInterface(pinName);
79                 pinNamesListThisSide.clear();
80                 pinNamesListThisSide.addAll(newPinNamesList);
81         }
82
83         public List<String> getInputPinNames()
84         {
85                 return inputPinNamesUnmodifiable;
86         }
87
88         public List<String> getOutputPinNames()
89         {
90                 return outputPinNamesUnmodifiable;
91         }
92
93         @Override
94         protected void renderSymbol(GeneralGC gc, Rectangle visibleRegion)
95         {
96                 double posX = getBounds().x;
97                 double posY = getBounds().y;
98
99                 Font oldFont = gc.getFont();
100                 gc.setFont(new Font(oldFont.getName(), labelFontHeight, oldFont.getStyle()));
101                 Point textExtent = gc.textExtent(label);
102                 gc.drawText(label, posX + (getBounds().width - textExtent.x) / 2, posY + (getBounds().height - textExtent.y) / 2, true);
103                 gc.setFont(new Font(oldFont.getName(), pinNameFontHeight, oldFont.getStyle()));
104                 for (int i = 0; i < inputPinNames.size(); i++)
105                 {
106                         String pinName = inputPinNames.get(i);
107                         textExtent = gc.textExtent(pinName);
108                         gc.drawText(pinName, posX + pinNameMargin, posY + i * pinDistance + (pinDistance - textExtent.y) / 2, true);
109                 }
110                 for (int i = 0; i < outputPinNames.size(); i++)
111                 {
112                         String pinName = outputPinNames.get(i);
113                         textExtent = gc.textExtent(pinName);
114                         gc.drawText(pinName, posX + width - textExtent.x - pinNameMargin, posY + i * pinDistance + (pinDistance - textExtent.y) / 2,
115                                         true);
116                 }
117                 gc.setFont(oldFont);
118         }
119
120         @Override
121         protected void renderOutline(GeneralGC gc, Rectangle visibleRegion)
122         {
123                 gc.drawRectangle(getBounds());
124         }
125
126         @Override
127         public SubmodelComponentParams calculateParams()
128         {
129                 SubmodelComponentParams ret = super.calculateParams();
130                 ret.type = SimpleRectangularSubmodelComponent.class.getSimpleName();
131                 Map<String, Object> m = new TreeMap<>();
132                 m.put(kLabel, label);
133                 m.put(kInCount, inputPinNames.size());
134                 m.put(kOutCount, outputPinNames.size());
135                 m.put(kLogicWidth, logicWidth);
136                 ret.specialized = m;
137                 return ret;
138         }
139
140         @Override
141         protected Pin addSubmodelInterface(String name, int logicWidth, double relX, double relY)
142         {
143                 throw new UnsupportedOperationException(
144                                 "Can't add submodel interfaces to a SimpleRectangularSubmodelComponent directly, call setInputPins / setOutputPins instead");
145         }
146
147         @Override
148         protected void removeSubmodelInterface(String name)
149         {
150                 throw new UnsupportedOperationException(
151                                 "Can't remove submodel interfaces of a SimpleRectangularSubmodelComponent directly, call setInputPins / setOutputPins instead");
152         }
153
154         @Override
155         protected void setSize(double width, double height)
156         {
157                 throw new UnsupportedOperationException(
158                                 "Can't set the size of a SimpleRectangularSubmodelComponent directly, call setInputPins / setOutputPins instead");
159         }
160 }