Restructured the Preferences system
[Mograsim.git] / plugins / net.mograsim.logic.model / src / net / mograsim / logic / model / model / components / atomic / ModelClock.java
1 package net.mograsim.logic.model.model.components.atomic;
2
3 import static net.mograsim.logic.model.preferences.RenderPreferences.FOREGROUND_COLOR;
4 import static net.mograsim.logic.model.preferences.RenderPreferences.TEXT_COLOR;
5
6 import java.util.ArrayList;
7 import java.util.List;
8 import java.util.function.Consumer;
9
10 import org.eclipse.swt.graphics.Color;
11
12 import com.google.gson.JsonSyntaxException;
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.core.LogicObserver;
19 import net.mograsim.logic.core.components.CoreClock;
20 import net.mograsim.logic.core.types.BitVector;
21 import net.mograsim.logic.model.model.LogicModelModifiable;
22 import net.mograsim.logic.model.model.components.ModelComponent;
23 import net.mograsim.logic.model.model.components.Orientation;
24 import net.mograsim.logic.model.model.components.OrientationCalculator;
25 import net.mograsim.logic.model.model.wires.Pin;
26 import net.mograsim.logic.model.model.wires.PinUsage;
27 import net.mograsim.logic.model.modeladapter.LogicCoreAdapter;
28 import net.mograsim.logic.model.modeladapter.componentadapters.ClockAdapter;
29 import net.mograsim.logic.model.preferences.RenderPreferences;
30 import net.mograsim.logic.model.serializing.IdentifyParams;
31 import net.mograsim.logic.model.serializing.IndirectModelComponentCreator;
32 import net.mograsim.logic.model.snippets.HighLevelStateHandler;
33 import net.mograsim.logic.model.util.JsonHandler;
34
35 public class ModelClock extends ModelComponent
36 {
37         private static final double width = 20;
38         private static final double height = 20;
39         private static final double fontHeight = 5;
40
41         private final Pin outputPin;
42
43         private final LogicObserver logicObs;
44         private ModelClockParams params;
45         private OrientationCalculator oc;
46         private CoreClock clock;
47
48         private final List<Consumer<Object>> hlsListeners;
49
50         public ModelClock(LogicModelModifiable model, ModelClockParams params)
51         {
52                 this(model, params, null);
53         }
54
55         public ModelClock(LogicModelModifiable model, ModelClockParams params, String name)
56         {
57                 super(model, name, false);
58                 this.params = params;
59
60                 oc = new OrientationCalculator(params.orientation, width, height);
61                 setSize(oc.width(), oc.height());
62
63                 this.outputPin = new Pin(model, this, "", 1, PinUsage.OUTPUT, oc.newX(width, height / 2), oc.newY(width, height / 2));
64                 addPin(outputPin);
65
66                 this.hlsListeners = new ArrayList<>();
67
68                 logicObs = i ->
69                 {
70                         model.requestRedraw();
71                         BitVector v = getOutValues();
72                         hlsListeners.forEach(l -> l.accept(v));
73                 };
74
75                 setHighLevelStateHandler(new HighLevelStateHandler()
76                 {
77                         @Override
78                         public Object get(String stateID)
79                         {
80                                 switch (stateID)
81                                 {
82                                 case "out":
83                                         if (clock != null)
84                                                 return getOutValues();
85                                         return null;
86                                 default:
87                                         throw new IllegalArgumentException("No high level state with ID " + stateID);
88                                 }
89                         }
90
91                         @Override
92                         public void set(String stateID, Object newState)
93                         {
94                                 switch (stateID)
95                                 {
96                                 case "out":
97                                         throw new UnsupportedOperationException("cannot set state of clock");
98                                 default:
99                                         throw new IllegalArgumentException("No high level state with ID " + stateID);
100                                 }
101                         }
102
103                         @Override
104                         public void addListener(String stateID, Consumer<Object> stateChanged)
105                         {
106                                 switch (stateID)
107                                 {
108                                 case "out":
109                                         hlsListeners.add(stateChanged);
110                                         break;
111                                 default:
112                                         throw new IllegalArgumentException("No high level state with ID " + stateID);
113                                 }
114                         }
115
116                         @Override
117                         public void removeListener(String stateID, java.util.function.Consumer<Object> stateChanged)
118                         {
119                                 switch (stateID)
120                                 {
121                                 case "out":
122                                         hlsListeners.remove(stateChanged);
123                                         break;
124                                 default:
125                                         throw new IllegalArgumentException("No high level state with ID " + stateID);
126                                 }
127                         }
128
129                         @Override
130                         public String getIDForSerializing(IdentifyParams idParams)
131                         {
132                                 return null;
133                         }
134
135                         @Override
136                         public Object getParamsForSerializing(IdentifyParams idParams)
137                         {
138                                 return null;
139                         }
140                 });
141
142                 init();
143         }
144
145         @Override
146         public void render(GeneralGC gc, RenderPreferences renderPrefs, Rectangle visibleRegion)
147         {
148                 Color foreground = renderPrefs.getColor(FOREGROUND_COLOR);
149                 if (foreground != null)
150                         gc.setForeground(foreground);
151                 gc.drawRectangle(getBounds());
152                 String label = clock == null ? "null" : (clock.isOn() ? "|" : "\u2015");
153                 Font oldFont = gc.getFont();
154                 Font labelFont = new Font(oldFont.getName(), fontHeight, oldFont.getStyle());
155                 gc.setFont(labelFont);
156                 Point textExtent = gc.textExtent(label);
157                 Color textColor = renderPrefs.getColor(TEXT_COLOR);
158                 if (textColor != null)
159                         gc.setForeground(textColor);
160                 gc.drawText(label, getPosX() + (oc.width() - textExtent.x) / 2, getPosY() + (oc.height() - textExtent.y) / 2, true);
161                 gc.setFont(oldFont);
162         }
163
164         public void setCoreModelBinding(CoreClock clock)
165         {
166                 if (this.clock != null)
167                         this.clock.deregisterObserver(logicObs);
168                 this.clock = clock;
169                 if (clock != null)
170                         clock.registerObserver(logicObs);
171         }
172
173         public boolean hasCoreModelBinding()
174         {
175                 return clock != null;
176         }
177
178         // TODO remove
179         public CoreClock getClock()
180         {
181                 return clock;
182         }
183
184         public Pin getOutputPin()
185         {
186                 return outputPin;
187         }
188
189         public int getDelta()
190         {
191                 return params.delta;
192         }
193
194         @Override
195         public String getIDForSerializing(IdentifyParams idParams)
196         {
197                 return "Clock";
198         }
199
200         @Override
201         public ModelClockParams getParamsForSerializing(IdentifyParams idParams)
202         {
203                 return params;
204         }
205
206         private BitVector getOutValues()
207         {
208                 return clock.getOutValues();
209         }
210
211         static
212         {
213                 LogicCoreAdapter.addComponentAdapter(new ClockAdapter());
214                 IndirectModelComponentCreator.setComponentSupplier(ModelClock.class.getName(), (m, p, n) ->
215                 {
216                         ModelClockParams params = JsonHandler.fromJsonTree(p, ModelClockParams.class);
217                         if (params == null)
218                                 throw new JsonSyntaxException("Invalid!!!");
219                         return new ModelClock(m, params, n);
220                 });
221         }
222
223         public static class ModelClockParams
224         {
225                 int delta;
226                 Orientation orientation;
227
228                 public ModelClockParams(int delta, Orientation orientation)
229                 {
230                         this.delta = delta;
231                         this.orientation = orientation;
232                 }
233         }
234 }