From 87df9a914624b295e3e93db621ed2a8256eaf846 Mon Sep 17 00:00:00 2001 From: syeyoung <42869671+cyoung06@users.noreply.github.com> Date: Fri, 13 Jan 2023 13:11:13 +0900 Subject: Dg4.0 guisystem (#269) * - XML Like configuration for GUI Signed-off-by: syeyoung * - Stylesheets were never a good idea Signed-off-by: syeyoung * - Ref's are always bindable Signed-off-by: syeyoung * - cool components Column Background (color_ Row SizedBox Stack Padding Signed-off-by: syeyoung * - Update copyright header v2 Signed-off-by: syeyoung * - Bunch of stuff Signed-off-by: syeyoung * - Few more elements Signed-off-by: syeyoung * - View!! Signed-off-by: syeyoung * - Better click handlign - Popups Signed-off-by: syeyoung * - ComponentCreator for DX - test view (for testin Signed-off-by: syeyoung * - Column and Row shrink to crossAxisSize if its max is infinity - Gui test. Signed-off-by: syeyoung * - Load attributes after super constructor - Fix Stackoverflow in RootDom.setCursor - Test Gui Command - Test Gui to testview.gui - XML Parser settings to ignore comments - Controller check if element is actually an element, not a textnode. Signed-off-by: syeyoung * - Component Parent propagation - better placeholder Signed-off-by: syeyoung * - Line needs texture2d Signed-off-by: syeyoung * - igitignore update Signed-off-by: syeyoung * - gradle build file update Signed-off-by: syeyoung * - Flexible - Background uses singlehcildpassinglayouter - Helper methods in ConstraintBox Signed-off-by: syeyoung * - Line and Border - add updating code Signed-off-by: syeyoung * - Textfield Signed-off-by: syeyoung * - Column and Row with flex elements when given maximum mainAxis now throws an error - Column and Row when given maximum mainAxis now shrinks to children Signed-off-by: syeyoung * - Better architecture - I'll document it later on separate repo Signed-off-by: syeyoung * LGTM. - Might change rendering architecture. Separate child rendering and itself rendering Signed-off-by: syeyoung * - Fix some typo's and issues Signed-off-by: syeyoung * - make it work Signed-off-by: syeyoung * - smth Signed-off-by: syeyoung * - Button Signed-off-by: syeyoung * - colored button - passthroughs Signed-off-by: syeyoung * - fix issue in text Signed-off-by: syeyoung * - Delegating widgets and scrollbar Signed-off-by: syeyoung * - scrollbar Signed-off-by: syeyoung * - list Signed-off-by: syeyoung * - popup - align - stack now only propagates events to first child (lol) Signed-off-by: syeyoung * - Event propagation changes - some presets Signed-off-by: syeyoung * - moving stuff Signed-off-by: syeyoung Signed-off-by: syeyoung --- .../syeyoung/dungeonsguide/mod/DungeonsGuide.java | 2 + .../dungeonsguide/mod/commands/CommandDgDebug.java | 11 + .../dungeonsguide/mod/guiv2/BindableAttribute.java | 99 +++++ .../syeyoung/dungeonsguide/mod/guiv2/Context.java | 31 ++ .../dungeonsguide/mod/guiv2/DomElement.java | 242 ++++++++++++ .../mod/guiv2/ElementTreeWalkIterator.java | 48 +++ .../dungeonsguide/mod/guiv2/GuiScreenAdapter.java | 284 ++++++++++++++ .../syeyoung/dungeonsguide/mod/guiv2/RootDom.java | 74 ++++ .../syeyoung/dungeonsguide/mod/guiv2/Widget.java | 94 +++++ .../dungeonsguide/mod/guiv2/elements/AbsXY.java | 69 ++++ .../dungeonsguide/mod/guiv2/elements/Align.java | 64 +++ .../mod/guiv2/elements/AspectRatioFitter.java | 87 +++++ .../mod/guiv2/elements/Background.java | 61 +++ .../dungeonsguide/mod/guiv2/elements/Border.java | 140 +++++++ .../dungeonsguide/mod/guiv2/elements/Button.java | 127 ++++++ .../dungeonsguide/mod/guiv2/elements/Clip.java | 70 ++++ .../dungeonsguide/mod/guiv2/elements/Column.java | 193 +++++++++ .../dungeonsguide/mod/guiv2/elements/Flexible.java | 77 ++++ .../dungeonsguide/mod/guiv2/elements/Line.java | 122 ++++++ .../dungeonsguide/mod/guiv2/elements/Measure.java | 59 +++ .../dungeonsguide/mod/guiv2/elements/Padding.java | 80 ++++ .../mod/guiv2/elements/Placeholder.java | 66 ++++ .../dungeonsguide/mod/guiv2/elements/PopupMgr.java | 68 ++++ .../dungeonsguide/mod/guiv2/elements/Row.java | 196 ++++++++++ .../dungeonsguide/mod/guiv2/elements/Scaler.java | 99 +++++ .../mod/guiv2/elements/ScrollablePanel.java | 136 +++++++ .../mod/guiv2/elements/Scrollbar.java | 166 ++++++++ .../dungeonsguide/mod/guiv2/elements/SizedBox.java | 72 ++++ .../dungeonsguide/mod/guiv2/elements/Slot.java | 43 ++ .../dungeonsguide/mod/guiv2/elements/Stack.java | 98 +++++ .../dungeonsguide/mod/guiv2/elements/Text.java | 214 ++++++++++ .../mod/guiv2/elements/TextField.java | 433 +++++++++++++++++++++ .../mod/guiv2/elements/UnconstrainedBox.java | 60 +++ .../mod/guiv2/elements/image/Image.java | 63 +++ .../mod/guiv2/elements/image/ResourceImage.java | 54 +++ .../dungeonsguide/mod/guiv2/layouter/Layouter.java | 32 ++ .../mod/guiv2/layouter/NullLayouter.java | 33 ++ .../guiv2/layouter/SingleChildPassingLayouter.java | 42 ++ .../mod/guiv2/primitive/Animation.java | 38 ++ .../mod/guiv2/primitive/ConstraintBox.java | 40 ++ .../mod/guiv2/primitive/IPosition.java | 25 ++ .../dungeonsguide/mod/guiv2/primitive/IRect.java | 34 ++ .../dungeonsguide/mod/guiv2/primitive/ISize.java | 29 ++ .../mod/guiv2/primitive/Position.java | 28 ++ .../dungeonsguide/mod/guiv2/primitive/Rect.java | 32 ++ .../dungeonsguide/mod/guiv2/primitive/Size.java | 28 ++ .../mod/guiv2/renderer/DrawNothingRenderer.java | 29 ++ .../mod/guiv2/renderer/OnlyChildrenRenderer.java | 51 +++ .../dungeonsguide/mod/guiv2/renderer/Renderer.java | 34 ++ .../mod/guiv2/renderer/RenderingContext.java | 138 +++++++ .../mod/guiv2/renderer/SingleChildRenderer.java | 51 +++ .../dungeonsguide/mod/guiv2/view/TestPopup.java | 38 ++ .../dungeonsguide/mod/guiv2/view/TestView.java | 51 +++ .../mod/guiv2/xml/AnnotatedExportOnlyWidget.java | 86 ++++ .../mod/guiv2/xml/AnnotatedImportOnlyWidget.java | 124 ++++++ .../mod/guiv2/xml/AnnotatedWidget.java | 149 +++++++ .../mod/guiv2/xml/DelegatingWidget.java | 96 +++++ .../mod/guiv2/xml/DelegatingWidgetConverter.java | 54 +++ .../mod/guiv2/xml/DomElementRegistry.java | 91 +++++ .../mod/guiv2/xml/ExportedWidget.java | 25 ++ .../mod/guiv2/xml/ExportedWidgetConverter.java | 48 +++ .../mod/guiv2/xml/ImportingWidget.java | 29 ++ .../mod/guiv2/xml/ParsedWidgetConverter.java | 43 ++ .../guiv2/xml/PropByPropParsedWidgetConverter.java | 140 +++++++ .../mod/guiv2/xml/StringConversions.java | 51 +++ .../mod/guiv2/xml/annotations/Bind.java | 30 ++ .../mod/guiv2/xml/annotations/Export.java | 30 ++ .../mod/guiv2/xml/annotations/On.java | 30 ++ .../mod/guiv2/xml/annotations/Passthrough.java | 32 ++ .../mod/guiv2/xml/annotations/Passthroughs.java | 27 ++ .../dungeonsguide/mod/guiv2/xml/data/Parser.java | 25 ++ .../mod/guiv2/xml/data/ParserElement.java | 34 ++ .../mod/guiv2/xml/data/ParserElementList.java | 26 ++ .../mod/guiv2/xml/data/ParserException.java | 38 ++ .../mod/guiv2/xml/data/W3CBackedParser.java | 70 ++++ .../mod/guiv2/xml/data/W3CBackedParserElement.java | 72 ++++ .../mod/guiv2/xml/data/WidgetList.java | 26 ++ 77 files changed, 5931 insertions(+) create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/BindableAttribute.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/Context.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/DomElement.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/ElementTreeWalkIterator.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/GuiScreenAdapter.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/RootDom.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/Widget.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/AbsXY.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Align.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/AspectRatioFitter.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Background.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Border.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Button.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Clip.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Column.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Flexible.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Line.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Measure.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Padding.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Placeholder.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/PopupMgr.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Row.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Scaler.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/ScrollablePanel.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Scrollbar.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/SizedBox.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Slot.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Stack.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Text.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/TextField.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/UnconstrainedBox.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/image/Image.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/image/ResourceImage.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/layouter/Layouter.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/layouter/NullLayouter.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/layouter/SingleChildPassingLayouter.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/primitive/Animation.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/primitive/ConstraintBox.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/primitive/IPosition.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/primitive/IRect.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/primitive/ISize.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/primitive/Position.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/primitive/Rect.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/primitive/Size.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/renderer/DrawNothingRenderer.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/renderer/OnlyChildrenRenderer.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/renderer/Renderer.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/renderer/RenderingContext.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/renderer/SingleChildRenderer.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/view/TestPopup.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/view/TestView.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/AnnotatedExportOnlyWidget.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/AnnotatedImportOnlyWidget.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/AnnotatedWidget.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/DelegatingWidget.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/DelegatingWidgetConverter.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/DomElementRegistry.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/ExportedWidget.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/ExportedWidgetConverter.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/ImportingWidget.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/ParsedWidgetConverter.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/PropByPropParsedWidgetConverter.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/StringConversions.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/annotations/Bind.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/annotations/Export.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/annotations/On.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/annotations/Passthrough.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/annotations/Passthroughs.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/data/Parser.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/data/ParserElement.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/data/ParserElementList.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/data/ParserException.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/data/W3CBackedParser.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/data/W3CBackedParserElement.java create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/xml/data/WidgetList.java (limited to 'mod/src/main/java/kr') diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/DungeonsGuide.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/DungeonsGuide.java index 0bdcacfc..9dd515c7 100755 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/DungeonsGuide.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/DungeonsGuide.java @@ -38,6 +38,7 @@ import kr.syeyoung.dungeonsguide.mod.events.listener.PacketListener; import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry; import kr.syeyoung.dungeonsguide.mod.party.PartyManager; import kr.syeyoung.dungeonsguide.mod.resources.DGTexturePack; +import kr.syeyoung.dungeonsguide.mod.stomp.StompManager; import kr.syeyoung.dungeonsguide.mod.utils.AhUtils; import kr.syeyoung.dungeonsguide.mod.utils.BlockCache; import kr.syeyoung.dungeonsguide.mod.utils.TimeScoreUtil; @@ -238,6 +239,7 @@ public class DungeonsGuide implements DGInterface { progressbar.step("Opening connection"); + StompManager.getInstance().init(); registerEventsForge(cosmeticsManager = new CosmeticsManager()); diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/commands/CommandDgDebug.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/commands/CommandDgDebug.java index ab69fec6..5b553bdc 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/commands/CommandDgDebug.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/commands/CommandDgDebug.java @@ -40,6 +40,10 @@ import kr.syeyoung.dungeonsguide.mod.dungeon.roomprocessor.bossfight.BossfightPr import kr.syeyoung.dungeonsguide.mod.events.impl.DungeonLeftEvent; import kr.syeyoung.dungeonsguide.mod.features.AbstractFeature; import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry; +import kr.syeyoung.dungeonsguide.mod.guiv2.xml.DomElementRegistry; +import kr.syeyoung.dungeonsguide.mod.guiv2.GuiScreenAdapter; +import kr.syeyoung.dungeonsguide.mod.guiv2.RootDom; +import kr.syeyoung.dungeonsguide.mod.guiv2.view.TestView; import kr.syeyoung.dungeonsguide.mod.party.PartyContext; import kr.syeyoung.dungeonsguide.mod.party.PartyManager; import kr.syeyoung.dungeonsguide.mod.utils.*; @@ -452,6 +456,13 @@ public class CommandDgDebug extends CommandBase { } catch (Exception e) { e.printStackTrace(); } + } else if ("testgui".equals(arg)) { + GuiScreenAdapter adapter = new GuiScreenAdapter(new TestView()); + new Thread(DungeonsGuide.THREAD_GROUP, () -> { + Minecraft.getMinecraft().addScheduledTask(() -> { + Minecraft.getMinecraft().displayGuiScreen(adapter); + }); + }).start(); } else { sender.addChatMessage(new ChatComponentText("ain't gonna find much anything here")); sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg loadrooms §7-§f Reloads dungeon roomdata.")); diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/BindableAttribute.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/BindableAttribute.java new file mode 100644 index 00000000..2070aef3 --- /dev/null +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/BindableAttribute.java @@ -0,0 +1,99 @@ +/* + * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod + * Copyright (C) 2022 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; + +import lombok.Getter; + +import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +public class BindableAttribute { + public BindableAttribute(Class type) { + this.type = type; + initialized = false; + } + public BindableAttribute(Class type, T defaultValue) { + this.type = type; + value = defaultValue; + initialized = true; + } + + private boolean initialized = false; + @Getter + private final Class type; + private T value; + private List> onUpdates = new ArrayList<>(); + + private boolean updating = false; + public void setValue(T t) { + if (updating) return; + updating = true; + T old = this.value; + this.value = t; + if (!Objects.equals(t, old)) + for (BiConsumer onUpdate : onUpdates) { + onUpdate.accept(old, value); + } + updating = false; + initialized = true; + } + public T getValue() { + return value; + } + + public void addOnUpdate(BiConsumer onUpdate) { + onUpdates.add(onUpdate); + } + public void removeOnUpdate(BiConsumer onUpdate) { + onUpdates.remove(onUpdate); + } + + private Set> linkedWith = new HashSet<>(); + + private void boundSet(T old, T neu) { + setValue(neu); + } + + public void exportTo(BindableAttribute bindableAttribute) { // This method has to be called by exporting bindable attribute + if (bindableAttribute.type != type) throw new IllegalArgumentException("Different type!!"); + + this.addOnUpdate(bindableAttribute::boundSet); + bindableAttribute.addOnUpdate(this::boundSet); + linkedWith.add(bindableAttribute); + + if (bindableAttribute.initialized) + setValue(bindableAttribute.getValue()); + else + bindableAttribute.setValue(getValue()); + } + + public void unexport(BindableAttribute bindableAttribute) { + bindableAttribute.removeOnUpdate(this::boundSet); + removeOnUpdate(bindableAttribute::boundSet); + linkedWith.remove(bindableAttribute); + } + + public void unexportAll() { + Set> copy = new HashSet<>(linkedWith); + for (BindableAttribute tBindableAttribute : copy) { + unexport(tBindableAttribute); + } + } +} diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/Context.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/Context.java new file mode 100644 index 00000000..b05c1e65 --- /dev/null +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/Context.java @@ -0,0 +1,31 @@ +/* + * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod + * Copyright (C) 2022 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; + +import java.util.HashMap; +import java.util.Map; + +// TODO: get rid of this and change it with tree walking. +public class Context { + public Map CONTEXT = new HashMap<>(); + + public T getValue(Class clazz, String key) { + return (T) CONTEXT.get(key); + } +} diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/DomElement.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/DomElement.java new file mode 100644 index 00000000..44c538d6 --- /dev/null +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/DomElement.java @@ -0,0 +1,242 @@ +/* + * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod + * Copyright (C) 2022 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; + +import kr.syeyoung.dungeonsguide.mod.guiv2.elements.Stack; +import kr.syeyoung.dungeonsguide.mod.guiv2.layouter.Layouter; +import kr.syeyoung.dungeonsguide.mod.guiv2.layouter.NullLayouter; +import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Position; +import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Rect; +import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Size; +import kr.syeyoung.dungeonsguide.mod.guiv2.renderer.DrawNothingRenderer; +import kr.syeyoung.dungeonsguide.mod.guiv2.renderer.Renderer; +import kr.syeyoung.dungeonsguide.mod.utils.cursor.EnumCursor; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +public class DomElement { + @Getter + @Setter(AccessLevel.PACKAGE) + private Widget widget; + @Getter + @Setter(AccessLevel.PACKAGE) + private Renderer renderer = DrawNothingRenderer.INSTANCE; // renders element itself. + @Getter + @Setter(AccessLevel.PACKAGE) + private Layouter layouter = NullLayouter.INSTANCE; // layouts subelements + + @Getter + @Setter + private DomElement parent; + @Getter + private List children = new ArrayList<>(); + + @Getter + Context context; + + public DomElement() { + } + + @Getter + private boolean isMounted; + + + public void setMounted(boolean mounted) { + if (isMounted == mounted) { + return; + } + isMounted = mounted; + + for (DomElement child : children) { + child.context = context; + child.setMounted(mounted); + } + + if (mounted) widget.onMount(); + else { + if (isFocused()) + context.CONTEXT.put("focus", null); + widget.onUnmount(); + }; + } + + @Getter + private Rect relativeBound; // relative bound from parent, unapplied transformation + + public void setRelativeBound(Rect relativeBound) { + this.relativeBound = relativeBound; + this.size = new Size(relativeBound.getWidth(), relativeBound.getHeight()); + } + + @Getter @Setter + private Size size; + + @Getter @Setter + private Rect absBounds; // absolute bound from screen top left + + + + // event propagation + + public void requestRelayout() { + if (parent != null) + parent.requestRelayout(); + } + + public void addElementFirst(DomElement element) { + element.setParent(this); + children.add(0, element); + element.context = context; + element.setMounted(isMounted); + requestRelayout(); + } + public void addElement(DomElement element) { + element.setParent(this); + children.add(element); + element.context = context; + element.setMounted(isMounted); + requestRelayout(); + } + public void removeElement(DomElement element) { + element.setParent(null); + children.remove(element); + element.setMounted(false); + requestRelayout(); + } + + public void keyPressed0(char typedChar, int keyCode) { + for (DomElement childComponent : children) { + childComponent.keyPressed0(typedChar, keyCode); + if (widget instanceof Stack) break; + } + + if (isFocused()) + widget.keyPressed(typedChar, keyCode); + } + public void keyHeld0(char typedChar, int keyCode) { + for (DomElement childComponent : children) { + childComponent.keyHeld0(typedChar, keyCode); + if (widget instanceof Stack) break; + } + + if (isFocused()) + widget.keyHeld(typedChar, keyCode); + } + public void keyReleased0(char typedChar, int keyCode) { + for (DomElement childComponent : children) { + childComponent.keyReleased0(typedChar, keyCode); + if (widget instanceof Stack) break; + } + if (isFocused()) + widget.keyReleased(typedChar, keyCode); + } + + public void obtainFocus() { + context.CONTEXT.put("focus", this); + } + + public boolean isFocused() { + return context.getValue(DomElement.class, "focus") == this; + } + + public boolean mouseClicked0(int absMouseX, int absMouseY, double relMouseX0, double relMouseY0, int mouseButton) { + if (absBounds == null) return false; + if (!absBounds.contains(absMouseX, absMouseY)) { + return false; + } + + for (DomElement childComponent : children) { + Position transformed = renderer.transformPoint(childComponent, new Position(relMouseX0, relMouseY0)); + + if (childComponent.mouseClicked0(absMouseX, absMouseY, transformed.x, transformed.y, mouseButton)) { + return true; + } + } + + return widget.mouseClicked(absMouseX, absMouseY, relMouseX0, relMouseY0, mouseButton); + } + + + public void mouseReleased0(int absMouseX, int absMouseY, double relMouseX0, double relMouseY0, int state) { + if (absBounds == null) return; + + for (DomElement childComponent : children) { + Position transformed = renderer.transformPoint(childComponent, new Position(relMouseX0, relMouseY0)); + + childComponent.mouseReleased0(absMouseX, absMouseY, transformed.x, transformed.y, state); + } + widget.mouseReleased(absMouseX, absMouseY, relMouseX0, relMouseY0, state); + } + + public void mouseClickMove0(int absMouseX, int absMouseY, double relMouseX0, double relMouseY0, int clickedMouseButton, long timeSinceLastClick) { + if (absBounds == null) return; + + for (DomElement childComponent : children) { + Position transformed = renderer.transformPoint(childComponent, new Position(relMouseX0, relMouseY0)); + + childComponent.mouseClickMove0(absMouseX, absMouseY, transformed.x, transformed.y, clickedMouseButton, timeSinceLastClick); + } + if (isFocused()) + widget.mouseClickMove(absMouseX, absMouseY, relMouseX0, relMouseY0, clickedMouseButton, timeSinceLastClick); + } + public boolean mouseScrolled0(int absMouseX, int absMouseY, double relMouseX0, double relMouseY0, int scrollAmount) { + if (absBounds == null) return false; + + for (DomElement childComponent : children) { + Position transformed = renderer.transformPoint(childComponent, new Position(relMouseX0, relMouseY0)); + + if (childComponent.mouseScrolled0(absMouseX, absMouseY, transformed.x, transformed.y, scrollAmount)) { + return true; + } + } + if (!absBounds.contains(absMouseX, absMouseY) && !isFocused()) return false; + return widget.mouseScrolled(absMouseX, absMouseY, relMouseX0, relMouseY0, scrollAmount); + } + + + private boolean wasMouseIn = false; + public boolean mouseMoved0(int absMouseX, int absMouseY, double relMouseX0, double relMouseY0) { + if (absBounds == null) return false; + if (!absBounds.contains(absMouseX, absMouseY)) { + if (wasMouseIn) widget.mouseExited(absMouseX, absMouseY, relMouseX0, relMouseY0); + wasMouseIn = false; + return false; + } + if (!wasMouseIn) widget.mouseEntered(absMouseX, absMouseY, relMouseX0, relMouseY0); + wasMouseIn = true; + + for (DomElement childComponent : children) { + Position transformed = renderer.transformPoint(childComponent, new Position(relMouseX0, relMouseY0)); + + if (childComponent.mouseMoved0(absMouseX, absMouseY, transformed.x, transformed.getY())) { + return true; + } + } + return widget.mouseMoved(absMouseX, absMouseY, relMouseX0, relMouseY0); + } + + public void setCursor(EnumCursor enumCursor) { + parent.setCursor(enumCursor); + } +} diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/ElementTreeWalkIterator.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/ElementTreeWalkIterator.java new file mode 100644 index 00000000..c83fe4df --- /dev/null +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/ElementTreeWalkIterator.java @@ -0,0 +1,48 @@ +/* + * 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; + +import org.jetbrains.annotations.NotNull; + +import java.util.Iterator; + +public class ElementTreeWalkIterator implements Iterator, Iterable { + private DomElement current; + public ElementTreeWalkIterator(DomElement child) { + this.current = child; + } + + @Override + public boolean hasNext() { + return current != null; + } + + @Override + public DomElement next() { + DomElement c1 = current; + current = current.getParent(); + return c1; + } + + @NotNull + @Override + public Iterator iterator() { + return this; + } +} diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/GuiScreenAdapter.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/GuiScreenAdapter.java new file mode 100644 index 00000000..438431e4 --- /dev/null +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/GuiScreenAdapter.java @@ -0,0 +1,284 @@ +/* + * 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; + +import kr.syeyoung.dungeonsguide.mod.guiv2.RootDom; +import kr.syeyoung.dungeonsguide.mod.guiv2.Widget; +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.RenderingContext; +import kr.syeyoung.dungeonsguide.mod.utils.cursor.EnumCursor; +import kr.syeyoung.dungeonsguide.mod.utils.cursor.GLCursors; +import lombok.Getter; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.vertex.VertexBuffer; +import org.lwjgl.LWJGLException; +import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; + +import java.io.IOException; + +import static org.lwjgl.opengl.GL11.GL_GREATER; + +public class GuiScreenAdapter extends GuiScreen { + + @Getter + private final RootDom view; + private boolean isOpen = false; + + public GuiScreenAdapter(Widget widget) { + view = new RootDom(widget); + + try { + Mouse.setNativeCursor(GLCursors.getCursor(EnumCursor.DEFAULT)); + } catch (Throwable e) { + e.printStackTrace(); + } + } + + @Override + public void initGui() { + super.initGui(); + Keyboard.enableRepeatEvents(true); + isOpen = true; + view.setRelativeBound(new Rect(0,0,Minecraft.getMinecraft().displayWidth, Minecraft.getMinecraft().displayHeight)); + view.setAbsBounds(new Rect(0,0, Minecraft.getMinecraft().displayWidth, Minecraft.getMinecraft().displayHeight)); + view.setSize(new Size(Minecraft.getMinecraft().displayWidth, Minecraft.getMinecraft().displayHeight)); + view.getLayouter().layout(view, new ConstraintBox( + Minecraft.getMinecraft().displayWidth, + Minecraft.getMinecraft().displayWidth, + Minecraft.getMinecraft().displayHeight, + Minecraft.getMinecraft().displayHeight + )); + view.setMounted(true); + } + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks) { + int i = Mouse.getEventX(); + int j = this.mc.displayHeight - Mouse.getEventY(); + + if (view.isRelayoutRequested()) { + long start = System.nanoTime(); + + view.setRelayoutRequested(false); + System.out.println("relayout!"); + view.getLayouter().layout(view, new ConstraintBox( + Minecraft.getMinecraft().displayWidth, + Minecraft.getMinecraft().displayWidth, + Minecraft.getMinecraft().displayHeight, + Minecraft.getMinecraft().displayHeight + )); + System.out.println("Relayout took "+(System.nanoTime() - start) +"ns"); + } + + + ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + GlStateManager.pushMatrix(); + GlStateManager.disableDepth(); + GlStateManager.enableBlend(); + GlStateManager.enableAlpha(); + GlStateManager.alphaFunc(GL_GREATER, 0); + GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); + GlStateManager.color(1, 1, 1, 1); + GlStateManager.scale(1.0 / scaledResolution.getScaleFactor(), 1.0 / scaledResolution.getScaleFactor(), 1.0d); + view.getRenderer().doRender(i, j, i, j, partialTicks, new RenderingContext(), view); + GlStateManager.alphaFunc(GL_GREATER, 0.1f); + GlStateManager.popMatrix(); + GlStateManager.enableDepth(); + GlStateManager.disableTexture2D(); + GL11.glDisable(GL11.GL_SCISSOR_TEST); + } + + @Override + public void keyTyped(char typedChar, int keyCode) throws IOException { + try { + view.keyPressed0(typedChar, keyCode); + super.keyTyped(typedChar, keyCode); + } catch (Throwable e) { + if (e.getMessage() == null || !e.getMessage().contains("hack to stop")) + e.printStackTrace(); + } + } + + public void keyHeld(int keyCode, char typedChar) throws IOException { + try { + view.keyHeld0(typedChar, keyCode); + } catch (Throwable e) { + if (e.getMessage() == null || !e.getMessage().contains("hack to stop")) + e.printStackTrace(); + } + } + + public void keyReleased(int keyCode, char typedChar) throws IOException { + try { + view.keyReleased0(typedChar, keyCode); + } catch (Throwable e) { + if (e.getMessage() == null || !e.getMessage().contains("hack to stop")) + e.printStackTrace(); + } + } + + @Override + public void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException { + try { + super.mouseClicked(mouseX, mouseY, mouseButton); + view.mouseClicked0(mouseX, mouseY + , mouseX, mouseY, mouseButton); + } catch (Throwable e) { + if (e.getMessage() == null || !e.getMessage().contains("hack to stop")) + e.printStackTrace(); + } + } + + @Override + public void onGuiClosed() { + super.onGuiClosed(); + Keyboard.enableRepeatEvents(false); + isOpen = false; + + try { + Mouse.setNativeCursor(null); + view.setCursor(EnumCursor.DEFAULT); + } catch (LWJGLException e) { + e.printStackTrace(); + } + } + + @Override + public void mouseReleased(int mouseX, int mouseY, int state) { + try { + view.mouseReleased0(mouseX, mouseY + , mouseX, mouseY, state); + } catch (Throwable e) { + if (e.getMessage() == null || !e.getMessage().contains("hack to stop")) + e.printStackTrace(); + } + } + + @Override + public void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) { + try { + view.mouseClickMove0(mouseX, mouseY + , mouseX, mouseY, clickedMouseButton, timeSinceLastClick); + } catch (Throwable e) { + if (e.getMessage() == null || !e.getMessage().contains("hack to stop")) + e.printStackTrace(); + } + } + + public void mouseMove(int mouseX, int mouseY) { + try { + view.mouseMoved0(mouseX, mouseY + , mouseX, mouseY); + } catch (Throwable e) { + if (e.getMessage() == null || !e.getMessage().contains("hack to stop")) + e.printStackTrace(); + } + } + + + private int touchValue; + private int eventButton; + private long lastMouseEvent; + + + private int lastX, lastY; + + + @Override + public void handleMouseInput() throws IOException { + if (!isOpen) return; + try { + int i = Mouse.getEventX(); + int j = this.mc.displayHeight - Mouse.getEventY(); + int k = Mouse.getEventButton(); + + if (Mouse.getEventButtonState()) { + if (this.mc.gameSettings.touchscreen && this.touchValue++ > 0) { + return; + } + + this.eventButton = k; + this.lastMouseEvent = Minecraft.getSystemTime(); + this.mouseClicked(i, j, this.eventButton); + } else if (k != -1) { + if (this.mc.gameSettings.touchscreen && --this.touchValue > 0) { + return; + } + + this.eventButton = -1; + this.mouseReleased(i, j, k); + } else if (this.eventButton != -1 && this.lastMouseEvent > 0L) { + long l = Minecraft.getSystemTime() - this.lastMouseEvent; + this.mouseClickMove(i, j, this.eventButton, l); + } + if (lastX != i || lastY != j) { + try { + EnumCursor prevCursor = view.getCurrentCursor(); + view.setCursor(EnumCursor.DEFAULT); + this.mouseMove(i, j); + EnumCursor newCursor = view.getCurrentCursor(); + if (prevCursor != newCursor) Mouse.setNativeCursor(GLCursors.getCursor(newCursor)); + } catch (Throwable e) { + if (e.getMessage() == null || !e.getMessage().contains("hack to stop")) + e.printStackTrace(); + } + } + + + int wheel = Mouse.getEventDWheel(); + if (wheel != 0) { + view.mouseScrolled0(i, j, i, j, wheel); + } + lastX = i; + lastY = j; + } catch (Throwable e) { + e.printStackTrace(); + } + } + + public void handleKeyboardInput() throws IOException { + if (!isOpen) return; + + if (Keyboard.getEventKeyState()) { + if (Keyboard.isRepeatEvent()) + this.keyHeld(Keyboard.getEventKey(), Keyboard.getEventCharacter()); + else + this.keyTyped(Keyboard.getEventCharacter(), Keyboard.getEventKey()); + } else { + this.keyReleased(Keyboard.getEventKey(), Keyboard.getEventCharacter()); + } + + this.mc.dispatchKeypresses(); + } + + @Override + public void handleInput() throws IOException { +// Keyboard.enableRepeatEvents(true); // i hope it's temproary solution + super.handleInput(); + } +} diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/RootDom.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/RootDom.java new file mode 100644 index 00000000..a9501212 --- /dev/null +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/RootDom.java @@ -0,0 +1,74 @@ +/* + * 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; + +import kr.syeyoung.dungeonsguide.mod.guiv2.Context; +import kr.syeyoung.dungeonsguide.mod.guiv2.DomElement; +import kr.syeyoung.dungeonsguide.mod.guiv2.Widget; +import kr.syeyoung.dungeonsguide.mod.guiv2.layouter.SingleChildPassingLayouter; +import kr.syeyoung.dungeonsguide.mod.guiv2.renderer.SingleChildRenderer; +import kr.syeyoung.dungeonsguide.mod.utils.cursor.EnumCursor; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +public class RootDom extends DomElement { + + private static class DummyWidget extends Widget { + @Override + public List build(DomElement buildContext) { + return null; + } + } + public RootDom(Widget widget) { + context = new Context(); + setLayouter(SingleChildPassingLayouter.INSTANCE); + setRenderer(SingleChildRenderer.INSTANCE); + setWidget(new DummyWidget()); + + DomElement element = widget.createDomElement(this);// and it's mounted! + addElement(element); + } + + @Getter + private EnumCursor currentCursor; + + @Override + public void setCursor(EnumCursor enumCursor) { + currentCursor = enumCursor; + } + + @Getter + @Setter + private boolean relayoutRequested; + + @Override + public void requestRelayout() { + relayoutRequested = true; + } + + + + @Override + public boolean mouseClicked0(int absMouseX, int absMouseY, double relMouseX0, double relMouseY0, int mouseButton) { + getContext().CONTEXT.put("focus", null); + return super.mouseClicked0(absMouseX, absMouseY, relMouseX0, relMouseY0, mouseButton); + } +} diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/Widget.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/Widget.java new file mode 100644 index 00000000..4895ae8b --- /dev/null +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/Widget.java @@ -0,0 +1,94 @@ +/* + * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod + * Copyright (C) 2022 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; + +import kr.syeyoung.dungeonsguide.mod.guiv2.layouter.Layouter; +import kr.syeyoung.dungeonsguide.mod.guiv2.layouter.SingleChildPassingLayouter; +import kr.syeyoung.dungeonsguide.mod.guiv2.renderer.Renderer; +import kr.syeyoung.dungeonsguide.mod.guiv2.renderer.SingleChildRenderer; +import lombok.Getter; + +import java.util.*; + +public abstract class Widget { + + @Getter + private DomElement domElement = new DomElement(); + + + private boolean multiatfirst = false; + public DomElement createDomElement(DomElement parent) { + if (domElement.getWidget() != null) throw new IllegalStateException("Controller already has corresponding DomElement!"); + domElement = new DomElement(); + domElement.setWidget(this); + domElement.setParent(parent); + + domElement.setLayouter(createLayouter()); + domElement.setRenderer(createRenderer()); + + // build + List widgets = build(domElement); + for (Widget widget : widgets) { + DomElement domElement1 = widget.createDomElement(domElement); + domElement.addElement(domElement1); + } + return domElement; + } + + protected Layouter createLayouter() { + if (this instanceof Layouter) return (Layouter) this; + return SingleChildPassingLayouter.INSTANCE; + } + protected Renderer createRenderer() { + if (this instanceof Renderer) return (Renderer) this; + return SingleChildRenderer.INSTANCE; + } + + public abstract List build(DomElement buildContext); + + public Widget() { + // parameters shall be passed through constructor + // or maybe a "builder" + // set bindable props in the builder and yeah + // or maybe set raw props + } + + + public boolean mouseScrolled(int absMouseX, int absMouseY, double relMouseX0, double relMouseY0, int scrollAmount) { + return false; + } + public boolean mouseMoved(int absMouseX, int absMouseY, double relMouseX0, double relMouseY0) { + return false; + } + public void mouseClickMove(int absMouseX, int absMouseY, double relMouseX, double relMouseY, int clickedMouseButton, long timeSinceLastClick) {} + public void mouseReleased(int absMouseX, int absMouseY, double relMouseX, double relMouseY, int state) {} + public boolean mouseClicked(int absMouseX, int absMouseY, double relMouseX, double relMouseY, int mouseButton) { + return false; + } + public void keyReleased(char typedChar, int keyCode) {} + public void keyHeld(char typedChar, int keyCode) {} + public void keyPressed(char typedChar, int keyCode) {} + public void mouseExited(int absMouseX, int absMouseY, double relMouseX, double relMouseY) {} + public void mouseEntered(int absMouseX, int absMouseY, double relMouseX, double relMouseY) {} + + public void onMount() { + } + public void onUnmount() { + } +} 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 new file mode 100644 index 00000000..eb9b07da --- /dev/null +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/AbsXY.java @@ -0,0 +1,69 @@ +/* + * 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 AbsXY extends AnnotatedExportOnlyWidget implements Layouter { + @Export(attributeName = "$") + public final BindableAttribute child = new BindableAttribute<>(Widget.class); + + @Export(attributeName = "x") + public final BindableAttribute x = new BindableAttribute<>(Double.class, 0.0); + + @Export(attributeName = "y") + public final BindableAttribute y = new BindableAttribute<>(Double.class, 0.0); + + public AbsXY() { + x.addOnUpdate(this::setLocations); + y.addOnUpdate(this::setLocations); + } + + private void setLocations(double old, double neu) { + if (getDomElement().getChildren().size() <= 0) return; + DomElement child = getDomElement().getChildren().get(0); + child.setRelativeBound(new Rect(x.getValue(), y.getValue(), child.getSize().getWidth(), child.getSize().getHeight())); + } + + @Override + public Size layout(DomElement buildContext, ConstraintBox constraintBox) { + DomElement child = buildContext.getChildren().get(0); + Size size = child.getLayouter().layout(buildContext, new ConstraintBox( + 0,constraintBox.getMaxWidth() - x.getValue(), 0, constraintBox.getMaxHeight()-y.getValue() + )); + child.setRelativeBound(new Rect(x.getValue(), y.getValue(), size.getWidth(), size.getHeight())); + return new Size(constraintBox.getMaxWidth(), constraintBox.getMaxHeight()); + } + + @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 new file mode 100644 index 00000000..5c1bce11 --- /dev/null +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Align.java @@ -0,0 +1,64 @@ +/* + * 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 Align extends AnnotatedExportOnlyWidget implements Layouter { + @Export(attributeName = "hAlign") + public final BindableAttribute hAlign = new BindableAttribute<>(Alignment.class, Alignment.CENTER); + @Export(attributeName = "vAlign") + public final BindableAttribute vAlign = new BindableAttribute<>(Alignment.class, Alignment.CENTER); + + @Export(attributeName = "$") + public final BindableAttribute child = new BindableAttribute<>(Widget.class); + public static enum Alignment { + START, CENTER, END + } + + @Override + public List build(DomElement buildContext) { + return Collections.singletonList(child.getValue()); + } + + @Override + public Size layout(DomElement buildContext, ConstraintBox constraintBox) { + DomElement theOnly = getDomElement().getChildren().get(0); + Size size = theOnly.getLayouter().layout(theOnly, new ConstraintBox( + 0, constraintBox.getMaxWidth(), 0, constraintBox.getMaxHeight() + )); + theOnly.setRelativeBound(new Rect( + (constraintBox.getMaxWidth() - size.getWidth())/2, + (constraintBox.getMaxHeight() - size.getHeight())/2, + size.getWidth(), size.getHeight() + )); + return new Size(constraintBox.getMaxWidth(), constraintBox.getMaxHeight()); + } +} 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 new file mode 100644 index 00000000..0e6f9ed9 --- /dev/null +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/AspectRatioFitter.java @@ -0,0 +1,87 @@ +/* + * 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 AspectRatioFitter extends AnnotatedExportOnlyWidget implements Layouter { + @Export(attributeName = "$") + public final BindableAttribute widget = new BindableAttribute<>(Widget.class); + @Export(attributeName = "width") + public final BindableAttribute width = new BindableAttribute<>(Integer.class, 1); + @Export(attributeName = "height") + public final BindableAttribute height = new BindableAttribute<>(Integer.class, 1); + + @Export(attributeName = "fit") + public final BindableAttribute fit = new BindableAttribute<>(Flexible.FlexFit.class, Flexible.FlexFit.TIGHT); + + + @Override + public Size layout(DomElement buildContext, ConstraintBox constraintBox) { + // ratio is width/height + + + double heightIfWidthFit = constraintBox.getMaxWidth() * height.getValue() / width.getValue(); + double widthIfHeightFit = constraintBox.getMaxHeight() * width.getValue() / height.getValue(); + + DomElement target = null; + if (!buildContext.getChildren().isEmpty()) + target = buildContext.getChildren().get(0); + if (heightIfWidthFit <= constraintBox.getMaxHeight()) { + if (target != null) { + Size size = target.getLayouter().layout(target, new ConstraintBox( + fit.getValue() == Flexible.FlexFit.LOOSE ? constraintBox.getMinWidth() : constraintBox.getMaxWidth(), constraintBox.getMaxWidth(), + fit.getValue() == Flexible.FlexFit.LOOSE ? constraintBox.getMinHeight() : heightIfWidthFit, heightIfWidthFit + )); + target.setRelativeBound(new Rect(0,0,size.getWidth(), size.getHeight())); + return size; + } + return new Size(constraintBox.getMaxWidth(), heightIfWidthFit); + } else if (widthIfHeightFit <= constraintBox.getMaxWidth()){ + if (target != null) { + Size size = target.getLayouter().layout(target, new ConstraintBox( + fit.getValue() == Flexible.FlexFit.LOOSE ? constraintBox.getMinWidth() : widthIfHeightFit, widthIfHeightFit, + fit.getValue() == Flexible.FlexFit.LOOSE ? constraintBox.getMinHeight() : constraintBox.getMaxHeight(), constraintBox.getMaxHeight() + )); + target.setRelativeBound(new Rect(0,0,size.getWidth(), size.getHeight())); + return size; + } + + return new Size(widthIfHeightFit, constraintBox.getMaxHeight()); + } else { + throw new IllegalStateException("How is this possible mathmatically?"); + } + } + + @Override + public List build(DomElement buildContext) { + return Collections.singletonList(widget.getValue()); + } +} diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Background.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Background.java new file mode 100644 index 00000000..e808f2fd --- /dev/null +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/Background.java @@ -0,0 +1,61 @@ +/* + * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod + * Copyright (C) 2022 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