From d31bf89cdfb4141a7030eaa9198e2ba4cb203c40 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 24 Mar 2021 22:16:15 -0700 Subject: [PATCH 1/2] feature: expiremental nui replacment --- nui-core/build.gradle | 25 +++++++ .../java/org/terasology/nui/core/UICore.java | 4 ++ .../org/terasology/nui/core/UIPaintable.java | 4 ++ .../java/org/terasology/nui/core/UISlot.java | 18 +++++ .../org/terasology/nui/core/UIWidget.java | 57 ++++++++++++++++ .../org/terasology/nui/core/bind/Binding.java | 10 +++ .../nui/core/bind/BindingFunction.java | 4 ++ .../terasology/nui/core/bind/BindingPair.java | 15 +++++ .../terasology/nui/core/bind/Function0.java | 7 ++ .../terasology/nui/core/bind/Function1.java | 6 ++ .../terasology/nui/core/bind/Function2.java | 5 ++ .../terasology/nui/core/bind/Function3.java | 5 ++ .../terasology/nui/core/bind/Function4.java | 5 ++ .../terasology/nui/core/bind/Function5.java | 5 ++ .../terasology/nui/core/bind/Function6.java | 5 ++ .../terasology/nui/core/bind/Function7.java | 5 ++ .../terasology/nui/core/bind/Function8.java | 5 ++ .../terasology/nui/core/bind/UIProperty.java | 19 ++++++ .../terasology/nui/core/bind/UISignal.java | 65 +++++++++++++++++++ .../org/terasology/nui/core/bind/UISlot.java | 26 ++++++++ .../org/terasology/nui/core/TestWidget.java | 37 +++++++++++ nui-guui/build.gradle | 25 +++++++ settings.gradle | 2 +- 23 files changed, 358 insertions(+), 1 deletion(-) create mode 100644 nui-core/build.gradle create mode 100644 nui-core/src/main/java/org/terasology/nui/core/UICore.java create mode 100644 nui-core/src/main/java/org/terasology/nui/core/UIPaintable.java create mode 100644 nui-core/src/main/java/org/terasology/nui/core/UISlot.java create mode 100644 nui-core/src/main/java/org/terasology/nui/core/UIWidget.java create mode 100644 nui-core/src/main/java/org/terasology/nui/core/bind/Binding.java create mode 100644 nui-core/src/main/java/org/terasology/nui/core/bind/BindingFunction.java create mode 100644 nui-core/src/main/java/org/terasology/nui/core/bind/BindingPair.java create mode 100644 nui-core/src/main/java/org/terasology/nui/core/bind/Function0.java create mode 100644 nui-core/src/main/java/org/terasology/nui/core/bind/Function1.java create mode 100644 nui-core/src/main/java/org/terasology/nui/core/bind/Function2.java create mode 100644 nui-core/src/main/java/org/terasology/nui/core/bind/Function3.java create mode 100644 nui-core/src/main/java/org/terasology/nui/core/bind/Function4.java create mode 100644 nui-core/src/main/java/org/terasology/nui/core/bind/Function5.java create mode 100644 nui-core/src/main/java/org/terasology/nui/core/bind/Function6.java create mode 100644 nui-core/src/main/java/org/terasology/nui/core/bind/Function7.java create mode 100644 nui-core/src/main/java/org/terasology/nui/core/bind/Function8.java create mode 100644 nui-core/src/main/java/org/terasology/nui/core/bind/UIProperty.java create mode 100644 nui-core/src/main/java/org/terasology/nui/core/bind/UISignal.java create mode 100644 nui-core/src/main/java/org/terasology/nui/core/bind/UISlot.java create mode 100644 nui-core/src/test/java/org/terasology/nui/core/TestWidget.java create mode 100644 nui-guui/build.gradle diff --git a/nui-core/build.gradle b/nui-core/build.gradle new file mode 100644 index 0000000000..2b8b7cbf1a --- /dev/null +++ b/nui-core/build.gradle @@ -0,0 +1,25 @@ +plugins { + id 'java-library' + id 'maven-publish' +} + +apply from: "$rootDir/gradle/common.gradle" + +dependencies { + api group: 'org.terasology.gestalt', name: 'gestalt-module', version: '7.0.3' + api group: 'org.terasology.gestalt', name: 'gestalt-asset-core', version: '7.0.3' + + api ('org.joml:joml') { + version { + require jomlVersion + } + } + + api ('org.terasology.joml-ext:joml-geometry') { + version { + require geomVersion + } + } + + implementation group: 'com.google.guava', name: 'guava', version: '23.0' +} diff --git a/nui-core/src/main/java/org/terasology/nui/core/UICore.java b/nui-core/src/main/java/org/terasology/nui/core/UICore.java new file mode 100644 index 0000000000..b6189e5b98 --- /dev/null +++ b/nui-core/src/main/java/org/terasology/nui/core/UICore.java @@ -0,0 +1,4 @@ +package org.terasology.nui.core; + +public class UICore { +} diff --git a/nui-core/src/main/java/org/terasology/nui/core/UIPaintable.java b/nui-core/src/main/java/org/terasology/nui/core/UIPaintable.java new file mode 100644 index 0000000000..2375f41636 --- /dev/null +++ b/nui-core/src/main/java/org/terasology/nui/core/UIPaintable.java @@ -0,0 +1,4 @@ +package org.terasology.nui.core; + +public interface UIPaintable { +} diff --git a/nui-core/src/main/java/org/terasology/nui/core/UISlot.java b/nui-core/src/main/java/org/terasology/nui/core/UISlot.java new file mode 100644 index 0000000000..9b3102cbf4 --- /dev/null +++ b/nui-core/src/main/java/org/terasology/nui/core/UISlot.java @@ -0,0 +1,18 @@ +package org.terasology.nui.core; + +import org.terasology.nui.core.bind.BindingFunction; + +import java.lang.ref.WeakReference; + +public class UISlot { + private WeakReference reference; + private T handler; + + public UISlot(T handler) { + this.handler = handler; + } + + public Object invoke(Object[] entry) { + return null; + } +} diff --git a/nui-core/src/main/java/org/terasology/nui/core/UIWidget.java b/nui-core/src/main/java/org/terasology/nui/core/UIWidget.java new file mode 100644 index 0000000000..2eda7d26e7 --- /dev/null +++ b/nui-core/src/main/java/org/terasology/nui/core/UIWidget.java @@ -0,0 +1,57 @@ +package org.terasology.nui.core; + +import org.joml.Vector2f; +import org.terasology.nui.core.bind.UIProperty; +import org.terasology.nui.core.bind.UISignal; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +public class UIWidget implements AutoCloseable { + private UIWidget parent; + private List children = new ArrayList<>(); + private boolean isFree = false; + + public final UISignal.UISignal0 destroy = new UISignal.UISignal0(); + + public final UIProperty z = new UIProperty<>(0.0f); + public final UIProperty pos = new UIProperty<>(new Vector2f()); + public final UIProperty size = new UIProperty<>(new Vector2f()); + + public UIWidget(UIWidget parent) { + this.parent = parent; + this.parent.children.add(this); + } + + public UIWidget(UIWidget parent, float z) { + this(parent); + this.z.set(z); + } + + public UIWidget(UIWidget parent, Vector2f pos) { + this(parent); + this.pos.set(pos); + } + + public UIWidget(UIWidget parent, Vector2f pos, Vector2f size) { + this(parent); + this.pos.set(pos); + this.size.set(size); + } + + public Collection children() { + return Collections.unmodifiableList(children); + } + + public boolean isDisposed() { + return isFree; + } + + @Override + public void close() { + this.isFree = true; + destroy.send(); + } +} diff --git a/nui-core/src/main/java/org/terasology/nui/core/bind/Binding.java b/nui-core/src/main/java/org/terasology/nui/core/bind/Binding.java new file mode 100644 index 0000000000..2c2abd1330 --- /dev/null +++ b/nui-core/src/main/java/org/terasology/nui/core/bind/Binding.java @@ -0,0 +1,10 @@ +package org.terasology.nui.core.bind; + +import org.terasology.nui.core.UIWidget; + +public class Binding { + public static void bind(UIWidget wid1, UISignal.UISignal1 signal, UIWidget wid2, UISlot.UISlot1 slot) { + BindingPair pair = new BindingPair(wid1, wid2); + signal.register(pair, slot); + } +} diff --git a/nui-core/src/main/java/org/terasology/nui/core/bind/BindingFunction.java b/nui-core/src/main/java/org/terasology/nui/core/bind/BindingFunction.java new file mode 100644 index 0000000000..ac453c44e8 --- /dev/null +++ b/nui-core/src/main/java/org/terasology/nui/core/bind/BindingFunction.java @@ -0,0 +1,4 @@ +package org.terasology.nui.core.bind; + +public interface BindingFunction { +} diff --git a/nui-core/src/main/java/org/terasology/nui/core/bind/BindingPair.java b/nui-core/src/main/java/org/terasology/nui/core/bind/BindingPair.java new file mode 100644 index 0000000000..f5660cb594 --- /dev/null +++ b/nui-core/src/main/java/org/terasology/nui/core/bind/BindingPair.java @@ -0,0 +1,15 @@ +package org.terasology.nui.core.bind; + +import org.terasology.nui.core.UIWidget; + +import java.lang.ref.WeakReference; + +public class BindingPair { + private WeakReference wid1; + private WeakReference wid2; + + public BindingPair(UIWidget w1, UIWidget w2) { + this.wid1 = new WeakReference<>(w1); + this.wid2 = new WeakReference<>(w2); + } +} diff --git a/nui-core/src/main/java/org/terasology/nui/core/bind/Function0.java b/nui-core/src/main/java/org/terasology/nui/core/bind/Function0.java new file mode 100644 index 0000000000..23c6116aad --- /dev/null +++ b/nui-core/src/main/java/org/terasology/nui/core/bind/Function0.java @@ -0,0 +1,7 @@ +package org.terasology.nui.core.bind; + + +@FunctionalInterface +public interface Function0 extends BindingFunction { + void apply(); +} diff --git a/nui-core/src/main/java/org/terasology/nui/core/bind/Function1.java b/nui-core/src/main/java/org/terasology/nui/core/bind/Function1.java new file mode 100644 index 0000000000..717037b16f --- /dev/null +++ b/nui-core/src/main/java/org/terasology/nui/core/bind/Function1.java @@ -0,0 +1,6 @@ +package org.terasology.nui.core.bind; + +@FunctionalInterface +public interface Function1 extends BindingFunction { + void apply(T1 t1); +} diff --git a/nui-core/src/main/java/org/terasology/nui/core/bind/Function2.java b/nui-core/src/main/java/org/terasology/nui/core/bind/Function2.java new file mode 100644 index 0000000000..9b70de7998 --- /dev/null +++ b/nui-core/src/main/java/org/terasology/nui/core/bind/Function2.java @@ -0,0 +1,5 @@ +package org.terasology.nui.core.bind; + +public interface Function2 extends BindingFunction { + void apply(T1 t1, T2 t2); +} diff --git a/nui-core/src/main/java/org/terasology/nui/core/bind/Function3.java b/nui-core/src/main/java/org/terasology/nui/core/bind/Function3.java new file mode 100644 index 0000000000..41cb663739 --- /dev/null +++ b/nui-core/src/main/java/org/terasology/nui/core/bind/Function3.java @@ -0,0 +1,5 @@ +package org.terasology.nui.core.bind; + +public interface Function3 extends BindingFunction { + void apply(T1 t1, T2 t2, T3 t3); +} diff --git a/nui-core/src/main/java/org/terasology/nui/core/bind/Function4.java b/nui-core/src/main/java/org/terasology/nui/core/bind/Function4.java new file mode 100644 index 0000000000..f5b124f0f7 --- /dev/null +++ b/nui-core/src/main/java/org/terasology/nui/core/bind/Function4.java @@ -0,0 +1,5 @@ +package org.terasology.nui.core.bind; + +public interface Function4extends BindingFunction { + void apply(T1 t1, T2 t2, T3 t3, T4 t4); +} diff --git a/nui-core/src/main/java/org/terasology/nui/core/bind/Function5.java b/nui-core/src/main/java/org/terasology/nui/core/bind/Function5.java new file mode 100644 index 0000000000..5f7f8db999 --- /dev/null +++ b/nui-core/src/main/java/org/terasology/nui/core/bind/Function5.java @@ -0,0 +1,5 @@ +package org.terasology.nui.core.bind; + +public interface Function5 extends BindingFunction { + void apply(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5); +} diff --git a/nui-core/src/main/java/org/terasology/nui/core/bind/Function6.java b/nui-core/src/main/java/org/terasology/nui/core/bind/Function6.java new file mode 100644 index 0000000000..9c273d1dc7 --- /dev/null +++ b/nui-core/src/main/java/org/terasology/nui/core/bind/Function6.java @@ -0,0 +1,5 @@ +package org.terasology.nui.core.bind; + +public interface Function6 extends BindingFunction { + void apply(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6); +} diff --git a/nui-core/src/main/java/org/terasology/nui/core/bind/Function7.java b/nui-core/src/main/java/org/terasology/nui/core/bind/Function7.java new file mode 100644 index 0000000000..f02669ce56 --- /dev/null +++ b/nui-core/src/main/java/org/terasology/nui/core/bind/Function7.java @@ -0,0 +1,5 @@ +package org.terasology.nui.core.bind; + +public interface Function7extends BindingFunction { + void apply(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7); +} diff --git a/nui-core/src/main/java/org/terasology/nui/core/bind/Function8.java b/nui-core/src/main/java/org/terasology/nui/core/bind/Function8.java new file mode 100644 index 0000000000..f36018c5d5 --- /dev/null +++ b/nui-core/src/main/java/org/terasology/nui/core/bind/Function8.java @@ -0,0 +1,5 @@ +package org.terasology.nui.core.bind; + +public interface Function8 extends BindingFunction { + void apply(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8); +} diff --git a/nui-core/src/main/java/org/terasology/nui/core/bind/UIProperty.java b/nui-core/src/main/java/org/terasology/nui/core/bind/UIProperty.java new file mode 100644 index 0000000000..e8085569d0 --- /dev/null +++ b/nui-core/src/main/java/org/terasology/nui/core/bind/UIProperty.java @@ -0,0 +1,19 @@ +package org.terasology.nui.core.bind; + +public class UIProperty { + private T1 value; + public final UISignal.UISignal1 propertyChanged = new UISignal.UISignal1(); + + public UIProperty(T1 initial) { + this.value = initial; + } + + public void set(T1 value) { + propertyChanged.send(value); + this.value = value; + } + + public T1 get() { + return value; + } +} diff --git a/nui-core/src/main/java/org/terasology/nui/core/bind/UISignal.java b/nui-core/src/main/java/org/terasology/nui/core/bind/UISignal.java new file mode 100644 index 0000000000..8d8f55f074 --- /dev/null +++ b/nui-core/src/main/java/org/terasology/nui/core/bind/UISignal.java @@ -0,0 +1,65 @@ +package org.terasology.nui.core.bind; + +import com.google.common.collect.Multimap; +import org.terasology.nui.core.UIWidget; + +import java.lang.ref.WeakReference; + +public class UISignal { + + public static class UISignal0 extends UISignal { + public Multimap bindings; + + public UISignal0() { + } + + protected boolean register(BindingPair pair, UISlot.UISlot0 slot) { + bindings.put(pair, slot); + return true; + } + + public void send() { + for (BindingPair pair : bindings.keys()) { + for (UISlot.UISlot0 slot : bindings.get(pair)) { + slot.invoke(); + } + } + } + } + + public static class UISignal1 extends UISignal { + public Multimap> bindings; + + public UISignal1() { + } + + protected boolean register(BindingPair pair, UISlot.UISlot1 slot) { + bindings.put(pair, slot); + return true; + } + + public void send(T1 handler) { + for (BindingPair pair : bindings.keys()) { + for (UISlot.UISlot1 slot : bindings.get(pair)) { + slot.invoke(handler); + } + } + } + } + + public static class UISignal2 extends UISignal { + private WeakReference reference; + + public UISignal2() { + } + + + public void send(T1 t1, T2 t2) { + + } + } + + +} + + diff --git a/nui-core/src/main/java/org/terasology/nui/core/bind/UISlot.java b/nui-core/src/main/java/org/terasology/nui/core/bind/UISlot.java new file mode 100644 index 0000000000..a34428273d --- /dev/null +++ b/nui-core/src/main/java/org/terasology/nui/core/bind/UISlot.java @@ -0,0 +1,26 @@ +package org.terasology.nui.core.bind; + +public class UISlot { + + public static class UISlot0 extends UISlot { + private Function0 binding; + public UISlot0(Function0 binding) { + this.binding = binding; + } + + public void invoke() { + binding.apply(); + } + } + + public static class UISlot1 extends UISlot { + private Function1 binding; + public UISlot1(Function1 binding) { + this.binding = binding; + } + + public void invoke(T1 t1) { + binding.apply(t1); + } + } +} diff --git a/nui-core/src/test/java/org/terasology/nui/core/TestWidget.java b/nui-core/src/test/java/org/terasology/nui/core/TestWidget.java new file mode 100644 index 0000000000..038f41800d --- /dev/null +++ b/nui-core/src/test/java/org/terasology/nui/core/TestWidget.java @@ -0,0 +1,37 @@ +package org.terasology.nui.core; + + +import org.terasology.nui.core.bind.Binding; +import org.terasology.nui.core.bind.UISignal; +import org.terasology.nui.core.bind.UISlot; +import org.terasology.nui.core.bind.Function1; + +public class TestWidget extends UIWidget{ + private UISignal.UISignal1 a1 = new UISignal.UISignal1<>(); + private TestWidget2 widget2 = new TestWidget2(this); + + public class TestWidget2 extends UIWidget { + private int counter; + public final UISlot.UISlot1 consumer = new UISlot.UISlot1<>(new Function1() { + @Override + public void apply(Integer integer) { + counter += integer; + handle1(); + } + }); + + public void handle1() { + + } + + public TestWidget2(UIWidget parent) { + super(parent); + } + } + + public TestWidget(UIWidget parent) { + super(parent); + Binding.bind(this, a1, widget2, widget2.consumer); + a1.send(10); + } +} diff --git a/nui-guui/build.gradle b/nui-guui/build.gradle new file mode 100644 index 0000000000..2b8b7cbf1a --- /dev/null +++ b/nui-guui/build.gradle @@ -0,0 +1,25 @@ +plugins { + id 'java-library' + id 'maven-publish' +} + +apply from: "$rootDir/gradle/common.gradle" + +dependencies { + api group: 'org.terasology.gestalt', name: 'gestalt-module', version: '7.0.3' + api group: 'org.terasology.gestalt', name: 'gestalt-asset-core', version: '7.0.3' + + api ('org.joml:joml') { + version { + require jomlVersion + } + } + + api ('org.terasology.joml-ext:joml-geometry') { + version { + require geomVersion + } + } + + implementation group: 'com.google.guava', name: 'guava', version: '23.0' +} diff --git a/settings.gradle b/settings.gradle index 379024ac49..6df715e1b9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,2 @@ rootProject.name = 'TeraNUI' -include 'nui-reflect', 'nui-input', 'nui', 'nui-gestalt5', 'nui-gestalt7', 'nui-libgdx' +include 'nui-reflect', 'nui-input', 'nui', 'nui-gestalt5', 'nui-gestalt7', 'nui-libgdx', 'nui-core' From 0313cf81d1e77100e5d537ee5698071e91148c92 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sun, 23 May 2021 17:51:57 -0700 Subject: [PATCH 2/2] feature: started on ui widget library --- .../terasology/nui/core/EventDispatcher.java | 49 +++++ .../org/terasology/nui/core/UIEngine.java | 5 + .../org/terasology/nui/core/UIObject.java | 85 ++++++++ .../org/terasology/nui/core/UIRenderable.java | 8 + .../java/org/terasology/nui/core/UISlot.java | 2 +- .../org/terasology/nui/core/UIWidget.java | 57 ----- .../org/terasology/nui/core/bind/Binding.java | 22 +- .../terasology/nui/core/bind/BindingPair.java | 52 ++++- .../terasology/nui/core/bind/BindingType.java | 8 + .../nui/core/bind/UIFloatProperty.java | 19 ++ .../terasology/nui/core/bind/UIProperty.java | 4 +- .../terasology/nui/core/bind/UISignal.java | 194 +++++++++++++++++- .../org/terasology/nui/core/bind/UISlot.java | 86 +++++++- .../org/terasology/nui/core/TestWidget.java | 8 +- {nui-guui => nui-widget}/build.gradle | 3 + .../terasology/nui/widget/UIAnchorLayout.java | 4 + .../org/terasology/nui/widget/UIWidget.java | 26 +++ settings.gradle | 2 +- 18 files changed, 547 insertions(+), 87 deletions(-) create mode 100644 nui-core/src/main/java/org/terasology/nui/core/EventDispatcher.java create mode 100644 nui-core/src/main/java/org/terasology/nui/core/UIEngine.java create mode 100644 nui-core/src/main/java/org/terasology/nui/core/UIObject.java create mode 100644 nui-core/src/main/java/org/terasology/nui/core/UIRenderable.java delete mode 100644 nui-core/src/main/java/org/terasology/nui/core/UIWidget.java create mode 100644 nui-core/src/main/java/org/terasology/nui/core/bind/BindingType.java create mode 100644 nui-core/src/main/java/org/terasology/nui/core/bind/UIFloatProperty.java rename {nui-guui => nui-widget}/build.gradle (94%) create mode 100644 nui-widget/src/main/java/org/terasology/nui/widget/UIAnchorLayout.java create mode 100644 nui-widget/src/main/java/org/terasology/nui/widget/UIWidget.java diff --git a/nui-core/src/main/java/org/terasology/nui/core/EventDispatcher.java b/nui-core/src/main/java/org/terasology/nui/core/EventDispatcher.java new file mode 100644 index 0000000000..5906f3d2ee --- /dev/null +++ b/nui-core/src/main/java/org/terasology/nui/core/EventDispatcher.java @@ -0,0 +1,49 @@ +package org.terasology.nui.core; + +import com.google.common.collect.Maps; +import org.terasology.nui.core.bind.BindingPair; +import org.terasology.nui.core.bind.BindingType; + +import java.util.Map; +import java.util.Optional; +import java.util.Queue; + +public class EventDispatcher { + Map> threadQueue = Maps.newConcurrentMap(); + + private ThreadLocal> localQueue = new ThreadLocal<>(); + + public void dispatch(BindingPair pair, Runnable runnable) { + BindingType type = pair.getBindingType(); + Optional slotWidgetOptional = pair.getSignalWidget(); + Optional signalWidgetOptional = pair.getSignalWidget(); + if (!slotWidgetOptional.isPresent() || !signalWidgetOptional.isPresent()) { + return; + } + + UIObject signalWidget = signalWidgetOptional.get(); + + + runnable.run(); +// +// switch (type) { +// case Auto: +// break; +// case Queue: +// break; +// case Direct: +// runnable.run(); +// break; +// case BlockedQueue: +// break; +// } + } + + public void dispatchQueue(Runnable runnable) { + + } + + public void dispatch() { + + } +} diff --git a/nui-core/src/main/java/org/terasology/nui/core/UIEngine.java b/nui-core/src/main/java/org/terasology/nui/core/UIEngine.java new file mode 100644 index 0000000000..43bd2c7d92 --- /dev/null +++ b/nui-core/src/main/java/org/terasology/nui/core/UIEngine.java @@ -0,0 +1,5 @@ +package org.terasology.nui.core; + +public interface UIEngine { + EventDispatcher dispatcher(); +} diff --git a/nui-core/src/main/java/org/terasology/nui/core/UIObject.java b/nui-core/src/main/java/org/terasology/nui/core/UIObject.java new file mode 100644 index 0000000000..d88c97d276 --- /dev/null +++ b/nui-core/src/main/java/org/terasology/nui/core/UIObject.java @@ -0,0 +1,85 @@ +package org.terasology.nui.core; + +import org.joml.Vector2f; +import org.terasology.nui.core.bind.Binding; +import org.terasology.nui.core.bind.UIProperty; +import org.terasology.nui.core.bind.UISignal; +import org.terasology.nui.core.bind.UISlot; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +public abstract class UIObject implements AutoCloseable { + private UIObject parent; + private final List children = new ArrayList<>(); + private boolean isFree = false; + private UIEngine uiEngine; + + public static UIEngine getEngine(UIObject widget) { + return widget.uiEngine; + } + + + public final UISignal.UISignal0 destroy = new UISignal.UISignal0(); + + + public UIObject(UIObject parent) { + // pass uiEngine to new widget + uiEngine = parent.uiEngine; + + this.parent = parent; + this.parent.children.add(this); + + } +// +// public UIObject(UIObject parent) { +// this(parent); +// +// } +// +// public UIObject(UIObject parent, Vector2f pos) { +// this(parent); +// this.pos.set(pos); +// } +// +// public UIObject(UIObject parent, Vector2f pos, Vector2f size) { +// this(parent); +// this.pos.set(pos); +// this.size.set(size); +// } + + + public Collection children() { + return Collections.unmodifiableList(children); + } + + public boolean isDisposed() { + return isFree; + } + + public void addChild(UIObject widget) { + if (widget.parent != null) { + widget.parent.removeChild(widget); + } + children.add(widget); + widget.parent = this; + } + + public void removeChild(UIObject widget) { + children.remove(widget); + widget.parent = null; + } + + public UIObject getParent() { + return parent; + } + + + @Override + public void close() { + this.isFree = true; + destroy.send(); + } +} diff --git a/nui-core/src/main/java/org/terasology/nui/core/UIRenderable.java b/nui-core/src/main/java/org/terasology/nui/core/UIRenderable.java new file mode 100644 index 0000000000..f057ef9710 --- /dev/null +++ b/nui-core/src/main/java/org/terasology/nui/core/UIRenderable.java @@ -0,0 +1,8 @@ +package org.terasology.nui.core; + +import java.util.Map; + +public class UIRenderable { + + +} diff --git a/nui-core/src/main/java/org/terasology/nui/core/UISlot.java b/nui-core/src/main/java/org/terasology/nui/core/UISlot.java index 9b3102cbf4..ec0e0cbbfd 100644 --- a/nui-core/src/main/java/org/terasology/nui/core/UISlot.java +++ b/nui-core/src/main/java/org/terasology/nui/core/UISlot.java @@ -5,7 +5,7 @@ import java.lang.ref.WeakReference; public class UISlot { - private WeakReference reference; + private WeakReference reference; private T handler; public UISlot(T handler) { diff --git a/nui-core/src/main/java/org/terasology/nui/core/UIWidget.java b/nui-core/src/main/java/org/terasology/nui/core/UIWidget.java deleted file mode 100644 index 2eda7d26e7..0000000000 --- a/nui-core/src/main/java/org/terasology/nui/core/UIWidget.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.terasology.nui.core; - -import org.joml.Vector2f; -import org.terasology.nui.core.bind.UIProperty; -import org.terasology.nui.core.bind.UISignal; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -public class UIWidget implements AutoCloseable { - private UIWidget parent; - private List children = new ArrayList<>(); - private boolean isFree = false; - - public final UISignal.UISignal0 destroy = new UISignal.UISignal0(); - - public final UIProperty z = new UIProperty<>(0.0f); - public final UIProperty pos = new UIProperty<>(new Vector2f()); - public final UIProperty size = new UIProperty<>(new Vector2f()); - - public UIWidget(UIWidget parent) { - this.parent = parent; - this.parent.children.add(this); - } - - public UIWidget(UIWidget parent, float z) { - this(parent); - this.z.set(z); - } - - public UIWidget(UIWidget parent, Vector2f pos) { - this(parent); - this.pos.set(pos); - } - - public UIWidget(UIWidget parent, Vector2f pos, Vector2f size) { - this(parent); - this.pos.set(pos); - this.size.set(size); - } - - public Collection children() { - return Collections.unmodifiableList(children); - } - - public boolean isDisposed() { - return isFree; - } - - @Override - public void close() { - this.isFree = true; - destroy.send(); - } -} diff --git a/nui-core/src/main/java/org/terasology/nui/core/bind/Binding.java b/nui-core/src/main/java/org/terasology/nui/core/bind/Binding.java index 2c2abd1330..84bb2d3cee 100644 --- a/nui-core/src/main/java/org/terasology/nui/core/bind/Binding.java +++ b/nui-core/src/main/java/org/terasology/nui/core/bind/Binding.java @@ -1,10 +1,26 @@ package org.terasology.nui.core.bind; -import org.terasology.nui.core.UIWidget; +import org.terasology.nui.core.UIObject; public class Binding { - public static void bind(UIWidget wid1, UISignal.UISignal1 signal, UIWidget wid2, UISlot.UISlot1 slot) { - BindingPair pair = new BindingPair(wid1, wid2); + private Binding() { + } + + public static void bind(UIObject wid1, UISignal.UISignal0 signal, UIObject wid2, UISlot.UISlot0 slot) { + bind(wid1, signal, wid2, slot, BindingType.Auto); + } + + public static void bind(UIObject wid1, UISignal.UISignal0 signal, UIObject wid2, UISlot.UISlot0 slot, BindingType type) { + BindingPair pair = new BindingPair(wid1, wid2, type); + signal.register(pair, slot); + } + + public static void bind(UIObject wid1, UISignal.UISignal1 signal, UIObject wid2, UISlot.UISlot1 slot) { + bind(wid1, signal, wid2, slot, BindingType.Auto); + } + + public static void bind(UIObject wid1, UISignal.UISignal1 signal, UIObject wid2, UISlot.UISlot1 slot, BindingType type) { + BindingPair pair = new BindingPair(wid1, wid2, type); signal.register(pair, slot); } } diff --git a/nui-core/src/main/java/org/terasology/nui/core/bind/BindingPair.java b/nui-core/src/main/java/org/terasology/nui/core/bind/BindingPair.java index f5660cb594..cfe3618d13 100644 --- a/nui-core/src/main/java/org/terasology/nui/core/bind/BindingPair.java +++ b/nui-core/src/main/java/org/terasology/nui/core/bind/BindingPair.java @@ -1,15 +1,55 @@ package org.terasology.nui.core.bind; -import org.terasology.nui.core.UIWidget; +import org.terasology.nui.core.EventDispatcher; +import org.terasology.nui.core.UIEngine; +import org.terasology.nui.core.UIObject; import java.lang.ref.WeakReference; +import java.util.Optional; public class BindingPair { - private WeakReference wid1; - private WeakReference wid2; + private WeakReference signalWidget; + private WeakReference slotWidget; + private BindingType type; + + public BindingPair(UIObject signalWidget, UIObject slotWidget, BindingType type) { + this.signalWidget = new WeakReference<>(signalWidget); + this.slotWidget = new WeakReference<>(slotWidget); + this.type = type; + } + + public Optional getSignalWidget() { + return Optional.ofNullable(signalWidget.get()); + } + + + public Optional getSlotWidget() { + return Optional.ofNullable(slotWidget.get()); + } + + public BindingType getBindingType() { + return this.type; + } + + public Optional getSlotDispatcher() { + UIObject target = this.slotWidget.get(); + if (target != null) { + UIEngine engine = UIObject.getEngine(target); + return Optional.ofNullable(engine.dispatcher()); + } + return Optional.empty(); + } + + public boolean isDisposed() { + UIObject slotWid = signalWidget.get(); + UIObject targetWid = slotWidget.get(); + if (slotWid == null || slotWid.isDisposed()) { + return true; + } + if (targetWid == null || targetWid.isDisposed()) { + return true; + } + return false; - public BindingPair(UIWidget w1, UIWidget w2) { - this.wid1 = new WeakReference<>(w1); - this.wid2 = new WeakReference<>(w2); } } diff --git a/nui-core/src/main/java/org/terasology/nui/core/bind/BindingType.java b/nui-core/src/main/java/org/terasology/nui/core/bind/BindingType.java new file mode 100644 index 0000000000..e88ce9a827 --- /dev/null +++ b/nui-core/src/main/java/org/terasology/nui/core/bind/BindingType.java @@ -0,0 +1,8 @@ +package org.terasology.nui.core.bind; + +public enum BindingType { + Auto, + Direct, + Queue, + BlockedQueue +} diff --git a/nui-core/src/main/java/org/terasology/nui/core/bind/UIFloatProperty.java b/nui-core/src/main/java/org/terasology/nui/core/bind/UIFloatProperty.java new file mode 100644 index 0000000000..3924c5d5d4 --- /dev/null +++ b/nui-core/src/main/java/org/terasology/nui/core/bind/UIFloatProperty.java @@ -0,0 +1,19 @@ +package org.terasology.nui.core.bind; + +public class UIFloatProperty { + private float value; + public final UISignal.UISignal0 propertyChanged = new UISignal.UISignal0(); + + public UIFloatProperty(float initial) { + this.value = initial; + } + + public void set(float value) { + propertyChanged.send(); + this.value = value; + } + + public float get() { + return value; + } +} diff --git a/nui-core/src/main/java/org/terasology/nui/core/bind/UIProperty.java b/nui-core/src/main/java/org/terasology/nui/core/bind/UIProperty.java index e8085569d0..2c8b7d4147 100644 --- a/nui-core/src/main/java/org/terasology/nui/core/bind/UIProperty.java +++ b/nui-core/src/main/java/org/terasology/nui/core/bind/UIProperty.java @@ -2,14 +2,14 @@ public class UIProperty { private T1 value; - public final UISignal.UISignal1 propertyChanged = new UISignal.UISignal1(); + public final UISignal.UISignal0 propertyChanged = new UISignal.UISignal0(); public UIProperty(T1 initial) { this.value = initial; } public void set(T1 value) { - propertyChanged.send(value); + propertyChanged.send(); this.value = value; } diff --git a/nui-core/src/main/java/org/terasology/nui/core/bind/UISignal.java b/nui-core/src/main/java/org/terasology/nui/core/bind/UISignal.java index 8d8f55f074..39cb895b44 100644 --- a/nui-core/src/main/java/org/terasology/nui/core/bind/UISignal.java +++ b/nui-core/src/main/java/org/terasology/nui/core/bind/UISignal.java @@ -1,14 +1,27 @@ package org.terasology.nui.core.bind; +import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; -import org.terasology.nui.core.UIWidget; -import java.lang.ref.WeakReference; +import java.util.Iterator; public class UISignal { + protected boolean handle(BindingPair pair, Runnable runnable) { + runnable.run(); + return true; + } + + protected boolean validate(BindingPair pair, Iterator pairs) { + if (pair.isDisposed()) { + pairs.remove(); + return false; + } + return true; + } + public static class UISignal0 extends UISignal { - public Multimap bindings; + private Multimap bindings; public UISignal0() { } @@ -19,16 +32,22 @@ protected boolean register(BindingPair pair, UISlot.UISlot0 slot) { } public void send() { - for (BindingPair pair : bindings.keys()) { + Iterator pairs = bindings.keySet().iterator(); + while (pairs.hasNext()) { + BindingPair pair = pairs.next(); + if (pair.isDisposed()) { + pairs.remove(); + continue; + } for (UISlot.UISlot0 slot : bindings.get(pair)) { - slot.invoke(); + handle(pair, slot::invoke); } } } } public static class UISignal1 extends UISignal { - public Multimap> bindings; + private Multimap> bindings = ArrayListMultimap.create(); public UISignal1() { } @@ -38,28 +57,183 @@ protected boolean register(BindingPair pair, UISlot.UISlot1 slot) { return true; } - public void send(T1 handler) { - for (BindingPair pair : bindings.keys()) { + public void send(T1 t1) { + Iterator pairs = bindings.keySet().iterator(); + while (pairs.hasNext()) { + BindingPair pair = pairs.next(); + if (!validate(pair, pairs)) continue; for (UISlot.UISlot1 slot : bindings.get(pair)) { - slot.invoke(handler); + handle(pair, () -> slot.invoke(t1)); } } } } public static class UISignal2 extends UISignal { - private WeakReference reference; + private final Multimap> bindings = ArrayListMultimap.create(); public UISignal2() { } + protected boolean register(BindingPair pair, UISlot.UISlot2 slot) { + bindings.put(pair, slot); + return true; + } + public void send(T1 t1, T2 t2) { + Iterator pairs = bindings.keySet().iterator(); + while (pairs.hasNext()) { + BindingPair pair = pairs.next(); + if (!validate(pair, pairs)) continue; + for (UISlot.UISlot2 slot : bindings.get(pair)) { + handle(pair, () -> slot.invoke(t1, t2)); + } + } + } + } + public static class UISignal3 extends UISignal { + private Multimap> bindings = ArrayListMultimap.create(); + + public UISignal3() { + } + + protected boolean register(BindingPair pair, UISlot.UISlot3 slot) { + bindings.put(pair, slot); + return true; + } + + public void send(T1 t1, T2 t2, T3 t3) { + Iterator pairs = bindings.keySet().iterator(); + while (pairs.hasNext()) { + BindingPair pair = pairs.next(); + if (!validate(pair, pairs)) continue; + for (UISlot.UISlot3 slot : bindings.get(pair)) { + handle(pair, () -> slot.invoke(t1, t2, t3)); + } + } } } + public static class UISignal4 extends UISignal { + public Multimap> bindings = ArrayListMultimap.create(); + + public UISignal4() { + } + protected boolean register(BindingPair pair, UISlot.UISlot4 slot) { + bindings.put(pair, slot); + return true; + } + + public void send(T1 t1, T2 t2, T3 t3, T4 t4) { + Iterator pairs = bindings.keySet().iterator(); + while (pairs.hasNext()) { + BindingPair pair = pairs.next(); + if (!validate(pair, pairs)) continue; + for (UISlot.UISlot4 slot : bindings.get(pair)) { + handle(pair, () -> slot.invoke(t1, t2, t3, t4)); + } + } + } + } + + public static class UISignal5 extends UISignal { + public Multimap> bindings = ArrayListMultimap.create(); + + public UISignal5() { + + } + + protected boolean register(BindingPair pair, UISlot.UISlot5 slot) { + bindings.put(pair, slot); + return true; + } + + public void send(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) { + Iterator pairs = bindings.keySet().iterator(); + while (pairs.hasNext()) { + BindingPair pair = pairs.next(); + if (!validate(pair, pairs)) continue; + for (UISlot.UISlot5 slot : bindings.get(pair)) { + handle(pair, () -> slot.invoke(t1, t2, t3, t4, t5)); + } + } + } + } + + public static class UISignal6 extends UISignal { + public Multimap> bindings = ArrayListMultimap.create(); + + public UISignal6() { + + } + + protected boolean register(BindingPair pair, UISlot.UISlot6 slot) { + bindings.put(pair, slot); + return true; + } + + public void send(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) { + Iterator pairs = bindings.keySet().iterator(); + while (pairs.hasNext()) { + BindingPair pair = pairs.next(); + if (!validate(pair, pairs)) continue; + for (UISlot.UISlot6 slot : bindings.get(pair)) { + handle(pair, () -> slot.invoke(t1, t2, t3, t4, t5, t6)); + } + } + } + } + + public static class UISignal7 extends UISignal { + public Multimap> bindings = ArrayListMultimap.create(); + + public UISignal7() { + + } + + protected boolean register(BindingPair pair, UISlot.UISlot7 slot) { + bindings.put(pair, slot); + return true; + } + + public void send(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) { + Iterator pairs = bindings.keySet().iterator(); + while (pairs.hasNext()) { + BindingPair pair = pairs.next(); + if (!validate(pair, pairs)) continue; + for (UISlot.UISlot7 slot : bindings.get(pair)) { + handle(pair, () -> slot.invoke(t1, t2, t3, t4, t5, t6, t7)); + } + } + } + } + + public static class UISignal8 extends UISignal { + public Multimap> bindings = ArrayListMultimap.create(); + + public UISignal8() { + + } + + protected boolean register(BindingPair pair, UISlot.UISlot8 slot) { + bindings.put(pair, slot); + return true; + } + + public void send(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) { + Iterator pairs = bindings.keySet().iterator(); + while (pairs.hasNext()) { + BindingPair pair = pairs.next(); + if (!validate(pair, pairs)) continue; + for (UISlot.UISlot8 slot : bindings.get(pair)) { + handle(pair, () -> slot.invoke(t1, t2, t3, t4, t5, t6, t7, t8)); + } + } + } + } } diff --git a/nui-core/src/main/java/org/terasology/nui/core/bind/UISlot.java b/nui-core/src/main/java/org/terasology/nui/core/bind/UISlot.java index a34428273d..9d5e23e8f5 100644 --- a/nui-core/src/main/java/org/terasology/nui/core/bind/UISlot.java +++ b/nui-core/src/main/java/org/terasology/nui/core/bind/UISlot.java @@ -1,9 +1,9 @@ package org.terasology.nui.core.bind; -public class UISlot { +public abstract class UISlot { public static class UISlot0 extends UISlot { - private Function0 binding; + private final Function0 binding; public UISlot0(Function0 binding) { this.binding = binding; } @@ -14,7 +14,7 @@ public void invoke() { } public static class UISlot1 extends UISlot { - private Function1 binding; + private final Function1 binding; public UISlot1(Function1 binding) { this.binding = binding; } @@ -23,4 +23,84 @@ public void invoke(T1 t1) { binding.apply(t1); } } + + public static class UISlot2 extends UISlot { + private final Function2 binding; + public UISlot2(Function2 binding) { + this.binding = binding; + } + + public void invoke(T1 t1, T2 t2) { + binding.apply(t1, t2); + } + } + + public static class UISlot3 extends UISlot { + private final Function3 binding; + public UISlot3(Function3 binding) { + this.binding = binding; + } + + public void invoke(T1 t1, T2 t2, T3 t3) { + binding.apply(t1, t2, t3); + } + } + + public static class UISlot4 extends UISlot { + private final Function4 binding; + public UISlot4(Function4 binding) { + this.binding = binding; + } + + public void invoke(T1 t1, T2 t2, T3 t3, T4 t4) { + binding.apply(t1, t2, t3, t4); + } + } + + public static class UISlot5 extends UISlot { + private final Function5 binding; + public UISlot5(Function5 binding) { + this.binding = binding; + } + + public void invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) { + binding.apply(t1, t2, t3, t4, t5); + } + } + + public static class UISlot6 extends UISlot { + private final Function6 binding; + + public UISlot6(Function6 binding) { + this.binding = binding; + } + + public void invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) { + binding.apply(t1, t2, t3, t4, t5, t6); + } + } + + public static class UISlot7 extends UISlot { + private final Function7 binding; + + public UISlot7(Function7 binding) { + this.binding = binding; + } + + public void invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) { + binding.apply(t1, t2, t3, t4, t5, t6, t7); + } + } + + public static class UISlot8 extends UISlot { + private final Function8 binding; + + public UISlot8(Function8 binding) { + this.binding = binding; + } + + public void invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) { + binding.apply(t1, t2, t3, t4, t5, t6, t7, t8); + } + } } diff --git a/nui-core/src/test/java/org/terasology/nui/core/TestWidget.java b/nui-core/src/test/java/org/terasology/nui/core/TestWidget.java index 038f41800d..5555c73eb6 100644 --- a/nui-core/src/test/java/org/terasology/nui/core/TestWidget.java +++ b/nui-core/src/test/java/org/terasology/nui/core/TestWidget.java @@ -6,11 +6,11 @@ import org.terasology.nui.core.bind.UISlot; import org.terasology.nui.core.bind.Function1; -public class TestWidget extends UIWidget{ +public class TestWidget extends UIObject { private UISignal.UISignal1 a1 = new UISignal.UISignal1<>(); private TestWidget2 widget2 = new TestWidget2(this); - public class TestWidget2 extends UIWidget { + public class TestWidget2 extends UIObject { private int counter; public final UISlot.UISlot1 consumer = new UISlot.UISlot1<>(new Function1() { @Override @@ -24,12 +24,12 @@ public void handle1() { } - public TestWidget2(UIWidget parent) { + public TestWidget2(UIObject parent) { super(parent); } } - public TestWidget(UIWidget parent) { + public TestWidget(UIObject parent) { super(parent); Binding.bind(this, a1, widget2, widget2.consumer); a1.send(10); diff --git a/nui-guui/build.gradle b/nui-widget/build.gradle similarity index 94% rename from nui-guui/build.gradle rename to nui-widget/build.gradle index 2b8b7cbf1a..ad120df936 100644 --- a/nui-guui/build.gradle +++ b/nui-widget/build.gradle @@ -8,6 +8,7 @@ apply from: "$rootDir/gradle/common.gradle" dependencies { api group: 'org.terasology.gestalt', name: 'gestalt-module', version: '7.0.3' api group: 'org.terasology.gestalt', name: 'gestalt-asset-core', version: '7.0.3' + api project(':nui-core') api ('org.joml:joml') { version { @@ -22,4 +23,6 @@ dependencies { } implementation group: 'com.google.guava', name: 'guava', version: '23.0' + + } diff --git a/nui-widget/src/main/java/org/terasology/nui/widget/UIAnchorLayout.java b/nui-widget/src/main/java/org/terasology/nui/widget/UIAnchorLayout.java new file mode 100644 index 0000000000..81d3a5b368 --- /dev/null +++ b/nui-widget/src/main/java/org/terasology/nui/widget/UIAnchorLayout.java @@ -0,0 +1,4 @@ +package org.terasology.nui.widget; + +public class UIAnchorLayout { +} diff --git a/nui-widget/src/main/java/org/terasology/nui/widget/UIWidget.java b/nui-widget/src/main/java/org/terasology/nui/widget/UIWidget.java new file mode 100644 index 0000000000..f17ab1222c --- /dev/null +++ b/nui-widget/src/main/java/org/terasology/nui/widget/UIWidget.java @@ -0,0 +1,26 @@ +package org.terasology.nui.widget; + +import org.joml.Vector2f; +import org.terasology.nui.core.UIObject; +import org.terasology.nui.core.bind.Binding; +import org.terasology.nui.core.bind.UIProperty; +import org.terasology.nui.core.bind.UISlot; + +public class UIWidget extends UIObject { + public final UIProperty z = new UIProperty<>(0.0f); + public final UIProperty pos = new UIProperty<>(new Vector2f()); + public final UIProperty size = new UIProperty<>(new Vector2f()); + + private final UISlot.UISlot0 layoutChange = new UISlot.UISlot0(this::updateLayout); + + public UIWidget(UIObject parent) { + super(parent); + + Binding.bind(this, z.propertyChanged, this, layoutChange); + Binding.bind(this, pos.propertyChanged, this, layoutChange); + Binding.bind(this, size.propertyChanged, this, layoutChange); + } + + public void updateLayout() { + } +} diff --git a/settings.gradle b/settings.gradle index 6df715e1b9..704c67fa70 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,2 @@ rootProject.name = 'TeraNUI' -include 'nui-reflect', 'nui-input', 'nui', 'nui-gestalt5', 'nui-gestalt7', 'nui-libgdx', 'nui-core' +include 'nui-reflect', 'nui-input', 'nui', 'nui-gestalt5', 'nui-gestalt7', 'nui-libgdx', 'nui-core', 'nui-widget'