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