aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.gradle13
-rw-r--r--javadoc/build.gradle6
-rw-r--r--javadoc/src/main/java/io/github/cottonmc/cotton/gui/jd/ExperimentalTaglet.java30
-rw-r--r--javadoc/src/main/java/io/github/cottonmc/cotton/gui/jd/PropertyTaglet.java174
-rw-r--r--settings.gradle1
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/client/CottonClientScreen.java22
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/client/CottonInventoryScreen.java26
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/impl/client/CottonScreenImpl.java3
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/impl/client/MouseInputHandler.java38
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/impl/client/NarrationHelper.java49
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/impl/client/NarrationMessages.java29
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/WAbstractSlider.java11
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/WButton.java17
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/WItemSlot.java59
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/WLabel.java8
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/WLabeledSlider.java15
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/WPanel.java12
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/WPlayerInvPanel.java9
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/WScrollBar.java10
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/WTabPanel.java17
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/WText.java8
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/WTextField.java15
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/WToggleButton.java25
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/WWidget.java69
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/data/ObservableProperty.java162
-rw-r--r--src/main/java/io/github/cottonmc/cotton/gui/widget/data/ObservableView.java75
-rw-r--r--src/main/resources/assets/libgui/lang/en_us.json20
27 files changed, 893 insertions, 30 deletions
diff --git a/build.gradle b/build.gradle
index 9f04998..4e6d927 100644
--- a/build.gradle
+++ b/build.gradle
@@ -16,6 +16,10 @@ archivesBaseName = project.archives_base_name
version = "$project.mod_version+$project.minecraft_version"
group = project.maven_group
+configurations {
+ javadocClasspath
+}
+
repositories {
maven { url "https://server.bbkr.space/artifactory/libs-release" }
/*maven {
@@ -47,6 +51,8 @@ dependencies {
modRuntime(modCompileOnly("com.terraformersmc:modmenu:$project.modmenu_version") {
exclude group: 'net.fabricmc.fabric-api'
})
+
+ javadocClasspath project(':javadoc')
}
processResources {
@@ -79,9 +85,16 @@ checkstyle {
toolVersion = '8.36.2'
}
+evaluationDependsOn(':javadoc')
+
javadoc {
+ dependsOn project(':javadoc').tasks.jar
+
options {
links("https://maven.fabricmc.net/docs/yarn-$project.yarn_mappings")
+ taglets 'io.github.cottonmc.cotton.gui.jd.ExperimentalTaglet'
+ taglets 'io.github.cottonmc.cotton.gui.jd.PropertyTaglet'
+ tagletPath project(':javadoc').tasks.jar.outputs.files.singleFile
}
exclude("**/impl/**")
diff --git a/javadoc/build.gradle b/javadoc/build.gradle
new file mode 100644
index 0000000..e8300bb
--- /dev/null
+++ b/javadoc/build.gradle
@@ -0,0 +1,6 @@
+plugins {
+ id 'java'
+}
+
+sourceCompatibility = rootProject.sourceCompatibility
+targetCompatibility = rootProject.targetCompatibility
diff --git a/javadoc/src/main/java/io/github/cottonmc/cotton/gui/jd/ExperimentalTaglet.java b/javadoc/src/main/java/io/github/cottonmc/cotton/gui/jd/ExperimentalTaglet.java
new file mode 100644
index 0000000..dbd2391
--- /dev/null
+++ b/javadoc/src/main/java/io/github/cottonmc/cotton/gui/jd/ExperimentalTaglet.java
@@ -0,0 +1,30 @@
+package io.github.cottonmc.cotton.gui.jd;
+
+import com.sun.source.doctree.DocTree;
+import jdk.javadoc.doclet.Taglet;
+
+import java.util.List;
+import java.util.Set;
+import javax.lang.model.element.Element;
+
+public class ExperimentalTaglet implements Taglet {
+ @Override
+ public Set<Location> getAllowedLocations() {
+ return Set.of(Location.values());
+ }
+
+ @Override
+ public boolean isInlineTag() {
+ return false;
+ }
+
+ @Override
+ public String getName() {
+ return "experimental";
+ }
+
+ @Override
+ public String toString(List<? extends DocTree> tags, Element element) {
+ return "<dt>Experimental API:</dt><dd>Might be modified or removed without prior notice until stabilised.</dd>";
+ }
+}
diff --git a/javadoc/src/main/java/io/github/cottonmc/cotton/gui/jd/PropertyTaglet.java b/javadoc/src/main/java/io/github/cottonmc/cotton/gui/jd/PropertyTaglet.java
new file mode 100644
index 0000000..163f1d6
--- /dev/null
+++ b/javadoc/src/main/java/io/github/cottonmc/cotton/gui/jd/PropertyTaglet.java
@@ -0,0 +1,174 @@
+package io.github.cottonmc.cotton.gui.jd;
+
+import com.sun.source.doctree.DocTree;
+import com.sun.source.doctree.TextTree;
+import com.sun.source.util.DocTrees;
+import com.sun.source.util.SimpleDocTreeVisitor;
+import jdk.javadoc.doclet.Doclet;
+import jdk.javadoc.doclet.DocletEnvironment;
+import jdk.javadoc.doclet.Taglet;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeVisitor;
+import javax.lang.model.util.ElementKindVisitor8;
+import javax.lang.model.util.SimpleTypeVisitor8;
+
+public class PropertyTaglet implements Taglet {
+ private static final Pattern PROPERTY_METHOD = Pattern.compile("^(.+)Property$");
+ private static final String OBSERVABLE_PROPERTY = "io.github.cottonmc.cotton.gui.widget.data.ObservableProperty";
+ private DocTrees docTrees;
+
+ @Override
+ public void init(DocletEnvironment env, Doclet doclet) {
+ docTrees = env.getDocTrees();
+ }
+
+ @Override
+ public Set<Location> getAllowedLocations() {
+ return Set.of(Location.TYPE);
+ }
+
+ @Override
+ public boolean isInlineTag() {
+ return false;
+ }
+
+ @Override
+ public String getName() {
+ return "properties";
+ }
+
+ @Override
+ public String toString(List<? extends DocTree> tags, Element element) {
+ if (!((element.getKind().isClass() || element.getKind().isInterface()) && element instanceof TypeElement type)) {
+ throw new IllegalArgumentException("Not a type: " + element);
+ }
+
+ List<PropertyEntry> myEntries = scan(type);
+ StringBuilder builder = new StringBuilder();
+
+ if (!myEntries.isEmpty()) {
+ builder.append("<div class=\"caption\"><span>Properties</span></div>");
+ builder.append("<div class=\"summary-table two-column-summary\">");
+ builder.append("<div class=\"table-header col-first\">Property</div>");
+ builder.append("<div class=\"table-header col-last\">Description</div>");
+
+ for (int i = 0; i < myEntries.size(); i++) {
+ PropertyEntry entry = myEntries.get(i);
+ String rowClass = (i % 2 == 0) ? "even-row-color" : "odd-row-color";
+ builder.append("<div class=\"col-first ").append(rowClass).append("\"><code><span class=\"member-name-link\">");
+ builder.append("<a href=\"#").append(entry.name).append("Property()\">").append(entry.name).append("</a>");
+ builder.append("</span></code></div>");
+ builder.append("<div class=\"col-last ").append(rowClass).append("\">").append(entry.doc).append("</div>");
+ }
+
+ builder.append("</div>");
+ }
+
+ Map<String, List<PropertyEntry>> inheritedProperties = new LinkedHashMap<>();
+ scanParents(type, inheritedProperties);
+
+ inheritedProperties.forEach((name, entries) -> {
+ if (!entries.isEmpty()) {
+ builder.append("<dt>Properties from <code>").append(name).append("</code></dt>");
+ builder.append("<dd>");
+ builder.append(entries.stream().map(entry -> "<code>" + entry.name + "</code>").collect(Collectors.joining(", ")));
+ builder.append("</dd>");
+ }
+ });
+
+ return builder.toString();
+ }
+
+ private static String getClassName(TypeElement cl) {
+ return cl.getQualifiedName().toString();
+ }
+
+ private List<PropertyEntry> scan(TypeElement cl) {
+ // Java classes don't have LibGui properties (yet? 😳)
+ if (getClassName(cl).startsWith("java.")) return List.of();
+
+ return cl.getEnclosedElements().stream()
+ .filter(el -> el.getKind() == ElementKind.METHOD)
+ .map(el -> (ExecutableElement) el)
+ .filter(el -> el.getReturnType().accept(new ObservableTypeFilter(), null))
+ .map(el -> {
+ Matcher matcher = PROPERTY_METHOD.matcher(el.getSimpleName());
+
+ if (matcher.matches()) {
+ String doc = docTrees.getDocCommentTree(el).getFirstSentence().stream()
+ .map(tree -> tree.accept(new SimpleDocTreeVisitor<String, Void>() {
+ @Override
+ public String visitText(TextTree node, Void o) {
+ return node.getBody();
+ }
+ }, null))
+ .filter(Objects::nonNull)
+ .findAny().orElse("");
+
+ return new PropertyEntry(matcher.group(1), doc);
+ }
+
+ return null;
+ })
+ .filter(Objects::nonNull)
+ .sorted()
+ .collect(Collectors.toList());
+ }
+
+ private void scanParents(TypeElement cl, Map<String, List<PropertyEntry>> inheritedProperties) {
+ TypeVisitor<Void, Void> typeVisitor = new SimpleTypeVisitor8<>() {
+ @Override
+ public Void visitDeclared(DeclaredType t, Void o) {
+ return t.asElement().accept(new ElementKindVisitor8<>() {
+ @Override
+ public Void visitType(TypeElement e, Object o) {
+ String fqn = e.getQualifiedName().toString();
+ inheritedProperties.put(fqn, scan(e));
+ scanParents(e, inheritedProperties);
+ return null;
+ }
+ }, null);
+ }
+ };
+
+ cl.getSuperclass().accept(typeVisitor, null);
+ cl.getInterfaces().forEach(itf -> itf.accept(typeVisitor, null));
+ }
+
+ private static final class ObservableTypeFilter extends SimpleTypeVisitor8<Boolean, Void> {
+ ObservableTypeFilter() {
+ super(false);
+ }
+
+ @Override
+ public Boolean visitDeclared(DeclaredType t, Void v) {
+ Element type = t.asElement();
+
+ if (type.getKind() == ElementKind.CLASS) {
+ return ((TypeElement) type).getQualifiedName().contentEquals(OBSERVABLE_PROPERTY);
+ }
+
+ return false;
+ }
+ }
+
+ private record PropertyEntry(String name, String doc) implements Comparable<PropertyEntry> {
+ @Override
+ public int compareTo(PropertyEntry o) {
+ return name.compareTo(o.name);
+ }
+ }
+}
diff --git a/settings.gradle b/settings.gradle
index 1dfe6ed..4e731fa 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -15,3 +15,4 @@ pluginManagement {
rootProject.name = 'LibGui'
include ':GuiTest'
+include 'javadoc'
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..331f68b 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
@@ -1,6 +1,7 @@
package io.github.cottonmc.cotton.gui.client;
import net.minecraft.client.gui.screen.Screen;
+import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Style;
@@ -10,6 +11,7 @@ import io.github.cottonmc.cotton.gui.GuiDescription;
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.impl.client.NarrationHelper;
import io.github.cottonmc.cotton.gui.widget.WPanel;
import io.github.cottonmc.cotton.gui.widget.WWidget;
import org.jetbrains.annotations.Nullable;
@@ -36,6 +38,8 @@ public class CottonClientScreen extends Screen implements CottonScreenImpl {
@Nullable
protected WWidget lastResponder = null;
+
+ private final MouseInputHandler<CottonClientScreen> mouseInputHandler = new MouseInputHandler<>(this);
public CottonClientScreen(GuiDescription description) {
this(new LiteralText(""), description);
@@ -46,7 +50,8 @@ public class CottonClientScreen extends Screen implements CottonScreenImpl {
this.description = description;
description.getRootPanel().validate(description);
}
-
+
+ @Override
public GuiDescription getDescription() {
return description;
}
@@ -176,7 +181,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 +192,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 +204,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 +215,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 +226,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
@@ -264,4 +269,9 @@ public class CottonClientScreen extends Screen implements CottonScreenImpl {
return true;
}
+
+ @Override
+ protected void addElementNarrations(NarrationMessageBuilder builder) {
+ if (description != null) NarrationHelper.addNarrations(description.getRootPanel(), builder);
+ }
}
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..953563c 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
@@ -1,6 +1,7 @@
package io.github.cottonmc.cotton.gui.client;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
+import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
import net.minecraft.client.render.DiffuseLighting;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerEntity;
@@ -8,12 +9,15 @@ 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.impl.client.NarrationHelper;
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 +30,7 @@ import org.lwjgl.opengl.GL11;
public class CottonInventoryScreen<T extends SyncedGuiDescription> extends HandledScreen<T> implements CottonScreenImpl {
protected SyncedGuiDescription description;
@Nullable protected WWidget lastResponder = null;
+ private final MouseInputHandler<CottonInventoryScreen<T>> mouseInputHandler = new MouseInputHandler<>(this);
/**
* Constructs a new screen without a title.
@@ -83,6 +88,12 @@ public class CottonInventoryScreen<T extends SyncedGuiDescription> extends Handl
VisualLogger.reset();
}
+ @ApiStatus.Internal
+ @Override
+ public GuiDescription getDescription() {
+ return description;
+ }
+
@Nullable
@Override
public WWidget getLastResponder() {
@@ -187,7 +198,7 @@ public class CottonInventoryScreen<T extends SyncedGuiDescription> 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 +208,7 @@ public class CottonInventoryScreen<T extends SyncedGuiDescription> 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 +219,7 @@ public class CottonInventoryScreen<T extends SyncedGuiDescription> 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 +230,7 @@ public class CottonInventoryScreen<T extends SyncedGuiDescription> 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 +241,7 @@ public class CottonInventoryScreen<T extends SyncedGuiDescription> extends Handl
int containerX = (int)mouseX-x;
int containerY = (int)mouseY-y;
- MouseInputHandler.onMouseMove(description, containerX, containerY);
+ mouseInputHandler.onMouseMove(containerX, containerY);
}
@Override
@@ -304,4 +315,9 @@ public class CottonInventoryScreen<T extends SyncedGuiDescription> extends Handl
return true;
}
+
+ @Override
+ protected void addElementNarrations(NarrationMessageBuilder builder) {
+ if (description != null) NarrationHelper.addNarrations(description.getRootPanel(), builder);
+ }
}
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..055df75 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,9 +2,9 @@ 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 io.github.cottonmc.cotton.gui.widget.data.ObservableProperty;
import org.jetbrains.annotations.Nullable;
import java.util.function.Function;
@@ -12,10 +12,21 @@ 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<S extends Screen & CottonScreenImpl> {
+ private final S screen;
+ private final ObservableProperty<WWidget> hovered = ObservableProperty.of(null);
+
+ public MouseInputHandler(S screen) {
+ this.screen = screen;
+ hovered.addListener((property, from, to) -> {
+ if (from != null) from.setHovered(false);
+ if (to != null) to.setHovered(true);
+ });
+ }
+
+ 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 +39,7 @@ public final class MouseInputHandler {
}
}
- public static <S extends Screen & CottonScreenImpl> 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 +59,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 +67,7 @@ public final class MouseInputHandler {
screen.setLastResponder(null);
}
- public static <S extends Screen & CottonScreenImpl> 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 +79,25 @@ 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);
+ hovered.set(hit);
+
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/impl/client/NarrationHelper.java b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/NarrationHelper.java
new file mode 100644
index 0000000..54567be
--- /dev/null
+++ b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/NarrationHelper.java
@@ -0,0 +1,49 @@
+package io.github.cottonmc.cotton.gui.impl.client;
+
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
+import net.minecraft.client.gui.screen.narration.NarrationPart;
+import net.minecraft.text.TranslatableText;
+
+import io.github.cottonmc.cotton.gui.widget.WPanel;
+import io.github.cottonmc.cotton.gui.widget.WWidget;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+@Environment(EnvType.CLIENT)
+public final class NarrationHelper {
+ public static void addNarrations(WPanel rootPanel, NarrationMessageBuilder builder) {
+ List<WWidget> narratableWidgets = getAllWidgets(rootPanel)
+ .filter(WWidget::isNarratable)
+ .collect(Collectors.toList());
+
+ for (int i = 0, childCount = narratableWidgets.size(); i < childCount; i++) {
+ WWidget child = narratableWidgets.get(i);
+ if (!child.isFocused() && !child.isHovered()) continue;
+
+ // replicates Screen.addElementNarrations
+ if (narratableWidgets.size() > 1) {
+ builder.put(NarrationPart.POSITION, new TranslatableText(NarrationMessages.Vanilla.SCREEN_POSITION_KEY, i + 1, childCount));
+
+ if (child.isFocused()) {
+ builder.put(NarrationPart.USAGE, NarrationMessages.Vanilla.COMPONENT_LIST_USAGE);
+ }
+ }
+
+ child.addNarrations(builder.nextMessage());
+ }
+ }
+
+ private static Stream<WWidget> getAllWidgets(WPanel panel) {
+ return Stream.concat(Stream.of(panel), panel.streamChildren().flatMap(widget -> {
+ if (widget instanceof WPanel nested) {
+ return getAllWidgets(nested);
+ }
+
+ return Stream.of(widget);
+ }));
+ }
+}
diff --git a/src/main/java/io/github/cottonmc/cotton/gui/impl/client/NarrationMessages.java b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/NarrationMessages.java
new file mode 100644
index 0000000..bc9ee48
--- /dev/null
+++ b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/NarrationMessages.java
@@ -0,0 +1,29 @@
+package io.github.cottonmc.cotton.gui.impl.client;
+
+import net.minecraft.text.Text;
+import net.minecraft.text.TranslatableText;
+
+public final class NarrationMessages {
+ public static final String ITEM_SLOT_TITLE_KEY = "widget.libgui.item_slot.narration.title";
+ public static final String LABELED_SLIDER_TITLE_KEY = "widget.libgui.labeled_slider.narration.title";
+ public static final Text PLAYER_INVENTORY_HOTBAR = new TranslatableText("widget.libgui.player_inventory.narration.hotbar");
+ public static final Text SCROLL_BAR_TITLE = new TranslatableText("widget.libgui.scroll_bar.narration.title");
+ public static final String SLIDER_MESSAGE_KEY = "widget.libgui.slider.narration.title";
+ public static final Text SLIDER_USAGE = new TranslatableText("widget.libgui.slider.narration.usage");
+ public static final String TAB_TITLE_KEY = "widget.libgui.tab.narration.title";
+ public static final String TAB_POSITION_KEY = "widget.libgui.tab.narration.position";
+ public static final String TEXT_FIELD_TITLE_KEY = "widget.libgui.text_field.narration.title";
+ public static final String TEXT_FIELD_SUGGESTION_KEY = "widget.libgui.text_field.narration.suggestion";
+ public static final String TOGGLE_BUTTON_NAMED_KEY = "widget.libgui.toggle_button.narration.named";
+ public static final Text TOGGLE_BUTTON_OFF = new TranslatableText("widget.libgui.toggle_button.narration.off");
+ public static final Text TOGGLE_BUTTON_ON = new TranslatableText("widget.libgui.toggle_button.narration.on");
+ public static final String TOGGLE_BUTTON_UNNAMED_KEY = "widget.libgui.toggle_button.narration.unnamed";
+
+ public static final class Vanilla {
+ public static final Text BUTTON_USAGE_FOCUSED = new TranslatableText("narration.button.usage.focused");
+ public static final Text BUTTON_USAGE_HOVERED = new TranslatableText("narration.button.usage.hovered");
+ public static final Text COMPONENT_LIST_USAGE = new TranslatableText("narration.component_list.usage");
+ public static final Text INVENTORY = new TranslatableText("container.inventory");
+ public static final String SCREEN_POSITION_KEY = "narrator.position.screen";
+ }
+}
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 7fda1d9..2af6092 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
@@ -2,8 +2,12 @@ package io.github.cottonmc.cotton.gui.widget;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
+import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
+import net.minecraft.client.gui.screen.narration.NarrationPart;
+import net.minecraft.text.TranslatableText;
import net.minecraft.util.math.MathHelper;
+import io.github.cottonmc.cotton.gui.impl.client.NarrationMessages;
import io.github.cottonmc.cotton.gui.widget.data.Axis;
import io.github.cottonmc.cotton.gui.widget.data.InputResult;
import org.jetbrains.annotations.Nullable;
@@ -342,6 +346,13 @@ public abstract class WAbstractSlider extends WWidget {
return dragging;
}
+ @Environment(EnvType.CLIENT)
+ @Override
+ public void addNarrations(NarrationMessageBuilder builder) {
+ builder.put(NarrationPart.TITLE, new TranslatableText(NarrationMessages.SLIDER_MESSAGE_KEY, value, min, max));
+ builder.put(NarrationPart.USAGE, NarrationMessages.SLIDER_USAGE);
+ }
+
/**
* Tests if the key should decrease sliders with the specified direction.
*
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 15cd6bb..533e436 100644
--- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WButton.java
+++ b/src/main/java/io/github/cottonmc/cotton/gui/wid