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.serializing.IdentifyParams;
19 import net.mograsim.logic.model.snippets.HighLevelStateHandler;
20 import net.mograsim.logic.model.snippets.outlinerenderers.DefaultOutlineRenderer;
21 import net.mograsim.logic.model.snippets.symbolrenderers.CenteredTextSymbolRenderer;
22 import net.mograsim.logic.model.snippets.symbolrenderers.CenteredTextSymbolRenderer.CenteredTextParams;
23 import net.mograsim.logic.model.snippets.symbolrenderers.PinNamesSymbolRenderer;
24 import net.mograsim.logic.model.snippets.symbolrenderers.PinNamesSymbolRenderer.PinNamesParams;
25 import net.mograsim.logic.model.snippets.symbolrenderers.PinNamesSymbolRenderer.PinNamesParams.Position;
26 import net.mograsim.logic.model.util.ObservableAtomicReference;
28 public abstract class SimpleRectangularHardcodedModelComponent extends ModelComponent
30 private static final double centerTextHeight = 5;
31 private static final double pinNamesHeight = 3.5;
32 private static final double pinNamesMargin = .5;
34 private final String id;
36 private final DefaultOutlineRenderer outlineRenderer;
37 private final CenteredTextSymbolRenderer centerTextRenderer;
38 private final PinNamesSymbolRenderer pinNamesRenderer;
40 private ObservableAtomicReference<Object> state;
41 private Runnable recalculate;
43 private final Map<String, Map<Consumer<Object>, Consumer<ObservableAtomicReference<Object>>>> stateObsPerHLSListenerPerStateID;
45 // creation and destruction
47 public SimpleRectangularHardcodedModelComponent(LogicModelModifiable model, String id, String name, String centerText)
49 this(model, id, name, centerText, true);
52 public SimpleRectangularHardcodedModelComponent(LogicModelModifiable model, String id, String name, String centerText, boolean callInit)
54 super(model, name, false);
56 this.outlineRenderer = new DefaultOutlineRenderer(this);
57 CenteredTextParams centeredTextParams = new CenteredTextParams();
58 centeredTextParams.text = centerText;
59 centeredTextParams.fontHeight = centerTextHeight;
60 this.centerTextRenderer = new CenteredTextSymbolRenderer(this, centeredTextParams);
61 PinNamesParams pinNamesParams = new PinNamesParams();
62 pinNamesParams.pinLabelHeight = pinNamesHeight;
63 pinNamesParams.pinLabelMargin = pinNamesMargin;
64 this.pinNamesRenderer = new PinNamesSymbolRenderer(this, pinNamesParams);
65 addPinRemovedListener(this::pinRemoved);
67 this.stateObsPerHLSListenerPerStateID = new HashMap<>();
69 setHighLevelStateHandler(new HighLevelStateHandler()
73 public Object get(String stateID)
75 return getHighLevelState(state.get(), stateID);
79 public void set(String stateID, Object newState)
81 state.updateAndGet(s -> SimpleRectangularHardcodedModelComponent.this.setHighLevelState(s, stateID, newState));
86 public void addListener(String stateID, Consumer<Object> stateChanged)
88 addHighLevelStateListener(state.get(), stateID, stateChanged);
92 public void removeListener(String stateID, Consumer<Object> stateChanged)
94 removeHighLevelStateListener(state.get(), stateID, stateChanged);
98 public String getIDForSerializing(IdentifyParams idParams)
100 return null;// we don't need to serialize this; it's implicit since we are a SimpleRectangularHardcodedModelComponent
104 public Object getParamsForSerializing(IdentifyParams idParams)
116 protected void addPin(Pin pin, Position namePosition)
118 super.addPin(pin); // do this first to catch errors
119 pinNamesRenderer.setPinPosition(pin, namePosition);
122 private void pinRemoved(Pin pin)
124 pinNamesRenderer.setPinPosition(pin, null);
129 @SuppressWarnings({ "static-method", "unused" }) // this method is intended to be overridden
130 protected Object getHighLevelState(Object state, String stateID)
132 throw new IllegalArgumentException("No high level state with ID " + stateID);
135 @SuppressWarnings({ "static-method", "unused" }) // this method is intended to be overridden
136 protected Object setHighLevelState(Object lastState, String stateID, Object newHighLevelState)
138 throw new IllegalArgumentException("No high level state with ID " + stateID);
141 protected void addHighLevelStateListener(Object state, String stateID, Consumer<Object> stateChanged)
143 AtomicReference<Object> lastHLSRef = new AtomicReference<>(getHighLevelState(state, stateID));
144 Consumer<ObservableAtomicReference<Object>> refObs = r ->
146 Object newHLS = getHighLevelState(stateID);
147 if (!Objects.equals(lastHLSRef.getAndSet(newHLS), newHLS))
148 stateChanged.accept(newHLS);
150 stateObsPerHLSListenerPerStateID.computeIfAbsent(stateID, s -> new HashMap<>()).put(stateChanged, refObs);
151 this.state.addObserver(refObs);
154 protected void removeHighLevelStateListener(Object state, String stateID, Consumer<Object> stateChanged)
156 getHighLevelState(state, stateID);// if this throws, we know there is no HLS with this name
157 var stateObsPerHLSListener = stateObsPerHLSListenerPerStateID.get(stateID);
158 if (stateObsPerHLSListener == null)
160 Consumer<ObservableAtomicReference<Object>> refObs = stateObsPerHLSListener.remove(stateChanged);
161 this.state.removeObserver(refObs);
166 public abstract Object recalculate(Object lastState, Map<String, ReadEnd> readEnds, Map<String, ReadWriteEnd> readWriteEnds);
168 // core model binding
170 public void setCoreModelBindingAndResetState(ObservableAtomicReference<Object> state, Runnable recalculate)
173 this.recalculate = recalculate;
176 // "graphical" operations
179 public void render(GeneralGC gc, Rectangle visibleRegion)
181 outlineRenderer.render(gc, visibleRegion);
182 centerTextRenderer.render(gc, visibleRegion);
183 pinNamesRenderer.render(gc, visibleRegion);
189 public String getIDForSerializing(IdentifyParams idParams)
194 // operations no longer supported
197 protected void addPin(Pin pin)
199 throw new UnsupportedOperationException("Can't add pins without setting usage, call addPin(Pin [, Position]) instead");
204 LogicCoreAdapter.addComponentAdapter(new SimpleRectangularHardcodedModelComponentAdapter());