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