From bad398cd1114b181f768c1cc3000903e39929e9e Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Wed, 18 Aug 2021 23:27:04 +0300 Subject: yes! --- .../cotton/gui/client/CottonClientScreen.java | 15 +-- .../cotton/gui/client/CottonInventoryScreen.java | 19 +++- .../cotton/gui/impl/client/CottonScreenImpl.java | 3 + .../cotton/gui/impl/client/MouseInputHandler.java | 42 +++++--- .../github/cottonmc/cotton/gui/widget/WWidget.java | 8 ++ .../cotton/gui/widget/data/ObservableProperty.java | 109 +++++++++++++++++++++ 6 files changed, 173 insertions(+), 23 deletions(-) create mode 100644 src/main/java/io/github/cottonmc/cotton/gui/widget/data/ObservableProperty.java (limited to 'src/main/java/io') diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/CottonClientScreen.java b/src/main/java/io/github/cottonmc/cotton/gui/client/CottonClientScreen.java index cb80707..674fd77 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/CottonClientScreen.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/CottonClientScreen.java @@ -36,6 +36,8 @@ public class CottonClientScreen extends Screen implements CottonScreenImpl { @Nullable protected WWidget lastResponder = null; + + private final MouseInputHandler mouseInputHandler = new MouseInputHandler<>(this); public CottonClientScreen(GuiDescription description) { this(new LiteralText(""), description); @@ -46,7 +48,8 @@ public class CottonClientScreen extends Screen implements CottonScreenImpl { this.description = description; description.getRootPanel().validate(description); } - + + @Override public GuiDescription getDescription() { return description; } @@ -176,7 +179,7 @@ public class CottonClientScreen extends Screen implements CottonScreenImpl { int containerX = (int)mouseX-left; int containerY = (int)mouseY-top; if (containerX<0 || containerY<0 || containerX>=width || containerY>=height) return true; - MouseInputHandler.onMouseDown(description, this, containerX, containerY, mouseButton); + mouseInputHandler.onMouseDown(containerX, containerY, mouseButton); return true; } @@ -187,7 +190,7 @@ public class CottonClientScreen extends Screen implements CottonScreenImpl { super.mouseReleased(mouseX, mouseY, mouseButton); int containerX = (int)mouseX-left; int containerY = (int)mouseY-top; - MouseInputHandler.onMouseUp(description, this, containerX, containerY, mouseButton); + mouseInputHandler.onMouseUp(containerX, containerY, mouseButton); return true; } @@ -199,7 +202,7 @@ public class CottonClientScreen extends Screen implements CottonScreenImpl { int containerX = (int)mouseX-left; int containerY = (int)mouseY-top; - MouseInputHandler.onMouseDrag(description, this, containerX, containerY, mouseButton, deltaX, deltaY); + mouseInputHandler.onMouseDrag(containerX, containerY, mouseButton, deltaX, deltaY); return true; } @@ -210,7 +213,7 @@ public class CottonClientScreen extends Screen implements CottonScreenImpl { int containerX = (int)mouseX-left; int containerY = (int)mouseY-top; - MouseInputHandler.onMouseScroll(description, containerX, containerY, amount); + mouseInputHandler.onMouseScroll(containerX, containerY, amount); return true; } @@ -221,7 +224,7 @@ public class CottonClientScreen extends Screen implements CottonScreenImpl { int containerX = (int)mouseX-left; int containerY = (int)mouseY-top; - MouseInputHandler.onMouseMove(description, containerX, containerY); + mouseInputHandler.onMouseMove(containerX, containerY); } @Override diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/CottonInventoryScreen.java b/src/main/java/io/github/cottonmc/cotton/gui/client/CottonInventoryScreen.java index 87d9453..01a5092 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/CottonInventoryScreen.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/CottonInventoryScreen.java @@ -8,12 +8,14 @@ import net.minecraft.text.LiteralText; import net.minecraft.text.Style; import net.minecraft.text.Text; +import io.github.cottonmc.cotton.gui.GuiDescription; import io.github.cottonmc.cotton.gui.SyncedGuiDescription; import io.github.cottonmc.cotton.gui.impl.VisualLogger; import io.github.cottonmc.cotton.gui.impl.client.CottonScreenImpl; import io.github.cottonmc.cotton.gui.impl.client.MouseInputHandler; import io.github.cottonmc.cotton.gui.widget.WPanel; import io.github.cottonmc.cotton.gui.widget.WWidget; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFW; import org.lwjgl.opengl.GL11; @@ -26,6 +28,7 @@ import org.lwjgl.opengl.GL11; public class CottonInventoryScreen extends HandledScreen implements CottonScreenImpl { protected SyncedGuiDescription description; @Nullable protected WWidget lastResponder = null; + private final MouseInputHandler> mouseInputHandler = new MouseInputHandler<>(this); /** * Constructs a new screen without a title. @@ -83,6 +86,12 @@ public class CottonInventoryScreen extends Handl VisualLogger.reset(); } + @ApiStatus.Internal + @Override + public GuiDescription getDescription() { + return description; + } + @Nullable @Override public WWidget getLastResponder() { @@ -187,7 +196,7 @@ public class CottonInventoryScreen extends Handl int containerX = (int)mouseX-x; int containerY = (int)mouseY-y; if (containerX<0 || containerY<0 || containerX>=width || containerY>=height) return result; - MouseInputHandler.onMouseDown(description, this, containerX, containerY, mouseButton); + mouseInputHandler.onMouseDown(containerX, containerY, mouseButton); return true; } @@ -197,7 +206,7 @@ public class CottonInventoryScreen extends Handl super.mouseReleased(mouseX, mouseY, mouseButton); int containerX = (int)mouseX-x; int containerY = (int)mouseY-y; - MouseInputHandler.onMouseUp(description, this, containerX, containerY, mouseButton); + mouseInputHandler.onMouseUp(containerX, containerY, mouseButton); return true; } @@ -208,7 +217,7 @@ public class CottonInventoryScreen extends Handl int containerX = (int)mouseX-x; int containerY = (int)mouseY-y; - MouseInputHandler.onMouseDrag(description, this, containerX, containerY, mouseButton, deltaX, deltaY); + mouseInputHandler.onMouseDrag(containerX, containerY, mouseButton, deltaX, deltaY); return true; } @@ -219,7 +228,7 @@ public class CottonInventoryScreen extends Handl int containerX = (int)mouseX-x; int containerY = (int)mouseY-y; - MouseInputHandler.onMouseScroll(description, containerX, containerY, amount); + mouseInputHandler.onMouseScroll(containerX, containerY, amount); return true; } @@ -230,7 +239,7 @@ public class CottonInventoryScreen extends Handl int containerX = (int)mouseX-x; int containerY = (int)mouseY-y; - MouseInputHandler.onMouseMove(description, containerX, containerY); + mouseInputHandler.onMouseMove(containerX, containerY); } @Override diff --git a/src/main/java/io/github/cottonmc/cotton/gui/impl/client/CottonScreenImpl.java b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/CottonScreenImpl.java index 2ef9632..cd215b3 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/impl/client/CottonScreenImpl.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/CottonScreenImpl.java @@ -5,11 +5,14 @@ import net.fabricmc.api.Environment; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.text.Style; +import io.github.cottonmc.cotton.gui.GuiDescription; import io.github.cottonmc.cotton.gui.widget.WWidget; import org.jetbrains.annotations.Nullable; @Environment(EnvType.CLIENT) public interface CottonScreenImpl { + GuiDescription getDescription(); + @Nullable WWidget getLastResponder(); 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 45fc17f..4791c39 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 @@ -2,7 +2,6 @@ package io.github.cottonmc.cotton.gui.impl.client; import net.minecraft.client.gui.screen.Screen; -import io.github.cottonmc.cotton.gui.GuiDescription; import io.github.cottonmc.cotton.gui.widget.WWidget; import io.github.cottonmc.cotton.gui.widget.data.InputResult; import org.jetbrains.annotations.Nullable; @@ -12,10 +11,17 @@ import java.util.function.Function; /** * The implementation for mouse inputs. */ -public final class MouseInputHandler { - public static void onMouseDown(GuiDescription description, CottonScreenImpl screen, int containerX, int containerY, int mouseButton) { +public final class MouseInputHandler { + private final S screen; + private @Nullable WWidget hovered; + + public MouseInputHandler(S screen) { + this.screen = screen; + } + + public void onMouseDown(int containerX, int containerY, int mouseButton) { if (screen.getLastResponder() == null) { - WWidget lastResponder = description.getRootPanel().hit(containerX, containerY); + WWidget lastResponder = screen.getDescription().getRootPanel().hit(containerX, containerY); screen.setLastResponder(lastResponder); if (lastResponder != null) { runTree( @@ -28,7 +34,7 @@ public final class MouseInputHandler { } } - public static void onMouseUp(GuiDescription description, S screen, int containerX, int containerY, int mouseButton) { + public void onMouseUp(int containerX, int containerY, int mouseButton) { WWidget lastResponder = screen.getLastResponder(); if (lastResponder != null) { @@ -48,7 +54,7 @@ public final class MouseInputHandler { } } else { runTree( - description.getRootPanel().hit(containerX, containerY), + screen.getDescription().getRootPanel().hit(containerX, containerY), widget -> widget.onMouseUp(containerX - widget.getAbsoluteX(), containerY - widget.getAbsoluteY(), mouseButton) ); } @@ -56,7 +62,7 @@ public final class MouseInputHandler { screen.setLastResponder(null); } - public static void onMouseDrag(GuiDescription description, S screen, int containerX, int containerY, int mouseButton, double deltaX, double deltaY) { + public void onMouseDrag(int containerX, int containerY, int mouseButton, double deltaX, double deltaY) { WWidget lastResponder = screen.getLastResponder(); if (lastResponder != null) { @@ -68,22 +74,34 @@ public final class MouseInputHandler { if (containerX < 0 || containerY < 0 || containerX >= width || containerY >= height) return; runTree( - description.getRootPanel().hit(containerX, containerY), + screen.getDescription().getRootPanel().hit(containerX, containerY), widget -> widget.onMouseDrag(containerX - widget.getAbsoluteX(), containerY - widget.getAbsoluteY(), mouseButton, deltaX, deltaY) ); } } - public static void onMouseScroll(GuiDescription description, int containerX, int containerY, double amount) { + public void onMouseScroll(int containerX, int containerY, double amount) { runTree( - description.getRootPanel().hit(containerX, containerY), + screen.getDescription().getRootPanel().hit(containerX, containerY), widget -> widget.onMouseScroll(containerX - widget.getAbsoluteX(), containerY - widget.getAbsoluteY(), amount) ); } - public static void onMouseMove(GuiDescription description, int containerX, int containerY) { + public void onMouseMove(int containerX, int containerY) { + WWidget hit = screen.getDescription().getRootPanel().hit(containerX, containerY); + + // TODO: Some sort of canHover? + if (hit != hovered) { + if (hovered != null) { + hovered.getHovered().set(false); + } + + hovered = hit; + hit.getHovered().set(true); + } + runTree( - description.getRootPanel().hit(containerX, containerY), + hit, widget -> widget.onMouseMove(containerX - widget.getAbsoluteX(), containerY - widget.getAbsoluteY()) ); } 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 2a6ae5e..30e14d5 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 @@ -1,5 +1,7 @@ package io.github.cottonmc.cotton.gui.widget; +import io.github.cottonmc.cotton.gui.widget.data.ObservableProperty; + import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.MinecraftClient; @@ -41,6 +43,8 @@ public class WWidget { @Nullable protected GuiDescription host; + private final ObservableProperty hovered = ObservableProperty.of(false).nonnullValues(); + /** * Sets the location of this widget relative to its parent. * @@ -456,6 +460,10 @@ public class WWidget { public void addPainters() { } + public ObservableProperty getHovered() { + return hovered; + } + /** * Tests if the provided key code is an activation key for widgets. * 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 new file mode 100644 index 0000000..723cf60 --- /dev/null +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/data/ObservableProperty.java @@ -0,0 +1,109 @@ +package io.github.cottonmc.cotton.gui.widget.data; + +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.function.Supplier; + +public final class ObservableProperty { + private Supplier value; + private final List> listeners = new ArrayList<>(); + private boolean allowNull = true; + + private ObservableProperty() { + } + + private ObservableProperty(Supplier value) { + this.value = value; + } + + public static ObservableProperty lateinit() { + return new ObservableProperty<>(); + } + + public static ObservableProperty of(T initialValue) { + return new ObservableProperty<>(() -> initialValue); + } + + public static ObservableProperty bound(Supplier initialValue) { + return new ObservableProperty<>(initialValue); + } + + /** + * {@return the value of this property} + * @throws IllegalStateException if not initialized + * @throws NullPointerException if the value is null and null values aren't allowed + */ + public T get() { + if (value == null) { + throw new IllegalStateException("Property not initialized!"); + } + + T ret = value.get(); + if (ret == null && !allowNull) throw new NullPointerException("Null value for nonnull property!"); + return ret; + } + + /** + * Sets this property to a constant value. + * + * @param value the new value + * @throws NullPointerException if the value is null and nulls aren't allowed + */ + public void set(T value) { + if (value == null && !allowNull) throw new NullPointerException("value"); + bind(() -> value); + } + + /** + * Binds this property to a supplier. + * + * @param value the new value supplier + */ + public void bind(Supplier value) { + Objects.requireNonNull(value, "value"); + T oldValue = this.value != null ? this.value.get() : null; + this.value = value; + + for (ChangeListener listener : listeners) { + listener.onPropertyChange(this, oldValue, value.get()); + } + } + + /** + * Clears the current value, if any, from this property. + */ + public void clear() { + T oldValue = this.value != null ? this.value.get() : null; + value = 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; + } + + public void addListener(ChangeListener listener) { + listeners.add(listener); + } + + public void removeListener(ChangeListener listener) { + listeners.remove(listener); + } + + @FunctionalInterface + public interface ChangeListener { + void onPropertyChange(ObservableProperty property, @Nullable T from, @Nullable T to); + } +} -- cgit