Restructured the Preferences system
[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 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 net.haspamelodica.swt.helper.gcs.GeneralGC;
13 import net.haspamelodica.swt.helper.swtobjectwrappers.Font;
14 import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
15 import net.mograsim.logic.core.LogicObserver;
16 import net.mograsim.logic.core.components.CoreManualSwitch;
17 import net.mograsim.logic.core.types.Bit;
18 import net.mograsim.logic.core.types.BitVector;
19 import net.mograsim.logic.model.BitVectorFormatter;
20 import net.mograsim.logic.model.model.LogicModelModifiable;
21 import net.mograsim.logic.model.model.components.ModelComponent;
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.ManualSwitchAdapter;
26 import net.mograsim.logic.model.preferences.RenderPreferences;
27 import net.mograsim.logic.model.serializing.IdentifyParams;
28 import net.mograsim.logic.model.serializing.IndirectModelComponentCreator;
29 import net.mograsim.logic.model.snippets.HighLevelStateHandler;
30 import net.mograsim.logic.model.util.TextRenderingHelper;
31
32 public class ModelManualSwitch extends ModelComponent
33 {
34         private static final double width = 20;
35         private static final double height = 10;
36         private static final double fontHeight = 5;
37         private static final double heightMiniButtons = 4; // 0 is disabled
38         private static final double textMargin = 0.5;
39
40         public final int logicWidth;
41         private final Pin outputPin;
42
43         private final LogicObserver logicObs;
44         private CoreManualSwitch manualSwitch;
45
46         private final List<Consumer<Object>> hlsListeners;
47
48         public ModelManualSwitch(LogicModelModifiable model, int logicWidth)
49         {
50                 this(model, logicWidth, null);
51         }
52
53         public ModelManualSwitch(LogicModelModifiable model, int logicWidth, String name)
54         {
55                 super(model, name, false);
56                 this.logicWidth = logicWidth;
57
58                 setSize(width, height);
59                 addPin(this.outputPin = new Pin(model, this, "", logicWidth, PinUsage.OUTPUT, width, height / 2));
60
61                 hlsListeners = new ArrayList<>();
62
63                 logicObs = i ->
64                 {
65                         model.requestRedraw();
66                         BitVector v = getOutValues();
67                         hlsListeners.forEach(l -> l.accept(v));
68                 };
69
70                 setHighLevelStateHandler(new HighLevelStateHandler()
71                 {
72                         @Override
73                         public Object get(String stateID)
74                         {
75                                 switch (stateID)
76                                 {
77                                 case "out":
78                                         if (manualSwitch != null)
79                                                 return getOutValues();
80                                         return null;
81                                 default:
82                                         throw new IllegalArgumentException("No high level state with ID " + stateID);
83                                 }
84                         }
85
86                         @Override
87                         public void set(String stateID, Object newState)
88                         {
89                                 switch (stateID)
90                                 {
91                                 case "out":
92                                         if (manualSwitch != null)
93                                                 manualSwitch.setState((BitVector) newState);
94                                         break;
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, RenderPreferences renderPrefs, Rectangle visibleRegion)
144         {
145                 Color foreground = renderPrefs.getColor(FOREGROUND_COLOR);
146                 if (foreground != null)
147                         gc.setForeground(foreground);
148                 gc.drawRectangle(getBounds());
149                 String label = BitVectorFormatter.formatAsString(manualSwitch == null ? null : getOutValues(), false);
150                 Font oldFont = gc.getFont();
151                 Font labelFont = new Font(oldFont.getName(), fontHeight, oldFont.getStyle());
152                 gc.setFont(labelFont);
153                 Color textColor = renderPrefs.getColor(TEXT_COLOR);
154                 if (textColor != null)
155                         gc.setForeground(textColor);
156                 TextRenderingHelper.drawTextFitting(gc, label, getBounds(), textMargin, true);
157                 gc.setFont(oldFont);
158
159                 if (manualSwitch != null && logicWidth > 1 && heightMiniButtons > 0 && visibleRegion.y < getPosY() + heightMiniButtons)
160                 {
161                         double x = getPosX();
162                         double y = getPosY();
163                         gc.drawLine(x, y + heightMiniButtons, x + width, y + heightMiniButtons);
164                         Color c = gc.getBackground();
165                         gc.setBackground(gc.getForeground());
166                         BitVector bv = getOutValues();
167                         double part = width / bv.length();
168                         for (int i = 0; i < bv.length(); i++)
169                         {
170                                 double start = x + part * i;
171                                 if (i != 0)
172                                         gc.drawLine(start, y, start, y + heightMiniButtons);
173                                 if (bv.getMSBit(i) == Bit.ONE)
174                                 {
175 //                                      gc.fillRectangle(start, y, part, heightMiniButtons); // alternative, but not always visible what Bit is where 
176                                         gc.drawLine(start, y, start + part, y + heightMiniButtons);
177                                         gc.drawLine(start + part, y, start, y + heightMiniButtons);
178                                 }
179                         }
180                         gc.setBackground(c);
181                 }
182         }
183
184         public void setCoreModelBinding(CoreManualSwitch logicSwitch)
185         {
186                 if (this.manualSwitch != null)
187                         this.manualSwitch.deregisterObserver(logicObs);
188                 this.manualSwitch = logicSwitch;
189                 if (logicSwitch != null)
190                         logicSwitch.registerObserver(logicObs);
191         }
192
193         public boolean hasCoreModelBinding()
194         {
195                 return manualSwitch != null;
196         }
197
198         @Override
199         public boolean clicked(double x, double y)
200         {
201                 if (manualSwitch != null)
202                 {
203                         if (heightMiniButtons > 0 && y - getPosY() < heightMiniButtons)
204                         {
205                                 int part = (int) ((x - getPosX()) * logicWidth / width);
206                                 manualSwitch.setState(getOutValues().withBitChanged(part, Bit::not));
207                         } else
208                         {
209                                 manualSwitch.toggle();
210                         }
211                 }
212                 return true;
213         }
214
215         public CoreManualSwitch getManualSwitch()
216         {
217                 return manualSwitch;
218         }
219
220         public Pin getOutputPin()
221         {
222                 return outputPin;
223         }
224
225         @Override
226         public String getIDForSerializing(IdentifyParams idParams)
227         {
228                 return "ManualSwitch";
229         }
230
231         @Override
232         public Integer getParamsForSerializing(IdentifyParams idParams)
233         {
234                 return logicWidth;
235         }
236
237         private BitVector getOutValues()
238         {
239                 return manualSwitch.getValues();
240         }
241
242         static
243         {
244                 LogicCoreAdapter.addComponentAdapter(new ManualSwitchAdapter());
245                 IndirectModelComponentCreator.setComponentSupplier(ModelManualSwitch.class.getName(),
246                                 (m, p, n) -> new ModelManualSwitch(m, p.getAsInt(), n));
247         }
248 }