From cd052a3d42fae2c80c58b28741dd66e9da1a6fcd Mon Sep 17 00:00:00 2001 From: Juuxel Date: Tue, 27 Aug 2019 11:10:30 +0300 Subject: Add sliders, WIP --- .../github/cottonmc/cotton/gui/widget/WSlider.java | 122 +++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java (limited to 'src/main/java') diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java new file mode 100644 index 0000000..ee0ce3a --- /dev/null +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java @@ -0,0 +1,122 @@ +package io.github.cottonmc.cotton.gui.widget; + +import io.github.cottonmc.cotton.gui.client.ScreenDrawing; +import net.minecraft.util.Identifier; + +import javax.annotation.Nullable; +import java.util.function.IntConsumer; + +public class WSlider extends WWidget { + private static final int TRACK_WIDTH = 6; + private static final int THUMB_SIZE = 8; + // TODO: Horizontal textures + private static final Identifier TEXTURE = new Identifier("libgui", "textures/widget/slider.png"); + + private final int min, max; + private final int valueRange; + private final Axis axis; + + private int value; + private float valueToCoordRatio, coordToValueRatio; + @Nullable private IntConsumer valueChangeListener = null; + @Nullable private Runnable mouseReleaseListener = null; + private boolean dragging = false; + + public WSlider(int min, int max, Axis axis) { + this.min = min; + this.max = max; + this.valueRange = max - min + 1; + this.axis = axis; + this.value = min; + } + + public WSlider(int max, Axis axis) { + this(0, max, axis); + } + + @Override + public void setSize(int x, int y) { + super.setSize(x, y); + // FIXME: that - and + stuff fixes the rendering but causes range issues (too large for X and too small for Y) + int trackHeight = (axis == Axis.HORIZONTAL ? (x - THUMB_SIZE) : (y + THUMB_SIZE)); + valueToCoordRatio = (float) valueRange / trackHeight; + coordToValueRatio = 1 / valueToCoordRatio; + } + + @Override + public boolean canResize() { + return true; + } + + @Override + public void onMouseDrag(int x, int y, int button) { + // a = mouse coordinate on slider axis, axisWidth = width of slider axis + // ao = axis-opposite mouse coordinate, aoCenter = center of ao's axis + int a = axis == Axis.HORIZONTAL ? x : y; + int axisWidth = axis == Axis.HORIZONTAL ? width : height; + int ao = axis == Axis.HORIZONTAL ? y : x; + int aoCenter = (axis == Axis.HORIZONTAL ? height : width) / 2; + if (dragging || ao >= aoCenter - TRACK_WIDTH / 2 && ao <= aoCenter + TRACK_WIDTH / 2) { + dragging = true; + int pos = axis == Axis.VERTICAL ? (axisWidth - a + THUMB_SIZE / 2) : (a - THUMB_SIZE / 2); + value = min + (int) (valueToCoordRatio * pos); + if (valueChangeListener != null) valueChangeListener.accept(value); + } + } + + @Override + public void onClick(int x, int y, int button) { + onMouseDrag(x, y, button); + onMouseUp(x, y, button); + } + + @Override + public WWidget onMouseUp(int x, int y, int button) { + dragging = false; + if (mouseReleaseListener != null) mouseReleaseListener.run(); + + return super.onMouseUp(x, y, button); + } + + @Override + public void paintBackground(int x, int y) { + float px = 1 / 16f; + if (axis == Axis.VERTICAL) { + int trackX = x + width / 2 - TRACK_WIDTH / 2; + int thumbY = y + height - (int) (coordToValueRatio * (value - min)); + + ScreenDrawing.rect(TEXTURE, trackX, y + 1, TRACK_WIDTH, 1, 0*px, 8*px, 6*px, 9*px, 0xFFFFFFFF); + ScreenDrawing.rect(TEXTURE, trackX, y + 2, TRACK_WIDTH, height - 2, 0*px, 9*px, 6*px, 10*px, 0xFFFFFFFF); + ScreenDrawing.rect(TEXTURE, trackX, y + height, TRACK_WIDTH, 1, 0*px, 10*px, 6*px, 11*px, 0xFFFFFFFF); + + ScreenDrawing.rect(TEXTURE, x + width / 2 - THUMB_SIZE / 2, thumbY, THUMB_SIZE, THUMB_SIZE, 0*px, 0*px, 8*px, 8*px, 0xFFFFFFFF); + } else { + int trackY = y + height / 2 - TRACK_WIDTH / 2; + int thumbX = x + (int) (coordToValueRatio * (value - min)); + + ScreenDrawing.rect(x, trackY, 1, TRACK_WIDTH, 0xFFFF0000); + ScreenDrawing.rect(x + 1, trackY, width - 2, TRACK_WIDTH, 0xFFFF0000); + ScreenDrawing.rect(x + width - 1, trackY, 1, TRACK_WIDTH, 0xFFFF0000); + + ScreenDrawing.rect(thumbX, y + height / 2 - THUMB_SIZE / 2, THUMB_SIZE, THUMB_SIZE, 0xFF00FFFF); + } + } + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + public WSlider setValueChangeListener(@Nullable IntConsumer valueChangeListener) { + this.valueChangeListener = valueChangeListener; + return this; + } + + public WSlider setMouseReleaseListener(@Nullable Runnable mouseReleaseListener) { + this.mouseReleaseListener = mouseReleaseListener; + return this; + } +} -- cgit From 5f3e03cba9fe46791c717071b2b209129099d35b Mon Sep 17 00:00:00 2001 From: Juuxel Date: Tue, 27 Aug 2019 17:10:06 +0300 Subject: More work on sliders --- build.gradle | 4 ++-- .../cotton/gui/client/modmenu/ConfigGui.java | 9 ++++---- .../github/cottonmc/cotton/gui/widget/WButton.java | 2 +- .../github/cottonmc/cotton/gui/widget/WSlider.java | 25 +++++++++++++-------- .../assets/libgui/textures/widget/slider.png | Bin 668 -> 1831 bytes 5 files changed, 23 insertions(+), 17 deletions(-) (limited to 'src/main/java') diff --git a/build.gradle b/build.gradle index c453a51..580618e 100644 --- a/build.gradle +++ b/build.gradle @@ -17,13 +17,13 @@ buildscript { } plugins { - //id 'fabric-loom' version '0.2.4-SNAPSHOT' + id 'fabric-loom' version '0.2.4-SNAPSHOT' id 'maven-publish' id "com.jfrog.artifactory" version "4.9.0" } -apply plugin: "fabric-loom"; +//apply plugin: "fabric-loom"; sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java b/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java index 23c5b6f..454df9d 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java @@ -3,10 +3,7 @@ package io.github.cottonmc.cotton.gui.client.modmenu; import io.github.cottonmc.cotton.gui.client.BackgroundPainter; import io.github.cottonmc.cotton.gui.client.LibGuiClient; import io.github.cottonmc.cotton.gui.client.LightweightGuiDescription; -import io.github.cottonmc.cotton.gui.widget.WButton; -import io.github.cottonmc.cotton.gui.widget.WGridPanel; -import io.github.cottonmc.cotton.gui.widget.WTextField; -import io.github.cottonmc.cotton.gui.widget.WToggleButton; +import io.github.cottonmc.cotton.gui.widget.*; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; import net.minecraft.text.TranslatableText; @@ -30,7 +27,9 @@ public class ConfigGui extends LightweightGuiDescription { WTextField testField = new WTextField(); testField.setSuggestion("test"); root.add(testField, 0, 3, 4, 1); - + root.add(new WSlider(100, 0, Axis.VERTICAL).setValueChangeListener(System.out::println), 0, 4, 1, 4); + root.add(new WSlider(0, 123, Axis.HORIZONTAL).setValueChangeListener(System.out::println), 1, 4, 4, 1); + root.add(new WKirbSprite(), 5, 4); WButton doneButton = new WButton(new TranslatableText("gui.done")); diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WButton.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WButton.java index 0f5159c..16a8d71 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WButton.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WButton.java @@ -31,7 +31,7 @@ public class WButton extends WWidget { @Override public void paintForeground(int x, int y, int mouseX, int mouseY) { - System.out.println("Mouse: { "+mouseX+", "+mouseY+" }"); + //System.out.println("Mouse: { "+mouseX+", "+mouseY+" }"); boolean hovered = (mouseX>=x && mouseY>=y && mouseX= min) + throw new IllegalArgumentException("Minimum value must be smaller than the maximum!"); + this.min = min; this.max = max; this.valueRange = max - min + 1; @@ -37,8 +44,7 @@ public class WSlider extends WWidget { @Override public void setSize(int x, int y) { super.setSize(x, y); - // FIXME: that - and + stuff fixes the rendering but causes range issues (too large for X and too small for Y) - int trackHeight = (axis == Axis.HORIZONTAL ? (x - THUMB_SIZE) : (y + THUMB_SIZE)); + int trackHeight = (axis == Axis.HORIZONTAL ? x : y) - THUMB_SIZE + 1; valueToCoordRatio = (float) valueRange / trackHeight; coordToValueRatio = 1 / valueToCoordRatio; } @@ -58,8 +64,9 @@ public class WSlider extends WWidget { int aoCenter = (axis == Axis.HORIZONTAL ? height : width) / 2; if (dragging || ao >= aoCenter - TRACK_WIDTH / 2 && ao <= aoCenter + TRACK_WIDTH / 2) { dragging = true; - int pos = axis == Axis.VERTICAL ? (axisWidth - a + THUMB_SIZE / 2) : (a - THUMB_SIZE / 2); - value = min + (int) (valueToCoordRatio * pos); + int pos = (axis == Axis.VERTICAL ? (axisWidth - a) : a) - THUMB_SIZE / 2; + int futureValue = min + (int) (valueToCoordRatio * pos); + value = MathHelper.clamp(futureValue, min, max); if (valueChangeListener != null) valueChangeListener.accept(value); } } @@ -83,7 +90,7 @@ public class WSlider extends WWidget { float px = 1 / 16f; if (axis == Axis.VERTICAL) { int trackX = x + width / 2 - TRACK_WIDTH / 2; - int thumbY = y + height - (int) (coordToValueRatio * (value - min)); + int thumbY = y + height - THUMB_SIZE + 1 - (int) (coordToValueRatio * (value - min)); ScreenDrawing.rect(TEXTURE, trackX, y + 1, TRACK_WIDTH, 1, 0*px, 8*px, 6*px, 9*px, 0xFFFFFFFF); ScreenDrawing.rect(TEXTURE, trackX, y + 2, TRACK_WIDTH, height - 2, 0*px, 9*px, 6*px, 10*px, 0xFFFFFFFF); @@ -94,11 +101,11 @@ public class WSlider extends WWidget { int trackY = y + height / 2 - TRACK_WIDTH / 2; int thumbX = x + (int) (coordToValueRatio * (value - min)); - ScreenDrawing.rect(x, trackY, 1, TRACK_WIDTH, 0xFFFF0000); - ScreenDrawing.rect(x + 1, trackY, width - 2, TRACK_WIDTH, 0xFFFF0000); - ScreenDrawing.rect(x + width - 1, trackY, 1, TRACK_WIDTH, 0xFFFF0000); + ScreenDrawing.rect(TEXTURE, x, trackY, 1, TRACK_WIDTH, 8*px, 0*px, 9*px, 6*px, 0xFFFFFFFF); + ScreenDrawing.rect(TEXTURE, x + 1, trackY, width - 2, TRACK_WIDTH, 9*px, 0*px, 10*px, 6*px, 0xFFFFFFFF); + ScreenDrawing.rect(TEXTURE, x + width - 1, trackY, 1, TRACK_WIDTH, 10*px, 0*px, 11*px, 6*px, 0xFFFFFFFF); - ScreenDrawing.rect(thumbX, y + height / 2 - THUMB_SIZE / 2, THUMB_SIZE, THUMB_SIZE, 0xFF00FFFF); + ScreenDrawing.rect(TEXTURE, thumbX, y + height / 2 - THUMB_SIZE / 2, THUMB_SIZE, THUMB_SIZE, 8*px, 8*px, 16*px, 16*px, 0xFFFFFFFF); } } diff --git a/src/main/resources/assets/libgui/textures/widget/slider.png b/src/main/resources/assets/libgui/textures/widget/slider.png index 8fbf16f..d4e2eda 100644 Binary files a/src/main/resources/assets/libgui/textures/widget/slider.png and b/src/main/resources/assets/libgui/textures/widget/slider.png differ -- cgit From c1cdad568698afbb2b0a938840fe4193cb8d1d9f Mon Sep 17 00:00:00 2001 From: Juuxel Date: Tue, 27 Aug 2019 19:06:47 +0300 Subject: Almost working sliders --- .../github/cottonmc/cotton/gui/widget/WSlider.java | 77 ++++++++++++++++----- .../assets/libgui/textures/widget/slider.png | Bin 1831 -> 2295 bytes 2 files changed, 59 insertions(+), 18 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java index c08d1bc..5aae891 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java @@ -1,12 +1,27 @@ package io.github.cottonmc.cotton.gui.widget; import io.github.cottonmc.cotton.gui.client.ScreenDrawing; +import net.minecraft.client.MinecraftClient; import net.minecraft.util.Identifier; import net.minecraft.util.math.MathHelper; +import org.lwjgl.glfw.GLFW; import javax.annotation.Nullable; import java.util.function.IntConsumer; +/** + * A slider widget that can be used to select int values. + * + *

You can set two listeners on a slider: + *

    + *
  • A value change listener that gets all value changes (except direct setValue calls)
  • + *
  • + * A mouse release listener that gets called when the player stops dragging the slider. + * For example, this can be used for sending sync packets to the server + * when the player has selected a value. + *
  • + *
+ */ public class WSlider extends WWidget { private static final int TRACK_WIDTH = 6; private static final int THUMB_SIZE = 8; @@ -22,12 +37,12 @@ public class WSlider extends WWidget { @Nullable private IntConsumer valueChangeListener = null; @Nullable private Runnable mouseReleaseListener = null; - // Used for detecting dragging after the user starts dragging + // Used for visuals and detecting dragging after the user starts dragging // on top of the slider, but then moves the mouse out but still within the widget's boundary. private boolean dragging = false; public WSlider(int min, int max, Axis axis) { - if (max >= min) + if (max <= min) throw new IllegalArgumentException("Minimum value must be smaller than the maximum!"); this.min = min; @@ -56,15 +71,14 @@ public class WSlider extends WWidget { @Override public void onMouseDrag(int x, int y, int button) { - // a = mouse coordinate on slider axis, axisWidth = width of slider axis + // a = mouse coordinate on slider axis // ao = axis-opposite mouse coordinate, aoCenter = center of ao's axis int a = axis == Axis.HORIZONTAL ? x : y; - int axisWidth = axis == Axis.HORIZONTAL ? width : height; int ao = axis == Axis.HORIZONTAL ? y : x; int aoCenter = (axis == Axis.HORIZONTAL ? height : width) / 2; - if (dragging || ao >= aoCenter - TRACK_WIDTH / 2 && ao <= aoCenter + TRACK_WIDTH / 2) { + if (dragging || ao >= aoCenter - TRACK_WIDTH / 2 - 2 && ao <= aoCenter + TRACK_WIDTH / 2 + 2) { dragging = true; - int pos = (axis == Axis.VERTICAL ? (axisWidth - a) : a) - THUMB_SIZE / 2; + int pos = (axis == Axis.VERTICAL ? (height - a) : a) - THUMB_SIZE / 2; int futureValue = min + (int) (valueToCoordRatio * pos); value = MathHelper.clamp(futureValue, min, max); if (valueChangeListener != null) valueChangeListener.accept(value); @@ -87,26 +101,53 @@ public class WSlider extends WWidget { @Override public void paintBackground(int x, int y) { - float px = 1 / 16f; + float px = 1 / 32f; + if (axis == Axis.VERTICAL) { int trackX = x + width / 2 - TRACK_WIDTH / 2; - int thumbY = y + height - THUMB_SIZE + 1 - (int) (coordToValueRatio * (value - min)); - - ScreenDrawing.rect(TEXTURE, trackX, y + 1, TRACK_WIDTH, 1, 0*px, 8*px, 6*px, 9*px, 0xFFFFFFFF); - ScreenDrawing.rect(TEXTURE, trackX, y + 2, TRACK_WIDTH, height - 2, 0*px, 9*px, 6*px, 10*px, 0xFFFFFFFF); - ScreenDrawing.rect(TEXTURE, trackX, y + height, TRACK_WIDTH, 1, 0*px, 10*px, 6*px, 11*px, 0xFFFFFFFF); - ScreenDrawing.rect(TEXTURE, x + width / 2 - THUMB_SIZE / 2, thumbY, THUMB_SIZE, THUMB_SIZE, 0*px, 0*px, 8*px, 8*px, 0xFFFFFFFF); + ScreenDrawing.rect(TEXTURE, trackX, y + 1, TRACK_WIDTH, 1, 16*px, 0*px, 22*px, 1*px, 0xFFFFFFFF); + ScreenDrawing.rect(TEXTURE, trackX, y + 2, TRACK_WIDTH, height - 2, 16*px, 1*px, 22*px, 2*px, 0xFFFFFFFF); + ScreenDrawing.rect(TEXTURE, trackX, y + height, TRACK_WIDTH, 1, 16*px, 2*px, 22*px, 3*px, 0xFFFFFFFF); } else { int trackY = y + height / 2 - TRACK_WIDTH / 2; - int thumbX = x + (int) (coordToValueRatio * (value - min)); - ScreenDrawing.rect(TEXTURE, x, trackY, 1, TRACK_WIDTH, 8*px, 0*px, 9*px, 6*px, 0xFFFFFFFF); - ScreenDrawing.rect(TEXTURE, x + 1, trackY, width - 2, TRACK_WIDTH, 9*px, 0*px, 10*px, 6*px, 0xFFFFFFFF); - ScreenDrawing.rect(TEXTURE, x + width - 1, trackY, 1, TRACK_WIDTH, 10*px, 0*px, 11*px, 6*px, 0xFFFFFFFF); + ScreenDrawing.rect(TEXTURE, x, trackY, 1, TRACK_WIDTH, 16*px, 3*px, 17*px, 9*px, 0xFFFFFFFF); + ScreenDrawing.rect(TEXTURE, x + 1, trackY, width - 2, TRACK_WIDTH, 17*px, 3*px, 18*px, 9*px, 0xFFFFFFFF); + ScreenDrawing.rect(TEXTURE, x + width - 1, trackY, 1, TRACK_WIDTH, 18*px, 3*px, 19*px, 9*px, 0xFFFFFFFF); + } + } + + @Override + public void paintForeground(int x, int y, int mouseX, int mouseY) { + float px = 1 / 32f; + int thumbX, thumbY, thumbXOffset; + + if (axis == Axis.VERTICAL) { + thumbX = x + width / 2 - THUMB_SIZE / 2; + thumbY = y + height - THUMB_SIZE + 1 - (int) (coordToValueRatio * (value - min)); + thumbXOffset = 0; + } else { + thumbX = x + (int) (coordToValueRatio * (value - min)); + thumbY = y + height / 2 - THUMB_SIZE / 2; + thumbXOffset = 8; + } - ScreenDrawing.rect(TEXTURE, thumbX, y + height / 2 - THUMB_SIZE / 2, THUMB_SIZE, THUMB_SIZE, 8*px, 8*px, 16*px, 16*px, 0xFFFFFFFF); + // FIXME: Ugly, I really should remove this + if (dragging) { + if (GLFW.glfwGetMouseButton(MinecraftClient.getInstance().window.getHandle(), GLFW.GLFW_MOUSE_BUTTON_1) == GLFW.GLFW_PRESS) { + onMouseDrag(mouseX - x, mouseY - y, 0); + } else { + onMouseUp(mouseX - x, mouseY - y, 0); + } } + + // thumbState values: + // 0: default, 1: dragging, 2: hovered + int thumbState = dragging ? 1 : (mouseX >= thumbX && mouseX <= thumbX + THUMB_SIZE && mouseY >= thumbY && mouseY <= thumbY + THUMB_SIZE ? 2 : 0); + ScreenDrawing.rect(TEXTURE, thumbX, thumbY, THUMB_SIZE, THUMB_SIZE, thumbXOffset*px, 0*px + thumbState * 8*px, (thumbXOffset + 8)*px, 8*px + thumbState * 8*px, 0xFFFFFFFF); + + super.paintForeground(x, y, mouseX, mouseY); } public int getValue() { diff --git a/src/main/resources/assets/libgui/textures/widget/slider.png b/src/main/resources/assets/libgui/textures/widget/slider.png index d4e2eda..d118877 100644 Binary files a/src/main/resources/assets/libgui/textures/widget/slider.png and b/src/main/resources/assets/libgui/textures/widget/slider.png differ -- cgit From 6bf2f8a563865d89d7e0ad32da6ca702c1cce641 Mon Sep 17 00:00:00 2001 From: Juuxel Date: Tue, 27 Aug 2019 19:09:13 +0300 Subject: Fix todo in WSlider --- .../java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java | 2 +- src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java b/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java index 454df9d..61d5d36 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java @@ -27,7 +27,7 @@ public class ConfigGui extends LightweightGuiDescription { WTextField testField = new WTextField(); testField.setSuggestion("test"); root.add(testField, 0, 3, 4, 1); - root.add(new WSlider(100, 0, Axis.VERTICAL).setValueChangeListener(System.out::println), 0, 4, 1, 4); + root.add(new WSlider(50, 100, Axis.VERTICAL).setValueChangeListener(System.out::println), 0, 4, 1, 4); root.add(new WSlider(0, 123, Axis.HORIZONTAL).setValueChangeListener(System.out::println), 1, 4, 4, 1); root.add(new WKirbSprite(), 5, 4); diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java index 5aae891..c63b5ee 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java @@ -22,10 +22,10 @@ import java.util.function.IntConsumer; * * */ +// TODO: Fix the blocked pixel at the top of vertical sliders public class WSlider extends WWidget { private static final int TRACK_WIDTH = 6; private static final int THUMB_SIZE = 8; - // TODO: Horizontal textures private static final Identifier TEXTURE = new Identifier("libgui", "textures/widget/slider.png"); private final int min, max; -- cgit From 3b18d099fbc4758cc69f99a8dc046822395e6aa4 Mon Sep 17 00:00:00 2001 From: Juuxel Date: Tue, 27 Aug 2019 20:59:17 +0300 Subject: Add focusing and support for background painters --- .../cotton/gui/client/modmenu/ConfigGui.java | 2 +- .../github/cottonmc/cotton/gui/widget/WSlider.java | 88 +++++++++++++++------- 2 files changed, 62 insertions(+), 28 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java b/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java index 61d5d36..1b5bf42 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java @@ -27,7 +27,7 @@ public class ConfigGui extends LightweightGuiDescription { WTextField testField = new WTextField(); testField.setSuggestion("test"); root.add(testField, 0, 3, 4, 1); - root.add(new WSlider(50, 100, Axis.VERTICAL).setValueChangeListener(System.out::println), 0, 4, 1, 4); + root.add(new WSlider(50, 100, Axis.VERTICAL).setValueChangeListener(System.out::println), 6, 0, 1, 3); root.add(new WSlider(0, 123, Axis.HORIZONTAL).setValueChangeListener(System.out::println), 1, 4, 4, 1); root.add(new WKirbSprite(), 5, 4); diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java index c63b5ee..65ef7e3 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java @@ -1,6 +1,9 @@ package io.github.cottonmc.cotton.gui.widget; +import io.github.cottonmc.cotton.gui.client.BackgroundPainter; import io.github.cottonmc.cotton.gui.client.ScreenDrawing; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; import net.minecraft.client.MinecraftClient; import net.minecraft.util.Identifier; import net.minecraft.util.math.MathHelper; @@ -16,13 +19,12 @@ import java.util.function.IntConsumer; *
    *
  • A value change listener that gets all value changes (except direct setValue calls)
  • *
  • - * A mouse release listener that gets called when the player stops dragging the slider. + * A focus release listener that gets called when the player stops dragging the slider. * For example, this can be used for sending sync packets to the server * when the player has selected a value. *
  • *
*/ -// TODO: Fix the blocked pixel at the top of vertical sliders public class WSlider extends WWidget { private static final int TRACK_WIDTH = 6; private static final int THUMB_SIZE = 8; @@ -35,11 +37,15 @@ public class WSlider extends WWidget { private int value; private float valueToCoordRatio, coordToValueRatio; @Nullable private IntConsumer valueChangeListener = null; - @Nullable private Runnable mouseReleaseListener = null; + @Nullable private Runnable focusReleaseListener = null; + + @Environment(EnvType.CLIENT) + @Nullable + private BackgroundPainter backgroundPainter = null; // Used for visuals and detecting dragging after the user starts dragging // on top of the slider, but then moves the mouse out but still within the widget's boundary. - private boolean dragging = false; +// private boolean dragging = false; public WSlider(int min, int max, Axis axis) { if (max <= min) @@ -70,15 +76,28 @@ public class WSlider extends WWidget { } @Override - public void onMouseDrag(int x, int y, int button) { - // a = mouse coordinate on slider axis + public boolean canFocus() { + return true; + } + + @Override + public WWidget onMouseDown(int x, int y, int button) { // ao = axis-opposite mouse coordinate, aoCenter = center of ao's axis - int a = axis == Axis.HORIZONTAL ? x : y; int ao = axis == Axis.HORIZONTAL ? y : x; int aoCenter = (axis == Axis.HORIZONTAL ? height : width) / 2; - if (dragging || ao >= aoCenter - TRACK_WIDTH / 2 - 2 && ao <= aoCenter + TRACK_WIDTH / 2 + 2) { - dragging = true; - int pos = (axis == Axis.VERTICAL ? (height - a) : a) - THUMB_SIZE / 2; + + // Check if cursor is inside or <=2px away from track + if (ao >= aoCenter - TRACK_WIDTH / 2 - 2 && ao <= aoCenter + TRACK_WIDTH / 2 + 2) { + requestFocus(); + } + return super.onMouseDown(x, y, button); + } + + @Override + public void onMouseDrag(int x, int y, int button) { + if (isFocused()) { + //dragging = true; + int pos = (axis == Axis.VERTICAL ? (height - y) : x) - THUMB_SIZE / 2; int futureValue = min + (int) (valueToCoordRatio * pos); value = MathHelper.clamp(futureValue, min, max); if (valueChangeListener != null) valueChangeListener.accept(value); @@ -93,31 +112,40 @@ public class WSlider extends WWidget { @Override public WWidget onMouseUp(int x, int y, int button) { - dragging = false; - if (mouseReleaseListener != null) mouseReleaseListener.run(); - + releaseFocus(); return super.onMouseUp(x, y, button); } + @Override + public void onFocusLost() { + if (focusReleaseListener != null) focusReleaseListener.run(); + } + + @Environment(EnvType.CLIENT) @Override public void paintBackground(int x, int y) { - float px = 1 / 32f; + if (backgroundPainter != null) { + backgroundPainter.paintBackground(x, y, this); + } else { + float px = 1 / 32f; - if (axis == Axis.VERTICAL) { - int trackX = x + width / 2 - TRACK_WIDTH / 2; + if (axis == Axis.VERTICAL) { + int trackX = x + width / 2 - TRACK_WIDTH / 2; - ScreenDrawing.rect(TEXTURE, trackX, y + 1, TRACK_WIDTH, 1, 16*px, 0*px, 22*px, 1*px, 0xFFFFFFFF); - ScreenDrawing.rect(TEXTURE, trackX, y + 2, TRACK_WIDTH, height - 2, 16*px, 1*px, 22*px, 2*px, 0xFFFFFFFF); - ScreenDrawing.rect(TEXTURE, trackX, y + height, TRACK_WIDTH, 1, 16*px, 2*px, 22*px, 3*px, 0xFFFFFFFF); - } else { - int trackY = y + height / 2 - TRACK_WIDTH / 2; + ScreenDrawing.rect(TEXTURE, trackX, y + 1, TRACK_WIDTH, 1, 16 * px, 0 * px, 22 * px, 1 * px, 0xFFFFFFFF); + ScreenDrawing.rect(TEXTURE, trackX, y + 2, TRACK_WIDTH, height - 2, 16 * px, 1 * px, 22 * px, 2 * px, 0xFFFFFFFF); + ScreenDrawing.rect(TEXTURE, trackX, y + height, TRACK_WIDTH, 1, 16 * px, 2 * px, 22 * px, 3 * px, 0xFFFFFFFF); + } else { + int trackY = y + height / 2 - TRACK_WIDTH / 2; - ScreenDrawing.rect(TEXTURE, x, trackY, 1, TRACK_WIDTH, 16*px, 3*px, 17*px, 9*px, 0xFFFFFFFF); - ScreenDrawing.rect(TEXTURE, x + 1, trackY, width - 2, TRACK_WIDTH, 17*px, 3*px, 18*px, 9*px, 0xFFFFFFFF); - ScreenDrawing.rect(TEXTURE, x + width - 1, trackY, 1, TRACK_WIDTH, 18*px, 3*px, 19*px, 9*px, 0xFFFFFFFF); + ScreenDrawing.rect(TEXTURE, x, trackY, 1, TRACK_WIDTH, 16 * px, 3 * px, 17 * px, 9 * px, 0xFFFFFFFF); + ScreenDrawing.rect(TEXTURE, x + 1, trackY, width - 2, TRACK_WIDTH, 17 * px, 3 * px, 18 * px, 9 * px, 0xFFFFFFFF); + ScreenDrawing.rect(TEXTURE, x + width - 1, trackY, 1, TRACK_WIDTH, 18 * px, 3 * px, 19 * px, 9 * px, 0xFFFFFFFF); + } } } + @Environment(EnvType.CLIENT) @Override public void paintForeground(int x, int y, int mouseX, int mouseY) { float px = 1 / 32f; @@ -133,7 +161,8 @@ public class WSlider extends WWidget { thumbXOffset = 8; } - // FIXME: Ugly, I really should remove this + boolean dragging = isFocused(); + // TODO: Replace with proper mouse events if (dragging) { if (GLFW.glfwGetMouseButton(MinecraftClient.getInstance().window.getHandle(), GLFW.GLFW_MOUSE_BUTTON_1) == GLFW.GLFW_PRESS) { onMouseDrag(mouseX - x, mouseY - y, 0); @@ -163,8 +192,13 @@ public class WSlider extends WWidget { return this; } - public WSlider setMouseReleaseListener(@Nullable Runnable mouseReleaseListener) { - this.mouseReleaseListener = mouseReleaseListener; + public WSlider setFocusReleaseListener(@Nullable Runnable focusReleaseListener) { + this.focusReleaseListener = focusReleaseListener; return this; } + + @Environment(EnvType.CLIENT) + public void setBackgroundPainter(BackgroundPainter backgroundPainter) { + this.backgroundPainter = backgroundPainter; + } } -- cgit From e6e0a169f43b20485f1bddf9993d21dd661f15d2 Mon Sep 17 00:00:00 2001 From: Juuxel Date: Tue, 27 Aug 2019 21:02:39 +0300 Subject: Revert some local changes, make slider paintBg formatting cleaner --- build.gradle | 6 +++--- .../java/io/github/cottonmc/cotton/gui/widget/WButton.java | 2 +- .../java/io/github/cottonmc/cotton/gui/widget/WSlider.java | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'src/main/java') diff --git a/build.gradle b/build.gradle index 580618e..ad484fd 100644 --- a/build.gradle +++ b/build.gradle @@ -17,13 +17,13 @@ buildscript { } plugins { - id 'fabric-loom' version '0.2.4-SNAPSHOT' + //id 'fabric-loom' version '0.2.4-SNAPSHOT' id 'maven-publish' id "com.jfrog.artifactory" version "4.9.0" } -//apply plugin: "fabric-loom"; +apply plugin: "fabric-loom"; sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 @@ -150,4 +150,4 @@ artifactory { } else { println "Cannot configure artifactory; please define ext.artifactoryUsername and ext.artifactoryPassword before running artifactoryPublish" } -} \ No newline at end of file +} diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WButton.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WButton.java index 16a8d71..0f5159c 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WButton.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WButton.java @@ -31,7 +31,7 @@ public class WButton extends WWidget { @Override public void paintForeground(int x, int y, int mouseX, int mouseY) { - //System.out.println("Mouse: { "+mouseX+", "+mouseY+" }"); + System.out.println("Mouse: { "+mouseX+", "+mouseY+" }"); boolean hovered = (mouseX>=x && mouseY>=y && mouseX Date: Tue, 27 Aug 2019 21:28:46 +0300 Subject: Some slider cleanup --- build.gradle | 2 +- src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) (limited to 'src/main/java') diff --git a/build.gradle b/build.gradle index ad484fd..c453a51 100644 --- a/build.gradle +++ b/build.gradle @@ -150,4 +150,4 @@ artifactory { } else { println "Cannot configure artifactory; please define ext.artifactoryUsername and ext.artifactoryPassword before running artifactoryPublish" } -} +} \ No newline at end of file diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java index e308b14..7de2deb 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java @@ -43,10 +43,6 @@ public class WSlider extends WWidget { @Nullable private BackgroundPainter backgroundPainter = null; - // Used for visuals and detecting dragging after the user starts dragging - // on top of the slider, but then moves the mouse out but still within the widget's boundary. -// private boolean dragging = false; - public WSlider(int min, int max, Axis axis) { if (max <= min) throw new IllegalArgumentException("Minimum value must be smaller than the maximum!"); @@ -96,10 +92,9 @@ public class WSlider extends WWidget { @Override public void onMouseDrag(int x, int y, int button) { if (isFocused()) { - //dragging = true; int pos = (axis == Axis.VERTICAL ? (height - y) : x) - THUMB_SIZE / 2; - int futureValue = min + (int) (valueToCoordRatio * pos); - value = MathHelper.clamp(futureValue, min, max); + int rawValue = min + (int) (valueToCoordRatio * pos); + value = MathHelper.clamp(rawValue, min, max); if (valueChangeListener != null) valueChangeListener.accept(value); } } -- cgit From 5172756942c1d5dc065afcc9be8d229e83ca1b44 Mon Sep 17 00:00:00 2001 From: Juuxel Date: Tue, 27 Aug 2019 21:30:41 +0300 Subject: Make some slider constants public --- src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java index 7de2deb..d475fe4 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java @@ -26,9 +26,9 @@ import java.util.function.IntConsumer; * */ public class WSlider extends WWidget { - private static final int TRACK_WIDTH = 6; - private static final int THUMB_SIZE = 8; - private static final Identifier TEXTURE = new Identifier("libgui", "textures/widget/slider.png"); + public static final int TRACK_WIDTH = 6; + public static final int THUMB_SIZE = 8; + public static final Identifier TEXTURE = new Identifier("libgui", "textures/widget/slider.png"); private final int min, max; private final int valueRange; -- cgit From dc70d8fbdc98a3f09dc9fb2477dc2210b8f82a25 Mon Sep 17 00:00:00 2001 From: Juuxel Date: Wed, 28 Aug 2019 19:07:35 +0300 Subject: Move thumb painting code to paintBg, remove fake mouse events --- .../cotton/gui/client/modmenu/ConfigGui.java | 4 +- .../github/cottonmc/cotton/gui/widget/WSlider.java | 60 +++++++++------------- 2 files changed, 26 insertions(+), 38 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java b/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java index 1b5bf42..9a95405 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java @@ -27,8 +27,8 @@ public class ConfigGui extends LightweightGuiDescription { WTextField testField = new WTextField(); testField.setSuggestion("test"); root.add(testField, 0, 3, 4, 1); - root.add(new WSlider(50, 100, Axis.VERTICAL).setValueChangeListener(System.out::println), 6, 0, 1, 3); - root.add(new WSlider(0, 123, Axis.HORIZONTAL).setValueChangeListener(System.out::println), 1, 4, 4, 1); + root.add(new WSlider(-150, -123, Axis.VERTICAL).setValueChangeListener(System.out::println), 6, 0, 1, 3); + root.add(new WSlider(-150, -123, Axis.HORIZONTAL).setValueChangeListener(System.out::println), 1, 4, 4, 1); root.add(new WKirbSprite(), 5, 4); diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java index d475fe4..d253cea 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java @@ -4,10 +4,8 @@ import io.github.cottonmc.cotton.gui.client.BackgroundPainter; import io.github.cottonmc.cotton.gui.client.ScreenDrawing; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.client.MinecraftClient; import net.minecraft.util.Identifier; import net.minecraft.util.math.MathHelper; -import org.lwjgl.glfw.GLFW; import javax.annotation.Nullable; import java.util.function.IntConsumer; @@ -118,60 +116,38 @@ public class WSlider extends WWidget { @Environment(EnvType.CLIENT) @Override - public void paintBackground(int x, int y) { + public void paintBackground(int x, int y, int mouseX, int mouseY) { if (backgroundPainter != null) { backgroundPainter.paintBackground(x, y, this); } else { float px = 1 / 32f; + int thumbX, thumbY, thumbXOffset; if (axis == Axis.VERTICAL) { int trackX = x + width / 2 - TRACK_WIDTH / 2; + thumbX = x + width / 2 - THUMB_SIZE / 2; + thumbY = y + height - THUMB_SIZE + 1 - (int) (coordToValueRatio * (value - min)); + thumbXOffset = 0; ScreenDrawing.rect(TEXTURE, trackX, y + 1, TRACK_WIDTH, 1, 16*px, 0*px, 22*px, 1*px, 0xFFFFFFFF); ScreenDrawing.rect(TEXTURE, trackX, y + 2, TRACK_WIDTH, height - 2, 16*px, 1*px, 22*px, 2*px, 0xFFFFFFFF); ScreenDrawing.rect(TEXTURE, trackX, y + height, TRACK_WIDTH, 1, 16*px, 2*px, 22*px, 3*px, 0xFFFFFFFF); } else { int trackY = y + height / 2 - TRACK_WIDTH / 2; + thumbX = x + (int) (coordToValueRatio * (value - min)); + thumbY = y + height / 2 - THUMB_SIZE / 2; + thumbXOffset = 8; ScreenDrawing.rect(TEXTURE, x, trackY, 1, TRACK_WIDTH, 16*px, 3*px, 17*px, 9*px, 0xFFFFFFFF); ScreenDrawing.rect(TEXTURE, x + 1, trackY, width - 2, TRACK_WIDTH, 17*px, 3*px, 18*px, 9*px, 0xFFFFFFFF); ScreenDrawing.rect(TEXTURE, x + width - 1, trackY, 1, TRACK_WIDTH, 18*px, 3*px, 19*px, 9*px, 0xFFFFFFFF); } - } - } - @Environment(EnvType.CLIENT) - @Override - public void paintForeground(int x, int y, int mouseX, int mouseY) { - float px = 1 / 32f; - int thumbX, thumbY, thumbXOffset; - - if (axis == Axis.VERTICAL) { - thumbX = x + width / 2 - THUMB_SIZE / 2; - thumbY = y + height - THUMB_SIZE + 1 - (int) (coordToValueRatio * (value - min)); - thumbXOffset = 0; - } else { - thumbX = x + (int) (coordToValueRatio * (value - min)); - thumbY = y + height / 2 - THUMB_SIZE / 2; - thumbXOffset = 8; - } - - boolean dragging = isFocused(); - // TODO: Replace with proper mouse events - if (dragging) { - if (GLFW.glfwGetMouseButton(MinecraftClient.getInstance().window.getHandle(), GLFW.GLFW_MOUSE_BUTTON_1) == GLFW.GLFW_PRESS) { - onMouseDrag(mouseX - x, mouseY - y, 0); - } else { - onMouseUp(mouseX - x, mouseY - y, 0); - } + // thumbState values: + // 0: default, 1: dragging, 2: hovered + int thumbState = isFocused() ? 1 : (mouseX >= thumbX && mouseX <= thumbX + THUMB_SIZE && mouseY >= thumbY && mouseY <= thumbY + THUMB_SIZE ? 2 : 0); + ScreenDrawing.rect(TEXTURE, thumbX, thumbY, THUMB_SIZE, THUMB_SIZE, thumbXOffset*px, 0*px + thumbState * 8*px, (thumbXOffset + 8)*px, 8*px + thumbState * 8*px, 0xFFFFFFFF); } - - // thumbState values: - // 0: default, 1: dragging, 2: hovered - int thumbState = dragging ? 1 : (mouseX >= thumbX && mouseX <= thumbX + THUMB_SIZE && mouseY >= thumbY && mouseY <= thumbY + THUMB_SIZE ? 2 : 0); - ScreenDrawing.rect(TEXTURE, thumbX, thumbY, THUMB_SIZE, THUMB_SIZE, thumbXOffset*px, 0*px + thumbState * 8*px, (thumbXOffset + 8)*px, 8*px + thumbState * 8*px, 0xFFFFFFFF); - - super.paintForeground(x, y, mouseX, mouseY); } public int getValue() { @@ -192,6 +168,18 @@ public class WSlider extends WWidget { return this; } + public int getMinValue() { + return min; + } + + public int getMaxValue() { + return max; + } + + public Axis getAxis() { + return axis; + } + @Environment(EnvType.CLIENT) public void setBackgroundPainter(BackgroundPainter backgroundPainter) { this.backgroundPainter = backgroundPainter; -- cgit From 01092d934ade473813b02825f4ea42749b5ed324 Mon Sep 17 00:00:00 2001 From: Juuxel Date: Wed, 28 Aug 2019 19:09:39 +0300 Subject: Remove star import in ConfigGui --- .../io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/main/java') diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java b/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java index 9a95405..674cb32 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java @@ -3,7 +3,12 @@ package io.github.cottonmc.cotton.gui.client.modmenu; import io.github.cottonmc.cotton.gui.client.BackgroundPainter; import io.github.cottonmc.cotton.gui.client.LibGuiClient; import io.github.cottonmc.cotton.gui.client.LightweightGuiDescription; -import io.github.cottonmc.cotton.gui.widget.*; +import io.github.cottonmc.cotton.gui.widget.Axis; +import io.github.cottonmc.cotton.gui.widget.WButton; +import io.github.cottonmc.cotton.gui.widget.WGridPanel; +import io.github.cottonmc.cotton.gui.widget.WSlider; +import io.github.cottonmc.cotton.gui.widget.WTextField; +import io.github.cottonmc.cotton.gui.widget.WToggleButton; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; import net.minecraft.text.TranslatableText; -- cgit From d7cbe76961b9927ced3398761ba448a898cbd782 Mon Sep 17 00:00:00 2001 From: Juuxel Date: Wed, 28 Aug 2019 19:33:43 +0300 Subject: Fix issues with small value ranges, only fire needed value change events --- .../cottonmc/cotton/gui/client/modmenu/ConfigGui.java | 4 ++-- .../io/github/cottonmc/cotton/gui/widget/WSlider.java | 17 ++++++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java b/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java index 674cb32..2bca040 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java @@ -32,8 +32,8 @@ public class ConfigGui extends LightweightGuiDescription { WTextField testField = new WTextField(); testField.setSuggestion("test"); root.add(testField, 0, 3, 4, 1); - root.add(new WSlider(-150, -123, Axis.VERTICAL).setValueChangeListener(System.out::println), 6, 0, 1, 3); - root.add(new WSlider(-150, -123, Axis.HORIZONTAL).setValueChangeListener(System.out::println), 1, 4, 4, 1); + root.add(new WSlider(-1, 1, Axis.VERTICAL).setValueChangeListener(System.out::println), 6, 0, 1, 3); + root.add(new WSlider(-1, 0, Axis.HORIZONTAL).setValueChangeListener(System.out::println), 1, 4, 4, 1); root.add(new WKirbSprite(), 5, 4); diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java index d253cea..26574dd 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java @@ -33,7 +33,17 @@ public class WSlider extends WWidget { private final Axis axis; private int value; - private float valueToCoordRatio, coordToValueRatio; + + /** + * A value:coordinate ratio. Used for converting user input into values. + */ + private float valueToCoordRatio; + + /** + * A coordinate:value ratio. Used for rendering the thumb. + */ + private float coordToValueRatio; + @Nullable private IntConsumer valueChangeListener = null; @Nullable private Runnable focusReleaseListener = null; @@ -47,7 +57,7 @@ public class WSlider extends WWidget { this.min = min; this.max = max; - this.valueRange = max - min + 1; + this.valueRange = max - min; this.axis = axis; this.value = min; } @@ -92,8 +102,9 @@ public class WSlider extends WWidget { if (isFocused()) { int pos = (axis == Axis.VERTICAL ? (height - y) : x) - THUMB_SIZE / 2; int rawValue = min + (int) (valueToCoordRatio * pos); + int previousValue = value; value = MathHelper.clamp(rawValue, min, max); - if (valueChangeListener != null) valueChangeListener.accept(value); + if (value != previousValue && valueChangeListener != null) valueChangeListener.accept(value); } } -- cgit From e71d2283b1eb16bc769e51910e2a400817021819 Mon Sep 17 00:00:00 2001 From: Juuxel Date: Wed, 28 Aug 2019 20:56:47 +0300 Subject: Sliders: Add keyboard support, fix clicking, highlight when focused --- .../cotton/gui/client/modmenu/ConfigGui.java | 2 +- .../github/cottonmc/cotton/gui/widget/WSlider.java | 80 ++++++++++++++++----- .../assets/libgui/textures/widget/slider.png | Bin 2295 -> 2597 bytes 3 files changed, 62 insertions(+), 20 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java b/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java index 2bca040..fc3e3b5 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java @@ -33,7 +33,7 @@ public class ConfigGui extends LightweightGuiDescription { testField.setSuggestion("test"); root.add(testField, 0, 3, 4, 1); root.add(new WSlider(-1, 1, Axis.VERTICAL).setValueChangeListener(System.out::println), 6, 0, 1, 3); - root.add(new WSlider(-1, 0, Axis.HORIZONTAL).setValueChangeListener(System.out::println), 1, 4, 4, 1); + root.add(new WSlider(1, 2, Axis.HORIZONTAL).setValueChangeListener(System.out::println), 1, 4, 4, 1); root.add(new WKirbSprite(), 5, 4); diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java index 26574dd..d981304 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java @@ -6,6 +6,7 @@ import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.util.Identifier; import net.minecraft.util.math.MathHelper; +import org.lwjgl.glfw.GLFW; import javax.annotation.Nullable; import java.util.function.IntConsumer; @@ -15,7 +16,9 @@ import java.util.function.IntConsumer; * *

You can set two listeners on a slider: *

    - *
  • A value change listener that gets all value changes (except direct setValue calls)
  • + *
  • + * A value change listener that gets all value changes (except direct setValue calls). + *
  • *
  • * A focus release listener that gets called when the player stops dragging the slider. * For example, this can be used for sending sync packets to the server @@ -29,11 +32,16 @@ public class WSlider extends WWidget { public static final Identifier TEXTURE = new Identifier("libgui", "textures/widget/slider.png"); private final int min, max; - private final int valueRange; private final Axis axis; private int value; + /** + * True if the user is currently dragging the thumb. + * Used for visuals. + */ + private boolean dragging = false; + /** * A value:coordinate ratio. Used for converting user input into values. */ @@ -57,7 +65,6 @@ public class WSlider extends WWidget { this.min = min; this.max = max; - this.valueRange = max - min; this.axis = axis; this.value = min; } @@ -70,7 +77,7 @@ public class WSlider extends WWidget { public void setSize(int x, int y) { super.setSize(x, y); int trackHeight = (axis == Axis.HORIZONTAL ? x : y) - THUMB_SIZE + 1; - valueToCoordRatio = (float) valueRange / trackHeight; + valueToCoordRatio = (float) (max - min) / trackHeight; coordToValueRatio = 1 / valueToCoordRatio; } @@ -100,23 +107,27 @@ public class WSlider extends WWidget { @Override public void onMouseDrag(int x, int y, int button) { if (isFocused()) { - int pos = (axis == Axis.VERTICAL ? (height - y) : x) - THUMB_SIZE / 2; - int rawValue = min + (int) (valueToCoordRatio * pos); - int previousValue = value; - value = MathHelper.clamp(rawValue, min, max); - if (value != previousValue && valueChangeListener != null) valueChangeListener.accept(value); + dragging = true; + moveSlider(x, y); } } @Override public void onClick(int x, int y, int button) { - onMouseDrag(x, y, button); - onMouseUp(x, y, button); + moveSlider(x, y); + } + + private void moveSlider(int x, int y) { + int pos = (axis == Axis.VERTICAL ? (height - y) : x) - THUMB_SIZE / 2; + int rawValue = min + Math.round(valueToCoordRatio * pos); + int previousValue = value; + value = MathHelper.clamp(rawValue, min, max); + if (value != previousValue && valueChangeListener != null) valueChangeListener.accept(value); } @Override public WWidget onMouseUp(int x, int y, int button) { - releaseFocus(); + dragging = false; return super.onMouseUp(x, y, button); } @@ -132,12 +143,15 @@ public class WSlider extends WWidget { backgroundPainter.paintBackground(x, y, this); } else { float px = 1 / 32f; - int thumbX, thumbY, thumbXOffset; + // thumbX/Y: thumb position in widget-space + int thumbX, thumbY; + // thumbXOffset: thumb texture x offset in pixels + int thumbXOffset; if (axis == Axis.VERTICAL) { int trackX = x + width / 2 - TRACK_WIDTH / 2; - thumbX = x + width / 2 - THUMB_SIZE / 2; - thumbY = y + height - THUMB_SIZE + 1 - (int) (coordToValueRatio * (value - min)); + thumbX = width / 2 - THUMB_SIZE / 2; + thumbY = height - THUMB_SIZE + 1 - (int) (coordToValueRatio * (value - min)); thumbXOffset = 0; ScreenDrawing.rect(TEXTURE, trackX, y + 1, TRACK_WIDTH, 1, 16*px, 0*px, 22*px, 1*px, 0xFFFFFFFF); @@ -145,8 +159,8 @@ public class WSlider extends WWidget { ScreenDrawing.rect(TEXTURE, trackX, y + height, TRACK_WIDTH, 1, 16*px, 2*px, 22*px, 3*px, 0xFFFFFFFF); } else { int trackY = y + height / 2 - TRACK_WIDTH / 2; - thumbX = x + (int) (coordToValueRatio * (value - min)); - thumbY = y + height / 2 - THUMB_SIZE / 2; + thumbX = (int) (coordToValueRatio * (value - min)); + thumbY = height / 2 - THUMB_SIZE / 2; thumbXOffset = 8; ScreenDrawing.rect(TEXTURE, x, trackY, 1, TRACK_WIDTH, 16*px, 3*px, 17*px, 9*px, 0xFFFFFFFF); @@ -156,8 +170,12 @@ public class WSlider extends WWidget { // thumbState values: // 0: default, 1: dragging, 2: hovered - int thumbState = isFocused() ? 1 : (mouseX >= thumbX && mouseX <= thumbX + THUMB_SIZE && mouseY >= thumbY && mouseY <= thumbY + THUMB_SIZE ? 2 : 0); - ScreenDrawing.rect(TEXTURE, thumbX, thumbY, THUMB_SIZE, THUMB_SIZE, thumbXOffset*px, 0*px + thumbState * 8*px, (thumbXOffset + 8)*px, 8*px + thumbState * 8*px, 0xFFFFFFFF); + int thumbState = dragging ? 1 : (mouseX >= thumbX && mouseX <= thumbX + THUMB_SIZE && mouseY >= thumbY && mouseY <= thumbY + THUMB_SIZE ? 2 : 0); + ScreenDrawing.rect(TEXTURE, x + thumbX, y + thumbY, THUMB_SIZE, THUMB_SIZE, thumbXOffset*px, 0*px + thumbState * 8*px, (thumbXOffset + 8)*px, 8*px + thumbState * 8*px, 0xFFFFFFFF); + + if (thumbState == 0 && isFocused()) { + ScreenDrawing.rect(TEXTURE, x + thumbX, y + thumbY, THUMB_SIZE, THUMB_SIZE, 0*px, 24*px, 8*px, 32*px, 0xFFFFFFFF); + } } } @@ -195,4 +213,28 @@ public class WSlider extends WWidget { public void setBackgroundPainter(BackgroundPainter backgroundPainter) { this.backgroundPainter = backgroundPainter; } + + @Override + public void onKeyPressed(int ch, int key, int modifiers) { + boolean valueChanged = false; + if (modifiers == 0) { + if ((ch == GLFW.GLFW_KEY_LEFT || ch == GLFW.GLFW_KEY_DOWN) && value > min) { + value--; + valueChanged = true; + } else if ((ch == GLFW.GLFW_KEY_RIGHT || ch == GLFW.GLFW_KEY_UP) && value < max) { + value++; + valueChanged = true; + } + } else if (modifiers == GLFW.GLFW_MOD_CONTROL) { + if ((ch == GLFW.GLFW_KEY_LEFT || ch == GLFW.GLFW_KEY_DOWN) && value != min) { + value = min; + valueChanged = true; + } else if ((ch == GLFW.GLFW_KEY_RIGHT || ch == GLFW.GLFW_KEY_UP) && value != max) { + value = max; + valueChanged = true; + } + } + + if (valueChanged && valueChangeListener != null) valueChangeListener.accept(value); + } } diff --git a/src/main/resources/assets/libgui/textures/widget/slider.png b/src/main/resources/assets/libgui/textures/widget/slider.png index d118877..ce8f434 100644 Binary files a/src/main/resources/assets/libgui/textures/widget/slider.png and b/src/main/resources/assets/libgui/textures/widget/slider.png differ -- cgit From 3632ccf292634fa785982a1d61e8cb8647a497e0 Mon Sep 17 00:00:00 2001 From: Juuxel Date: Wed, 28 Aug 2019 22:19:44 +0300 Subject: Add WAbstractSlider and do some initial code for labeled sliders --- .../cotton/gui/client/modmenu/ConfigGui.java | 5 +- .../cotton/gui/widget/WAbstractSlider.java | 185 +++++++++++++++++++++ .../cottonmc/cotton/gui/widget/WLabeledSlider.java | 80 +++++++++ .../github/cottonmc/cotton/gui/widget/WSlider.java | 147 +--------------- 4 files changed, 274 insertions(+), 143 deletions(-) create mode 100644 src/main/java/io/github/cottonmc/cotton/gui/widget/WAbstractSlider.java create mode 100644 src/main/java/io/github/cottonmc/cotton/gui/widget/WLabeledSlider.java (limited to 'src/main/java') diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java b/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java index fc3e3b5..97b3cfc 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java @@ -6,6 +6,7 @@ import io.github.cottonmc.cotton.gui.client.LightweightGuiDescription; import io.github.cottonmc.cotton.gui.widget.Axis; import io.github.cottonmc.cotton.gui.widget.WButton; import io.github.cottonmc.cotton.gui.widget.WGridPanel; +import io.github.cottonmc.cotton.gui.widget.WLabeledSlider; import io.github.cottonmc.cotton.gui.widget.WSlider; import io.github.cottonmc.cotton.gui.widget.WTextField; import io.github.cottonmc.cotton.gui.widget.WToggleButton; @@ -32,8 +33,8 @@ public class ConfigGui extends LightweightGuiDescription { WTextField testField = new WTextField(); testField.setSuggestion("test"); root.add(testField, 0, 3, 4, 1); - root.add(new WSlider(-1, 1, Axis.VERTICAL).setValueChangeListener(System.out::println), 6, 0, 1, 3); - root.add(new WSlider(1, 2, Axis.HORIZONTAL).setValueChangeListener(System.out::println), 1, 4, 4, 1); + root.add(new WSlider(-100, 100, Axis.VERTICAL).setValueChangeListener(System.out::println), 6, 0, 1, 3); + root.add(new WLabeledSlider(1, 100).setValueChangeListener(System.out::println), 1, 4, 4, 1); root.add(new WKirbSprite(), 5, 4); diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WAbstractSlider.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WAbstractSlider.java new file mode 100644 index 0000000..bfa455e --- /dev/null +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WAbstractSlider.java @@ -0,0 +1,185 @@ +package io.github.cottonmc.cotton.gui.widget; + +import net.minecraft.util.math.MathHelper; +import org.lwjgl.glfw.GLFW; + +import javax.annotation.Nullable; +import java.util.function.IntConsumer; + +/** + * A base class for slider widgets that can be used to select int values. + * + *

    You can set two listeners on a slider: + *

      + *
    • + * A value change listener that gets all value changes (except direct setValue calls). + *
    • + *
    • + * A focus release listener that gets called when the player stops dragging the slider. + * For example, this can be used for sending sync packets to the server + * when the player has selected a value. + *
    • + *
    + */ +public abstract class WAbstractSlider extends WWidget { + protected final int min, max; + protected final Axis axis; + + protected int value; + + /** + * True if the user is currently dragging the thumb. + * Used for visuals. + */ + protected boolean dragging = false; + + /** + * A value:coordinate ratio. Used for converting user input into values. + */ + protected float valueToCoordRatio; + + /** + * A coordinate:value ratio. Used for rendering the thumb. + */ + protected float coordToValueRatio; + + @Nullable private IntConsumer valueChangeListener = null; + @Nullable private Runnable focusReleaseListener = null; + + protected WAbstractSlider(int min, int max, Axis axis) { + if (max <= min) + throw new IllegalArgumentException("Minimum value must be smaller than the maximum!"); + + this.min = min; + this.max = max; + this.axis = axis; + this.value = min; + } + + /** + * @return the thumb size along the slider axis + */ + protected abstract int getThumbWidth(); + + /** + * Checks if the mouse cursor is close enough to the slider that the user can start dragging. + * + * @param x the mouse x position + * @param y the mouse y position + * @return if the cursor is inside dragging bounds + */ + protected abstract boolean isMouseInsideBounds(int x, int y); + + @Override + public void setSize(int x, int y) { + super.setSize(x, y); + int trackHeight = (axis == Axis.HORIZONTAL ? x : y) - getThumbWidth() + 1; + valueToCoordRatio = (float) (max - min) / trackHeight; + coordToValueRatio = 1 / valueToCoordRatio; + } + + @Override + public boolean canResize() { + return true; + } + + @Override + public boolean canFocus() { + return true; + } + + @Override + public WWidget onMouseDown(int x, int y, int button) { + // Check if cursor is inside or <=2px away from track + if (isMouseInsideBounds(x, y)) { + requestFocus(); + } + return super.onMouseDown(x, y, button); + } + + @Override + public void onMouseDrag(int x, int y, int button) { + if (isFocused()) { + dragging = true; + moveSlider(x, y); + } + } + + @Override + public void onClick(int x, int y, int button) { + moveSlider(x, y); + } + + private void moveSlider(int x, int y) { + int pos = (axis == Axis.VERTICAL ? (height - y) : x) - getThumbWidth() / 2; + int rawValue = min + Math.round(valueToCoordRatio * pos); + int previousValue = value; + value = MathHelper.clamp(rawValue, min, max); + if (value != previousValue && valueChangeListener != null) valueChangeListener.accept(value); + } + + @Override + public WWidget onMouseUp(int x, int y, int button) { + dragging = false; + return super.onMouseUp(x, y, button); + } + + @Override + public void onFocusLost() { + if (focusReleaseListener != null) focusReleaseListener.run(); + } + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + public WAbstractSlider setValueChangeListener(@Nullable IntConsumer valueChangeListener) { + this.valueChangeListener = valueChangeListener; + return this; + } + + public WAbstractSlider setFocusReleaseListener(@Nullable Runnable focusReleaseListener) { + this.focusReleaseListener = focusReleaseListener; + return this; + } + + public int getMinValue() { + return min; + } + + public int getMaxValue() { + return max; + } + + public Axis getAxis() { + return axis; + } + + @Override + public void onKeyPressed(int ch, int key, int modifiers) { + boolean valueChanged = false; + if (modifiers == 0) { + if ((ch == GLFW.GLFW_KEY_LEFT || ch == GLFW.GLFW_KEY_DOWN) && value > min) { + value--; + valueChanged = true; + } else if ((ch == GLFW.GLFW_KEY_RIGHT || ch == GLFW.GLFW_KEY_UP) && value < max) { + value++; + valueChanged = true; + } + } else if (modifiers == GLFW.GLFW_MOD_CONTROL) { + if ((ch == GLFW.GLFW_KEY_LEFT || ch == GLFW.GLFW_KEY_DOWN) && value != min) { + value = min; + valueChanged = true; + } else if ((ch == GLFW.GLFW_KEY_RIGHT || ch == GLFW.GLFW_KEY_UP) && value != max) { + value = max; + valueChanged = true; + } + } + + if (valueChanged && valueChangeListener != null) valueChangeListener.accept(value); + } +} diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WLabeledSlider.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WLabeledSlider.java new file mode 100644 index 0000000..77a3325 --- /dev/null +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WLabeledSlider.java @@ -0,0 +1,80 @@ +package io.github.cottonmc.cotton.gui.widget; + +import io.github.cottonmc.cotton.gui.client.ScreenDrawing; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.gui.widget.AbstractButtonWidget; +import net.minecraft.util.Identifier; + +/** + * A vanilla-style labeled slider widget. + * + * @see WAbstractSlider for more information about listeners + */ +/* + TODO: + - Add the labels + - Better textures for thumbs when dragging + - The thumb goes 1px outside the track on the right side + */ +public class WLabeledSlider extends WAbstractSlider { + private static final Identifier TEXTURE = AbstractButtonWidget.WIDGETS_LOCATION; + + public WLabeledSlider(int min, int max) { + super(min, max, Axis.HORIZONTAL); + } + + public WLabeledSlider(int max) { + this(0, max); + } + + @Override + public void setSize(int x, int y) { + super.setSize(x, 20); + } + + @Override + protected int getThumbWidth() { + return 6; + } + + @Override + protected boolean isMouseInsideBounds(int x, int y) { + return x >= 0 && x <= width && y >= 0 && y <= height; + } + + @Environment(EnvType.CLIENT) + @Override + public void paintBackground(int x, int y, int mouseX, int mouseY) { + drawButton(x, y, 0, width); + + // 1: regular, 2: hovered, 0: disabled/dragging + int thumbX = (int) (coordToValueRatio * (value - min)); + int thumbY = 0; + int thumbWidth = getThumbWidth(); + int thumbHeight = height; + int thumbState = dragging ? 0 : (mouseX >= thumbX && mouseX <= thumbX + thumbWidth && mouseY >= thumbY && mouseY <= thumbY + thumbHeight ? 2 : 1); + + drawButton(x + thumbX, y + thumbY, thumbState, thumbWidth); + + if (thumbState == 1 && isFocused()) { + // TODO: draw the focus border + } + } + + // state = 1: regular, 2: hovered, 0: disabled/dragging + @Environment(EnvType.CLIENT) + private void drawButton(int x, int y, int state, int width) { + float px = 1 / 256f; + float buttonLeft = 0 * px; + float buttonTop = (46 + (state * 20)) * px; + int halfWidth = width / 2; + if (halfWidth > 198) halfWidth = 198; + float buttonWidth = halfWidth * px; + float buttonHeight = 20 * px; + float buttonEndLeft = (200 - halfWidth) * px; + + ScreenDrawing.rect(AbstractButtonWidget.WIDGETS_LOCATION, x, y, halfWidth, 20, buttonLeft, buttonTop, buttonLeft + buttonWidth, buttonTop + buttonHeight, 0xFFFFFFFF); + ScreenDrawing.rect(AbstractButtonWidget.WIDGETS_LOCATION, x + halfWidth, y, halfWidth, 20, buttonEndLeft, buttonTop, 200 * px, buttonTop + buttonHeight, 0xFFFFFFFF); + } +} diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java index d981304..14e9972 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java @@ -5,11 +5,8 @@ import io.github.cottonmc.cotton.gui.client.ScreenDrawing; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.util.Identifier; -import net.minecraft.util.math.MathHelper; -import org.lwjgl.glfw.GLFW; import javax.annotation.Nullable; -import java.util.function.IntConsumer; /** * A slider widget that can be used to select int values. @@ -26,47 +23,17 @@ import java.util.function.IntConsumer; *
  • *
*/ -public class WSlider extends WWidget { +public class WSlider extends WAbstractSlider { public static final int TRACK_WIDTH = 6; public static final int THUMB_SIZE = 8; public static final Identifier TEXTURE = new Identifier("libgui", "textures/widget/slider.png"); - private final int min, max; - private final Axis axis; - - private int value; - - /** - * True if the user is currently dragging the thumb. - * Used for visuals. - */ - private boolean dragging = false; - - /** - * A value:coordinate ratio. Used for converting user input into values. - */ - private float valueToCoordRatio; - - /** - * A coordinate:value ratio. Used for rendering the thumb. - */ - private float coordToValueRatio; - - @Nullable private IntConsumer valueChangeListener = null; - @Nullable private Runnable focusReleaseListener = null; - @Environment(EnvType.CLIENT) @Nullable private BackgroundPainter backgroundPainter = null; public WSlider(int min, int max, Axis axis) { - if (max <= min) - throw new IllegalArgumentException("Minimum value must be smaller than the maximum!"); - - this.min = min; - this.max = max; - this.axis = axis; - this.value = min; + super(min, max, axis); } public WSlider(int max, Axis axis) { @@ -74,66 +41,18 @@ public class WSlider extends WWidget { } @Override - public void setSize(int x, int y) { - super.setSize(x, y); - int trackHeight = (axis == Axis.HORIZONTAL ? x : y) - THUMB_SIZE + 1; - valueToCoordRatio = (float) (max - min) / trackHeight; - coordToValueRatio = 1 / valueToCoordRatio; - } - - @Override - public boolean canResize() { - return true; - } - - @Override - public boolean canFocus() { - return true; + protected int getThumbWidth() { + return THUMB_SIZE; } @Override - public WWidget onMouseDown(int x, int y, int button) { + protected boolean isMouseInsideBounds(int x, int y) { // ao = axis-opposite mouse coordinate, aoCenter = center of ao's axis int ao = axis == Axis.HORIZONTAL ? y : x; int aoCenter = (axis == Axis.HORIZONTAL ? height : width) / 2; // Check if cursor is inside or <=2px away from track - if (ao >= aoCenter - TRACK_WIDTH / 2 - 2 && ao <= aoCenter + TRACK_WIDTH / 2 + 2) { - requestFocus(); - } - return super.onMouseDown(x, y, button); - } - - @Override - public void onMouseDrag(int x, int y, int button) { - if (isFocused()) { - dragging = true; - moveSlider(x, y); - } - } - - @Override - public void onClick(int x, int y, int button) { - moveSlider(x, y); - } - - private void moveSlider(int x, int y) { - int pos = (axis == Axis.VERTICAL ? (height - y) : x) - THUMB_SIZE / 2; - int rawValue = min + Math.round(valueToCoordRatio * pos); - int previousValue = value; - value = MathHelper.clamp(rawValue, min, max); - if (value != previousValue && valueChangeListener != null) valueChangeListener.accept(value); - } - - @Override - public WWidget onMouseUp(int x, int y, int button) { - dragging = false; - return super.onMouseUp(x, y, button); - } - - @Override - public void onFocusLost() { - if (focusReleaseListener != null) focusReleaseListener.run(); + return ao >= aoCenter - TRACK_WIDTH / 2 - 2 && ao <= aoCenter + TRACK_WIDTH / 2 + 2; } @Environment(EnvType.CLIENT) @@ -179,62 +98,8 @@ public class WSlider extends WWidget { } } - public int getValue() { - return value; - } - - public void setValue(int value) { - this.value = value; - } - - public WSlider setValueChangeListener(@Nullable IntConsumer valueChangeListener) { - this.valueChangeListener = valueChangeListener; - return this; - } - - public WSlider setFocusReleaseListener(@Nullable Runnable focusReleaseListener) { - this.focusReleaseListener = focusReleaseListener; - return this; - } - - public int getMinValue() { - return min; - } - - public int getMaxValue() { - return max; - } - - public Axis getAxis() { - return axis; - } - @Environment(EnvType.CLIENT) public void setBackgroundPainter(BackgroundPainter backgroundPainter) { this.backgroundPainter = backgroundPainter; } - - @Override - public void onKeyPressed(int ch, int key, int modifiers) { - boolean valueChanged = false; - if (modifiers == 0) { - if ((ch == GLFW.GLFW_KEY_LEFT || ch == GLFW.GLFW_KEY_DOWN) && value > min) { - value--; - valueChanged = true; - } else if ((ch == GLFW.GLFW_KEY_RIGHT || ch == GLFW.GLFW_KEY_UP) && value < max) { - value++; - valueChanged = true; - } - } else if (modifiers == GLFW.GLFW_MOD_CONTROL) { - if ((ch == GLFW.GLFW_KEY_LEFT || ch == GLFW.GLFW_KEY_DOWN) && value != min) { - value = min; - valueChanged = true; - } else if ((ch == GLFW.GLFW_KEY_RIGHT || ch == GLFW.GLFW_KEY_UP) && value != max) { - value = max; - valueChanged = true; - } - } - - if (valueChanged && valueChangeListener != null) valueChangeListener.accept(value); - } } -- cgit From 4c7158c99f0186a8ed7dd2fd37db4b6df4164f4c Mon Sep 17 00:00:00 2001 From: Juuxel Date: Thu, 29 Aug 2019 12:11:03 +0300 Subject: Sliders are done! --- .../cotton/gui/client/modmenu/ConfigGui.java | 19 ++++-- .../cotton/gui/widget/WAbstractSlider.java | 65 ++++++++++++++------- .../cottonmc/cotton/gui/widget/WLabeledSlider.java | 64 +++++++++++++++----- .../github/cottonmc/cotton/gui/widget/WSlider.java | 16 +---- .../assets/libgui/textures/widget/slider.png | Bin 2597 -> 2978 bytes 5 files changed, 112 insertions(+), 52 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java b/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java index 97b3cfc..b8abd22 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java @@ -3,11 +3,8 @@ package io.github.cottonmc.cotton.gui.client.modmenu; import io.github.cottonmc.cotton.gui.client.BackgroundPainter; import io.github.cottonmc.cotton.gui.client.LibGuiClient; import io.github.cottonmc.cotton.gui.client.LightweightGuiDescription; -import io.github.cottonmc.cotton.gui.widget.Axis; import io.github.cottonmc.cotton.gui.widget.WButton; import io.github.cottonmc.cotton.gui.widget.WGridPanel; -import io.github.cottonmc.cotton.gui.widget.WLabeledSlider; -import io.github.cottonmc.cotton.gui.widget.WSlider; import io.github.cottonmc.cotton.gui.widget.WTextField; import io.github.cottonmc.cotton.gui.widget.WToggleButton; import net.minecraft.client.MinecraftClient; @@ -33,8 +30,20 @@ public class ConfigGui extends LightweightGuiDescription { WTextField testField = new WTextField(); testField.setSuggestion("test"); root.add(testField, 0, 3, 4, 1); - root.add(new WSlider(-100, 100, Axis.VERTICAL).setValueChangeListener(System.out::println), 6, 0, 1, 3); - root.add(new WLabeledSlider(1, 100).setValueChangeListener(System.out::println), 1, 4, 4, 1); + + /* + WSlider verticalSlider = new WSlider(-100, 100, Axis.VERTICAL); + verticalSlider.setDraggingFinishedListener(() -> System.out.println("Mouse released")); + verticalSlider.setValueChangeListener(System.out::println); + + WLabeledSlider horizontalSlider = new WLabeledSlider(0, 500); + horizontalSlider.setLabelUpdater(value -> new LiteralText(value + "!")); + horizontalSlider.setDraggingFinishedListener(() -> System.out.println("Mouse released")); + horizontalSlider.setValue(250); + + root.add(verticalSlider, 6, 0, 1, 3); + root.add(horizontalSlider, 1, 4, 4, 1); + */ root.add(new WKirbSprite(), 5, 4); diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WAbstractSlider.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WAbstractSlider.java index bfa455e..074371f 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WAbstractSlider.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WAbstractSlider.java @@ -12,10 +12,11 @@ import java.util.function.IntConsumer; *

You can set two listeners on a slider: *

    *
  • - * A value change listener that gets all value changes (except direct setValue calls). + * A value change listener that gets all value changes (including direct setValue calls). *
  • *
  • - * A focus release listener that gets called when the player stops dragging the slider. + * A dragging finished listener that gets called when the player stops dragging the slider + * or modifies the value with the keyboard. * For example, this can be used for sending sync packets to the server * when the player has selected a value. *
  • @@ -43,8 +44,13 @@ public abstract class WAbstractSlider extends WWidget { */ protected float coordToValueRatio; + /** + * True if there is a pending dragging finished event caused by the keyboard. + */ + private boolean valueChangedWithKeys = false; + @Nullable private IntConsumer valueChangeListener = null; - @Nullable private Runnable focusReleaseListener = null; + @Nullable private Runnable draggingFinishedListener = null; protected WAbstractSlider(int min, int max, Axis axis) { if (max <= min) @@ -73,7 +79,7 @@ public abstract class WAbstractSlider extends WWidget { @Override public void setSize(int x, int y) { super.setSize(x, y); - int trackHeight = (axis == Axis.HORIZONTAL ? x : y) - getThumbWidth() + 1; + int trackHeight = (axis == Axis.HORIZONTAL ? x : y) - getThumbWidth(); valueToCoordRatio = (float) (max - min) / trackHeight; coordToValueRatio = 1 / valueToCoordRatio; } @@ -108,6 +114,7 @@ public abstract class WAbstractSlider extends WWidget { @Override public void onClick(int x, int y, int button) { moveSlider(x, y); + if (draggingFinishedListener != null) draggingFinishedListener.run(); } private void moveSlider(int x, int y) { @@ -115,36 +122,31 @@ public abstract class WAbstractSlider extends WWidget { int rawValue = min + Math.round(valueToCoordRatio * pos); int previousValue = value; value = MathHelper.clamp(rawValue, min, max); - if (value != previousValue && valueChangeListener != null) valueChangeListener.accept(value); + if (value != previousValue) onValueChanged(value); } @Override public WWidget onMouseUp(int x, int y, int button) { dragging = false; + if (draggingFinishedListener != null) draggingFinishedListener.run(); return super.onMouseUp(x, y, button); } - @Override - public void onFocusLost() { - if (focusReleaseListener != null) focusReleaseListener.run(); - } - public int getValue() { return value; } public void setValue(int value) { this.value = value; + onValueChanged(value); } - public WAbstractSlider setValueChangeListener(@Nullable IntConsumer valueChangeListener) { + public void setValueChangeListener(@Nullable IntConsumer valueChangeListener) { this.valueChangeListener = valueChangeListener; - return this; } - public WAbstractSlider setFocusReleaseListener(@Nullable Runnable focusReleaseListener) { - this.focusReleaseListener = focusReleaseListener; - return this; + public void setDraggingFinishedListener(@Nullable Runnable draggingFinishedListener) { + this.draggingFinishedListener = draggingFinishedListener; } public int getMinValue() { @@ -159,27 +161,50 @@ public abstract class WAbstractSlider extends WWidget { return axis; } + protected void onValueChanged(int value) { + if (valueChangeListener != null) valueChangeListener.accept(value); + } + @Override public void onKeyPressed(int ch, int key, int modifiers) { boolean valueChanged = false; if (modifiers == 0) { - if ((ch == GLFW.GLFW_KEY_LEFT || ch == GLFW.GLFW_KEY_DOWN) && value > min) { + if (isDecreasingKey(ch) && value > min) { value--; valueChanged = true; - } else if ((ch == GLFW.GLFW_KEY_RIGHT || ch == GLFW.GLFW_KEY_UP) && value < max) { + } else if (isIncreasingKey(ch) && value < max) { value++; valueChanged = true; } } else if (modifiers == GLFW.GLFW_MOD_CONTROL) { - if ((ch == GLFW.GLFW_KEY_LEFT || ch == GLFW.GLFW_KEY_DOWN) && value != min) { + if (isDecreasingKey(ch) && value != min) { value = min; valueChanged = true; - } else if ((ch == GLFW.GLFW_KEY_RIGHT || ch == GLFW.GLFW_KEY_UP) && value != max) { + } else if (isIncreasingKey(ch) && value != max) { value = max; valueChanged = true; } } - if (valueChanged && valueChangeListener != null) valueChangeListener.accept(value); + if (valueChanged) { + onValueChanged(value); + valueChangedWithKeys = true; + } + } + + @Override + public void onKeyReleased(int ch, int key, int modifiers) { + if (valueChangedWithKeys && (isDecreasingKey(ch) || isIncreasingKey(ch))) { + if (draggingFinishedListener != null) draggingFinishedListener.run(); + valueChangedWithKeys = false; + } + } + + private static boolean isDecreasingKey(int ch) { + return ch == GLFW.GLFW_KEY_LEFT || ch == GLFW.GLFW_KEY_DOWN; + } + + private static boolean isIncreasingKey(int ch) { + return ch == GLFW.GLFW_KEY_RIGHT || ch == GLFW.GLFW_KEY_UP; } } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WLabeledSlider.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WLabeledSlider.java index 77a3325..37fe464 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WLabeledSlider.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WLabeledSlider.java @@ -4,38 +4,62 @@ import io.github.cottonmc.cotton.gui.client.ScreenDrawing; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.gui.widget.AbstractButtonWidget; -import net.minecraft.util.Identifier; +import net.minecraft.text.Text; + +import javax.annotation.Nullable; /** * A vanilla-style labeled slider widget. * + *

    In addition to the standard slider listeners, + * labeled sliders also support "label updaters" that can update the label + * when the value is changed. + * * @see WAbstractSlider for more information about listeners */ -/* - TODO: - - Add the labels - - Better textures for thumbs when dragging - - The thumb goes 1px outside the track on the right side - */ public class WLabeledSlider extends WAbstractSlider { - private static final Identifier TEXTURE = AbstractButtonWidget.WIDGETS_LOCATION; + @Nullable private Text label = null; + @Nullable private LabelUpdater labelUpdater = null; public WLabeledSlider(int min, int max) { super(min, max, Axis.HORIZONTAL); } - public WLabeledSlider(int max) { - this(0, max); + public WLabeledSlider(int min, int max, Text label) { + this(min, max); + this.label = label; } + @Override public void setSize(int x, int y) { super.setSize(x, 20); } + @Nullable + public Text getLabel() { + return label; + } + + public void setLabel(@Nullable Text label) { + this.label = label; + } + + @Override + protected void onValueChanged(int value) { + super.onValueChanged(value); + if (labelUpdater != null) { + label = labelUpdater.updateLabel(value); + } + } + + public void setLabelUpdater(@Nullable LabelUpdater labelUpdater) { + this.labelUpdater = labelUpdater; + } + @Override protected int getThumbWidth() { - return 6; + return 8; } @Override @@ -49,16 +73,23 @@ public class WLabeledSlider extends WAbstractSlider { drawButton(x, y, 0, width); // 1: regular, 2: hovered, 0: disabled/dragging - int thumbX = (int) (coordToValueRatio * (value - min)); + int thumbX = Math.round(coordToValueRatio * (value - min)); int thumbY = 0; int thumbWidth = getThumbWidth(); int thumbHeight = height; - int thumbState = dragging ? 0 : (mouseX >= thumbX && mouseX <= thumbX + thumbWidth && mouseY >= thumbY && mouseY <= thumbY + thumbHeight ? 2 : 1); + boolean hovering = mouseX >= thumbX && mouseX <= thumbX + thumbWidth && mouseY >= thumbY && mouseY <= thumbY + thumbHeight; + int thumbState = dragging || hovering ? 2 : 1; drawButton(x + thumbX, y + thumbY, thumbState, thumbWidth); if (thumbState == 1 && isFocused()) { - // TODO: draw the focus border + float px = 1 / 32f; + ScreenDrawing.rect(WSlider.TEXTURE, x + thumbX, y + thumbY, thumbWidth, thumbHeight, 24*px, 0*px, 32*px, 20*px, 0xFFFFFFFF); + } + + if (label != null) { + int color = isMouseInsideBounds(mouseX, mouseY) ? 0xFFFFA0 : 0xE0E0E0; + ScreenDrawing.drawCenteredWithShadow(label.asFormattedString(), x + width / 2, y + height / 2 - 4, color); } } @@ -77,4 +108,9 @@ public class WLabeledSlider extends WAbstractSlider { ScreenDrawing.rect(AbstractButtonWidget.WIDGETS_LOCATION, x, y, halfWidth, 20, buttonLeft, buttonTop, buttonLeft + buttonWidth, buttonTop + buttonHeight, 0xFFFFFFFF); ScreenDrawing.rect(AbstractButtonWidget.WIDGETS_LOCATION, x + halfWidth, y, halfWidth, 20, buttonEndLeft, buttonTop, 200 * px, buttonTop + buttonHeight, 0xFFFFFFFF); } + + @FunctionalInterface + public interface LabelUpdater { + Text updateLabel(int value); + } } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java index 14e9972..c57b705 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java @@ -9,19 +9,9 @@ import net.minecraft.util.Identifier; import javax.annotation.Nullable; /** - * A slider widget that can be used to select int values. + * A simple slider widget that can be used to select int values. * - *

    You can set two listeners on a slider: - *

      - *
    • - * A value change listener that gets all value changes (except direct setValue calls). - *
    • - *
    • - * A focus release listener that gets called when the player stops dragging the slider. - * For example, this can be used for sending sync packets to the server - * when the player has selected a value. - *
    • - *
    + * @see WAbstractSlider for supported listeners */ public class WSlider extends WAbstractSlider { public static final int TRACK_WIDTH = 6; @@ -78,7 +68,7 @@ public class WSlider extends WAbstractSlider { ScreenDrawing.rect(TEXTURE, trackX, y + height, TRACK_WIDTH, 1, 16*px, 2*px, 22*px, 3*px, 0xFFFFFFFF); } else { int trackY = y + height / 2 - TRACK_WIDTH / 2; - thumbX = (int) (coordToValueRatio * (value - min)); + thumbX = Math.round(coordToValueRatio * (value - min)); thumbY = height / 2 - THUMB_SIZE / 2; thumbXOffset = 8; diff --git a/src/main/resources/assets/libgui/textures/widget/slider.png b/src/main/resources/assets/libgui/textures/widget/slider.png index ce8f434..e41250e 100644 Binary files a/src/main/resources/assets/libgui/textures/widget/slider.png and b/src/main/resources/assets/libgui/textures/widget/slider.png differ -- cgit