From baa1b1476bbca91d1a5b6c89bd7b3c39a3efae15 Mon Sep 17 00:00:00 2001 From: syeyoung Date: Tue, 17 Jan 2023 15:57:51 +0900 Subject: - Intrinsics Signed-off-by: syeyoung --- .../impl/discord/inviteViewer/ImageTexture.java | 74 ++++++++++++--- .../discord/inviteViewer/PartyInviteViewer.java | 4 +- .../dungeonsguide/mod/guiv2/elements/AbsXY.java | 10 ++ .../dungeonsguide/mod/guiv2/elements/Align.java | 13 ++- .../mod/guiv2/elements/AspectRatioFitter.java | 10 ++ .../dungeonsguide/mod/guiv2/elements/Border.java | 32 +++++++ .../dungeonsguide/mod/guiv2/elements/Column.java | 55 +++++++++-- .../dungeonsguide/mod/guiv2/elements/Flexible.java | 15 ++- .../mod/guiv2/elements/IntrinsicHeight.java | 65 +++++++++++++ .../mod/guiv2/elements/IntrinsicWidth.java | 65 +++++++++++++ .../dungeonsguide/mod/guiv2/elements/Line.java | 9 ++ .../dungeonsguide/mod/guiv2/elements/Measure.java | 10 ++ .../dungeonsguide/mod/guiv2/elements/Padding.java | 15 ++- .../dungeonsguide/mod/guiv2/elements/Row.java | 57 ++++++++++-- .../dungeonsguide/mod/guiv2/elements/Scaler.java | 14 ++- .../dungeonsguide/mod/guiv2/elements/SizedBox.java | 10 ++ .../dungeonsguide/mod/guiv2/elements/Stack.java | 18 ++++ .../dungeonsguide/mod/guiv2/elements/Text.java | 14 +++ .../mod/guiv2/elements/TextField.java | 9 ++ .../mod/guiv2/elements/UnconstrainedBox.java | 11 +++ .../mod/guiv2/elements/image/URLImage.java | 103 +++++++++++++++++++++ .../dungeonsguide/mod/guiv2/layouter/Layouter.java | 7 ++ .../guiv2/layouter/SingleChildPassingLayouter.java | 11 +++ .../mod/guiv2/xml/DomElementRegistry.java | 5 +- 24 files changed, 604 insertions(+), 32 deletions(-) create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/IntrinsicHeight.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/IntrinsicWidth.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/image/URLImage.java (limited to 'mod/src/main/java/kr/syeyoung/dungeonsguide') diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/discord/inviteViewer/ImageTexture.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/discord/inviteViewer/ImageTexture.java index 3a4c226a..df3b4043 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/discord/inviteViewer/ImageTexture.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/discord/inviteViewer/ImageTexture.java @@ -19,6 +19,7 @@ package kr.syeyoung.dungeonsguide.mod.features.impl.discord.inviteViewer; +import kr.syeyoung.dungeonsguide.mod.DungeonsGuide; import lombok.Data; import lombok.Getter; import lombok.Setter; @@ -30,16 +31,26 @@ import net.minecraft.client.renderer.texture.DynamicTexture; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.util.ResourceLocation; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import javax.imageio.ImageIO; import javax.imageio.ImageReader; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.metadata.IIOMetadataNode; import javax.imageio.stream.ImageInputStream; import java.awt.*; import java.awt.image.BufferedImage; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; +import java.util.HashMap; import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.function.Consumer; @Data public class ImageTexture { @@ -53,8 +64,9 @@ public class ImageTexture { private int frames; private int size; - @Getter @Setter - private int lastFrame = 0; + private long startedPlayingAt = -1; + + private int delayTime; public void buildGLThings() { previewTexture = new DynamicTexture(image); @@ -76,6 +88,15 @@ public class ImageTexture { BufferedImage dummyFrame = reader.read(0); width = dummyFrame.getWidth(); height = dummyFrame.getHeight(); + IIOMetadata imageMetaData = reader.getImageMetadata(0); + String metaFormatName = imageMetaData.getNativeMetadataFormatName(); + + IIOMetadataNode root = (IIOMetadataNode)imageMetaData.getAsTree(metaFormatName); + + IIOMetadataNode graphicsControlExtensionNode = getNode(root, "GraphicControlExtension"); + + delayTime = Integer.parseInt(graphicsControlExtensionNode.getAttribute("delayTime")); + image = new BufferedImage(width, height * frames, dummyFrame.getType()); Graphics2D graphics2D = image.createGraphics(); @@ -87,9 +108,25 @@ public class ImageTexture { reader.dispose(); imageInputStream.close(); huc.disconnect(); } - public void drawFrame(int frame, int x, int y, int width, int height) { + + private static IIOMetadataNode getNode(IIOMetadataNode rootNode, String nodeName) { + int nNodes = rootNode.getLength(); + for (int i = 0; i < nNodes; i++) { + if (rootNode.item(i).getNodeName().compareToIgnoreCase(nodeName)== 0) { + return((IIOMetadataNode) rootNode.item(i)); + } + } + IIOMetadataNode node = new IIOMetadataNode(nodeName); + rootNode.appendChild(node); + return(node); + } + + public void drawFrame(double x, double y, double width, double height) { if (getResourceLocation() == null) buildGLThings(); + if (startedPlayingAt == -1) startedPlayingAt = System.currentTimeMillis(); + + int frame = (int) (((System.currentTimeMillis() - startedPlayingAt) / delayTime) % frames); TextureManager textureManager = Minecraft.getMinecraft().getTextureManager(); textureManager.bindTexture(getResourceLocation()); @@ -99,20 +136,35 @@ public class ImageTexture { Tessellator tessellator = Tessellator.getInstance(); WorldRenderer worldrenderer = tessellator.getWorldRenderer(); worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX); - worldrenderer.pos((double)x, (double)(y + height), 0.0D) + worldrenderer.pos(x, (y + height), 0.0D) .tex(0,((frame+1) * height)/ ((double)frames * height)).endVertex(); - worldrenderer.pos((double)(x + width), (double)(y + height), 0.0D) + worldrenderer.pos((x + width), (y + height), 0.0D) .tex(1, ((frame+1) * height)/ ((double)frames * height)).endVertex(); - worldrenderer.pos((double)(x + width), (double)y, 0.0D) + worldrenderer.pos((x + width), y, 0.0D) .tex(1,(frame * height)/ ((double)frames * height)).endVertex(); - worldrenderer.pos((double)x, (double)y, 0.0D) + worldrenderer.pos(x, y, 0.0D) .tex(0, (frame * height) / ((double)frames * height)).endVertex(); tessellator.draw(); } - public void drawFrameAndIncrement(int x, int y, int width, int height) { - drawFrame(lastFrame, x,y,width,height); - lastFrame++; - if (lastFrame >= frames) lastFrame = 0; + public static final ExecutorService executorService = Executors.newFixedThreadPool(3, DungeonsGuide.THREAD_FACTORY); + public static final Map imageMap = new HashMap<>(); + public static final Logger logger = LogManager.getLogger("DG-ImageLoader"); + public static void loadImage(String url, Consumer callback) { + if (imageMap.containsKey(url)) { + callback.accept(imageMap.get(url)); + return; + } + if (url.isEmpty()) callback.accept(null); + executorService.submit(() -> { + try { + ImageTexture imageTexture = new ImageTexture(url); + imageMap.put(url, imageTexture); + callback.accept(imageTexture); + } catch (Exception e) { + callback.accept(null); + logger.log(Level.WARN, "An error occured while loading image from: "+url, e); + } + }); } } diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/discord/inviteViewer/PartyInviteViewer.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/discord/inviteViewer/PartyInviteViewer.java index 42ea79c1..e537c311 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/discord/inviteViewer/PartyInviteViewer.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/discord/inviteViewer/PartyInviteViewer.java @@ -47,6 +47,8 @@ import java.util.concurrent.*; public class PartyInviteViewer extends SimpleFeature { public PartyInviteViewer() { super("Discord", "Party Invite Viewer","Simply type /dg asktojoin or /dg atj to toggle whether ask-to-join would be presented as option on discord!\n\nRequires Discord RPC to be enabled", "discord.party_invite_viewer"); + + } @Override @@ -222,7 +224,7 @@ public class PartyInviteViewer extends SimpleFeature { } } if (loadedImage != null) { - loadedImage.drawFrameAndIncrement( 7,7,height-14,height-14); + loadedImage.drawFrame( 7,7,height-14,height-14); } else { Gui.drawRect(7, 7, height - 7, height-7, 0xFF4E4E4E); } diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/AbsXY.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/AbsXY.java index eb9b07da..ecfb9883 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/AbsXY.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/AbsXY.java @@ -62,6 +62,16 @@ public class AbsXY extends AnnotatedExportOnlyWidget implements Layouter { return new Size(constraintBox.getMaxWidth(), constraintBox.getMaxHeight()); } + + @Override + public double getMaxIntrinsicWidth(DomElement buildContext, double height) { + return buildContext.getChildren().isEmpty() ? 0 : buildContext.getChildren().get(0).getLayouter().getMaxIntrinsicWidth(buildContext.getChildren().get(0), height); + } + + @Override + public double getMaxIntrinsicHeight(DomElement buildContext, double width) { + return buildContext.getChildren().isEmpty() ? 0 : buildContext.getChildren().get(0).getLayouter().getMaxIntrinsicHeight(buildContext.getChildren().get(0), width); + } @Override public List build(DomElement buildContext) { return Collections.singletonList(child.getValue()); diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Align.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Align.java index 5c1bce11..921ad522 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Align.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Align.java @@ -50,7 +50,7 @@ public class Align extends AnnotatedExportOnlyWidget implements Layouter { @Override public Size layout(DomElement buildContext, ConstraintBox constraintBox) { - DomElement theOnly = getDomElement().getChildren().get(0); + DomElement theOnly = buildContext.getChildren().get(0); Size size = theOnly.getLayouter().layout(theOnly, new ConstraintBox( 0, constraintBox.getMaxWidth(), 0, constraintBox.getMaxHeight() )); @@ -61,4 +61,15 @@ public class Align extends AnnotatedExportOnlyWidget implements Layouter { )); return new Size(constraintBox.getMaxWidth(), constraintBox.getMaxHeight()); } + + + @Override + public double getMaxIntrinsicWidth(DomElement buildContext, double height) { + return buildContext.getChildren().isEmpty() ? 0 : buildContext.getChildren().get(0).getLayouter().getMaxIntrinsicWidth(buildContext.getChildren().get(0), height); + } + + @Override + public double getMaxIntrinsicHeight(DomElement buildContext, double width) { + return buildContext.getChildren().isEmpty() ? 0 : buildContext.getChildren().get(0).getLayouter().getMaxIntrinsicHeight(buildContext.getChildren().get(0), width); + } } diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/AspectRatioFitter.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/AspectRatioFitter.java index 6984bf32..873c0640 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/AspectRatioFitter.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/AspectRatioFitter.java @@ -80,6 +80,16 @@ public class AspectRatioFitter extends AnnotatedExportOnlyWidget implements Layo } } + @Override + public double getMaxIntrinsicWidth(DomElement buildContext, double height) { + return height * this.width.getValue() / this.height.getValue(); + } + + @Override + public double getMaxIntrinsicHeight(DomElement buildContext, double width) { + return width * this.height.getValue() / this.width.getValue(); + } + @Override public boolean canCutRequest() { return Flexible.FlexFit.TIGHT == fit.getValue(); diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Border.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Border.java index e743a8af..e4ce27ea 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Border.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Border.java @@ -118,6 +118,38 @@ public class Border extends AnnotatedExportOnlyWidget implements Layouter { return new Size(dimension.getWidth() + lw + rw, dimension.getHeight() + th + bh); } + + + @Override + public double getMaxIntrinsicWidth(DomElement buildContext, double height) { + DomElement top = null, bottom = null, left = null, right = null, content = null; + for (DomElement child : buildContext.getChildren()) { + if (child.getWidget() == this.top.getValue()) top = child; + if (child.getWidget() == this.bottom.getValue()) bottom = child; + if (child.getWidget() == this.left.getValue()) left = child; + if (child.getWidget() == this.right.getValue()) right = child; + if (child.getWidget() == this.content.getValue()) content = child; + } + return content.getLayouter().getMaxIntrinsicWidth(content, height) + + left.getLayouter().getMaxIntrinsicWidth(left, height) + + right.getLayouter().getMaxIntrinsicWidth(right, height); + } + + @Override + public double getMaxIntrinsicHeight(DomElement buildContext, double width) { + DomElement top = null, bottom = null, left = null, right = null, content = null; + for (DomElement child : buildContext.getChildren()) { + if (child.getWidget() == this.top.getValue()) top = child; + if (child.getWidget() == this.bottom.getValue()) bottom = child; + if (child.getWidget() == this.left.getValue()) left = child; + if (child.getWidget() == this.right.getValue()) right = child; + if (child.getWidget() == this.content.getValue()) content = child; + } + return content.getLayouter().getMaxIntrinsicHeight(content, width) + + top.getLayouter().getMaxIntrinsicHeight(top, width) + + bottom.getLayouter().getMaxIntrinsicHeight(bottom, width); + } + @Override protected Renderer createRenderer() { return OnlyChildrenRenderer.INSTANCE; diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Column.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Column.java index f61838ee..b310e6cf 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Column.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Column.java @@ -93,7 +93,7 @@ public class Column extends AnnotatedExportOnlyWidget implements Layouter { CrossAxisAlignment crossAxisAlignment = hAlign.getValue(); MainAxisAlignment mainAxisAlignment = vAlign.getValue(); Map saved = new HashMap<>(); - for (DomElement child : getDomElement().getChildren()) { + for (DomElement child : buildContext.getChildren()) { if (!(child.getWidget() instanceof Flexible)) { Size requiredSize = child.getLayouter().layout(child, new ConstraintBox( crossAxisAlignment == CrossAxisAlignment.STRETCH @@ -109,7 +109,7 @@ public class Column extends AnnotatedExportOnlyWidget implements Layouter { boolean flexFound = false; int sumFlex = 0; - for (DomElement child : getDomElement().getChildren()) { + for (DomElement child : buildContext.getChildren()) { if (child.getWidget() instanceof Flexible) { sumFlex += Math.min(1, ((Flexible) child.getWidget()).flex.getValue()); flexFound = true; @@ -123,7 +123,7 @@ public class Column extends AnnotatedExportOnlyWidget implements Layouter { double remainingHeight = effheight - height; double heightPer = remainingHeight / sumFlex; - for (DomElement child : getDomElement().getChildren()) { + for (DomElement child : buildContext.getChildren()) { if (child.getWidget() instanceof Flexible) { Size requiredSize = child.getLayouter().layout(child, new ConstraintBox( crossAxisAlignment == CrossAxisAlignment.STRETCH @@ -150,14 +150,14 @@ public class Column extends AnnotatedExportOnlyWidget implements Layouter { double remaining = effheight - height; if (remaining > 0) { starty = 0; - heightDelta = remaining / (getDomElement().getChildren().size()-1); + heightDelta = remaining / (buildContext.getChildren().size()-1); } else { starty = (effheight - height) / 2; } } else if (mainAxisAlignment == MainAxisAlignment.SPACE_EVENLY) { double remaining = effheight - height; if (remaining > 0) { - heightDelta = remaining / (getDomElement().getChildren().size()+1); + heightDelta = remaining / (buildContext.getChildren().size()+1); starty = heightDelta; } else { starty= (effheight - height) / 2; @@ -165,14 +165,14 @@ public class Column extends AnnotatedExportOnlyWidget implements Layouter { } else if (mainAxisAlignment == MainAxisAlignment.SPACE_AROUND) { double remaining = effheight - height; if (remaining > 0) { - heightDelta = 2 * remaining / getDomElement().getChildren().size(); + heightDelta = 2 * remaining / buildContext.getChildren().size(); starty = heightDelta / 2; } else { starty = (effheight - height / 2); } } - for (DomElement child : getDomElement().getChildren()) { + for (DomElement child : buildContext.getChildren()) { Size size = saved.get(child); child.setRelativeBound(new Rect( @@ -190,4 +190,45 @@ public class Column extends AnnotatedExportOnlyWidget implements Layouter { effheight ); } + @Override + public double getMaxIntrinsicHeight(DomElement buildContext, double width) { + double height = 0; + double flex = 0; + double maxPer = 0; + for (DomElement child : buildContext.getChildren()) { + if (child.getWidget() instanceof Flexible) { + flex += ((Flexible) child.getWidget()).flex.getValue(); + maxPer = Double.max(maxPer, child.getLayouter().getMaxIntrinsicHeight(buildContext, width) / + ((Flexible) child.getWidget()).flex.getValue()); + } else { + height += child.getLayouter().getMaxIntrinsicHeight(buildContext, width); + } + } + return height + maxPer * flex; + } + + @Override + public double getMaxIntrinsicWidth(DomElement buildContext, double height) { + double maxWidth = 0; + double heightTaken = 0; + int sumFlex = 0; + for (DomElement child : buildContext.getChildren()) { + if (!(child.getWidget() instanceof Flexible)) { + heightTaken += child.getLayouter().getMaxIntrinsicWidth(buildContext, Double.POSITIVE_INFINITY); + maxWidth = Double.max(maxWidth, child.getLayouter().getMaxIntrinsicWidth(buildContext, 0)); + } else { + sumFlex += ((Flexible) child.getWidget()).flex.getValue(); + } + } + double leftOver = height - heightTaken; + if (sumFlex > 0) { + double per = leftOver / sumFlex; + for (DomElement child : buildContext.getChildren()) { + if (child.getWidget() instanceof Flexible) { + maxWidth = Double.max(maxWidth, child.getLayouter().getMaxIntrinsicWidth(buildContext, per * ((Flexible) child.getWidget()).flex.getValue())); + } + } + } + return maxWidth; + } } diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Flexible.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Flexible.java index 5585395a..09c1dcaf 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Flexible.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Flexible.java @@ -67,14 +67,25 @@ public class Flexible extends AnnotatedExportOnlyWidget implements Layouter { new ConstraintBox(constraintBox.getMaxWidth() == Integer.MAX_VALUE ? 0 : constraintBox.getMaxWidth(), constraintBox.getMaxWidth() , constraintBox.getMaxHeight() == Integer.MAX_VALUE ? 0 : constraintBox.getMaxHeight(), constraintBox.getMaxHeight()) : ConstraintBox.loose(constraintBox.getMaxWidth(), constraintBox.getMaxHeight()); - DomElement child = getDomElement().getChildren().get(0); + DomElement child = buildContext.getChildren().get(0); Size dim = child.getLayouter().layout(child, box); - getDomElement().getChildren().get(0).setRelativeBound(new Rect(0,0, dim.getWidth(),dim.getHeight())); + buildContext.getChildren().get(0).setRelativeBound(new Rect(0,0, dim.getWidth(),dim.getHeight())); return dim; } + + @Override + public double getMaxIntrinsicWidth(DomElement buildContext, double height) { + return buildContext.getChildren().isEmpty() ? 0 : buildContext.getChildren().get(0).getLayouter().getMaxIntrinsicWidth(buildContext.getChildren().get(0), height); + } + + @Override + public double getMaxIntrinsicHeight(DomElement buildContext, double width) { + return buildContext.getChildren().isEmpty() ? 0 : buildContext.getChildren().get(0).getLayouter().getMaxIntrinsicHeight(buildContext.getChildren().get(0), width); + } + @Override public boolean canCutRequest() { return Flexible.FlexFit.TIGHT == fit.getValue(); diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/IntrinsicHeight.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/IntrinsicHeight.java new file mode 100644 index 00000000..484e46f7 --- /dev/null +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/IntrinsicHeight.java @@ -0,0 +1,65 @@ +/* + * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod + * Copyright (C) 2023 cyoung06 (syeyoung) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package kr.syeyoung.dungeonsguide.mod.guiv2.elements; + +import kr.syeyoung.dungeonsguide.mod.guiv2.BindableAttribute; +import kr.syeyoung.dungeonsguide.mod.guiv2.DomElement; +import kr.syeyoung.dungeonsguide.mod.guiv2.Widget; +import kr.syeyoung.dungeonsguide.mod.guiv2.layouter.Layouter; +import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.ConstraintBox; +import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Rect; +import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Size; +import kr.syeyoung.dungeonsguide.mod.guiv2.xml.AnnotatedExportOnlyWidget; +import kr.syeyoung.dungeonsguide.mod.guiv2.xml.annotations.Export; + +import java.util.Collections; +import java.util.List; + +public class IntrinsicHeight extends AnnotatedExportOnlyWidget implements Layouter { + @Export(attributeName = "$") + public final BindableAttribute widget = new BindableAttribute<>(Widget.class); + + @Override + public List build(DomElement buildContext) { + return Collections.singletonList(widget.getValue()); + } + + @Override + public Size layout(DomElement buildContext, ConstraintBox constraintBox) { + DomElement elem = buildContext.getChildren().get(0); + double height = elem.getLayouter().getMaxIntrinsicHeight(elem, constraintBox.getMaxWidth() == Double.POSITIVE_INFINITY ? 0 : constraintBox.getMaxWidth()); + Size size = elem.getLayouter().layout(buildContext, new ConstraintBox( + constraintBox.getMinWidth(), constraintBox.getMaxWidth(), height, height + )); + elem.setRelativeBound(new Rect(0,0,size.getWidth(), size.getHeight())); + return size; + } + + @Override + public double getMaxIntrinsicWidth(DomElement buildContext, double height) { + DomElement elem = buildContext.getChildren().get(0); + return elem.getLayouter().getMaxIntrinsicWidth(elem, height); + } + + @Override + public double getMaxIntrinsicHeight(DomElement buildContext, double width) { + DomElement elem = buildContext.getChildren().get(0); + return elem.getLayouter().getMaxIntrinsicHeight(elem, width); + } +} diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/IntrinsicWidth.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/IntrinsicWidth.java new file mode 100644 index 00000000..9754ec1c --- /dev/null +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/IntrinsicWidth.java @@ -0,0 +1,65 @@ +/* + * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod + * Copyright (C) 2023 cyoung06 (syeyoung) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package kr.syeyoung.dungeonsguide.mod.guiv2.elements; + +import kr.syeyoung.dungeonsguide.mod.guiv2.BindableAttribute; +import kr.syeyoung.dungeonsguide.mod.guiv2.DomElement; +import kr.syeyoung.dungeonsguide.mod.guiv2.Widget; +import kr.syeyoung.dungeonsguide.mod.guiv2.layouter.Layouter; +import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.ConstraintBox; +import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Rect; +import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Size; +import kr.syeyoung.dungeonsguide.mod.guiv2.xml.AnnotatedExportOnlyWidget; +import kr.syeyoung.dungeonsguide.mod.guiv2.xml.annotations.Export; + +import java.util.Collections; +import java.util.List; + +public class IntrinsicWidth extends AnnotatedExportOnlyWidget implements Layouter { + @Export(attributeName = "$") + public final BindableAttribute widget = new BindableAttribute<>(Widget.class); + + @Override + public List build(DomElement buildContext) { + return Collections.singletonList(widget.getValue()); + } + + @Override + public Size layout(DomElement buildContext, ConstraintBox constraintBox) { + DomElement elem = buildContext.getChildren().get(0); + double width = elem.getLayouter().getMaxIntrinsicWidth(elem, constraintBox.getMaxHeight() == Double.POSITIVE_INFINITY ? 0 : constraintBox.getMaxHeight()); + Size size = elem.getLayouter().layout(buildContext, new ConstraintBox( + width, width, constraintBox.getMinHeight(), constraintBox.getMaxHeight() + )); + elem.setRelativeBound(new Rect(0,0,size.getWidth(), size.getHeight())); + return size; + } + + @Override + public double getMaxIntrinsicWidth(DomElement buildContext, double height) { + DomElement elem = buildContext.getChildren().get(0); + return elem.getLayouter().getMaxIntrinsicWidth(elem, height); + } + + @Override + public double getMaxIntrinsicHeight(DomElement buildContext, double width) { + DomElement elem = buildContext.getChildren().get(0); + return elem.getLayouter().getMaxIntrinsicHeight(elem, width); + } +} diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Line.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Line.java index d84cfa46..5f0d0395 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Line.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Line.java @@ -91,6 +91,15 @@ public class Line extends AnnotatedExportOnlyWidget implements Layouter, Rendere } } + @Override + public double getMaxIntrinsicWidth(DomElement buildContext, double height) { + return direction.getValue() == Orientation.HORIZONTAL ? 0 : this.thickness.getValue(); + } + @Override + public double getMaxIntrinsicHeight(DomElement buildContext, double width) { + return direction.getValue() == Orientation.VERTICAL ? 0 : this.thickness.getValue(); + } + @Override public void doRender(int absMouseX, int absMouseY, double relMouseX, double relMouseY, float partialTicks, RenderingContext context, DomElement buildContext) { double w = buildContext.getSize().getWidth(), h = buildContext.getSize().getHeight(); diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Measure.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Measure.java index 24da1a93..a3b3af7f 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Measure.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Measure.java @@ -46,6 +46,16 @@ public class Measure extends AnnotatedExportOnlyWidget implements Layouter { return new Size(dim.getWidth(), dim.getHeight()); } + @Override + public double getMaxIntrinsicWidth(DomElement buildContext, double height) { + return buildContext.getChildren().isEmpty() ? 0 : buildContext.getChildren().get(0).getLayouter().getMaxIntrinsicWidth(buildContext.getChildren().get(0), height); + } + + @Override + public double getMaxIntrinsicHeight(DomElement buildContext, double width) { + return buildContext.getChildren().isEmpty() ? 0 : buildContext.getChildren().get(0).getLayouter().getMaxIntrinsicHeight(buildContext.getChildren().get(0), width); + } + @Export(attributeName = "$") public final BindableAttribute widget = new BindableAttribute<>(Widget.class); diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Padding.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Padding.java index 396efbe0..9814b038 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Padding.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Padding.java @@ -56,7 +56,7 @@ public class Padding extends AnnotatedExportOnlyWidget implements Layouter { @Override public Size layout(DomElement buildContext, ConstraintBox constraintBox) { - DomElement domElement = getDomElement().getChildren().get(0); + DomElement domElement = buildContext.getChildren().get(0); double width = (left.getValue() + right.getValue()); double height = (top.getValue() + bottom.getValue()); @@ -77,4 +77,17 @@ public class Padding extends AnnotatedExportOnlyWidget implements Layouter { return new Size(dim.getWidth() + width, dim.getHeight() + height); } + + + @Override + public double getMaxIntrinsicWidth(DomElement buildContext, double height) { + return left.getValue() + right.getValue() + + (buildContext.getChildren().isEmpty() ? 0 : buildContext.getChildren().get(0).getLayouter().getMaxIntrinsicWidth(buildContext.getChildren().get(0), height)); + } + + @Override + public double getMaxIntrinsicHeight(DomElement buildContext, double width) { + return top.getValue() + bottom.getValue() + ( + buildContext.getChildren().isEmpty() ? 0 : buildContext.getChildren().get(0).getLayouter().getMaxIntrinsicHeight(buildContext.getChildren().get(0), width)); + } } diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Row.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Row.java index 5a159e1b..c3539f7c 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Row.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Row.java @@ -95,7 +95,7 @@ public class Row extends AnnotatedExportOnlyWidget implements Layouter { MainAxisAlignment mainAxisAlignment = hAlign.getValue(); Map saved = new HashMap<>(); - for (DomElement child : getDomElement().getChildren()) { + for (DomElement child : buildContext.getChildren()) { if (!(child.getWidget() instanceof Flexible)) { Size requiredSize = child.getLayouter().layout(child, new ConstraintBox( 0, Integer.MAX_VALUE, @@ -110,7 +110,7 @@ public class Row extends AnnotatedExportOnlyWidget implements Layouter { boolean flexFound = false; int sumFlex = 0; - for (DomElement child : getDomElement().getChildren()) { + for (DomElement child : buildContext.getChildren()) { if (child.getWidget() instanceof Flexible) { sumFlex += Math.min(1, ((Flexible) child.getWidget()).flex.getValue()); flexFound =true; @@ -124,7 +124,7 @@ public class Row extends AnnotatedExportOnlyWidget implements Layouter { double remainingWidth = effwidth - width; double widthPer = remainingWidth / sumFlex; - for (DomElement child : getDomElement().getChildren()) { + for (DomElement child : buildContext.getChildren()) { if (child.getWidget() instanceof Flexible) { Size requiredSize = child.getLayouter().layout(child, new ConstraintBox( 0, widthPer * ((Flexible) child.getWidget()).flex.getValue(), @@ -153,14 +153,14 @@ public class Row extends AnnotatedExportOnlyWidget implements Layouter { double remaining = effwidth - width; if (remaining > 0) { startx = 0; - widthDelta = remaining / (getDomElement().getChildren().size()-1); + widthDelta = remaining / (buildContext.getChildren().size()-1); } else { startx = (effwidth - width) / 2; } } else if (mainAxisAlignment == MainAxisAlignment.SPACE_EVENLY) { double remaining = effwidth - width; if (remaining > 0) { - widthDelta = remaining / (getDomElement().getChildren().size()+1); + widthDelta = remaining / (buildContext.getChildren().size()+1); startx = widthDelta; } else { startx = (effwidth - width) / 2; @@ -168,14 +168,14 @@ public class Row extends AnnotatedExportOnlyWidget implements Layouter { } else if (mainAxisAlignment == MainAxisAlignment.SPACE_AROUND) { double remaining = effwidth - width; if (remaining > 0) { - widthDelta = 2 * remaining / getDomElement().getChildren().size(); + widthDelta = 2 * remaining / buildContext.getChildren().size(); startx = widthDelta / 2; } else { startx = (effwidth - width / 2); } } - for (DomElement child : getDomElement().getChildren()) { + for (DomElement child : buildContext.getChildren()) { Size size = saved.get(child); child.setRelativeBound(new Rect( @@ -193,4 +193,47 @@ public class Row extends AnnotatedExportOnlyWidget implements Layouter { height ); } + + + @Override + public double getMaxIntrinsicHeight(DomElement buildContext, double width) { + double maxHeight = 0; + double widthTaken = 0; + int sumFlex = 0; + for (DomElement child : buildContext.getChildren()) { + if (!(child.getWidget() instanceof Flexible)) { + widthTaken += child.getLayouter().getMaxIntrinsicWidth(buildContext, Double.POSITIVE_INFINITY); + maxHeight = Double.max(maxHeight, child.getLayouter().getMaxIntrinsicHeight(buildContext, 0)); + } else { + sumFlex += ((Flexible) child.getWidget()).flex.getValue(); + } + } + double leftOver = width - widthTaken; + if (sumFlex > 0) { + double per = leftOver / sumFlex; + for (DomElement child : buildContext.getChildren()) { + if (child.getWidget() instanceof Flexible) { + maxHeight = Double.max(maxHeight, child.getLayouter().getMaxIntrinsicHeight(buildContext, per * ((Flexible) child.getWidget()).flex.getValue())); + } + } + } + return maxHeight; + } + + @Override + public double getMaxIntrinsicWidth(DomElement buildContext, double height) { + double width = 0; + double flex = 0; + double maxPer = 0; + for (DomElement child : buildContext.getChildren()) { + if (child.getWidget() instanceof Flexible) { + flex += ((Flexible) child.getWidget()).flex.getValue(); + maxPer = Double.max(maxPer, child.getLayouter().getMaxIntrinsicWidth(buildContext, height) / + ((Flexible) child.getWidget()).flex.getValue()); + } else { + width += child.getLayouter().getMaxIntrinsicWidth(buildContext, height); + } + } + return width + maxPer * flex; + } } diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Scaler.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Scaler.java index b4682dc1..ccb5e94e 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Scaler.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Scaler.java @@ -49,7 +49,7 @@ public class Scaler extends AnnotatedExportOnlyWidget implements Layouter, Rende } @Override public Size layout(DomElement buildContext, ConstraintBox constraintBox) { - DomElement child = getDomElement().getChildren().get(0); + DomElement child = buildContext.getChildren().get(0); Size dims = child.getLayouter().layout(child, new ConstraintBox( (constraintBox.getMinWidth() / scale.getValue()), (constraintBox.getMaxWidth() / scale.getValue()), @@ -64,6 +64,18 @@ public class Scaler extends AnnotatedExportOnlyWidget implements Layouter, Rende return new Size(dims.getWidth() * scale.getValue(), dims.getHeight() * scale.getValue()); } + @Override + public double getMaxIntrinsicHeight(DomElement buildContext, double width) { + DomElement child = buildContext.getChildren().get(0); + return child.getLayouter().getMaxIntrinsicHeight(child, width / scale.getValue()) * scale.getValue(); + } + + @Override + public double getMaxIntrinsicWidth(DomElement buildContext, double height) { + DomElement child = buildContext.getChildren().get(0); + return child.getLayouter().getMaxIntrinsicWidth(child, height / scale.getValue()) * scale.getValue(); + } + @Override public Position transformPoint(DomElement element, Position pos) { Rect elementRect = element.getRelativeBound(); diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/SizedBox.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/SizedBox.java index 123cf53c..e06cd20e 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/SizedBox.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/SizedBox.java @@ -74,4 +74,14 @@ public class SizedBox extends AnnotatedExportOnlyWidget implements Layouter { public boolean canCutRequest() { return true; } + + @Override + public double getMaxIntrinsicHeight(DomElement buildContext, double width) { + return this.height.getValue(); + } + + @Override + public double getMaxIntrinsicWidth(DomElement buildContext, double height) { + return this.width.getValue(); + } } diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Stack.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Stack.java index cb5e492f..e9f04d13 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Stack.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Stack.java @@ -81,6 +81,24 @@ public class Stack extends AnnotatedExportOnlyWidget implements Renderer { } return new Size(maxW, maxH); } + + @Override + public double getMaxIntrinsicWidth(DomElement buildContext, double height) { + double max = 0; + for (DomElement child : buildContext.getChildren()) { + max = Double.max(max, child.getLayouter().getMaxIntrinsicWidth(child, height)); + } + return max; + } + + @Override + public double getMaxIntrinsicHeight(DomElement buildContext, double width) { + double max = 0; + for (DomElement child : buildContext.getChildren()) { + max = Double.max(max, child.getLayouter().getMaxIntrinsicHeight(child, width)); + } + return max; + } } diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Text.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Text.java index c03f06ea..3c5b1a2d 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Text.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Text.java @@ -211,4 +211,18 @@ public class Text extends AnnotatedExportOnlyWidget implements Layouter, Rendere Layouter.clamp(maxWidth2, constraintBox.getMinWidth(), constraintBox.getMaxWidth()), Layouter.clamp( (fr.FONT_HEIGHT * lineSpacing.getValue()) * wrappedTexts.size(), constraintBox.getMinHeight(), constraintBox.getMaxHeight())); } + + @Override + public double getMaxIntrinsicWidth(DomElement buildContext, double height) { + int max = 0; + for (String s : this.text.getValue().split("\n")) { + max = Integer.max(max, fr.getStringWidth(s)); + } + return max; + } + + @Override + public double getMaxIntrinsicHeight(DomElement buildContext, double width) { + return this.text.getValue().split("\n").length * (fr.FONT_HEIGHT * lineSpacing.getValue()); + } } diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/TextField.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/TextField.java index fedc9fc2..178d355d 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/TextField.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/TextField.java @@ -79,6 +79,15 @@ public class TextField extends AnnotatedExportOnlyWidget implements Renderer, La return Collections.EMPTY_LIST; } + @Override + public double getMaxIntrinsicWidth(DomElement buildContext, double height) { + return 0; + } + + @Override + public double getMaxIntrinsicHeight(DomElement buildContext, double width) { + return 15; + } @Override public Size layout(DomElement buildContext, ConstraintBox constraintBox) { diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/UnconstrainedBox.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/UnconstrainedBox.java index ed1ff211..b3a2db56 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/UnconstrainedBox.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/UnconstrainedBox.java @@ -57,4 +57,15 @@ public class UnconstrainedBox extends AnnotatedExportOnlyWidget implements Layou childCtx.setRelativeBound(new Rect(0,0, dim.getWidth(), dim.getHeight())); return new Size(dim.getWidth(), dim.getHeight()); } + + + @Override + public double getMaxIntrinsicWidth(DomElement buildContext, double height) { + return buildContext.getChildren().isEmpty() ? 0 : buildContext.getChildren().get(0).getLayouter().getMaxIntrinsicWidth(buildContext.getChildren().get(0), height); + } + + @Override + public double getMaxIntrinsicHeight(DomElement buildContext, double width) { + return buildContext.getChildren().isEmpty() ? 0 : buildContext.getChildren().get(0).getLayouter().getMaxIntrinsicHeight(buildContext.getChildren().get(0), width); + } } diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/image/URLImage.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/image/URLImage.java new file mode 100644 index 00000000..05996853 --- /dev/null +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/image/URLImage.java @@ -0,0 +1,103 @@ +/* + * Dungeons Guide - The most Integerelligent Hypixel Skyblock Dungeons Mod + * Copyright (C) 2023 cyoung06 (syeyoung) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package kr.syeyoung.dungeonsguide.mod.guiv2.elements.image; + +import kr.syeyoung.dungeonsguide.mod.DungeonsGuide; +import kr.syeyoung.dungeonsguide.mod.features.impl.discord.inviteViewer.ImageTexture; +import kr.syeyoung.dungeonsguide.mod.guiv2.BindableAttribute; +import kr.syeyoung.dungeonsguide.mod.guiv2.DomElement; +import kr.syeyoung.dungeonsguide.mod.guiv2.Widget; +import kr.syeyoung.dungeonsguide.mod.guiv2.elements.Flexible; +import kr.syeyoung.dungeonsguide.mod.guiv2.layouter.Layouter; +import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.ConstraintBox; +import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Rect; +import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Size; +import kr.syeyoung.dungeonsguide.mod.guiv2.renderer.Renderer; +import kr.syeyoung.dungeonsguide.mod.guiv2.renderer.RenderingContext; +import kr.syeyoung.dungeonsguide.mod.guiv2.xml.AnnotatedExportOnlyWidget; +import kr.syeyoung.dungeonsguide.mod.guiv2.xml.annotations.Export; +import net.minecraft.client.Minecraft; +import net.minecraft.util.ResourceLocation; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.function.Consumer; + +public class URLImage extends AnnotatedExportOnlyWidget implements Renderer, Layouter { + @Export(attributeName="url") + public final BindableAttribute url = new BindableAttribute(String.class); + + private ImageTexture imageTexture; + + public URLImage() { + url.addOnUpdate((prev, neu) -> { + ImageTexture.loadImage(neu, (texture) -> { + this.imageTexture = texture; + if (getDomElement() != null) + getDomElement().requestRelayout(); + }); + }); + } + + @Override + public List build(DomElement buildContext) { + return Collections.emptyList(); + } + + @Override + public void doRender(int absMouseX, int absMouseY, double relMouseX, double relMouseY, float partialTicks, RenderingContext context, DomElement buildContext) { + if (imageTexture == null) return; + imageTexture.drawFrame(0,0,buildContext.getSize().getWidth(), buildContext.getSize().getHeight()); + } + + @Override + public Size layout(DomElement buildContext, ConstraintBox constraintBox) { + if (imageTexture == null) return new Size(constraintBox.getMinWidth(), constraintBox.getMinHeight()); + + double heightIfWidthFit = constraintBox.getMaxWidth() * imageTexture.getHeight() / imageTexture.getWidth(); + double widthIfHeightFit = constraintBox.getMaxHeight() * imageTexture.getWidth() / imageTexture.getHeight(); + + if (heightIfWidthFit <= constraintBox.getMaxHeight()) { + return new Size(constraintBox.getMaxWidth(), Layouter.clamp(heightIfWidthFit, constraintBox.getMinHeight(), constraintBox.getMaxHeight())); + } else if (widthIfHeightFit <= constraintBox.getMaxWidth()){ + return new Size(Layouter.clamp(widthIfHeightFit, constraintBox.getMinWidth(), constraintBox.getMaxWidth()), constraintBox.getMaxHeight()); + } else { + throw new IllegalStateException("How is this possible mathmatically?"); + } + } + + @Override + public double getMaxIntrinsicWidth(DomElement buildContext, double height) { + return imageTexture == null ? 0 : height * imageTexture.getWidth() / imageTexture.getHeight(); + } + + @Override + public double getMaxIntrinsicHeight(DomElement buildContext, double width) { + return imageTexture == null ? 0 : width * imageTexture.getHeight() / imageTexture.getWidth(); + } +} diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/layouter/Layouter.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/layouter/Layouter.java index 6afcf07b..93a83fc1 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/layouter/Layouter.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/layouter/Layouter.java @@ -33,4 +33,11 @@ public interface Layouter { default boolean canCutRequest() { return false; } + + default double getMaxIntrinsicWidth(DomElement buildContext, double height) { + return 0; + } + default double getMaxIntrinsicHeight(DomElement buildContext, double width) { + return 0; + } } diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/layouter/SingleChildPassingLayouter.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/layouter/SingleChildPassingLayouter.java index 571e473d..dce30f29 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/layouter/SingleChildPassingLayouter.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/layouter/SingleChildPassingLayouter.java @@ -39,4 +39,15 @@ public class SingleChildPassingLayouter implements Layouter { childCtx.setRelativeBound(new Rect(0,0, dim.getWidth(), dim.getHeight())); return new Size(dim.getWidth(), dim.getHeight()); } + + + @Override + public double getMaxIntrinsicWidth(DomElement buildContext, double height) { + return buildContext.getChildren().isEmpty() ? 0 : buildContext.getChildren().get(0).getLayouter().getMaxIntrinsicWidth(buildContext.getChildren().get(0), height); + } + + @Override + public double getMaxIntrinsicHeight(DomElement buildContext, double width) { + return buildContext.getChildren().isEmpty() ? 0 : buildContext.getChildren().get(0).getLayouter().getMaxIntrinsicHeight(buildContext.getChildren().get(0), width); + } } diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/DomElementRegistry.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/DomElementRegistry.java index e2c79b22..6d446f32 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/DomElementRegistry.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/DomElementRegistry.java @@ -21,6 +21,7 @@ package kr.syeyoung.dungeonsguide.mod.guiv2.xml; import kr.syeyoung.dungeonsguide.mod.guiv2.Widget; import kr.syeyoung.dungeonsguide.mod.guiv2.elements.*; import kr.syeyoung.dungeonsguide.mod.guiv2.elements.image.ResourceImage; +import kr.syeyoung.dungeonsguide.mod.guiv2.elements.image.URLImage; import kr.syeyoung.dungeonsguide.mod.guiv2.view.TestView; import kr.syeyoung.dungeonsguide.mod.guiv2.xml.data.Parser; import kr.syeyoung.dungeonsguide.mod.guiv2.xml.data.ParserException; @@ -69,6 +70,8 @@ public class DomElementRegistry { register("AbstractScrollBar", new ExportedWidgetConverter(Scrollbar::new)); register("aspectRatio", new ExportedWidgetConverter(AspectRatioFitter::new)); register("BareResourceImage", new ExportedWidgetConverter(ResourceImage::new)); + register("IntrinsicWidth", new ExportedWidgetConverter(IntrinsicWidth::new)); + register("IntrinsicHeight", new ExportedWidgetConverter(IntrinsicHeight::new)); register("TestView", new ExportedWidgetConverter(TestView::new)); register("ColorButton", new DelegatingWidgetConverter(new ResourceLocation("dungeonsguide:gui/elements/simpleButton.gui"))); @@ -77,7 +80,7 @@ public class DomElementRegistry { register("SlowList", new DelegatingWidgetConverter(new ResourceLocation("dungeonsguide:gui/elements/slowlist.gui"))); register("ResourceImage", new DelegatingWidgetConverter(new ResourceLocation("dungeonsguide:gui/elements/ratioResourceImage.gui"))); - + register("UrlImage", new ExportedWidgetConverter(URLImage::new)); } public static Parser obtainParser(ResourceLocation resourceLocation) { -- cgit