From d493eb273dd98bf7063146af1a8b4a71f4e93381 Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Sat, 11 Sep 2021 14:30:38 +0300 Subject: Refactor observable properties --- .../cotton/gui/impl/client/MouseInputHandler.java | 2 +- .../github/cottonmc/cotton/gui/widget/WWidget.java | 2 +- .../cotton/gui/widget/data/ObservableProperty.java | 117 +++++++++++++-------- 3 files changed, 75 insertions(+), 46 deletions(-) diff --git a/src/main/java/io/github/cottonmc/cotton/gui/impl/client/MouseInputHandler.java b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/MouseInputHandler.java index 055df75..156f967 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/impl/client/MouseInputHandler.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/MouseInputHandler.java @@ -14,7 +14,7 @@ import java.util.function.Function; */ public final class MouseInputHandler { private final S screen; - private final ObservableProperty hovered = ObservableProperty.of(null); + private final ObservableProperty<@Nullable WWidget> hovered = ObservableProperty.of(null).build(); public MouseInputHandler(S screen) { this.screen = screen; diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WWidget.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WWidget.java index 27e62f8..417c01d 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WWidget.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WWidget.java @@ -46,7 +46,7 @@ public class WWidget { @Nullable protected GuiDescription host; - private final ObservableProperty hovered = ObservableProperty.of(false).nonnullValues().setName("WWidget.hovered"); + private final ObservableProperty hovered = ObservableProperty.of(false).nonnull().name("WWidget.hovered").build(); /** * Sets the location of this widget relative to its parent. diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/data/ObservableProperty.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/data/ObservableProperty.java index eb92387..5f375c2 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/data/ObservableProperty.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/data/ObservableProperty.java @@ -21,23 +21,44 @@ import java.util.Objects; */ @ApiStatus.Experimental public final class ObservableProperty implements ObservableView { + private static final String DEFAULT_NAME = ""; private boolean hasValue; private T value; private final List> listeners = new ArrayList<>(); - private boolean allowNull = true; - private String name = ""; + private final boolean allowNull; + private final String name; - private ObservableProperty(@Nullable T value, boolean hasValue) { + private ObservableProperty(@Nullable T value, boolean hasValue, boolean allowNull, String name) { this.value = value; this.hasValue = hasValue; + this.allowNull = allowNull; + this.name = name; + + if (hasValue && value == null && !allowNull) { + throw new NullPointerException("Cannot initialise nonnull property " + name + " with null value"); + } } - public static ObservableProperty lateinit() { - return new ObservableProperty<>(null, false); + /** + * Creates a "late init" property without an initial value. + * The created property will throw an exception if it has not been initialised yet. + * + * @param the contained value type + * @return the created empty property builder + */ + public static Builder empty() { + return new Builder<>(null, false); } - public static ObservableProperty of(T initialValue) { - return new ObservableProperty<>(initialValue, true); + /** + * Creates a property with an initial value. + * + * @param initialValue the initial value + * @param the contained value type + * @return the created property + */ + public static Builder of(T initialValue) { + return new Builder<>(initialValue, true); } @Override @@ -48,7 +69,7 @@ public final class ObservableProperty implements ObservableView { @Override public T get() { if (!hasValue) { - throw new IllegalStateException("Property " + name + " not initialized!"); + throw new IllegalStateException("Property " + name + " not initialised!"); } return value; @@ -73,31 +94,6 @@ public final class ObservableProperty implements ObservableView { } } - /** - * Clears the current value, if any, from this property. - */ - public void clear() { - T oldValue = value; - value = null; - hasValue = false; - - if (oldValue != null) { - for (ChangeListener listener : listeners) { - listener.onPropertyChange(this, oldValue, null); - } - } - } - - /** - * Prevents this property from accepting null values. - * - * @return this property - */ - public ObservableProperty nonnullValues() { - allowNull = false; - return this; - } - /** * Returns a read-only view of this property. * The result is not an instance of {@link ObservableProperty}, @@ -137,17 +133,6 @@ public final class ObservableProperty implements ObservableView { return name; } - /** - * Sets the name of this property, which is used in debug messages. - * - * @param name the new name - * @return this property - */ - public ObservableProperty setName(String name) { - this.name = Objects.requireNonNull(name, "name"); - return this; - } - @Override public void addListener(ChangeListener listener) { Objects.requireNonNull(listener); @@ -159,4 +144,48 @@ public final class ObservableProperty implements ObservableView { Objects.requireNonNull(listener); listeners.remove(listener); } + + /** + * A builder for properties. + * + * @param the contained value type + */ + public static final class Builder { + private final T initialValue; + private final boolean hasValue; + private String name = DEFAULT_NAME; + private boolean allowNull = true; + + Builder(@Nullable T initialValue, boolean hasValue) { + this.initialValue = initialValue; + this.hasValue = hasValue; + } + + /** + * Disallows null values. + * + * @return this builder + */ + public Builder nonnull() { + allowNull = false; + return this; + } + + /** + * Sets the name of this property, which is used in debug messages. + */ + public Builder name(String name) { + this.name = Objects.requireNonNull(name, "name"); + return this; + } + + /** + * Builds the observable property. + * + * @return the created property + */ + public ObservableProperty build() { + return new ObservableProperty<>(initialValue, hasValue, allowNull, name); + } + } } -- cgit