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