Some work on improving BitVector<->String conversions
[Mograsim.git] / plugins / net.mograsim.logic.model / src / net / mograsim / logic / model / model / components / atomic / ModelManualSwitch.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 net.haspamelodica.swt.helper.gcs.GeneralGC;
10 import net.haspamelodica.swt.helper.swtobjectwrappers.Font;
11 import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
12 import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
13 import net.mograsim.logic.core.LogicObserver;
14 import net.mograsim.logic.core.components.CoreManualSwitch;
15 import net.mograsim.logic.core.types.Bit;
16 import net.mograsim.logic.core.types.BitVector;
17 import net.mograsim.logic.core.types.BitVectorFormatter;
18 import net.mograsim.logic.model.model.LogicModelModifiable;
19 import net.mograsim.logic.model.model.components.ModelComponent;
20 import net.mograsim.logic.model.model.wires.Pin;
21 import net.mograsim.logic.model.model.wires.PinUsage;
22 import net.mograsim.logic.model.modeladapter.LogicCoreAdapter;
23 import net.mograsim.logic.model.modeladapter.componentadapters.ManualSwitchAdapter;
24 import net.mograsim.logic.model.serializing.IdentifyParams;
25 import net.mograsim.logic.model.serializing.IndirectModelComponentCreator;
26 import net.mograsim.logic.model.snippets.HighLevelStateHandler;
27 import net.mograsim.preferences.Preferences;
28
29 public class ModelManualSwitch extends ModelComponent
30 {
31         private static final double width = 20;
32         private static final double height = 15;
33         private static final double fontHeight = 5;
34         private static final double heightMiniButtons = 4; // 0 is disabled
35
36         public final int logicWidth;
37         private final Pin outputPin;
38
39         private final LogicObserver logicObs;
40         private CoreManualSwitch manualSwitch;
41
42         private final List<Consumer<Object>> hlsListeners;
43
44         public ModelManualSwitch(LogicModelModifiable model, int logicWidth)
45         {
46                 this(model, logicWidth, null);
47         }
48
49         public ModelManualSwitch(LogicModelModifiable model, int logicWidth, String name)
50         {
51                 super(model, name, false);
52                 this.logicWidth = logicWidth;
53
54                 setSize(width, height);
55                 addPin(this.outputPin = new Pin(model, this, "", logicWidth, PinUsage.OUTPUT, width, height / 2));
56
57                 hlsListeners = new ArrayList<>();
58
59                 logicObs = i ->
60                 {
61                         model.requestRedraw();
62                         BitVector v = getOutValues();
63                         hlsListeners.forEach(l -> l.accept(v));
64                 };
65
66                 setHighLevelStateHandler(new HighLevelStateHandler()
67                 {
68                         @Override
69                         public Object get(String stateID)
70                         {
71                                 switch (stateID)
72                                 {
73                                 case "out":
74                                         if (manualSwitch != null)
75                                                 return getOutValues();
76                                         return null;
77                                 default:
78                                         throw new IllegalArgumentException("No high level state with ID " + stateID);
79                                 }
80                         }
81
82                         @Override
83                         public void set(String stateID, Object newState)
84                         {
85                                 switch (stateID)
86                                 {
87                                 case "out":
88                                         if (manualSwitch != null)
89                                                 manualSwitch.setState((BitVector) newState);
90                                         break;
91                                 default:
92                                         throw new IllegalArgumentException("No high level state with ID " + stateID);
93                                 }
94                         }
95
96                         @Override
97                         public void addListener(String stateID, Consumer<Object> stateChanged)
98                         {
99                                 switch (stateID)
100                                 {
101                                 case "out":
102                                         hlsListeners.add(stateChanged);
103                                         break;
104                                 default:
105                                         throw new IllegalArgumentException("No high level state with ID " + stateID);
106                                 }
107                         }
108
109                         @Override
110                         public void removeListener(String stateID, java.util.function.Consumer<Object> stateChanged)
111                         {
112                                 switch (stateID)
113                                 {
114                                 case "out":
115                                         hlsListeners.remove(stateChanged);
116                                         break;
117                                 default:
118                                         throw new IllegalArgumentException("No high level state with ID " + stateID);
119                                 }
120                         }
121
122                         @Override
123                         public String getIDForSerializing(IdentifyParams idParams)
124                         {
125                                 return null;
126                         }
127
128                         @Override
129                         public Object getParamsForSerializing(IdentifyParams idParams)
130                         {
131                                 return null;
132                         }
133                 });
134
135                 init();
136         }
137
138         @Override
139         public void render(GeneralGC gc, Rectangle visibleRegion)
140         {
141                 Color foreground = Preferences.current().getColor("net.mograsim.logic.model.color.foreground");
142                 if (foreground != null)
143                         gc.setForeground(foreground);
144                 gc.drawRectangle(getBounds());
145                 String label = BitVectorFormatter.formatAsString(manualSwitch == null ? null : getOutValues());
146                 Font oldFont = gc.getFont();
147                 Font labelFont = new Font(oldFont.getName(), fontHeight, oldFont.getStyle());
148                 gc.setFont(labelFont);
149                 Point textExtent = gc.textExtent(label);
150                 Color textColor = Preferences.current().getColor("net.mograsim.logic.model.color.text");
151                 if (textColor != null)
152                         gc.setForeground(textColor);
153                 gc.drawText(label, getPosX() + (width - textExtent.x) / 2, getPosY() + (height - textExtent.y) / 2, true);
154                 gc.setFont(oldFont);
155
156                 if (manualSwitch != null && logicWidth > 1 && heightMiniButtons > 0 && visibleRegion.y < getPosY() + heightMiniButtons)
157                 {
158                         double x = getPosX();
159                         double y = getPosY();
160                         gc.drawLine(x, y + heightMiniButtons, x + width, y + heightMiniButtons);
161                         Color c = gc.getBackground();
162                         gc.setBackground(gc.getForeground());
163                         BitVector bv = getOutValues();
164                         double part = width / bv.length();
165                         for (int i = 0; i < bv.length(); i++)
166                         {
167                                 double start = x + part * i;
168                                 if (i != 0)
169                                         gc.drawLine(start, y, start, y + heightMiniButtons);
170                                 if (bv.getMSBit(i) == Bit.ONE)
171                                 {
172 //                                      gc.fillRectangle(start, y, part, heightMiniButtons); // alternative, but not always visible what Bit is where 
173                                         gc.drawLine(start, y, start + part, y + heightMiniButtons);
174                                         gc.drawLine(start + part, y, start, y + heightMiniButtons);
175                                 }
176                         }
177                         gc.setBackground(c);
178                 }
179         }
180
181         public void setCoreModelBinding(CoreManualSwitch logicSwitch)
182         {
183                 if (this.manualSwitch != null)
184                         this.manualSwitch.deregisterObserver(logicObs);
185                 this.manualSwitch = logicSwitch;
186                 if (logicSwitch != null)
187                         logicSwitch.registerObserver(logicObs);
188         }
189
190         public boolean hasCoreModelBinding()
191         {
192                 return manualSwitch != null;
193         }
194
195         @Override
196         public boolean clicked(double x, double y)
197         {
198                 if (manualSwitch != null)
199                 {
200                         if (heightMiniButtons > 0 && y - getPosY() < heightMiniButtons)
201                         {
202                                 int part = (int) ((x - getPosX()) * logicWidth / width);
203                                 manualSwitch.setState(getOutValues().withBitChanged(part, Bit::not));
204                         } else
205                         {
206                                 manualSwitch.toggle();
207                         }
208                 }
209                 return true;
210         }
211
212         public CoreManualSwitch getManualSwitch()
213         {
214                 return manualSwitch;
215         }
216
217         public Pin getOutputPin()
218         {
219                 return outputPin;
220         }
221
222         @Override
223         public String getIDForSerializing(IdentifyParams idParams)
224         {
225                 return "ManualSwitch";
226         }
227
228         @Override
229         public Integer getParamsForSerializing(IdentifyParams idParams)
230         {
231                 return logicWidth;
232         }
233
234         private BitVector getOutValues()
235         {
236                 return manualSwitch.getValues();
237         }
238
239         static
240         {
241                 LogicCoreAdapter.addComponentAdapter(new ManualSwitchAdapter());
242                 IndirectModelComponentCreator.setComponentSupplier(ModelManualSwitch.class.getName(),
243                                 (m, p, n) -> new ModelManualSwitch(m, p.getAsInt(), n));
244         }
245 }