Introduced mini-buttons to the GUIManualSwitch to flip single bits
[Mograsim.git] / net.mograsim.logic.model / src / net / mograsim / logic / model / model / components / atomic / GUIManualSwitch.java
1 package net.mograsim.logic.model.model.components.atomic;
2
3 import org.eclipse.swt.graphics.Color;
4
5 import com.google.gson.JsonElement;
6 import com.google.gson.JsonPrimitive;
7
8 import net.haspamelodica.swt.helper.gcs.GeneralGC;
9 import net.haspamelodica.swt.helper.swtobjectwrappers.Font;
10 import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
11 import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
12 import net.mograsim.logic.core.LogicObserver;
13 import net.mograsim.logic.core.components.ManualSwitch;
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.ViewModelModifiable;
18 import net.mograsim.logic.model.model.components.GUIComponent;
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.ViewLogicModelAdapter;
22 import net.mograsim.logic.model.modeladapter.componentadapters.ManualSwitchAdapter;
23 import net.mograsim.logic.model.serializing.IdentifierGetter;
24 import net.mograsim.logic.model.serializing.IndirectGUIComponentCreator;
25 import net.mograsim.preferences.Preferences;
26
27 public class GUIManualSwitch extends GUIComponent
28 {
29         private static final double width = 20;
30         private static final double height = 15;
31         private static final double fontHeight = 5;
32         private static final double heightMiniButtons = 4; // 0 is disabled
33
34         public final int logicWidth;
35         private final Pin outputPin;
36
37         private final LogicObserver logicObs;
38         private ManualSwitch logicSwitch;
39
40         public GUIManualSwitch(ViewModelModifiable model, int logicWidth)
41         {
42                 this(model, logicWidth, null);
43         }
44
45         public GUIManualSwitch(ViewModelModifiable model, int logicWidth, String name)
46         {
47                 super(model, name);
48                 this.logicWidth = logicWidth;
49                 logicObs = (i) -> model.requestRedraw();
50
51                 setSize(width, height);
52                 addPin(this.outputPin = new Pin(this, "", logicWidth, PinUsage.OUTPUT, width, height / 2));
53         }
54
55         @Override
56         public void render(GeneralGC gc, Rectangle visibleRegion)
57         {
58                 Color foreground = Preferences.current().getColor("net.mograsim.logic.model.color.foreground");
59                 if (foreground != null)
60                         gc.setForeground(foreground);
61                 gc.drawRectangle(getBounds());
62                 String label = BitVectorFormatter.formatAsString(logicSwitch == null ? null : logicSwitch.getValues());
63                 Font oldFont = gc.getFont();
64                 Font labelFont = new Font(oldFont.getName(), fontHeight, oldFont.getStyle());
65                 gc.setFont(labelFont);
66                 Point textExtent = gc.textExtent(label);
67                 Color textColor = Preferences.current().getColor("net.mograsim.logic.model.color.text");
68                 if (textColor != null)
69                         gc.setForeground(textColor);
70                 gc.drawText(label, getPosX() + (width - textExtent.x) / 2, getPosY() + (height - textExtent.y) / 2, true);
71                 gc.setFont(oldFont);
72
73                 if (logicSwitch != null && logicWidth > 1 && heightMiniButtons > 0 && visibleRegion.y < getPosY() + heightMiniButtons)
74                 {
75                         double x = getPosX();
76                         double y = getPosY();
77                         gc.drawLine(x, y + heightMiniButtons, x + width, y + heightMiniButtons);
78                         Color c = gc.getBackground();
79                         gc.setBackground(gc.getForeground());
80                         BitVector bv = logicSwitch.getValues();
81                         double part = width / bv.length();
82                         for (int i = 0; i < bv.length(); i++)
83                         {
84                                 double start = x + part * i;
85                                 if (i != 0)
86                                         gc.drawLine(start, y, start, y + heightMiniButtons);
87                                 if (bv.getMSBit(i) == Bit.ONE)
88                                 {
89 //                                      gc.fillRectangle(start, y, part, heightMiniButtons); // alternative, but not always visible what Bit is where 
90                                         gc.drawLine(start, y, start + part, y + heightMiniButtons);
91                                         gc.drawLine(start + part, y, start, y + heightMiniButtons);
92                                 }
93                         }
94                         gc.setBackground(c);
95                 }
96         }
97
98         public void setLogicModelBinding(ManualSwitch logicSwitch)
99         {
100                 if (this.logicSwitch != null)
101                         this.logicSwitch.deregisterObserver(logicObs);
102                 this.logicSwitch = logicSwitch;
103                 if (logicSwitch != null)
104                         logicSwitch.registerObserver(logicObs);
105         }
106
107         public boolean hasLogicModelBinding()
108         {
109                 return logicSwitch != null;
110         }
111
112         @Override
113         public Object getHighLevelState(String stateID)
114         {
115                 switch (stateID)
116                 {
117                 case "out":
118                         if (logicSwitch != null)
119                                 return logicSwitch.getValues();
120                         return null;
121                 default:
122                         return super.getHighLevelState(stateID);
123                 }
124         }
125
126         @Override
127         public void setHighLevelState(String stateID, Object newState)
128         {
129                 switch (stateID)
130                 {
131                 case "out":
132                         if (logicSwitch != null)
133                                 logicSwitch.setState((BitVector) newState);
134                         break;
135                 default:
136                         super.setHighLevelState(stateID, newState);
137                         break;
138                 }
139         }
140
141         @Override
142         public boolean clicked(double x, double y)
143         {
144                 if (logicSwitch != null)
145                 {
146                         if (heightMiniButtons > 0 && y - getPosY() < heightMiniButtons)
147                         {
148                                 int part = (int) ((x - getPosX()) * logicWidth / width);
149                                 logicSwitch.setState(logicSwitch.getValues().withBitChanged(part, Bit::not));
150                         } else
151                         {
152                                 logicSwitch.toggle();
153                         }
154                 }
155                 return true;
156         }
157
158         public ManualSwitch getManualSwitch()
159         {
160                 return logicSwitch;
161         }
162
163         public Pin getOutputPin()
164         {
165                 return outputPin;
166         }
167
168         @Override
169         public JsonElement getParamsForSerializing(IdentifierGetter idGetter)
170         {
171                 return new JsonPrimitive(logicWidth);
172         }
173
174         static
175         {
176                 ViewLogicModelAdapter.addComponentAdapter(new ManualSwitchAdapter());
177                 IndirectGUIComponentCreator.setComponentSupplier(GUIManualSwitch.class.getName(),
178                                 (m, p, n) -> new GUIManualSwitch(m, p.getAsInt(), n));
179         }
180 }