789798254491d489a9cbed7ce3010fcf6e5253e0
[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.Rectangle;
12 import net.mograsim.logic.core.LogicObserver;
13 import net.mograsim.logic.core.components.CoreManualSwitch;
14 import net.mograsim.logic.core.types.Bit;
15 import net.mograsim.logic.core.types.BitVector;
16 import net.mograsim.logic.core.types.BitVectorFormatter;
17 import net.mograsim.logic.model.model.LogicModelModifiable;
18 import net.mograsim.logic.model.model.components.ModelComponent;
19 import net.mograsim.logic.model.model.wires.Pin;
20 import net.mograsim.logic.model.model.wires.PinUsage;
21 import net.mograsim.logic.model.modeladapter.LogicCoreAdapter;
22 import net.mograsim.logic.model.modeladapter.componentadapters.ManualSwitchAdapter;
23 import net.mograsim.logic.model.serializing.IdentifyParams;
24 import net.mograsim.logic.model.serializing.IndirectModelComponentCreator;
25 import net.mograsim.logic.model.snippets.HighLevelStateHandler;
26 import net.mograsim.logic.model.util.TextRenderingHelper;
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 = 10;
33         private static final double fontHeight = 5;
34         private static final double heightMiniButtons = 4; // 0 is disabled
35         private static final double textMargin = 0.5;
36
37         public final int logicWidth;
38         private final Pin outputPin;
39
40         private final LogicObserver logicObs;
41         private CoreManualSwitch manualSwitch;
42
43         private final List<Consumer<Object>> hlsListeners;
44
45         public ModelManualSwitch(LogicModelModifiable model, int logicWidth)
46         {
47                 this(model, logicWidth, null);
48         }
49
50         public ModelManualSwitch(LogicModelModifiable model, int logicWidth, String name)
51         {
52                 super(model, name, false);
53                 this.logicWidth = logicWidth;
54
55                 setSize(width, height);
56                 addPin(this.outputPin = new Pin(model, this, "", logicWidth, PinUsage.OUTPUT, width, height / 2));
57
58                 hlsListeners = new ArrayList<>();
59
60                 logicObs = i ->
61                 {
62                         model.requestRedraw();
63                         BitVector v = getOutValues();
64                         hlsListeners.forEach(l -> l.accept(v));
65                 };
66
67                 setHighLevelStateHandler(new HighLevelStateHandler()
68                 {
69                         @Override
70                         public Object get(String stateID)
71                         {
72                                 switch (stateID)
73                                 {
74                                 case "out":
75                                         if (manualSwitch != null)
76                                                 return getOutValues();
77                                         return null;
78                                 default:
79                                         throw new IllegalArgumentException("No high level state with ID " + stateID);
80                                 }
81                         }
82
83                         @Override
84                         public void set(String stateID, Object newState)
85                         {
86                                 switch (stateID)
87                                 {
88                                 case "out":
89                                         if (manualSwitch != null)
90                                                 manualSwitch.setState((BitVector) newState);
91                                         break;
92                                 default:
93                                         throw new IllegalArgumentException("No high level state with ID " + stateID);
94                                 }
95                         }
96
97                         @Override
98                         public void addListener(String stateID, Consumer<Object> stateChanged)
99                         {
100                                 switch (stateID)
101                                 {
102                                 case "out":
103                                         hlsListeners.add(stateChanged);
104                                         break;
105                                 default:
106                                         throw new IllegalArgumentException("No high level state with ID " + stateID);
107                                 }
108                         }
109
110                         @Override
111                         public void removeListener(String stateID, java.util.function.Consumer<Object> stateChanged)
112                         {
113                                 switch (stateID)
114                                 {
115                                 case "out":
116                                         hlsListeners.remove(stateChanged);
117                                         break;
118                                 default:
119                                         throw new IllegalArgumentException("No high level state with ID " + stateID);
120                                 }
121                         }
122
123                         @Override
124                         public String getIDForSerializing(IdentifyParams idParams)
125                         {
126                                 return null;
127                         }
128
129                         @Override
130                         public Object getParamsForSerializing(IdentifyParams idParams)
131                         {
132                                 return null;
133                         }
134                 });
135
136                 init();
137         }
138
139         @Override
140         public void render(GeneralGC gc, Rectangle visibleRegion)
141         {
142                 Color foreground = Preferences.current().getColor("net.mograsim.logic.model.color.foreground");
143                 if (foreground != null)
144                         gc.setForeground(foreground);
145                 gc.drawRectangle(getBounds());
146                 String label = BitVectorFormatter.formatAsString(manualSwitch == null ? null : getOutValues(), false);
147                 Font oldFont = gc.getFont();
148                 Font labelFont = new Font(oldFont.getName(), fontHeight, oldFont.getStyle());
149                 gc.setFont(labelFont);
150                 Color textColor = Preferences.current().getColor("net.mograsim.logic.model.color.text");
151                 if (textColor != null)
152                         gc.setForeground(textColor);
153                 TextRenderingHelper.drawTextFitting(gc, label, getBounds(), textMargin, 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 }