1 package net.mograsim.logic.model.model.components.atomic;
3 import java.util.HashMap;
5 import java.util.Objects;
6 import java.util.concurrent.atomic.AtomicReference;
7 import java.util.function.Consumer;
9 import net.haspamelodica.swt.helper.gcs.GeneralGC;
10 import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
11 import net.mograsim.logic.core.wires.CoreWire.ReadEnd;
12 import net.mograsim.logic.core.wires.CoreWire.ReadWriteEnd;
13 import net.mograsim.logic.model.model.LogicModelModifiable;
14 import net.mograsim.logic.model.model.components.ModelComponent;
15 import net.mograsim.logic.model.model.wires.Pin;
16 import net.mograsim.logic.model.modeladapter.LogicCoreAdapter;
17 import net.mograsim.logic.model.modeladapter.componentadapters.SimpleRectangularHardcodedModelComponentAdapter;
18 import net.mograsim.logic.model.preferences.RenderPreferences;
19 import net.mograsim.logic.model.serializing.IdentifyParams;
20 import net.mograsim.logic.model.snippets.HighLevelStateHandler;
21 import net.mograsim.logic.model.snippets.outlinerenderers.DefaultOutlineRenderer;
22 import net.mograsim.logic.model.snippets.symbolrenderers.CenteredTextSymbolRenderer;
23 import net.mograsim.logic.model.snippets.symbolrenderers.CenteredTextSymbolRenderer.CenteredTextParams;
24 import net.mograsim.logic.model.snippets.symbolrenderers.PinNamesSymbolRenderer;
25 import net.mograsim.logic.model.snippets.symbolrenderers.PinNamesSymbolRenderer.PinNamesParams;
26 import net.mograsim.logic.model.snippets.symbolrenderers.PinNamesSymbolRenderer.PinNamesParams.Position;
27 import net.mograsim.logic.model.util.ObservableAtomicReference;
29 public abstract class SimpleRectangularHardcodedModelComponent extends ModelComponent
31 private static final double centerTextHeight = 5;
32 private static final double pinNamesHeight = 3.5;
33 private static final double pinNamesMargin = .5;
35 private final String id;
37 private final DefaultOutlineRenderer outlineRenderer;
38 private final CenteredTextSymbolRenderer centerTextRenderer;
39 private final PinNamesSymbolRenderer pinNamesRenderer;
41 private ObservableAtomicReference<Object> state;
42 private Runnable recalculate;
44 private final Map<String, Map<Consumer<Object>, Consumer<ObservableAtomicReference<Object>>>> stateObsPerHLSListenerPerStateID;
46 // creation and destruction
48 public SimpleRectangularHardcodedModelComponent(LogicModelModifiable model, String id, String name, String centerText)
50 this(model, id, name, centerText, true);
53 public SimpleRectangularHardcodedModelComponent(LogicModelModifiable model, String id, String name, String centerText, boolean callInit)
55 super(model, name, false);
57 this.outlineRenderer = new DefaultOutlineRenderer(this);
58 CenteredTextParams centeredTextParams = new CenteredTextParams();
59 centeredTextParams.text = centerText;
60 centeredTextParams.fontHeight = centerTextHeight;
61 this.centerTextRenderer = new CenteredTextSymbolRenderer(this, centeredTextParams);
62 PinNamesParams pinNamesParams = new PinNamesParams();
63 pinNamesParams.pinLabelHeight = pinNamesHeight;
64 pinNamesParams.pinLabelMargin = pinNamesMargin;
65 this.pinNamesRenderer = new PinNamesSymbolRenderer(this, pinNamesParams);
66 addPinRemovedListener(this::pinRemoved);
68 this.stateObsPerHLSListenerPerStateID = new HashMap<>();
70 setHighLevelStateHandler(new HighLevelStateHandler()
74 public Object get(String stateID)
76 return getHighLevelState(state.get(), stateID);
80 public void set(String stateID, Object newState)
82 state.updateAndGet(s -> SimpleRectangularHardcodedModelComponent.this.setHighLevelState(s, stateID, newState));
87 public void addListener(String stateID, Consumer<Object> stateChanged)
89 addHighLevelStateListener(state.get(), stateID, stateChanged);
93 public void removeListener(String stateID, Consumer<Object> stateChanged)
95 removeHighLevelStateListener(state.get(), stateID, stateChanged);
99 public String getIDForSerializing(IdentifyParams idParams)
101 return null;// we don't need to serialize this; it's implicit since we are a SimpleRectangularHardcodedModelComponent
105 public Object getParamsForSerializing(IdentifyParams idParams)
117 protected void addPin(Pin pin, Position namePosition)
119 super.addPin(pin); // do this first to catch errors
120 pinNamesRenderer.setPinPosition(pin, namePosition);
123 private void pinRemoved(Pin pin)
125 pinNamesRenderer.setPinPosition(pin, null);
130 @SuppressWarnings({ "static-method", "unused" }) // this method is intended to be overridden
131 protected Object getHighLevelState(Object state, String stateID)
133 throw new IllegalArgumentException("No high level state with ID " + stateID);
136 @SuppressWarnings({ "static-method", "unused" }) // this method is intended to be overridden
137 protected Object setHighLevelState(Object lastState, String stateID, Object newHighLevelState)
139 throw new IllegalArgumentException("No high level state with ID " + stateID);
142 protected void addHighLevelStateListener(Object state, String stateID, Consumer<Object> stateChanged)
144 AtomicReference<Object> lastHLSRef = new AtomicReference<>(getHighLevelState(state, stateID));
145 Consumer<ObservableAtomicReference<Object>> refObs = r ->
147 Object newHLS = getHighLevelState(stateID);
148 if (!Objects.equals(lastHLSRef.getAndSet(newHLS), newHLS))
149 stateChanged.accept(newHLS);
151 stateObsPerHLSListenerPerStateID.computeIfAbsent(stateID, s -> new HashMap<>()).put(stateChanged, refObs);
152 this.state.addObserver(refObs);
155 protected void removeHighLevelStateListener(Object state, String stateID, Consumer<Object> stateChanged)
157 getHighLevelState(state, stateID);// if this throws, we know there is no HLS with this name
158 var stateObsPerHLSListener = stateObsPerHLSListenerPerStateID.get(stateID);
159 if (stateObsPerHLSListener == null)
161 Consumer<ObservableAtomicReference<Object>> refObs = stateObsPerHLSListener.remove(stateChanged);
162 this.state.removeObserver(refObs);
167 public abstract Object recalculate(Object lastState, Map<String, ReadEnd> readEnds, Map<String, ReadWriteEnd> readWriteEnds);
169 // core model binding
171 public void setCoreModelBindingAndResetState(ObservableAtomicReference<Object> state, Runnable recalculate)
174 this.recalculate = recalculate;
177 // "graphical" operations
180 public void render(GeneralGC gc, RenderPreferences renderPrefs, Rectangle visibleRegion)
182 outlineRenderer.render(gc, renderPrefs, visibleRegion);
183 centerTextRenderer.render(gc, renderPrefs, visibleRegion);
184 pinNamesRenderer.render(gc, renderPrefs, visibleRegion);
190 public String getIDForSerializing(IdentifyParams idParams)
195 // operations no longer supported
198 protected void addPin(Pin pin)
200 throw new UnsupportedOperationException("Can't add pins without setting usage, call addPin(Pin [, Position]) instead");
205 LogicCoreAdapter.addComponentAdapter(new SimpleRectangularHardcodedModelComponentAdapter());