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