From d19168614cd34fed3d621ac02ff153eebd7ada61 Mon Sep 17 00:00:00 2001 From: tanishisherewith <120117618+tanishisherewithhh@users.noreply.github.com> Date: Thu, 26 Feb 2026 13:46:04 +0530 Subject: [PATCH 01/22] An attempt to 1.21.11 Runs, but rendering is broken. --- build.gradle | 7 +- gradle.properties | 13 +- gradle/wrapper/gradle-wrapper.properties | 5 +- .../dynamichud/DynamicHUD.java | 43 +- .../dynamichud/HudRender.java | 30 - .../dynamichud/IntegrationTest.java | 22 +- .../dynamichud/config/GlobalConfig.java | 56 +- .../dynamichud/helpers/ColorHelper.java | 16 +- .../dynamichud/helpers/DrawHelper.java | 549 ++++++++---------- .../dynamichud/helpers/MouseColorQuery.java | 16 +- .../dynamichud/helpers/TextureHelper.java | 50 +- .../animations/MathAnimations.java | 20 +- .../integration/DefaultIntegrationImpl.java | 6 + .../integration/DynamicHudIntegration.java | 19 +- .../integration/IntegrationManager.java | 20 +- .../dynamichud/internal/IBufferBuilder.java | 8 + .../dynamichud/internal/IRenderLayer.java | 22 - .../dynamichud/internal/WarningScreen.java | 62 +- .../dynamichud/mixins/BufferBuilderMixin.java | 33 ++ .../dynamichud/mixins/MinecraftMixin.java | 15 + .../dynamichud/mixins/OptionsScreenMixin.java | 48 +- .../dynamichud/mixins/RenderLayerMixin.java | 41 -- .../dynamichud/mixins/ScreenMixin.java | 13 +- .../renderstates/GeometryRenderState.java | 38 ++ .../GradientShadowRenderState.java | 44 ++ .../InterpolatedCurveRenderState.java | 59 ++ .../QuadColorRectRenderState.java | 42 ++ .../renderstates/RoundedRectRenderState.java | 57 ++ .../screens/AbstractMoveableScreen.java | 109 ++-- .../dynamichud/utils/CustomRenderLayers.java | 152 +++-- .../dynamichud/utils/Util.java | 8 +- .../utils/contextmenu/ContextMenu.java | 17 +- .../utils/contextmenu/ContextMenuManager.java | 6 +- .../contextmenuscreen/ContextMenuScreen.java | 62 +- .../ContextMenuScreenFactory.java | 2 +- .../ContextMenuScreenRegistry.java | 2 +- .../DefaultContextMenuScreenFactory.java | 2 +- .../contextmenu/layout/LayoutContext.java | 52 +- .../contextmenu/options/BooleanOption.java | 24 +- .../contextmenu/options/ColorOption.java | 4 +- .../contextmenu/options/DoubleOption.java | 12 +- .../utils/contextmenu/options/EnumOption.java | 4 +- .../utils/contextmenu/options/ListOption.java | 4 +- .../utils/contextmenu/options/Option.java | 26 +- .../contextmenu/options/OptionGroup.java | 12 +- .../contextmenu/options/RunnableOption.java | 6 +- .../contextmenu/options/SubMenuOption.java | 10 +- .../options/coloroption/AlphaSlider.java | 10 +- .../options/coloroption/ColorGradient.java | 23 +- .../coloroption/ColorPickerButton.java | 13 +- .../options/coloroption/HueSlider.java | 14 +- .../options/coloroption/SaturationHueBox.java | 13 +- .../contextmenu/skinsystem/ClassicSkin.java | 121 ++-- .../contextmenu/skinsystem/MinecraftSkin.java | 219 ++++--- .../contextmenu/skinsystem/ModernSkin.java | 406 +++++++------ .../utils/contextmenu/skinsystem/Skin.java | 10 +- .../skinsystem/interfaces/GroupableSkin.java | 4 +- .../skinsystem/interfaces/SkinRenderer.java | 4 +- .../utils/handlers/ScrollHandler.java | 9 +- .../dynamichud/widget/DynamicValueWidget.java | 6 +- .../dynamichud/widget/UserManageable.java | 6 - .../dynamichud/widget/Widget.java | 79 ++- .../dynamichud/widget/WidgetManager.java | 17 +- .../dynamichud/widget/WidgetRenderer.java | 51 +- .../dynamichud/widgets/GraphWidget.java | 141 ++--- .../dynamichud/widgets/ItemWidget.java | 20 +- .../dynamichud/widgets/TextWidget.java | 93 ++- src/main/resources/dynamichud.mixins.json | 11 +- src/main/resources/fabric.mod.json | 5 +- 69 files changed, 1663 insertions(+), 1480 deletions(-) delete mode 100644 src/main/java/com/tanishisherewith/dynamichud/HudRender.java create mode 100644 src/main/java/com/tanishisherewith/dynamichud/internal/IBufferBuilder.java delete mode 100644 src/main/java/com/tanishisherewith/dynamichud/internal/IRenderLayer.java create mode 100644 src/main/java/com/tanishisherewith/dynamichud/mixins/BufferBuilderMixin.java create mode 100644 src/main/java/com/tanishisherewith/dynamichud/mixins/MinecraftMixin.java delete mode 100644 src/main/java/com/tanishisherewith/dynamichud/mixins/RenderLayerMixin.java create mode 100644 src/main/java/com/tanishisherewith/dynamichud/renderstates/GeometryRenderState.java create mode 100644 src/main/java/com/tanishisherewith/dynamichud/renderstates/GradientShadowRenderState.java create mode 100644 src/main/java/com/tanishisherewith/dynamichud/renderstates/InterpolatedCurveRenderState.java create mode 100644 src/main/java/com/tanishisherewith/dynamichud/renderstates/QuadColorRectRenderState.java create mode 100644 src/main/java/com/tanishisherewith/dynamichud/renderstates/RoundedRectRenderState.java delete mode 100644 src/main/java/com/tanishisherewith/dynamichud/widget/UserManageable.java diff --git a/build.gradle b/build.gradle index b6f4027..8d9cd23 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'fabric-loom' version '1.10-SNAPSHOT' + id 'net.fabricmc.fabric-loom-remap' version "${loom_version}" id 'maven-publish' } @@ -13,8 +13,6 @@ base { allprojects { apply plugin: "java" apply plugin: "maven-publish" - - archivesBaseName = rootProject.archives_base_name } repositories { @@ -33,7 +31,7 @@ repositories { dependencies { // To change the versions see the gradle.properties file minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" + mappings loom.officialMojangMappings() modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" @@ -64,7 +62,6 @@ java { sourceCompatibility = JavaVersion.VERSION_21 targetCompatibility = JavaVersion.VERSION_21 - archivesBaseName = project.archives_base_name // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task // if it is present. // If you remove this line, sources will not be generated. diff --git a/gradle.properties b/gradle.properties index d78b830..1c7c0d3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,11 +2,14 @@ org.gradle.jvmargs=-Xmx1G org.gradle.parallel=true +# IntelliJ IDEA is not yet fully compatible with configuration cache, see: https://github.com/FabricMC/fabric-loom/issues/1349 +org.gradle.configuration-cache=false + # Fabric Properties # check these on https://fabricmc.net/develop -minecraft_version=1.21.5 -yarn_mappings=1.21.5+build.1 -loader_version=0.16.10 +minecraft_version=1.21.11 +loader_version=0.18.2 +loom_version=1.14-SNAPSHOT # Mod Properties # need versioning system @@ -15,5 +18,5 @@ maven_group = com.tanishisherewith archives_base_name = dynamichud # Dependencies -fabric_version=0.119.5+1.21.5 -yacl_version=3.6.6+1.21.5-fabric \ No newline at end of file +fabric_version=0.139.4+1.21.11 +yacl_version=3.8.2+1.21.11-fabric \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9bf7bd3..d205b54 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists +zipStorePath=wrapper/dists \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/DynamicHUD.java b/src/main/java/com/tanishisherewith/dynamichud/DynamicHUD.java index 7021a07..53dc955 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/DynamicHUD.java +++ b/src/main/java/com/tanishisherewith/dynamichud/DynamicHUD.java @@ -1,25 +1,41 @@ package com.tanishisherewith.dynamichud; +import com.mojang.blaze3d.platform.InputConstants; import com.tanishisherewith.dynamichud.config.GlobalConfig; import com.tanishisherewith.dynamichud.helpers.MouseColorQuery; import com.tanishisherewith.dynamichud.integration.IntegrationManager; +import com.tanishisherewith.dynamichud.widget.WidgetRenderer; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; -import net.fabricmc.fabric.api.client.rendering.v1.HudLayerRegistrationCallback; -import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; -import net.minecraft.client.MinecraftClient; +import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; +import net.fabricmc.fabric.api.client.rendering.v1.hud.HudElementRegistry; +import net.fabricmc.fabric.api.client.rendering.v1.hud.VanillaHudElements; +import net.fabricmc.fabric.impl.client.rendering.hud.HudElementRegistryImpl; +import net.minecraft.client.KeyMapping; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.rendertype.RenderType; +import net.minecraft.client.renderer.rendertype.RenderTypes; +import net.minecraft.resources.Identifier; +import org.lwjgl.glfw.GLFW; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Environment(EnvType.CLIENT) public class DynamicHUD implements ClientModInitializer { - public static MinecraftClient MC = MinecraftClient.getInstance(); + public static Minecraft MC = Minecraft.getInstance(); public static final Logger logger = LoggerFactory.getLogger("DynamicHud"); public static String MOD_ID = "dynamichud"; + static KeyMapping EDITOR_SCREEN_KEYBIND = KeyBindingHelper.registerKeyBinding(new KeyMapping( + "DynamicHud Editor Screen", + InputConstants.Type.KEYSYM, + GLFW.GLFW_KEY_RIGHT_SHIFT, + KeyMapping.Category.register(Identifier.fromNamespaceAndPath("dynamichud", "editor_screen")) + )); + public static void printInfo(String msg) { logger.info(msg); } @@ -28,6 +44,7 @@ public static void printWarn(String msg) { logger.warn(msg); } + @Override public void onInitializeClient() { printInfo("Initialising DynamicHUD"); @@ -35,10 +52,22 @@ public void onInitializeClient() { //YACL load GlobalConfig.HANDLER.load(); - IntegrationManager.integrate(); + ClientLifecycleEvents.CLIENT_STARTED.register((minecraft)-> IntegrationManager.integrate()); + //In game screen render. - HudLayerRegistrationCallback.EVENT.register(new HudRender()); + /* + * Using the fabric event {@link HudElementRegistry} to render widgets in the game HUD. + * Mouse positions are passed in the negatives even though theoretically it's in the centre of the screen. + */ + HudElementRegistryImpl.attachElementAfter(VanillaHudElements.MISC_OVERLAYS, + Identifier.fromNamespaceAndPath("dynamichud","hudrender_callback"), + (graphics, tickCounter) -> { + for (WidgetRenderer widgetRenderer : IntegrationManager.getWidgetRenderers()) { + widgetRenderer.renderWidgets(graphics, -120, -120); + } + }); + ClientTickEvents.END_CLIENT_TICK.register(mc-> MouseColorQuery.processIfPending()); } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/HudRender.java b/src/main/java/com/tanishisherewith/dynamichud/HudRender.java deleted file mode 100644 index f7abd75..0000000 --- a/src/main/java/com/tanishisherewith/dynamichud/HudRender.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.tanishisherewith.dynamichud; - -import com.tanishisherewith.dynamichud.integration.IntegrationManager; -import com.tanishisherewith.dynamichud.widget.WidgetRenderer; -import net.fabricmc.fabric.api.client.rendering.v1.HudLayerRegistrationCallback; -import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; -import net.fabricmc.fabric.api.client.rendering.v1.IdentifiedLayer; -import net.fabricmc.fabric.api.client.rendering.v1.LayeredDrawerWrapper; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.render.RenderTickCounter; -import net.minecraft.util.Identifier; - -/** - * Using the fabric event {@link HudLayerRegistrationCallback} to render widgets in the game HUD. - * Mouse positions are passed in the negatives even though theoretically it's in the centre of the screen. - */ -public class HudRender implements HudLayerRegistrationCallback { - @Override - public void register(LayeredDrawerWrapper layeredDrawer) { - layeredDrawer.attachLayerAfter( - IdentifiedLayer.MISC_OVERLAYS, - IdentifiedLayer.of(Identifier.of("dynamichud","hudrender_callback"), - (context, tickCounter) -> { - for (WidgetRenderer widgetRenderer : IntegrationManager.getWidgetRenderers()) { - widgetRenderer.renderWidgets(context, -120, -120); - } - }) - ); - } -} diff --git a/src/main/java/com/tanishisherewith/dynamichud/IntegrationTest.java b/src/main/java/com/tanishisherewith/dynamichud/IntegrationTest.java index e6c010c..1dd92c6 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/IntegrationTest.java +++ b/src/main/java/com/tanishisherewith/dynamichud/IntegrationTest.java @@ -1,5 +1,6 @@ package com.tanishisherewith.dynamichud; +import com.mojang.blaze3d.platform.InputConstants; import com.tanishisherewith.dynamichud.integration.DynamicHudConfigurator; import com.tanishisherewith.dynamichud.integration.DynamicHudIntegration; import com.tanishisherewith.dynamichud.screens.AbstractMoveableScreen; @@ -7,8 +8,12 @@ import com.tanishisherewith.dynamichud.widget.Widget; import com.tanishisherewith.dynamichud.widgets.GraphWidget; import com.tanishisherewith.dynamichud.widgets.TextWidget; -import net.minecraft.client.gui.screen.TitleScreen; -import net.minecraft.text.Text; +import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; +import net.minecraft.client.KeyMapping; +import net.minecraft.client.gui.screens.TitleScreen; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.Identifier; +import org.lwjgl.glfw.GLFW; import java.awt.*; @@ -23,13 +28,13 @@ public class IntegrationTest implements DynamicHudIntegration { public void init() { //Global registry // We recommend using the syntax "modid:key_name" for easier debugging and to prevent data conflicts in global registries. - DynamicValueRegistry.registerGlobal("dynamichud:FPS", () -> "FPS: " + DynamicHUD.MC.getCurrentFps()); + DynamicValueRegistry.registerGlobal("dynamichud:FPS", () -> "FPS: " + DynamicHUD.MC.getFps()); //Local registry registry = new DynamicValueRegistry(DynamicHUD.MOD_ID); - registry.registerLocal("Hello", () -> "Hello " + DynamicHUD.MC.getSession().getUsername() + "!"); + registry.registerLocal("Hello", () -> "Hello " + DynamicHUD.MC.getGameProfile().name() + "!"); registry.registerLocal("DynamicHUD", () -> "DynamicHUD"); - registry.registerLocal("FPS", () -> DynamicHUD.MC.getCurrentFps()); + registry.registerLocal("FPS", () -> DynamicHUD.MC.getFps()); FPSWidget = new TextWidget.Builder() .setX(250) @@ -99,7 +104,7 @@ public DynamicHudConfigurator configure(DynamicHudConfigurator configurator) { //renderer.shouldRenderInGameHud(true); renderer.addScreen(TitleScreen.class); }) - .withMoveableScreen(config -> new AbstractMoveableScreen(Text.literal("Editor Screen"), config.getRenderer()) {}); + .withMoveableScreen(config -> new AbstractMoveableScreen(Component.literal("Editor Screen"), config.getRenderer()) {}); return configurator; } @@ -108,4 +113,9 @@ public DynamicHudConfigurator configure(DynamicHudConfigurator configurator) { public void registerCustomWidgets() { //WidgetManager.addWidgetData(MyWidget.DATA); } + + @Override + public KeyMapping getKeyBind() { + return DynamicHUD.EDITOR_SCREEN_KEYBIND; + } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/config/GlobalConfig.java b/src/main/java/com/tanishisherewith/dynamichud/config/GlobalConfig.java index e832380..b1dcd44 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/config/GlobalConfig.java +++ b/src/main/java/com/tanishisherewith/dynamichud/config/GlobalConfig.java @@ -6,16 +6,16 @@ import dev.isxander.yacl3.config.v2.api.SerialEntry; import dev.isxander.yacl3.config.v2.api.serializer.GsonConfigSerializerBuilder; import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.text.Text; -import net.minecraft.util.Identifier; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.Identifier; import java.awt.*; public final class GlobalConfig { public static final ConfigClassHandler HANDLER = ConfigClassHandler.createBuilder(GlobalConfig.class) - .id(Identifier.of("dynamichud", "dynamichud_config")) + .id(Identifier.fromNamespaceAndPath("dynamichud", "dynamichud_config")) .serializer(config -> GsonConfigSerializerBuilder.create(config) .setPath(FabricLoader.getInstance().getConfigDir().resolve("dynamichud.json5")) .setJson5(true) @@ -60,69 +60,69 @@ public static GlobalConfig get() { public Screen createYACLGUI() { return YetAnotherConfigLib.createBuilder() - .title(Text.literal("DynamicHUD config screen.")) + .title(Component.literal("DynamicHUD config screen.")) .category(ConfigCategory.createBuilder() - .name(Text.literal("General")) - .tooltip(Text.literal("Set the general settings for all widgets.")) + .name(Component.literal("General")) + .tooltip(Component.literal("Set the general settings for all widgets.")) .group(OptionGroup.createBuilder() - .name(Text.literal("Global")) - .description(OptionDescription.of(Text.literal("Global settings for all widgets."))) + .name(Component.literal("Global")) + .description(OptionDescription.of(Component.literal("Global settings for all widgets."))) .option(Option.createBuilder() - .name(Text.literal("Scale")) - .description(OptionDescription.of(Text.literal("Set scale for all widgets."))) + .name(Component.literal("Scale")) + .description(OptionDescription.of(Component.literal("Set scale for all widgets."))) .binding(1.0f, () -> this.scale, newVal -> this.scale = newVal) .controller(floatOption -> FloatSliderControllerBuilder.create(floatOption).range(0.1f, 2.5f).step(0.1f)) .build()) .option(Option.createBuilder() - .name(Text.literal("Render in debug screen")) - .description(OptionDescription.of(Text.literal("Renders widgets even when the debug screen is on"))) + .name(Component.literal("Render in debug screen")) + .description(OptionDescription.of(Component.literal("Renders widgets even when the debug screen is on"))) .binding(true, () -> this.renderInDebugScreen, newVal -> this.renderInDebugScreen = newVal) .controller(booleanOption -> BooleanControllerBuilder.create(booleanOption).yesNoFormatter()) .build()) .option(Option.createBuilder() - .name(Text.literal("Show Color picker preview")) - .description(OptionDescription.of(Text.literal("Shows the preview below your mouse pointer on selecting color from the screen. Note: You may drop some frames with the preview on."))) + .name(Component.literal("Show Color picker preview")) + .description(OptionDescription.of(Component.literal("Shows the preview below your mouse pointer on selecting color from the screen. Note: You may drop some frames with the preview on."))) .binding(true, () -> this.showColorPickerPreview, newVal -> this.showColorPickerPreview = newVal) .controller(booleanOption -> BooleanControllerBuilder.create(booleanOption).yesNoFormatter()) .build()) .option(Option.createBuilder() - .name(Text.literal("Show widget descriptions/tooltips")) - .description(OptionDescription.of(Text.literal("Shows the description of widgets as tooltips."))) + .name(Component.literal("Show widget descriptions/tooltips")) + .description(OptionDescription.of(Component.literal("Shows the description of widgets as tooltips."))) .binding(true, () -> this.displayDescriptions, newVal -> this.displayDescriptions = newVal) .controller(booleanOption -> BooleanControllerBuilder.create(booleanOption).yesNoFormatter()) .build()) .option(Option.createBuilder() - .name(Text.literal("Snap Size")) - .description(OptionDescription.of(Text.literal("Grid size for snapping widgets"))) + .name(Component.literal("Snap Size")) + .description(OptionDescription.of(Component.literal("Grid size for snapping widgets"))) .binding(100, () -> this.snapSize, newVal -> this.snapSize = newVal) .controller(integerOption -> IntegerFieldControllerBuilder.create(integerOption).range(10, 500)) .build()) .build()) .option(Option.createBuilder() - .name(Text.literal("Widget HUD Active Background Color")) - .description(OptionDescription.of(Text.literal("Color of the background of the widget when it will be rendered"))) + .name(Component.literal("Widget HUD Active Background Color")) + .description(OptionDescription.of(Component.literal("Color of the background of the widget when it will be rendered"))) .binding(new Color(0, 0, 0, 128), () -> this.hudActiveColor, newVal -> this.hudActiveColor = newVal) .controller(ColorControllerBuilder::create) .build()) .option(Option.createBuilder() - .name(Text.literal("Widget HUD Inactive Background Color")) - .description(OptionDescription.of(Text.literal("Color of the background of the widget when it will NOT be rendered"))) + .name(Component.literal("Widget HUD Inactive Background Color")) + .description(OptionDescription.of(Component.literal("Color of the background of the widget when it will NOT be rendered"))) .binding(new Color(255, 0, 0, 128), () -> this.hudInactiveColor, newVal -> this.hudInactiveColor = newVal) .controller(ColorControllerBuilder::create) .build()) .option(Option.createBuilder() - .name(Text.literal("Settings Complexity")) - .description(OptionDescription.of(Text.literal("The level of options to display. Options equal to or below this level will be displayed"))) + .name(Component.literal("Settings Complexity")) + .description(OptionDescription.of(Component.literal("The level of options to display. Options equal to or below this level will be displayed"))) .binding(com.tanishisherewith.dynamichud.utils.contextmenu.options.Option.Complexity.Simple, () -> this.complexity, newVal -> this.complexity = newVal) .controller((option) -> EnumControllerBuilder.create(option) .enumClass(com.tanishisherewith.dynamichud.utils.contextmenu.options.Option.Complexity.class) - .formatValue(value -> Text.of(value.name())) + .formatValue(value -> Component.literal(value.name())) ) .build()) .build()) .save(HANDLER::save) .build() - .generateScreen(MinecraftClient.getInstance().currentScreen); + .generateScreen(Minecraft.getInstance().screen); } public float getScale() { diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/ColorHelper.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/ColorHelper.java index 3e39197..1e59066 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/helpers/ColorHelper.java +++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/ColorHelper.java @@ -1,16 +1,8 @@ package com.tanishisherewith.dynamichud.helpers; -import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gl.Framebuffer; -import net.minecraft.client.util.Window; -import net.minecraft.util.math.MathHelper; -import org.lwjgl.BufferUtils; -import org.lwjgl.opengl.GL11; -import org.lwjgl.opengl.GL30; +import net.minecraft.util.Mth; import java.awt.*; -import java.nio.ByteBuffer; /** * This class provides helper methods for working with colors. @@ -113,9 +105,9 @@ public static float[] getRainbowColor() { float pi = (float) Math.PI; float[] rainbow = new float[3]; - rainbow[0] = 0.5F + 0.5F * MathHelper.sin(x * pi); - rainbow[1] = 0.5F + 0.5F * MathHelper.sin((x + 4F / 3F) * pi); - rainbow[2] = 0.5F + 0.5F * MathHelper.sin((x + 8F / 3F) * pi); + rainbow[0] = 0.5F + 0.5F * Mth.sin(x * pi); + rainbow[1] = 0.5F + 0.5F * Mth.sin((x + 4F / 3F) * pi); + rainbow[2] = 0.5F + 0.5F * Mth.sin((x + 8F / 3F) * pi); return rainbow; } diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java index 0d26f32..e089219 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java +++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java @@ -1,25 +1,26 @@ package com.tanishisherewith.dynamichud.helpers; -import com.mojang.blaze3d.systems.ProjectionType; import com.mojang.blaze3d.systems.RenderSystem; import com.tanishisherewith.dynamichud.DynamicHUD; -import com.tanishisherewith.dynamichud.internal.IRenderLayer; +import com.tanishisherewith.dynamichud.renderstates.GeometryRenderState; +import com.tanishisherewith.dynamichud.renderstates.QuadColorRectRenderState; +import com.tanishisherewith.dynamichud.renderstates.RoundedRectRenderState; import com.tanishisherewith.dynamichud.utils.CustomRenderLayers; import com.tanishisherewith.dynamichud.widget.WidgetBox; -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.render.*; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.client.util.math.Vector2f; -import net.minecraft.text.Text; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.navigation.ScreenPosition; +import net.minecraft.client.gui.navigation.ScreenRectangle; +import net.minecraft.client.renderer.RenderPipelines; +import net.minecraft.network.chat.Component; +import net.minecraft.util.ARGB; import net.minecraft.util.Util; -import net.minecraft.util.math.MathHelper; import org.jetbrains.annotations.NotNull; -import org.joml.Matrix4f; +import org.joml.Matrix3x2fStack; import org.joml.Vector4f; -import org.lwjgl.opengl.GL40C; import java.awt.*; +import java.util.Arrays; import java.util.Objects; import static com.tanishisherewith.dynamichud.helpers.TextureHelper.mc; @@ -40,59 +41,42 @@ public class DrawHelper { * @param endColor end color of the gradient * @param direction Draws the gradient in the given direction */ - public static void drawGradient(DrawContext drawContext, float x, float y, float width, float height, int startColor, int endColor, Direction direction) { - drawContext.draw(vcp -> { - Matrix4f matrix4f = drawContext.getMatrices().peek().getPositionMatrix(); - VertexConsumer consumer = vcp.getBuffer(RenderLayer.getDebugQuads()); - - switch (direction) { - case LEFT_RIGHT: - consumer.vertex(matrix4f, x, y + height, 0.0F).color(startColor); - consumer.vertex(matrix4f, x + width, y + height, 0.0F).color(endColor); - consumer.vertex(matrix4f, x + width, y, 0.0F).color(endColor); - consumer.vertex(matrix4f, x, y, 0.0F).color(startColor); - break; - case TOP_BOTTOM: - consumer.vertex(matrix4f, x, y + height, 0.0F).color(endColor); - consumer.vertex(matrix4f, x + width, y + height, 0.0F).color(endColor); - consumer.vertex(matrix4f, x + width, y, 0.0F).color(startColor); - consumer.vertex(matrix4f, x, y, 0.0F).color(startColor); - break; - case RIGHT_LEFT: - consumer.vertex(matrix4f, x, y + height, 0.0F).color(endColor); - consumer.vertex(matrix4f, x + width, y + height, 0.0F).color(startColor); - consumer.vertex(matrix4f, x + width, y, 0.0F).color(startColor); - consumer.vertex(matrix4f, x, y, 0.0F).color(endColor); - break; - case BOTTOM_TOP: - consumer.vertex(matrix4f, x, y + height, 0.0F).color(startColor); - consumer.vertex(matrix4f, x + width, y + height, 0.0F).color(startColor); - consumer.vertex(matrix4f, x + width, y, 0.0F).color(endColor); - consumer.vertex(matrix4f, x, y, 0.0F).color(endColor); - break; - } - }); - } - - public static void enableScissor(int x, int y, int width, int height) { - enableScissor(x, y, width, height, mc.getWindow().getScaleFactor()); - } - - public static void enableScissor(WidgetBox box) { - enableScissor((int) box.x, (int) box.y, (int) box.getWidth(), (int) box.getHeight(), mc.getWindow().getScaleFactor()); - } - - public static void enableScissor(int x, int y, int width, int height, double scaleFactor) { + public static void drawGradient(GuiGraphics g, float x, float y, float width, float height, int startColor, int endColor, Direction direction) { + int[] c = switch(direction) { + case TOP_BOTTOM -> new int[]{startColor, startColor, endColor, endColor}; + case LEFT_RIGHT -> new int[]{startColor, endColor, endColor, startColor}; + case RIGHT_LEFT -> new int[]{endColor, startColor, startColor, endColor}; + case BOTTOM_TOP -> new int[]{endColor, endColor, startColor, startColor}; + }; + + g.guiRenderState.submitGuiElement( + new QuadColorRectRenderState(RenderPipelines.GUI,g.pose(),x,y,width,height,c, + new ScreenRectangle((int) x, (int) y,(int)width,(int) height), + g.scissorStack.peek()) + ); + } + + public static void enableScissor(int x, int y, int width, int height, GuiGraphics graphics) { + enableScissor(x, y, width, height, mc.getWindow().getGuiScale(),graphics); + } + + public static void enableScissor(WidgetBox box,GuiGraphics graphics) { + enableScissor((int) box.x, (int) box.y, (int) box.getWidth(), (int) box.getHeight(), mc.getWindow().getGuiScale(),graphics); + } + + public static void enableScissor(int x, int y, int width, int height, double scaleFactor, GuiGraphics graphics) { int scissorX = (int) (x * scaleFactor); - int scissorY = (int) (DynamicHUD.MC.getWindow().getHeight() - ((y + height) * scaleFactor)); + int scissorY = (int) (y * scaleFactor); int scissorWidth = (int) (width * scaleFactor); int scissorHeight = (int) (height * scaleFactor); - RenderSystem.enableScissor(scissorX, scissorY, scissorWidth, scissorHeight); + ScreenRectangle rect = new ScreenRectangle(x, y, width, height); + graphics.scissorStack.push(rect); } - public static void disableScissor() { - RenderSystem.disableScissor(); + + public static void disableScissor(GuiGraphics graphics) { + graphics.disableScissor(); } /** @@ -104,16 +88,8 @@ public static void disableScissor() { * @param height Height of the rectangle * @param color Color of the rectangle */ - public static void drawRectangle(DrawContext drawContext, float x, float y, float width, float height, int color) { - drawContext.draw(vcp -> { - Matrix4f matrix4f = drawContext.getMatrices().peek().getPositionMatrix(); - VertexConsumer consumer = vcp.getBuffer(RenderLayer.getDebugQuads()); - - consumer.vertex(matrix4f, x, y + height, 0.0F).color(color); - consumer.vertex(matrix4f, x + width, y + height, 0.0F).color(color); - consumer.vertex(matrix4f, x + width, y, 0.0F).color(color); - consumer.vertex(matrix4f, x, y, 0.0F).color(color); - }); + public static void drawRectangle(GuiGraphics graphics, float x, float y, float width, float height, int color) { + drawGradient(graphics,x,y,width,height,color,color,Direction.LEFT_RIGHT); } /* ==== Drawing Rectangles ==== */ @@ -127,11 +103,11 @@ public static void drawRectangle(DrawContext drawContext, float x, float y, floa * @param height Height of the rectangle * @param color Color of the rectangle */ - public static void drawOutlineBox(DrawContext drawContext, float x, float y, float width, float height, float thickness, int color) { - drawRectangle(drawContext, x, y, width, thickness, color); - drawRectangle(drawContext, x, y + height - thickness, width, thickness, color); - drawRectangle(drawContext, x, y + thickness, thickness, height - thickness * 2, color); - drawRectangle(drawContext, x + width - thickness, y + thickness, thickness, height - thickness * 2, color); + public static void drawOutlineBox(GuiGraphics graphics, float x, float y, float width, float height, float thickness, int color) { + drawRectangle(graphics, x, y, width, thickness, color); + drawRectangle(graphics, x, y + height - thickness, width, thickness, color); + drawRectangle(graphics, x, y + thickness, thickness, height - thickness * 2, color); + drawRectangle(graphics, x + width - thickness, y + thickness, thickness, height - thickness * 2, color); } /** @@ -147,12 +123,12 @@ public static void drawOutlineBox(DrawContext drawContext, float x, float y, flo * @param shadowOffsetX X position Offset of the shadow from the main rectangle X pos * @param shadowOffsetY Y position Offset of the shadow from the main rectangle Y pos */ - public static void drawRectangleWithShadowBadWay(DrawContext drawContext, float x, float y, float width, float height, int color, int shadowOpacity, float shadowOffsetX, float shadowOffsetY) { + public static void drawRectangleWithShadowBadWay(GuiGraphics graphics, float x, float y, float width, float height, int color, int shadowOpacity, float shadowOffsetX, float shadowOffsetY) { // First, render the shadow - drawRectangle(drawContext, x + shadowOffsetX, y + shadowOffsetY, width, height, ColorHelper.getColor(0, 0, 0, shadowOpacity)); + drawRectangle(graphics, x + shadowOffsetX, y + shadowOffsetY, width, height, ColorHelper.getColor(0, 0, 0, shadowOpacity)); // Then, render the rectangle - drawRectangle(drawContext, x, y, width, height, color); + drawRectangle(graphics, x, y, width, height, color); } /** @@ -166,12 +142,12 @@ public static void drawRectangleWithShadowBadWay(DrawContext drawContext, float * @param color Color of the rounded.fsh rectangle * @param thickness thickness of the outline */ - public static void drawOutlineRoundedBox(DrawContext drawContext, float x, float y, float width, float height, float radius, float thickness, int color) { + public static void drawOutlineRoundedBox(GuiGraphics graphics, float x, float y, float width, float height, float radius, float thickness, int color) { Color c = new Color(color, true); - drawOutlineRoundedBox(drawContext,x,y,width,height,new Vector4f(radius),thickness,c,c,c,c); + drawOutlineRoundedBox(graphics,x,y,width,height,new Vector4f(radius),thickness,c,c,c,c); } - public static void drawOutlineRoundedBox(DrawContext drawContext, float x, float y, float width, float height, Vector4f radii, float thickness, Color tl, Color tr, Color br, Color bl) { + public static void drawOutlineRoundedBox(GuiGraphics graphics, float x, float y, float width, float height, Vector4f radii, float thickness, Color tl, Color tr, Color br, Color bl) { if (width <= 0 || height <= 0) return; float maxRadius = Math.min(width, height) / 2; radii.set(Math.min(radii.x, maxRadius), // top-left @@ -179,43 +155,42 @@ public static void drawOutlineRoundedBox(DrawContext drawContext, float x, float Math.min(radii.z, maxRadius), // bottom-right Math.min(radii.w, maxRadius) // bottom-left ); - drawContext.draw(vcp -> { - VertexConsumer dvc = vcp.getBuffer(CustomRenderLayers.ROUNDED_RECT_OUTLINE.apply(new CustomRenderLayers.OutlineParameters(radii, thickness ,new float[]{width, height}))); - Matrix4f matrix4f = drawContext.getMatrices().peek().getPositionMatrix(); + int[] intColors = {tl.getRGB(),tr.getRGB(),br.getRGB(),bl.getRGB()}; - dvc.vertex(matrix4f, x, y + height, 0).texture(0, 0).color(bl.getRGB()); - dvc.vertex(matrix4f, x + width, y + height, 0).texture(width, 0).color(br.getRGB()); - dvc.vertex(matrix4f, x + width, y, 0).texture(width, height).color(tr.getRGB()); - dvc.vertex(matrix4f, x, y, 0).texture(0, height).color(tl.getRGB()); - }); + graphics.guiRenderState.submitGuiElement(new RoundedRectRenderState( + CustomRenderLayers.ROUNDED_RECT_OUTLINE, + graphics.pose(), + x, y, width, height, thickness, intColors, radii, graphics.scissorStack.peek(), + new ScreenRectangle(new ScreenPosition((int) x, (int) y), (int) width, (int) height) + )); } /** - * Draw chroma text (text with a nice rainbow effect) + * Draw chroma Component (Component with a nice rainbow effect) * - * @param drawContext A drawContext object - * @param text The text to display - * @param x X pos of text - * @param y Y pos of text + * @param graphics A graphics object + * @param Component The Component to display + * @param x X pos of Component + * @param y Y pos of Component * @param speed Speed of rainbow * @param saturation Saturation of the rainbow colors * @param brightness Brightness of the rainbow colors * @param spread How much the color difference should be between each character (ideally between 0.001 to 0.2) - * @param shadow Whether to render the text as shadow. + * @param shadow Whether to render the Component as shadow. */ - public static void drawChromaText(@NotNull DrawContext drawContext, String text, int x, int y, float speed, float saturation, float brightness, float spread, boolean shadow) { + public static void drawChromaText(@NotNull GuiGraphics graphics, String Component, int x, int y, float speed, float saturation, float brightness, float spread, boolean shadow) { long time = System.currentTimeMillis(); - int length = text.length(); + int length = Component.length(); for (int i = 0; i < length; i++) { float hue = (time % (int) (5000 / speed)) / (5000f / speed) + (i * spread); // Adjust the hue based on time and character position - hue = MathHelper.floorMod(hue, 1.0f); // hue should stay within the range [0, 1] + hue = floorMod(hue, 1.0f); // hue should stay within the range [0, 1] // Convert the hue to an RGB color int color = Color.HSBtoRGB(hue, saturation, brightness); // Draw the character with the calculated color - drawContext.drawText(mc.textRenderer, String.valueOf(text.charAt(i)), x + mc.textRenderer.getWidth(text.substring(0, i)), y, color, shadow); + graphics.drawString(mc.font, String.valueOf(Component.charAt(i)), x + mc.font.width(Component.substring(0, i)), y, color, shadow); } } @@ -231,20 +206,30 @@ public static void drawChromaText(@NotNull DrawContext drawContext, String text, * @param radius radius of the circle outline * @param color color of the circle outline */ - public static void drawOutlineCircle(DrawContext drawContext, float xCenter, float yCenter, float radius, float lineWidth, int color) { - drawContext.draw(vcp -> { - Matrix4f matrix4f = drawContext.getMatrices().peek().getPositionMatrix(); - VertexConsumer consumer = vcp.getBuffer(RenderLayer.getDebugLineStrip(lineWidth)); - - for (int i = 0; i <= 360; i++) { - double x = xCenter + Math.sin(Math.toRadians(i)) * radius; - double y = yCenter + Math.cos(Math.toRadians(i)) * radius; - double x2 = xCenter + Math.sin(Math.toRadians(i)) * (radius + lineWidth); - double y2 = yCenter + Math.cos(Math.toRadians(i)) * (radius + lineWidth); - consumer.vertex(matrix4f, (float) x, (float) y, 0).color(color); - consumer.vertex(matrix4f, (float) x2, (float) y2, 0).color(color); - } - }); + public static void drawOutlineCircle(GuiGraphics graphics, float xCenter, float yCenter, float radius, float lineWidth, int color) { + int segments = 72; // 5-degree steps + float[] verts = new float[(segments + 1) * 4]; + int[] colors = new int[(segments + 1) * 2]; + Arrays.fill(colors, color); + + for (int i = 0; i <= segments; i++) { + float rad = (float) Math.toRadians(i * 5); + float sin = (float) Math.sin(rad); + float cos = (float) Math.cos(rad); + + + int base = i * 4; + verts[base] = xCenter + sin * radius; + verts[base + 1] = yCenter + cos * radius; + verts[base + 2] = xCenter + sin * (radius + lineWidth); + verts[base + 3] = yCenter + cos * (radius + lineWidth); + } + + graphics.guiRenderState.submitGuiElement(new GeometryRenderState( + CustomRenderLayers.TRIANGLE_STRIP, + graphics.pose(), + verts, colors, graphics.scissorStack.peek() + )); } /** @@ -255,19 +240,28 @@ public static void drawOutlineCircle(DrawContext drawContext, float xCenter, flo * @param radius radius of the circle outline * @param color color of the circle outline */ - public static void drawFilledCircle(DrawContext drawContext, float xCenter, float yCenter, float radius, int color) { - drawContext.draw(vcp -> { - Matrix4f matrix4f = drawContext.getMatrices().peek().getPositionMatrix(); - VertexConsumer consumer = vcp.getBuffer(RenderLayer.getDebugTriangleFan()); - - consumer.vertex(matrix4f, xCenter, yCenter, 0).color(color); + public static void drawFilledCircle(GuiGraphics graphics, float xCenter, float yCenter, float radius, int color) { + int segments = 72; // 5-degree steps for smoothness + float[] verts = new float[(segments + 2) * 2]; + int[] colors = new int[segments + 2]; + + // Center point + verts[0] = xCenter; verts[1] = yCenter; + colors[0] = color; + + for (int i = 0; i <= segments; i++) { + float rad = (float) Math.toRadians(i * 5); + int idx = (i + 1) * 2; + verts[idx] = xCenter + (float) Math.sin(rad) * radius; + verts[idx + 1] = yCenter + (float) Math.cos(rad) * radius; + colors[i + 1] = color; + } - for (int i = 0; i <= 360; i++) { - double x = xCenter + Math.sin(Math.toRadians(i)) * radius; - double y = yCenter + Math.cos(Math.toRadians(i)) * radius; - consumer.vertex(matrix4f, (float) x, (float) y, 0).color(color); - } - }); + graphics.guiRenderState.submitGuiElement(new GeometryRenderState( + CustomRenderLayers.TRIANGLE_FAN_CUSTOM_BLEND, + graphics.pose(), + verts, colors, graphics.scissorStack.peek() + )); } /** @@ -281,42 +275,14 @@ public static void drawFilledCircle(DrawContext drawContext, float xCenter, floa * @param shadowOffsetY X position of the circle shadow offset from main circle * @param shadowOpacity Opacity of the circle shadow offset from main circle */ - public static void drawCircleWithShadow(DrawContext drawContext, float xCenter, float yCenter, float radius, int color, int shadowOpacity, float shadowOffsetX, float shadowOffsetY) { + public static void drawCircleWithShadow(GuiGraphics graphics, float xCenter, float yCenter, float radius, int color, int shadowOpacity, float shadowOffsetX, float shadowOffsetY) { // First, render the shadow - drawFilledCircle(drawContext, xCenter + shadowOffsetX, yCenter + shadowOffsetY, radius, ColorHelper.getColor(0, 0, 0, shadowOpacity)); + drawFilledCircle(graphics, xCenter + shadowOffsetX, yCenter + shadowOffsetY, radius, ColorHelper.getColor(0, 0, 0, shadowOpacity)); // Then, render the circle - drawFilledCircle(drawContext, xCenter, yCenter, radius, color); + drawFilledCircle(graphics, xCenter, yCenter, radius, color); } - /** - * Not Tested - * - * @param x - * @param y - * @param radius - * @param startAngle - * @param endAngle - * @param color - */ - @Deprecated - public static void drawFilledArc(DrawContext drawContext, float x, float y, float radius, float startAngle, float endAngle, int color) { - drawContext.draw(vcp -> { - Matrix4f matrix4f = drawContext.getMatrices().peek().getPositionMatrix(); - VertexConsumer consumer = vcp.getBuffer(RenderLayer.getDebugLineStrip(1.0f)); - - for (float angle = startAngle; angle <= endAngle; angle += 1.0F) { - float x1 = x + MathHelper.cos(angle * 0.017453292F) * radius; - float y1 = y + MathHelper.sin(angle * 0.017453292F) * radius; - float x2 = x + MathHelper.cos((angle + 1.0F) * 0.017453292F) * radius; - float y2 = y + MathHelper.sin((angle + 1.0F) * 0.017453292F) * radius; - - consumer.vertex(matrix4f, x, y, 0).color(color); - consumer.vertex(matrix4f, x1, y1, 0).color(color); - consumer.vertex(matrix4f, x2, y2, 0).color(color); - } - }); - } /* ==== Drawing Quadrants, Arcs, and Triangles ==== */ /** @@ -329,37 +295,29 @@ public static void drawFilledArc(DrawContext drawContext, float x, float y, floa * @param endColor end color of the gradient * @param quadrant Integer value of the quadrant of the circle. 1 == Top Right, 2 == Top Left, 3 == Bottom Right, 4 == Bottom Left */ - public static void drawFilledGradientQuadrant(DrawContext drawContext, float xCenter, float yCenter, float radius, int startColor, int endColor, int quadrant) { - float startRed = (float) (startColor >> 16 & 255) / 255.0F; - float startGreen = (float) (startColor >> 8 & 255) / 255.0F; - float startBlue = (float) (startColor & 255) / 255.0F; - float startAlpha = (float) (startColor >> 24 & 255) / 255.0F; - - float endRed = (float) (endColor >> 16 & 255) / 255.0F; - float endGreen = (float) (endColor >> 8 & 255) / 255.0F; - float endBlue = (float) (endColor & 255) / 255.0F; - float endAlpha = (float) (endColor >> 24 & 255) / 255.0F; - - drawContext.draw(vcp -> { - Matrix4f matrix4f = drawContext.getMatrices().peek().getPositionMatrix(); - VertexConsumer consumer = vcp.getBuffer(RenderLayer.getDebugTriangleFan()); - - consumer.vertex(matrix4f, xCenter, yCenter, 0).color(startColor); - - for (int i = quadrant * 90; i <= quadrant * 90 + 90; i++) { - double x = xCenter + Math.sin(Math.toRadians(i)) * radius; - double y = yCenter + Math.cos(Math.toRadians(i)) * radius; - - // Interpolate the color based on the angle - float t = (float) (i - quadrant * 90) / 90.0f; - float red = startRed * (1 - t) + endRed * t; - float green = startGreen * (1 - t) + endGreen * t; - float blue = startBlue * (1 - t) + endBlue * t; - float alpha = startAlpha * (1 - t) + endAlpha * t; + public static void drawFilledGradientQuadrant(GuiGraphics graphics, float xCenter, float yCenter, float radius, int startColor, int endColor, int quadrant) { + int segments = 18; // 90 degrees / 5 + float[] verts = new float[(segments + 2) * 2]; + int[] colors = new int[segments + 2]; + + verts[0] = xCenter; verts[1] = yCenter; + colors[0] = startColor; + + for (int i = 0; i <= segments; i++) { + float angle = (quadrant * 90) + (i * 5); + float rad = (float) Math.toRadians(angle); + + int idx = (i + 1) * 2; + verts[idx] = xCenter + (float) Math.sin(rad) * radius; + verts[idx + 1] = yCenter + (float) Math.cos(rad) * radius; + colors[i + 1] = ARGB.linearLerp((float) i / segments, startColor, endColor); + } - consumer.vertex(matrix4f, (float) x, (float) y, 0).color(red,green,blue,alpha); - } - }); + graphics.guiRenderState.submitGuiElement(new GeometryRenderState( + CustomRenderLayers.TRIANGLE_FAN_CUSTOM_BLEND, + graphics.pose(), + verts, colors, graphics.scissorStack.peek() + )); } /** @@ -372,23 +330,37 @@ public static void drawFilledGradientQuadrant(DrawContext drawContext, float xCe * @param endAngle end Angle of the arc * @param thickness Thickness of the arc (width of the arc) */ - public static void drawArc(DrawContext drawContext, float xCenter, float yCenter, float radius, float thickness, int color, int startAngle, int endAngle) { - drawContext.draw(vcp -> { - Matrix4f matrix4f = drawContext.getMatrices().peek().getPositionMatrix(); - VertexConsumer consumer = vcp.getBuffer(RenderLayer.getDebugTriangleFan()); - - for (int i = startAngle; i <= endAngle; i++) { - double innerX = xCenter + Math.sin(Math.toRadians(i)) * (radius - thickness); - double innerY = yCenter + Math.cos(Math.toRadians(i)) * (radius - thickness); - double outerX = xCenter + Math.sin(Math.toRadians(i)) * radius; - double outerY = yCenter + Math.cos(Math.toRadians(i)) * radius; + public static void drawArc(GuiGraphics graphics, float xCenter, float yCenter, float radius, float thickness, int color, int startAngle, int endAngle) { + int segments = Math.max(1, (endAngle - startAngle) / 5); + float[] verts = new float[(segments + 1) * 4]; + int[] colors = new int[(segments + 1) * 2]; + Arrays.fill(colors, color); + + for (int i = 0; i <= segments; i++) { + int currentAngle = startAngle + (i * 5); + if (currentAngle > endAngle) currentAngle = endAngle; + + float rad = (float) Math.toRadians(currentAngle); + float sin = (float) Math.sin(rad); + float cos = (float) Math.cos(rad); + + int base = i * 4; + // Inner Vertex + verts[base] = xCenter + sin * (radius - thickness); + verts[base + 1] = yCenter + cos * (radius - thickness); + // Outer Vertex + verts[base + 2] = xCenter + sin * radius; + verts[base + 3] = yCenter + cos * radius; + } - consumer.vertex(matrix4f, (float) innerX, (float) innerY, 0).color(color); - consumer.vertex(matrix4f, (float) outerX, (float) outerY, 0).color(color); - } - }); + graphics.guiRenderState.submitGuiElement(new GeometryRenderState( + CustomRenderLayers.TRIANGLE_FAN_CUSTOM_BLEND, + graphics.pose(), + verts, colors, graphics.scissorStack.peek() + )); } + /** * Draws a filled quadrant * @@ -398,44 +370,32 @@ public static void drawArc(DrawContext drawContext, float xCenter, float yCenter * @param color color of the quadrant * @param quadrant Integer value of the quadrant of the circle. 1 == Top Right, 2 == Top Left, 3 == Bottom Right, 4 == Bottom Left */ - public static void drawFilledQuadrant(DrawContext drawContext, float xCenter, float yCenter, float radius, int color, int quadrant) { - drawContext.draw(vcp -> { - Matrix4f matrix4f = drawContext.getMatrices().peek().getPositionMatrix(); - VertexConsumer consumer = vcp.getBuffer(RenderLayer.getDebugTriangleFan()); - - consumer.vertex(matrix4f, xCenter, yCenter, 0).color(color); - - for (int i = quadrant * 90; i <= quadrant * 90 + 90; i++) { - double x = xCenter + Math.sin(Math.toRadians(i)) * radius; - double y = yCenter + Math.cos(Math.toRadians(i)) * radius; - consumer.vertex(matrix4f, (float) x, (float) y, 0).color(color); - } - }); + public static void drawFilledQuadrant(GuiGraphics graphics, float xCenter, float yCenter, float radius, int color, int quadrant) { + drawFilledGradientQuadrant(graphics, xCenter, yCenter, radius, color, color, quadrant); } /** * Draws a Triangle with the given coordinates - * - * @param x1 - * @param y1 - * @param x2 - * @param y2 - * @param x3 - * @param y3 - * @param color */ - public static void drawOutlineTriangle(DrawContext drawContext, int x1, int y1, int x2, int y2, int x3, int y3, int color) { - drawContext.draw(vcp -> { - Matrix4f matrix4f = drawContext.getMatrices().peek().getPositionMatrix(); - VertexConsumer consumer = vcp.getBuffer(RenderLayer.getLines()); - - consumer.vertex(matrix4f, x1, y1, 0).color(color); - consumer.vertex(matrix4f, x2, y2, 0).color(color); - consumer.vertex(matrix4f, x3, y3, 0).color(color); - consumer.vertex(matrix4f, x1, y1, 0).color(color); - }); + public static void drawOutlineTriangle(GuiGraphics graphics, int x1, int y1, int x2, int y2, int x3, int y3, int color) { + // 3 lines require 6 vertices (1-2, 2-3, 3-1) to form a closed loop + float[] vertices = { + (float)x1, (float)y1, (float)x2, (float)y2, // Line 1 + (float)x2, (float)y2, (float)x3, (float)y3, // Line 2 + (float)x3, (float)y3, (float)x1, (float)y1 // Line 3 + }; + + int[] colors = new int[6]; + java.util.Arrays.fill(colors, color); + + graphics.guiRenderState.submitGuiElement(new GeometryRenderState( + CustomRenderLayers.COLOR_LINE, + graphics.pose(), + vertices, + colors, + graphics.scissorStack.peek() + )); } - /** * Draws a outline quadrant * @@ -445,7 +405,7 @@ public static void drawOutlineTriangle(DrawContext drawContext, int x1, int y1, * @param color color of the quadrant * @param quadrant Integer value of the quadrant of the circle. 1 == Top Right, 2 == Top Left, 3 == Bottom Right, 4 == Bottom Left */ - public static void drawOutlineQuadrant(DrawContext drawContext, float xCenter, float yCenter, float radius, int quadrant, int color) { + public static void drawOutlineQuadrant(GuiGraphics graphics, float xCenter, float yCenter, float radius, int quadrant, int color) { int startAngle = 0; int endAngle = 0; @@ -462,7 +422,7 @@ public static void drawOutlineQuadrant(DrawContext drawContext, float xCenter, f endAngle = 90; } - drawArc(drawContext, xCenter, yCenter, radius, 1f, color, startAngle, endAngle); + drawArc(graphics, xCenter, yCenter, radius, 1f, color, startAngle, endAngle); } /** @@ -475,8 +435,8 @@ public static void drawOutlineQuadrant(DrawContext drawContext, float xCenter, f * @param radius Radius of the quadrants / the rounded.fsh rectangle * @param color Color of the rounded.fsh rectangle */ - public static void drawRoundedRectangle(DrawContext drawContext, float x, float y, float width, float height, float radius, int color) { - drawRoundedRectangle(drawContext, x, y, true, true, true, true, width, height, radius, color); + public static void drawRoundedRectangle(GuiGraphics graphics, float x, float y, float width, float height, float radius, int color) { + drawRoundedRectangle(graphics, x, y, true, true, true, true, width, height, radius, color); } /* ==== Drawing Rounded Rectangles ==== */ @@ -495,17 +455,17 @@ public static void drawRoundedRectangle(DrawContext drawContext, float x, float * @param radius Radius of the quadrants / the rounded.fsh rectangle * @param color Color of the rounded.fsh rectangle */ - public static void drawRoundedRectangle(DrawContext drawContext, float x, float y, boolean TL, boolean TR, boolean BL, boolean BR, float width, float height, float radius, int color) { + public static void drawRoundedRectangle(GuiGraphics graphics, float x, float y, boolean TL, boolean TR, boolean BL, boolean BR, float width, float height, float radius, int color) { Vector4f radii = new Vector4f(TR ? radius : 0.0f, BR ? radius : 0.0f, TL ? radius : 0.0f, BL ? radius : 0.0f); // Turns out Color class takes rgb by default not rgba Color c = new Color(color, true); - drawRoundedRectangle(drawContext,x,y,width, height, radii, c,c,c,c); + drawRoundedRectangle(graphics,x,y,width, height, radii, c,c,c,c); } /** * Draws a rounded rectangle with customizable corner radii, corner colors, and selective corner rounding. - * @param drawContext DrawContext for rendering + * @param graphics GuiGraphics for rendering * @param x X position * @param y Y position * @@ -514,7 +474,7 @@ public static void drawRoundedRectangle(DrawContext drawContext, float x, float * @param height Height of the rectangle * @param radii Vector4f specifying radii for top-left, top-right, bottom-right, bottom-left corners */ - public static void drawRoundedRectangle(DrawContext drawContext, float x, float y, float width, float height, + public static void drawRoundedRectangle(GuiGraphics graphics, float x, float y, float width, float height, Vector4f radii, Color tl, Color tr, Color br, Color bl) { if (width <= 0 || height <= 0) return; float maxRadius = Math.min(width, height) / 2; @@ -523,17 +483,17 @@ public static void drawRoundedRectangle(DrawContext drawContext, float x, float Math.min(radii.z, maxRadius), // bottom-right Math.min(radii.w, maxRadius) // bottom-left ); - drawContext.draw(vcp -> { - VertexConsumer dvc = vcp.getBuffer(CustomRenderLayers.ROUNDED_RECT.apply(new CustomRenderLayers.RoundedParameters(radii, new float[]{width, height}))); - Matrix4f matrix4f = drawContext.getMatrices().peek().getPositionMatrix(); + int[] intColors = {tl.getRGB(),tr.getRGB(),br.getRGB(),bl.getRGB()}; - dvc.vertex(matrix4f, x, y + height, 0).texture(0, 0).color(bl.getRGB()); - dvc.vertex(matrix4f, x + width, y + height, 0).texture(width, 0).color(br.getRGB()); - dvc.vertex(matrix4f, x + width, y, 0).texture(width, height).color(tr.getRGB()); - dvc.vertex(matrix4f, x, y, 0).texture(0, height).color(tl.getRGB()); - }); + graphics.guiRenderState.submitGuiElement(new RoundedRectRenderState( + CustomRenderLayers.ROUNDED_RECT, + graphics.pose(), + x, y, width, height, 0f, intColors, radii, graphics.scissorStack.peek(), + new ScreenRectangle(new ScreenPosition((int) x, (int) y), (int) width, (int) height) + )); } + /** * Draws an outline rounded.fsh gradient rectangle * @@ -547,15 +507,8 @@ public static void drawRoundedRectangle(DrawContext drawContext, float x, float * @param height Height of rounded.fsh gradient rectangle * @param radius Radius of the quadrants / the rounded.fsh gradient rectangle */ - public static void drawOutlineGradientRoundedBox(DrawContext drawContext, float x, float y, float width, float height, float radius, float thickness, Color tl, Color tr, Color br, Color bl) { - drawOutlineRoundedBox(drawContext,x,y,width,height,new Vector4f(radius),thickness,tl, tr, br,bl); - } - - public static void drawCutRectangle(DrawContext drawContext, int x1, int y1, int x2, int y2, int z, int color, int cornerRadius) { - // Draw the rectangles - drawContext.fill(x1 + cornerRadius, y1, x2 - cornerRadius, y1 + cornerRadius, z, color); - drawContext.fill(x1 + cornerRadius, y2 - cornerRadius, x2 - cornerRadius, y2, z, color); - drawContext.fill(x1, y1 + cornerRadius, x2, y2 - cornerRadius, z, color); + public static void drawOutlineGradientRoundedBox(GuiGraphics graphics, float x, float y, float width, float height, float radius, float thickness, Color tl, Color tr, Color br, Color bl) { + drawOutlineRoundedBox(graphics,x,y,width,height,new Vector4f(radius),thickness,tl, tr, br,bl); } /** @@ -571,12 +524,12 @@ public static void drawCutRectangle(DrawContext drawContext, int x1, int y1, int * @param shadowOffsetX X offset of the shadow * @param shadowOffsetY Y offset of the shadow */ - public static void drawRoundedRectangleWithShadowBadWay(DrawContext drawContext, float x, float y, float width, float height, float radius, int color, int shadowOpacity, float shadowOffsetX, float shadowOffsetY) { + public static void drawRoundedRectangleWithShadowBadWay(GuiGraphics graphics, float x, float y, float width, float height, float radius, int color, int shadowOpacity, float shadowOffsetX, float shadowOffsetY) { // First, render the shadow - drawRoundedRectangle(drawContext, x + shadowOffsetX, y + shadowOffsetY, width, height, radius, ColorHelper.getColor(0, 0, 0, shadowOpacity)); + drawRoundedRectangle(graphics, x + shadowOffsetX, y + shadowOffsetY, width, height, radius, ColorHelper.getColor(0, 0, 0, shadowOpacity)); // Then, render the rounded.fsh rectangle - drawRoundedRectangle(drawContext, x, y, width, height, radius, color); + drawRoundedRectangle(graphics, x, y, width, height, radius, color); } /** @@ -592,8 +545,8 @@ public static void drawRoundedRectangleWithShadowBadWay(DrawContext drawContext, * @param height Height of rounded.fsh gradient rectangle * @param radius Radius of the quadrants / the rounded.fsh gradient rectangle */ - public static void drawRoundedGradientRectangle(DrawContext drawContext, Color tl, Color tr, Color br, Color bl, float x, float y, float width, float height, float radius) { - drawRoundedGradientRectangle(drawContext, tl,tr,br,bl, x, y, width, height, radius, true, true, true, true); + public static void drawRoundedGradientRectangle(GuiGraphics graphics, Color tl, Color tr, Color br, Color bl, float x, float y, float width, float height, float radius) { + drawRoundedGradientRectangle(graphics, tl,tr,br,bl, x, y, width, height, radius, true, true, true, true); } /** @@ -609,19 +562,19 @@ public static void drawRoundedGradientRectangle(DrawContext drawContext, Color t * @param height Height of rounded.fsh gradient rectangle * @param radius Radius of the quadrants / the rounded.fsh gradient rectangle */ - public static void drawRoundedGradientRectangle(DrawContext drawContext, Color tl, Color tr, Color br, Color bl, float x, float y, float width, float height, float radius, boolean TL, boolean TR, boolean BL, boolean BR) { - drawRoundedRectangle(drawContext, x, y, width, height, + public static void drawRoundedGradientRectangle(GuiGraphics graphics, Color tl, Color tr, Color br, Color bl, float x, float y, float width, float height, float radius, boolean TL, boolean TR, boolean BL, boolean BR) { + drawRoundedRectangle(graphics, x, y, width, height, new Vector4f(TR ? radius : 0.0f, BR ? radius : 0.0f, TL ? radius : 0.0f, BL ? radius : 0.0f), tl,tr,br,bl); } /* ==== Drawing Lines ==== */ - public static void drawVerticalLine(DrawContext drawContext, float x, float y1, float height, float thickness, int color) { - drawRectangle(drawContext, x, y1, thickness, height, color); + public static void drawVerticalLine(GuiGraphics graphics, float x, float y1, float height, float thickness, int color) { + drawRectangle(graphics, x, y1, thickness, height, color); } - public static void drawHorizontalLine(DrawContext drawContext, float x1, float width, float y, float thickness, int color) { - drawRectangle(drawContext, x1, y, width, thickness, color); + public static void drawHorizontalLine(GuiGraphics graphics, float x1, float width, float y, float thickness, int color) { + drawRectangle(graphics, x1, y, width, thickness, color); } /** @@ -633,23 +586,23 @@ public static void drawHorizontalLine(DrawContext drawContext, float x1, float w * @param y2 The y position of the bottom right corner of the box * @param color The color to draw the box with */ - public static void drawOutlinedBox(DrawContext drawContext, int x1, int y1, int x2, int y2, int color) { - drawContext.fill(x1, y1, x2, y1 + 1, color); - drawContext.fill(x1, y2 - 1, x2, y2, color); - drawContext.fill(x1, y1 + 1, x1 + 1, y2 - 1, color); - drawContext.fill(x2 - 1, y1 + 1, x2, y2 - 1, color); + public static void drawOutlinedBox(GuiGraphics graphics, int x1, int y1, int x2, int y2, int color) { + graphics.fill(x1, y1, x2, y1 + 1, color); + graphics.fill(x1, y2 - 1, x2, y2, color); + graphics.fill(x1, y1 + 1, x1 + 1, y2 - 1, color); + graphics.fill(x2 - 1, y1 + 1, x2, y2 - 1, color); } public static void unscaledProjection() { - RenderSystem.setProjectionMatrix(new Matrix4f().setOrtho(0, mc.getWindow().getFramebufferWidth(), mc.getWindow().getFramebufferHeight(), 0, 1000, 21000), ProjectionType.ORTHOGRAPHIC); + //RenderSystem.setProjectionMatrix(new Matrix4f().setOrtho(0, mc.getWindow().getWidth(), mc.getWindow().getHeight(), 0, 1000, 21000), ProjectionType.ORTHOGRAPHIC); } public static void scaledProjection() { - RenderSystem.setProjectionMatrix(new Matrix4f().setOrtho(0, (float) (mc.getWindow().getFramebufferWidth() / mc.getWindow().getScaleFactor()), (float) (mc.getWindow().getFramebufferHeight() / mc.getWindow().getScaleFactor()), 0, 1000, 21000), ProjectionType.ORTHOGRAPHIC); + //RenderSystem.setProjectionMatrix(new Matrix4f().setOrtho(0, (float) (mc.getWindow().getWidth() / mc.getWindow().getGuiScale()), (float) (mc.getWindow().getFramebufferHeight() / mc.getWindow().getScaleFactor()), 0, 1000, 21000), ProjectionType.ORTHOGRAPHIC); } public static void customScaledProjection(float scale) { - RenderSystem.setProjectionMatrix(new Matrix4f().setOrtho(0, mc.getWindow().getFramebufferWidth() / scale, mc.getWindow().getFramebufferHeight() / scale, 0, 1000, 21000), ProjectionType.ORTHOGRAPHIC); + //RenderSystem.setProjectionMatrix(new Matrix4f().setOrtho(0, mc.getWindow().getWidth() / scale, mc.getWindow().getHeight() / scale, 0, 1000, 21000), ProjectionType.ORTHOGRAPHIC); } /** @@ -659,16 +612,16 @@ public static void customScaledProjection(float scale) { * @param y Y position of widget * @param scale Scale the matrices */ - public static void scaleAndPosition(MatrixStack matrices, float x, float y, float scale) { - matrices.push(); // Save the current transformation state + public static void scaleAndPosition(Matrix3x2fStack matrices, float x, float y, float scale) { + matrices.pushMatrix(); // Save the current transformation state // Translate the origin back to the desired position - matrices.translate(x, y, 0); + matrices.translate(x, y); // Scale the matrix - matrices.scale(scale, scale, 1.0F); + matrices.scale(scale, scale); - matrices.translate(-x, -y, 0); + matrices.translate(-x, -y); } /** @@ -680,48 +633,52 @@ public static void scaleAndPosition(MatrixStack matrices, float x, float y, floa * @param width width of widget * @param scale Scale the matrices */ - public static void scaleAndPosition(MatrixStack matrices, float x, float y, float width, float height, float scale) { - matrices.push(); // Save the current transformation state + public static void scaleAndPosition(Matrix3x2fStack matrices, float x, float y, float width, float height, float scale) { + matrices.pushMatrix(); // Save the current transformation state // Translate the origin back to the desired position - matrices.translate(x + width / 2.0f, y + height / 2.0f, 0); + matrices.translate(x + width / 2.0f, y + height / 2.0f); // Scale the matrix - matrices.scale(scale, scale, 1.0F); + matrices.scale(scale, scale); - matrices.translate(-(x + width / 2.0f), -(y + height / 2.0f), 0); + matrices.translate(-(x + width / 2.0f), -(y + height / 2.0f)); } - public static void stopScaling(MatrixStack matrices) { - matrices.pop(); // Restore the previous transformation state + public static void stopScaling(Matrix3x2fStack matrices) { + matrices.popMatrix(); // Restore the previous transformation state } /** * From minecraft */ - public static void drawScrollableText(DrawContext context, TextRenderer textRenderer, Text text, int centerX, int startX, int startY, int endX, int endY, int color) { - int i = textRenderer.getWidth(text); + public static void drawScrollableText(GuiGraphics graphics, Font font, Component Component, int centerX, int startX, int startY, int endX, int endY, int color) { + int i = font.width(Component); int var10000 = startY + endY; - Objects.requireNonNull(textRenderer); + Objects.requireNonNull(font); int j = (var10000 - 9) / 2 + 1; int k = endX - startX; int l; if (i > k) { l = i - k; - double d = (double) Util.getMeasuringTimeMs() / 1000.0; + double d = (double) Util.getMillis() / 1000.0; double e = Math.max((double) l * 0.5, 3.0); double f = Math.sin(1.5707963267948966 * Math.cos(6.283185307179586 * d / e)) / 2.0 + 0.5; - double g = MathHelper.lerp(f, 0.0, l); - context.enableScissor(startX, startY, endX, endY); - context.drawTextWithShadow(textRenderer, text, startX - (int) g, j, color); - context.disableScissor(); + double g = org.joml.Math.lerp(f, 0.0, l); + graphics.enableScissor(startX, startY, endX, endY); + graphics.drawString(font, Component, startX - (int) g, j, color,true); + graphics.disableScissor(); } else { - l = MathHelper.clamp(centerX, startX + i / 2, endX - i / 2); - context.drawCenteredTextWithShadow(textRenderer, text, l, j, color); + l = Math.clamp(centerX, startX + i / 2, endX - i / 2); + graphics.drawCenteredString(font, Component, l, j, color); } } + public static float floorMod(float x, float y) { + return x - y * (float) Math.floor(x / y); + } + public enum Direction { /* LEFT_RIGHT means from left to right. Same for others */ LEFT_RIGHT, TOP_BOTTOM, RIGHT_LEFT, BOTTOM_TOP diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/MouseColorQuery.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/MouseColorQuery.java index 095bbf9..644b8ad 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/helpers/MouseColorQuery.java +++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/MouseColorQuery.java @@ -1,9 +1,9 @@ package com.tanishisherewith.dynamichud.helpers; +import com.mojang.blaze3d.pipeline.RenderTarget; +import com.mojang.blaze3d.platform.Window; import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gl.Framebuffer; -import net.minecraft.client.util.Window; +import net.minecraft.client.Minecraft; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; @@ -26,14 +26,14 @@ public static void request(double mouseX, double mouseY, Consumer callbac public static void processIfPending() { if (pendingRequest == null) return; - MinecraftClient client = MinecraftClient.getInstance(); - Framebuffer framebuffer = client.getFramebuffer(); + Minecraft client = Minecraft.getInstance(); + RenderTarget framebuffer = client.getMainRenderTarget(); Window window = client.getWindow(); int windowWidth = window.getWidth(); int windowHeight = window.getHeight(); - int framebufferWidth = framebuffer.textureWidth; - int framebufferHeight = framebuffer.textureHeight; + int framebufferWidth = framebuffer.width; + int framebufferHeight = framebuffer.height; double scaleX = (double) framebufferWidth / windowWidth; double scaleY = (double) framebufferHeight / windowHeight; @@ -50,11 +50,9 @@ public static void processIfPending() { // Make sure rendering is complete RenderSystem.assertOnRenderThread(); - // buffer to store the pixel data ByteBuffer buffer = BufferUtils.createByteBuffer(4); - GL11.glReadPixels(x, y, 1, 1, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer); int red = buffer.get(0) & 0xFF; diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/TextureHelper.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/TextureHelper.java index 48b5779..3dfaa37 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/helpers/TextureHelper.java +++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/TextureHelper.java @@ -1,8 +1,8 @@ package com.tanishisherewith.dynamichud.helpers; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.texture.NativeImage; -import net.minecraft.util.Identifier; +import com.mojang.blaze3d.platform.NativeImage; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.Identifier; import java.io.IOException; import java.io.InputStream; @@ -11,11 +11,11 @@ * This class is entirely untested so some issues may occur which in case should be reported immediately. */ public class TextureHelper { - static MinecraftClient mc = MinecraftClient.getInstance(); + static Minecraft mc = Minecraft.getInstance(); public static NativeImage loadTexture(Identifier textureId) { if (mc.getResourceManager().getResource(textureId).isPresent()) { - try (InputStream inputStream = mc.getResourceManager().getResource(textureId).get().getInputStream()) { + try (InputStream inputStream = mc.getResourceManager().getResource(textureId).get().open()) { return NativeImage.read(inputStream); } catch (IOException e) { throw new RuntimeException("Failed to load texture " + textureId, e); @@ -35,7 +35,7 @@ public static NativeImage resizeTexture(NativeImage image, int newWidth, int new int srcX = x * oldWidth / newWidth; int srcY = y * oldHeight / newHeight; - result.setColorArgb(x, y, image.getColorArgb(srcX, srcY)); + result.setPixelABGR(x, y, image.getPixel(srcX, srcY)); } } @@ -58,10 +58,10 @@ public static NativeImage resizeTextureUsingBilinearInterpolation(NativeImage im y_diff = (y_ratio * i) - y; // Indexes of the 4 surrounding pixels - a = image.getColorArgb(x, y); - b = image.getColorArgb(x + 1, y); - c = image.getColorArgb(x, y + 1); - d = image.getColorArgb(x + 1, y + 1); + a = image.getPixel(x, y); + b = image.getPixel(x + 1, y); + c = image.getPixel(x, y + 1); + d = image.getPixel(x + 1, y + 1); // Blue element blue = (a & 0xff) * (1 - x_diff) * (1 - y_diff) + (b & 0xff) * (x_diff) * (1 - y_diff) + @@ -75,7 +75,7 @@ public static NativeImage resizeTextureUsingBilinearInterpolation(NativeImage im red = ((a >> 16) & 0xff) * (1 - x_diff) * (1 - y_diff) + ((b >> 16) & 0xff) * (x_diff) * (1 - y_diff) + ((c >> 16) & 0xff) * (y_diff) * (1 - x_diff) + ((d >> 16) & 0xff) * (x_diff * y_diff); - result.setColorArgb(j, i, + result.setPixelABGR(j, i, ((((int) red) << 16) & 0xff0000) | ((((int) green) << 8) & 0xff00) | ((int) blue) & 0xff); @@ -92,7 +92,7 @@ public static NativeImage invertTexture(NativeImage image) { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { - int argb = image.getColorArgb(x, y); + int argb = image.getPixel(x, y); int alpha = (argb >> 24) & 0xFF; int red = 255 - ((argb >> 16) & 0xFF); @@ -101,7 +101,7 @@ public static NativeImage invertTexture(NativeImage image) { int newArgb = (alpha << 24) | (red << 16) | (green << 8) | blue; - result.setColorArgb(x, y, newArgb); + result.setPixelABGR(x, y, newArgb); } } @@ -123,7 +123,7 @@ public static NativeImage rotateTexture(NativeImage image, int degrees) { int newY = (int) ((x - centerX) * Math.sin(angle) + (y - centerY) * Math.cos(angle) + centerY); if (newX >= 0 && newX < width && newY >= 0 && newY < height) { - result.setColorArgb(newY, newX, image.getColorArgb(x, y)); + result.setPixelABGR(newY, newX, image.getPixel(x, y)); } } } @@ -138,7 +138,7 @@ private static NativeImage flipTextureHorizontally(NativeImage image) { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { - result.setColorArgb(width - x - 1, y, image.getColorArgb(x, y)); + result.setPixelABGR(width - x - 1, y, image.getPixel(x, y)); } } @@ -152,7 +152,7 @@ private static NativeImage flipTextureVertically(NativeImage image) { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { - result.setColorArgb(x, height - y - 1, image.getColorArgb(x, y)); + result.setPixelABGR(x, height - y - 1, image.getPixel(x, y)); } } @@ -174,7 +174,7 @@ public static NativeImage applyGrayScaleFilter(NativeImage image) { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { - int argb = image.getColorArgb(x, y); + int argb = image.getPixel(x, y); int alpha = (argb >> 24) & 0xFF; int red = (argb >> 16) & 0xFF; @@ -184,7 +184,7 @@ public static NativeImage applyGrayScaleFilter(NativeImage image) { int gray = (red + green + blue) / 3; int newArgb = (alpha << 24) | (gray << 16) | (gray << 8) | gray; - result.setColorArgb(x, y, newArgb); + result.setPixelABGR(x, y, newArgb); } } @@ -196,7 +196,7 @@ public static NativeImage cropTexture(NativeImage image, int x, int y, int width for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { - result.setColorArgb(j, i, image.getColorArgb(x + j, y + i)); + result.setPixelABGR(j, i, image.getPixel(x + j, y + i)); } } @@ -210,7 +210,7 @@ public static NativeImage tintTexture(NativeImage image, int color) { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { - int argb = image.getColorArgb(x, y); + int argb = image.getPixel(x, y); int alpha = (argb >> 24) & 0xFF; int red = ((argb >> 16) & 0xFF) * ((color >> 16) & 0xFF) / 255; @@ -219,7 +219,7 @@ public static NativeImage tintTexture(NativeImage image, int color) { int newArgb = (alpha << 24) | (red << 16) | (green << 8) | blue; - result.setColorArgb(x, y, newArgb); + result.setPixelABGR(x, y, newArgb); } } @@ -233,8 +233,8 @@ public static NativeImage overlayTexture(NativeImage image, NativeImage overlay) for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { - int argb1 = image.getColorArgb(x, y); - int argb2 = overlay.getColorArgb(x, y); + int argb1 = image.getPixel(x, y); + int argb2 = overlay.getPixel(x, y); int alpha = Math.max((argb1 >> 24) & 0xFF, (argb2 >> 24) & 0xFF); int red = Math.min(255, ((argb1 >> 16) & 0xFF) + ((argb2 >> 16) & 0xFF)); @@ -243,7 +243,7 @@ public static NativeImage overlayTexture(NativeImage image, NativeImage overlay) int newArgb = (alpha << 24) | (red << 16) | (green << 8) | blue; - result.setColorArgb(x, y, newArgb); + result.setPixelABGR(x, y, newArgb); } } @@ -258,7 +258,7 @@ public static int getAverageColor(NativeImage image) { for (int y = 0; y < image.getHeight(); y++) { for (int x = 0; x < image.getWidth(); x++) { - int argb = image.getColorArgb(x, y); + int argb = image.getPixel(x, y); redTotal += (argb >> 16) & 0xFF; greenTotal += (argb >> 8) & 0xFF; diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/MathAnimations.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/MathAnimations.java index 6850fff..028e442 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/MathAnimations.java +++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/MathAnimations.java @@ -2,8 +2,10 @@ import com.tanishisherewith.dynamichud.helpers.animationhelper.Easing; import com.tanishisherewith.dynamichud.helpers.animationhelper.EasingType; -import net.minecraft.util.math.Vec2f; -import net.minecraft.util.math.random.Random; +import net.minecraft.util.RandomSource; +import net.minecraft.world.phys.Vec2; + +import java.util.Random; public class MathAnimations { /// SHAKE: Random offset animation with smooth decay @@ -14,8 +16,8 @@ public static float shake(float intensity, float frequency, float decay) { } /// 2D Shake with different X/Y frequencies - public static Vec2f shake2D(float intensity, float freqX, float freqY) { - return new Vec2f( + public static Vec2 shake2D(float intensity, float freqX, float freqY) { + return new Vec2( (float) Math.sin(System.currentTimeMillis() * freqX) * intensity, (float) Math.cos(System.currentTimeMillis() * freqY) * intensity ); @@ -23,16 +25,16 @@ public static Vec2f shake2D(float intensity, float freqX, float freqY) { /// FLICKER: Random flashing effect public static float flicker(float min, float max, float chance) { - Random rand = Random.create(); + RandomSource rand = RandomSource.create(); return rand.nextFloat() < chance ? min + (max - min) * rand.nextFloat() : max; } /// CIRCULAR MOTION: Perfect for rotation/orbital animations - public static Vec2f circularMotion(float radius, float speed, float phase) { + public static Vec2 circularMotion(float radius, float speed, float phase) { double angle = Math.toRadians((System.currentTimeMillis() * speed) % 360 + phase); - return new Vec2f( + return new Vec2( (float) (Math.cos(angle) * radius), (float) (Math.sin(angle) * radius) ); @@ -68,9 +70,9 @@ public static float pulse1(float base, float amplitude, float frequency) { } /// SPIRAL: Circular motion with expanding radius - public static Vec2f spiral(float baseRadius, float expansionRate, float speed) { + public static Vec2 spiral(float baseRadius, float expansionRate, float speed) { float t = System.currentTimeMillis() / 1000f; - return new Vec2f( + return new Vec2( (float) ((baseRadius + expansionRate * t) * Math.cos(t * speed)), (float) ((baseRadius + expansionRate * t) * Math.sin(t * speed)) ); diff --git a/src/main/java/com/tanishisherewith/dynamichud/integration/DefaultIntegrationImpl.java b/src/main/java/com/tanishisherewith/dynamichud/integration/DefaultIntegrationImpl.java index 33ae2b7..50bc203 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/integration/DefaultIntegrationImpl.java +++ b/src/main/java/com/tanishisherewith/dynamichud/integration/DefaultIntegrationImpl.java @@ -4,6 +4,7 @@ import com.tanishisherewith.dynamichud.widgets.GraphWidget; import com.tanishisherewith.dynamichud.widgets.ItemWidget; import com.tanishisherewith.dynamichud.widgets.TextWidget; +import net.minecraft.client.KeyMapping; /** * The default implementation for included widgets. @@ -27,4 +28,9 @@ public void registerCustomWidgets() { GraphWidget.DATA ); } + + @Override + public KeyMapping getKeyBind() { + return null; + } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/integration/DynamicHudIntegration.java b/src/main/java/com/tanishisherewith/dynamichud/integration/DynamicHudIntegration.java index bcc32de..156ccb8 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/integration/DynamicHudIntegration.java +++ b/src/main/java/com/tanishisherewith/dynamichud/integration/DynamicHudIntegration.java @@ -1,5 +1,6 @@ package com.tanishisherewith.dynamichud.integration; +import com.mojang.blaze3d.platform.InputConstants; import com.tanishisherewith.dynamichud.IntegrationTest; import com.tanishisherewith.dynamichud.screens.AbstractMoveableScreen; import com.tanishisherewith.dynamichud.widget.WidgetData; @@ -7,8 +8,8 @@ import com.tanishisherewith.dynamichud.widget.WidgetRenderer; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.client.option.KeyBinding; -import net.minecraft.client.util.InputUtil; +import net.minecraft.client.KeyMapping; +import net.minecraft.resources.Identifier; import org.lwjgl.glfw.GLFW; import java.io.File; @@ -19,16 +20,6 @@ * @see DefaultIntegrationImpl */ public interface DynamicHudIntegration { - /** - * The key binding for opening the editor screen. - */ - KeyBinding EDITOR_SCREEN_KEY_BINDING = KeyBindingHelper.registerKeyBinding(new KeyBinding( - "DynamicHud Editor Screen", - InputUtil.Type.KEYSYM, - GLFW.GLFW_KEY_RIGHT_SHIFT, - "DynamicHud" - )); - /** * The filename for the widgets file. */ @@ -97,7 +88,5 @@ default File getWidgetsFile() { * * @return The keybind. */ - default KeyBinding getKeyBind() { - return EDITOR_SCREEN_KEY_BINDING; - } + KeyMapping getKeyBind(); } diff --git a/src/main/java/com/tanishisherewith/dynamichud/integration/IntegrationManager.java b/src/main/java/com/tanishisherewith/dynamichud/integration/IntegrationManager.java index 485a616..fbaa215 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/integration/IntegrationManager.java +++ b/src/main/java/com/tanishisherewith/dynamichud/integration/IntegrationManager.java @@ -13,8 +13,8 @@ import net.fabricmc.loader.api.ModContainer; import net.fabricmc.loader.api.entrypoint.EntrypointContainer; import net.fabricmc.loader.api.metadata.ModMetadata; -import net.minecraft.client.gui.screen.TitleScreen; -import net.minecraft.client.option.KeyBinding; +import net.minecraft.client.KeyMapping; +import net.minecraft.client.gui.screens.TitleScreen; import java.io.File; import java.io.IOException; @@ -49,8 +49,8 @@ public static List getWidgetRenderers() { * @param key The key to listen for * @param screen The AbstractMoveableScreen instance to use to set the screen */ - public static void openScreen(KeyBinding key, AbstractMoveableScreen screen) { - if (key.wasPressed()) { + public static void openScreen(KeyMapping key, AbstractMoveableScreen screen) { + if (key.isDown()) { DynamicHUD.MC.setScreen(screen); } } @@ -92,7 +92,7 @@ public static void integrate() { String modId = metadata.getId(); AbstractMoveableScreen screen; - KeyBinding binding; + KeyMapping binding; WidgetRenderer widgetRenderer; File widgetsFile; try { @@ -161,7 +161,7 @@ public static void integrate() { ClientTickEvents.START_CLIENT_TICK.register((client) -> { if (BooleanPool.get("WarningScreenFlag")) return; - if (DynamicHUD.MC.currentScreen instanceof TitleScreen) { + if (DynamicHUD.MC.screen instanceof TitleScreen) { DynamicHUD.MC.setScreen(new WarningScreen(bad_implementations)); BooleanPool.put("WarningScreenFlag", true); } @@ -185,13 +185,13 @@ private static List> getRegisteredInt } /** - * This makes it so that if minecraft is launched with the program arguments + * If minecraft is launched with the program arguments *

* {@code --dynamicHudTest true} *

- * then it will - * load the {@link com.tanishisherewith.dynamichud.IntegrationTest} class as an entrypoint, eliminating any errors due to human incapacity of - * adding/removing a single line from the `fabric.mod.json` + * then it wil load the {@link com.tanishisherewith.dynamichud.IntegrationTest} class as an entrypoint, + * eliminating any errors due to human incapacity of adding/removing a single line from the `fabric.mod.json` + * This is for myself. */ private static EntrypointContainer getTestIntegration() { DynamicHudIntegration testIntegration; diff --git a/src/main/java/com/tanishisherewith/dynamichud/internal/IBufferBuilder.java b/src/main/java/com/tanishisherewith/dynamichud/internal/IBufferBuilder.java new file mode 100644 index 0000000..0aaabea --- /dev/null +++ b/src/main/java/com/tanishisherewith/dynamichud/internal/IBufferBuilder.java @@ -0,0 +1,8 @@ +package com.tanishisherewith.dynamichud.internal; + +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.blaze3d.vertex.VertexFormatElement; + +public interface IBufferBuilder { + VertexConsumer dynamicHUD$writeGenericFloats(VertexFormatElement element, float... values); +} \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/internal/IRenderLayer.java b/src/main/java/com/tanishisherewith/dynamichud/internal/IRenderLayer.java deleted file mode 100644 index 3dbc1a2..0000000 --- a/src/main/java/com/tanishisherewith/dynamichud/internal/IRenderLayer.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.tanishisherewith.dynamichud.internal; - -import org.joml.Vector4f; - -public interface IRenderLayer { - /** - * Set uniform u to the value described by v4f, formatted as a vec4 (4 floats) - * @param u Name - * @param v4f Value - */ - default void dynamichud$setUniform(String u, Vector4f v4f) { - float[] v = new float[]{v4f.x, v4f.y, v4f.z, v4f.w}; - dynamichud$setUniform(u, v); - } - - /** - * Set uniform u to the value of v, should be an int[], float[] or Matrix4f - * @param u Name - * @param v Value - */ - void dynamichud$setUniform(String u, Object v); -} \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/internal/WarningScreen.java b/src/main/java/com/tanishisherewith/dynamichud/internal/WarningScreen.java index 2b7ef4b..204760e 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/internal/WarningScreen.java +++ b/src/main/java/com/tanishisherewith/dynamichud/internal/WarningScreen.java @@ -1,12 +1,13 @@ package com.tanishisherewith.dynamichud.internal; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.text.OrderedText; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; +import com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.Skin; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import net.minecraft.util.FormattedCharSequence; import net.minecraft.util.Util; import java.awt.*; @@ -17,52 +18,53 @@ public class WarningScreen extends Screen { private final List modErrors; public WarningScreen(List modErrors) { - super(Text.of("DynamicHUD Warning")); + super(Component.literal("DynamicHUD Warning")); this.modErrors = modErrors; } @Override protected void init() { - ButtonWidget confirmButton = ButtonWidget.builder(Text.of("I Understand"), button -> MinecraftClient.getInstance().setScreen(null)) - .dimensions(this.width / 2 - 100, this.height - 40, 200, 20) - .narrationSupplier((e) -> Text.literal("I understand")) + Button confirmButton = Button.builder(Component.literal("I Understand"), button -> Minecraft.getInstance().setScreen(null)) + .bounds(this.width / 2 - 100, this.height - 40, 200, 20) + .createNarration((e) -> Component.literal("I understand")) .build(); - ButtonWidget logs_folder = ButtonWidget.builder(Text.of("Open logs"), button -> { - File logsFolder = new File(MinecraftClient.getInstance().runDirectory, "logs"); - Util.getOperatingSystem().open(logsFolder); + Button logs_folder = Button.builder(Component.literal("Open logs"), button -> { + File logsFolder = new File(Minecraft.getInstance().gameDirectory, "logs"); + Util.getPlatform().openFile(logsFolder); }) - .dimensions(this.width / 2 - 100, this.height - 70, 200, 20) - .narrationSupplier((e) -> Text.literal("Open logs")) + .bounds(this.width / 2 - 100, this.height - 70, 200, 20) + .createNarration((e) -> Component.literal("Open logs")) .build(); // Add "I Understand" button - this.addDrawableChild(confirmButton); - this.addDrawableChild(logs_folder); + this.addRenderableWidget(confirmButton); + this.addRenderableWidget(logs_folder); } @Override - public void render(DrawContext context, int mouseX, int mouseY, float delta) { - super.render(context, mouseX, mouseY, delta); + public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) { + super.render(graphics, mouseX, mouseY, delta); - context.drawCenteredTextWithShadow(this.textRenderer, this.title, this.width / 2, 20, 0xFFFFFF); - context.drawCenteredTextWithShadow(this.textRenderer, "Mods with bad implementation of DynamicHUD found!", this.width / 2, 35, Color.ORANGE.getRGB()); + graphics.drawCenteredString(this.font, this.title, this.width / 2, 20, 0xFFFFFF); + graphics.drawCenteredString(this.font, "Mods with bad implementation of DynamicHUD found!", this.width / 2, 35, Color.ORANGE.getRGB()); int y = 60; for (ModError error : modErrors) { - Text modName = Text.literal("> \"" + error.modName() + "\"").formatted(Formatting.RED); - context.drawText(this.textRenderer, modName, this.width / 2 - 100, y, -1, false); - List errorMessage = this.textRenderer.wrapLines(Text.literal("Error: " + error.errorMessage()), this.width / 2); + Component modName = Component.literal("> \"" + error.modName() + "\"").withStyle(ChatFormatting.RED); + graphics.drawString(this.font, modName, this.width / 2 - 100, y, -1, false); + List errorMessage = + this.font.split(Component.literal("Error: " + error.errorMessage()), this.width / 2); - if (mouseX >= this.width / 2 - 100 && mouseX <= this.width / 2 - 100 + this.textRenderer.getWidth(modName) && mouseY >= y && mouseY <= y + this.textRenderer.fontHeight) { - context.drawOrderedTooltip(textRenderer, errorMessage, mouseX, mouseY); + if (Skin.isMouseOver(mouseX,mouseY,(double) this.width / 2 - 102, y - 1, this.font.width(modName) + 4,this.font.lineHeight + 2)) { + graphics.setTooltipForNextFrame(errorMessage, mouseX, mouseY); } y += 11; // Space between mod errors } y += 5; - context.drawCenteredTextWithShadow(this.textRenderer, Text.of("Please report this problem to the respective mod owners."), this.width / 2, y, -1); - context.drawCenteredTextWithShadow(this.textRenderer, Text.literal("Widgets of these mods won't work.").formatted(Formatting.YELLOW), this.width / 2, y + 10, -1); - context.drawCenteredTextWithShadow(this.textRenderer, Text.literal("Check latest.log for more details").formatted(Formatting.ITALIC), this.width / 2, y + 30, -1); + graphics.drawCenteredString(this.font, Component.literal("Please report this problem to the respective mod owners."), this.width / 2, y, -1); + graphics.drawCenteredString(this.font, Component.literal("Widgets of these mods won't work.").withStyle(ChatFormatting.YELLOW), this.width / 2, y + 10, -1); + graphics.drawCenteredString(this.font, Component.literal("Check latest.log for more details").withStyle(ChatFormatting.ITALIC), this.width / 2, y + 30, -1); } } \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/mixins/BufferBuilderMixin.java b/src/main/java/com/tanishisherewith/dynamichud/mixins/BufferBuilderMixin.java new file mode 100644 index 0000000..8f2e442 --- /dev/null +++ b/src/main/java/com/tanishisherewith/dynamichud/mixins/BufferBuilderMixin.java @@ -0,0 +1,33 @@ +package com.tanishisherewith.dynamichud.mixins; + +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.blaze3d.vertex.VertexFormatElement; +import com.tanishisherewith.dynamichud.internal.IBufferBuilder; +import org.lwjgl.system.MemoryUtil; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(BufferBuilder.class) +public abstract class BufferBuilderMixin implements VertexConsumer, IBufferBuilder { + + @Shadow + protected abstract long beginElement(VertexFormatElement element); + + /** + * The "Library" secret sauce. + * This allows you to write N floats to a custom GENERIC element. + */ + @Unique + public VertexConsumer dynamicHUD$writeGenericFloats(VertexFormatElement element, float... values) { + long addr = this.beginElement(element); + if (addr != -1L) { + for (int i = 0; i < values.length; i++) { + // We use the same MemoryUtil Mojang uses in addVertex and setUv + MemoryUtil.memPutFloat(addr + (i * 4L), values[i]); + } + } + return this; + } +} \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/mixins/MinecraftMixin.java b/src/main/java/com/tanishisherewith/dynamichud/mixins/MinecraftMixin.java new file mode 100644 index 0000000..5a20cd4 --- /dev/null +++ b/src/main/java/com/tanishisherewith/dynamichud/mixins/MinecraftMixin.java @@ -0,0 +1,15 @@ +package com.tanishisherewith.dynamichud.mixins; + +import com.tanishisherewith.dynamichud.DynamicHUD; +import com.tanishisherewith.dynamichud.integration.IntegrationManager; +import net.minecraft.client.Minecraft; +import net.minecraft.client.main.GameConfig; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Minecraft.class) +public abstract class MinecraftMixin { + +} diff --git a/src/main/java/com/tanishisherewith/dynamichud/mixins/OptionsScreenMixin.java b/src/main/java/com/tanishisherewith/dynamichud/mixins/OptionsScreenMixin.java index 5b0367a..ba6887b 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/mixins/OptionsScreenMixin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/mixins/OptionsScreenMixin.java @@ -2,11 +2,14 @@ import com.llamalad7.mixinextras.sugar.Local; import com.tanishisherewith.dynamichud.config.GlobalConfig; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.screen.option.OptionsScreen; -import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.client.gui.widget.DirectionalLayoutWidget; -import net.minecraft.text.Text; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.layouts.HeaderAndFooterLayout; +import net.minecraft.client.gui.layouts.LayoutSettings; +import net.minecraft.client.gui.layouts.LinearLayout; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.options.OptionsScreen; +import net.minecraft.network.chat.Component; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -18,21 +21,30 @@ @Mixin(OptionsScreen.class) public abstract class OptionsScreenMixin extends Screen { @Shadow - protected abstract ButtonWidget createButton(Text message, Supplier screenSupplier); + protected abstract Button openScreenButton(Component component, Supplier supplier); - protected OptionsScreenMixin(Text title) { + @Shadow + @Final + private HeaderAndFooterLayout layout; + + protected OptionsScreenMixin(Component title) { super(title); } - @Inject(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/widget/GridWidget$Adder;add(Lnet/minecraft/client/gui/widget/Widget;)Lnet/minecraft/client/gui/widget/Widget;", ordinal = 0)) - private void init(CallbackInfo ci, @Local(ordinal = 0) DirectionalLayoutWidget directionalLayoutWidget) { - DirectionalLayoutWidget directionalLayoutWidget2 = directionalLayoutWidget.add(DirectionalLayoutWidget.horizontal()); - - directionalLayoutWidget2.getMainPositioner().marginLeft(-26).marginY(-28); - - ButtonWidget widget = createButton(Text.of("DH"), () -> GlobalConfig.get().createYACLGUI()); - widget.setDimensions(20, 20); - - directionalLayoutWidget2.add(widget); + @Inject( + method = "init", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/gui/layouts/LinearLayout;addChild(Lnet/minecraft/client/gui/layouts/LayoutElement;)Lnet/minecraft/client/gui/layouts/LayoutElement;", + ordinal = 1 // this is where the FOV row is added + ) + ) + private void injectDHLayout(CallbackInfo ci, @Local(ordinal = 0) LinearLayout header) { + LinearLayout dhLayout = header.addChild(LinearLayout.vertical(), layoutSettings -> layoutSettings.paddingLeft(-20)); + + Button dhButton = openScreenButton(Component.literal("DH"), () -> GlobalConfig.get().createYACLGUI()); + dhButton.setWidth(20); + + dhLayout.addChild(dhButton); } -} \ No newline at end of file +} diff --git a/src/main/java/com/tanishisherewith/dynamichud/mixins/RenderLayerMixin.java b/src/main/java/com/tanishisherewith/dynamichud/mixins/RenderLayerMixin.java deleted file mode 100644 index cc4795f..0000000 --- a/src/main/java/com/tanishisherewith/dynamichud/mixins/RenderLayerMixin.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.tanishisherewith.dynamichud.mixins; - - -import com.llamalad7.mixinextras.sugar.Local; -import com.mojang.blaze3d.systems.RenderPass; -import com.tanishisherewith.dynamichud.internal.IRenderLayer; -import net.minecraft.client.render.BuiltBuffer; -import net.minecraft.client.render.RenderLayer; -import org.joml.Matrix4f; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.util.HashMap; -import java.util.Map; - -@Mixin(RenderLayer.MultiPhase.class) -public class RenderLayerMixin implements IRenderLayer { - @Unique - private final Map uniforms = new HashMap<>(); - - @Override - public void dynamichud$setUniform(String u, Object v) { - if (v == null) uniforms.remove(u); - else uniforms.put(u, v); - } - - @Inject(method = "draw", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderPass;drawIndexed(II)V")) - void beforeDraw(BuiltBuffer par1, CallbackInfo ci, @Local(ordinal = 0) RenderPass pass) { - uniforms.forEach((k, v) -> { - switch (v) { - case float[] fa -> pass.setUniform(k, fa); - case int[] ia -> pass.setUniform(k, ia); - case Matrix4f mat -> pass.setUniform(k, mat); - default -> throw new IllegalStateException("Unknown uniform type " + v.getClass() + " (" + v + ")"); - } - }); - } -} \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/mixins/ScreenMixin.java b/src/main/java/com/tanishisherewith/dynamichud/mixins/ScreenMixin.java index 21446b4..bf685ba 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/mixins/ScreenMixin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/mixins/ScreenMixin.java @@ -3,9 +3,8 @@ import com.tanishisherewith.dynamichud.integration.IntegrationManager; import com.tanishisherewith.dynamichud.widget.WidgetManager; import com.tanishisherewith.dynamichud.widget.WidgetRenderer; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -21,19 +20,19 @@ public abstract class ScreenMixin { public int height; @Inject(at = @At("RETURN"), method = "render") - private void render(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) { + private void render(GuiGraphics graphics, int mouseX, int mouseY, float delta, CallbackInfo ci) { for (WidgetRenderer widgetRenderer : IntegrationManager.getWidgetRenderers()) { - widgetRenderer.renderWidgets(context, mouseX, mouseY); + widgetRenderer.renderWidgets(graphics, mouseX, mouseY); } } //Injected before the screen is actually resized to get the new and also the old dimensions. @Inject(at = @At("HEAD"), method = "resize") - private void onScreenResize(MinecraftClient client, int width, int height, CallbackInfo ci) { + private void onScreenResize(int i, int j, CallbackInfo ci) { WidgetManager.onScreenResized(width, height, this.width, this.height); } - @Inject(at = @At("HEAD"), method = "close") + @Inject(at = @At("HEAD"), method = "onClose") private void onClose(CallbackInfo ci) { for (WidgetRenderer widgetRenderer : IntegrationManager.getWidgetRenderers()) { widgetRenderer.onCloseScreen(); diff --git a/src/main/java/com/tanishisherewith/dynamichud/renderstates/GeometryRenderState.java b/src/main/java/com/tanishisherewith/dynamichud/renderstates/GeometryRenderState.java new file mode 100644 index 0000000..8926ee4 --- /dev/null +++ b/src/main/java/com/tanishisherewith/dynamichud/renderstates/GeometryRenderState.java @@ -0,0 +1,38 @@ +package com.tanishisherewith.dynamichud.renderstates; + +import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.gui.navigation.ScreenRectangle; +import net.minecraft.client.gui.render.TextureSetup; +import net.minecraft.client.gui.render.state.GuiElementRenderState; +import org.jetbrains.annotations.Nullable; +import org.joml.Matrix3x2fStack; + +// State for Geometric Shapes (Circles, Arcs, Fans) +public record GeometryRenderState( + RenderPipeline pipeline, + Matrix3x2fStack pose, + float[] vertices, // Flat array: [x1, y1, x2, y2, ...] + int[] colors, // Parallel array of ARGB colors + @Nullable ScreenRectangle scissorArea +) implements GuiElementRenderState { + + public record VertexData(float x, float y, int color) {} + + @Override + public void buildVertices(VertexConsumer consumer) { + for (int i = 0; i < vertices.length / 2; i++) { + consumer.addVertexWith2DPose(pose, vertices[i * 2], vertices[i * 2 + 1]) + .setColor(colors[i]); + } + } + + @Override + public TextureSetup textureSetup() { + return TextureSetup.noTexture(); + } + @Override + public @Nullable ScreenRectangle bounds() { + return null; + } +} \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/renderstates/GradientShadowRenderState.java b/src/main/java/com/tanishisherewith/dynamichud/renderstates/GradientShadowRenderState.java new file mode 100644 index 0000000..1e4af63 --- /dev/null +++ b/src/main/java/com/tanishisherewith/dynamichud/renderstates/GradientShadowRenderState.java @@ -0,0 +1,44 @@ +package com.tanishisherewith.dynamichud.renderstates; + +import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.gui.navigation.ScreenRectangle; +import net.minecraft.client.gui.render.TextureSetup; +import net.minecraft.client.gui.render.state.GuiElementRenderState; +import org.jetbrains.annotations.Nullable; +import org.joml.Matrix3x2fc; +import org.jspecify.annotations.NonNull; + +import java.util.List; + +//TODO: just use fillGradient in GuiGraphics +public record GradientShadowRenderState( + List points, + float bottomY, + int startColor, + int endColor, + Matrix3x2fc pose, + RenderPipeline pipeline, + @Nullable ScreenRectangle scissorArea +) implements GuiElementRenderState { + + @Override + public void buildVertices(@NonNull VertexConsumer consumer) { + for (float[] point : points) { + float x = point[0]; + float y = point[1]; + + consumer.addVertexWith2DPose(pose, x, y).setColor(startColor); + consumer.addVertexWith2DPose(pose, x, bottomY).setColor(endColor); + } + } + @Override + public TextureSetup textureSetup() { + return TextureSetup.noTexture(); + } + + @Override + public @org.jspecify.annotations.Nullable ScreenRectangle bounds() { + return null; + } +} \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/renderstates/InterpolatedCurveRenderState.java b/src/main/java/com/tanishisherewith/dynamichud/renderstates/InterpolatedCurveRenderState.java new file mode 100644 index 0000000..96031ee --- /dev/null +++ b/src/main/java/com/tanishisherewith/dynamichud/renderstates/InterpolatedCurveRenderState.java @@ -0,0 +1,59 @@ +package com.tanishisherewith.dynamichud.renderstates; + +import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.gui.navigation.ScreenRectangle; +import net.minecraft.client.gui.render.TextureSetup; +import net.minecraft.client.gui.render.state.GuiElementRenderState; +import org.jetbrains.annotations.Nullable; +import org.joml.Matrix3x2fc; +import org.jspecify.annotations.NonNull; + +import java.util.List; + +public record InterpolatedCurveRenderState( + List points, + float thickness, + int color, + Matrix3x2fc pose, + RenderPipeline pipeline, + @Nullable ScreenRectangle scissorArea +) implements GuiElementRenderState { + + @Override + public void buildVertices(@NonNull VertexConsumer consumer) { + consumer.addVertexWith2DPose(pose, 10, 10).setColor(color); + consumer.addVertexWith2DPose(pose, 100, 10).setColor(color); + consumer.addVertexWith2DPose(pose, 10, 20).setColor(color); + consumer.addVertexWith2DPose(pose, 100, 20).setColor(color); + /* + for (int i = 0; i < points.size(); i++) { + float[] point = points.get(i); + float x = point[0]; + float y = point[1]; + + float dx = (i < points.size() - 1) ? points.get(i + 1)[0] - x : x - points.get(i - 1)[0]; + float dy = (i < points.size() - 1) ? points.get(i + 1)[1] - y : y - points.get(i - 1)[1]; + float length = (float) Math.sqrt(dx * dx + dy * dy); + if (length == 0) continue; + + float offsetX = (thickness * 0.5f * dy) / length; + float offsetY = (thickness * 0.5f * -dx) / length; + + consumer.addVertexWith2DPose(pose, x + offsetX, y + offsetY).setColor(color); + consumer.addVertexWith2DPose(pose, x - offsetX, y - offsetY).setColor(color); + } + + */ + } + + @Override + public TextureSetup textureSetup() { + return TextureSetup.noTexture(); + } + + @Override + public @Nullable ScreenRectangle bounds() { + return null; + } +} diff --git a/src/main/java/com/tanishisherewith/dynamichud/renderstates/QuadColorRectRenderState.java b/src/main/java/com/tanishisherewith/dynamichud/renderstates/QuadColorRectRenderState.java new file mode 100644 index 0000000..4921a73 --- /dev/null +++ b/src/main/java/com/tanishisherewith/dynamichud/renderstates/QuadColorRectRenderState.java @@ -0,0 +1,42 @@ +package com.tanishisherewith.dynamichud.renderstates; + +import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.gui.navigation.ScreenRectangle; +import net.minecraft.client.gui.render.TextureSetup; +import net.minecraft.client.gui.render.state.GuiElementRenderState; +import org.joml.Matrix3x2f; +import org.jspecify.annotations.Nullable; + +import java.awt.*; + +public record QuadColorRectRenderState( + RenderPipeline pipeline, + Matrix3x2f pose, + float x, + float y, + float width, + float height, + int[] color, + ScreenRectangle bounds, + ScreenRectangle scissorArea +) implements GuiElementRenderState { + + @Override + public void buildVertices(VertexConsumer vertices) { + vertices.addVertexWith2DPose(this.pose(),x, y).setColor(this.color[1]); + vertices.addVertexWith2DPose(this.pose(), x, y + height).setColor(this.color[2]); + vertices.addVertexWith2DPose(this.pose(), x + width, y + height).setColor(this.color[3]); + vertices.addVertexWith2DPose(this.pose(), x + width, y).setColor(this.color[0]); + } + + @Override + public TextureSetup textureSetup() { + return TextureSetup.noTexture(); + } + + @Override + public @Nullable ScreenRectangle bounds() { + return this.scissorArea != null ? this.scissorArea.intersection(bounds) : this.bounds; + } +} diff --git a/src/main/java/com/tanishisherewith/dynamichud/renderstates/RoundedRectRenderState.java b/src/main/java/com/tanishisherewith/dynamichud/renderstates/RoundedRectRenderState.java new file mode 100644 index 0000000..01a6788 --- /dev/null +++ b/src/main/java/com/tanishisherewith/dynamichud/renderstates/RoundedRectRenderState.java @@ -0,0 +1,57 @@ +package com.tanishisherewith.dynamichud.renderstates; + +import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.tanishisherewith.dynamichud.internal.IBufferBuilder; +import com.tanishisherewith.dynamichud.utils.CustomRenderLayers; +import net.minecraft.client.gui.navigation.ScreenRectangle; +import net.minecraft.client.gui.render.TextureSetup; +import net.minecraft.client.gui.render.state.GuiElementRenderState; +import org.jetbrains.annotations.Nullable; +import org.joml.Matrix3x2fc; +import org.joml.Vector4f; +import org.jspecify.annotations.NonNull; + +public record RoundedRectRenderState( + RenderPipeline pipeline, + Matrix3x2fc pose, + float x, + float y, + float width, + float height, + float thickness, + int[] colors, + Vector4f roundness, + @Nullable ScreenRectangle scissorArea, + @Nullable ScreenRectangle bounds +) implements GuiElementRenderState { + + @Override + public void buildVertices(@NonNull VertexConsumer consumer) { + if (consumer instanceof IBufferBuilder builder) { + float[][] uvs = {{0, 0}, {0, 1}, {1, 1}, {1, 0}}; + float[][] coords = {{x, y}, {x, y + height}, {x + width, y + height}, {x + width, y}}; + + for (int i = 0; i < 4; i++) { + consumer.addVertexWith2DPose(pose, coords[i][0], coords[i][1]) + .setColor(colors[i % colors.length]) + .setUv(uvs[i][0], uvs[i][1]); + + builder.dynamicHUD$writeGenericFloats(CustomRenderLayers.ELM_WIDTH_HEIGHT, width, height); + + builder.dynamicHUD$writeGenericFloats(CustomRenderLayers.ELM_ROUNDNESS, + roundness.x, roundness.y, roundness.z, roundness.w); + } + } + } + + @Override + public TextureSetup textureSetup() { + return TextureSetup.noTexture(); + } + + @Override + public @org.jspecify.annotations.Nullable ScreenRectangle bounds() { + return this.scissorArea != null ? this.scissorArea.intersection(this.bounds) : this.bounds; + } +} diff --git a/src/main/java/com/tanishisherewith/dynamichud/screens/AbstractMoveableScreen.java b/src/main/java/com/tanishisherewith/dynamichud/screens/AbstractMoveableScreen.java index 55ad285..5dcf628 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/screens/AbstractMoveableScreen.java +++ b/src/main/java/com/tanishisherewith/dynamichud/screens/AbstractMoveableScreen.java @@ -1,12 +1,19 @@ package com.tanishisherewith.dynamichud.screens; import com.tanishisherewith.dynamichud.config.GlobalConfig; +import com.tanishisherewith.dynamichud.utils.Util; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenuManager; import com.tanishisherewith.dynamichud.widget.Widget; import com.tanishisherewith.dynamichud.widget.WidgetRenderer; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.text.Text; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.input.CharacterEvent; +import net.minecraft.client.input.KeyEvent; +import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.vehicle.minecart.Minecart; +import org.jspecify.annotations.NonNull; import org.lwjgl.glfw.GLFW; public abstract class AbstractMoveableScreen extends Screen { @@ -15,7 +22,7 @@ public abstract class AbstractMoveableScreen extends Screen { /** * Constructs a AbstractMoveableScreen object. */ - public AbstractMoveableScreen(Text title, WidgetRenderer renderer) { + public AbstractMoveableScreen(Component title, WidgetRenderer renderer) { super(title); this.widgetRenderer = renderer; } @@ -26,92 +33,95 @@ protected void init() { } @Override - public void onDisplayed() { - super.onDisplayed(); + public void added() { + super.added(); widgetRenderer.isInEditor = true; } @Override - public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { - widgetRenderer.mouseDragged(mouseX, mouseY, button, deltaX, deltaY, GlobalConfig.get().getSnapSize()); - ContextMenuManager.getInstance().mouseDragged(mouseX, mouseY, button, deltaX, deltaY); - return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); + public boolean mouseDragged(MouseButtonEvent event, double dx, double dy) { + widgetRenderer.mouseDragged(event.x(), event.y(), event.button(), + dx, dy, + GlobalConfig.get().getSnapSize()); + ContextMenuManager.getInstance().mouseDragged(event.x(), event.y(), event.button(), + dx, dy); + return super.mouseDragged(event, dx, dy); } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (widgetRenderer.mouseClicked(mouseX, mouseY, button)) { - handleClickOnWidget(widgetRenderer.selectedWidget, mouseX, mouseY, button); + public boolean mouseClicked(MouseButtonEvent event, boolean bl) { + if (widgetRenderer.mouseClicked(event.x(), event.y(), event.button())) { + handleClickOnWidget(widgetRenderer.selectedWidget, event.x(), event.y(), event.button()); } - ContextMenuManager.getInstance().mouseClicked(mouseX, mouseY, button); - return super.mouseClicked(mouseX, mouseY, button); + ContextMenuManager.getInstance().mouseClicked(event.x(), event.y(), event.button()); + return super.mouseClicked(event, bl); } @Override - public boolean charTyped(char chr, int modifiers) { - widgetRenderer.charTyped(chr, modifiers); - ContextMenuManager.getInstance().charTyped(chr, modifiers); - return super.charTyped(chr, modifiers); + public boolean charTyped(CharacterEvent event) { + widgetRenderer.charTyped((char) event.codepoint(), event.modifiers()); + ContextMenuManager.getInstance().charTyped((char) event.codepoint(), event.modifiers()); + return super.charTyped(event); } @Override - public boolean mouseReleased(double mouseX, double mouseY, int button) { - widgetRenderer.mouseReleased(mouseX, mouseY, button); - ContextMenuManager.getInstance().mouseReleased(mouseX, mouseY, button); - return super.mouseReleased(mouseX, mouseY, button); + public boolean mouseReleased(MouseButtonEvent event) { + widgetRenderer.mouseReleased(event.x(), event.y(), event.button()); + ContextMenuManager.getInstance().mouseReleased(event.x(), event.y(), event.button()); + return super.mouseReleased(event); } @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - widgetRenderer.keyPressed(keyCode, scanCode, modifiers); - ContextMenuManager.getInstance().keyPressed(keyCode, scanCode, modifiers); - if (widgetRenderer.selectedWidget != null && (keyCode == GLFW.GLFW_KEY_DELETE || keyCode == GLFW.GLFW_KEY_BACKSPACE)) { - // trayWidget.minimizeWidget(widgetRenderer.selectedWidget); + public boolean keyPressed(KeyEvent event) { + widgetRenderer.keyPressed(event.key(), event.scancode(), event.modifiers()); + ContextMenuManager.getInstance().keyPressed(event.key(), event.scancode(), event.modifiers()); + if (widgetRenderer.selectedWidget != null && + (event.key() == GLFW.GLFW_KEY_DELETE || event.key() == GLFW.GLFW_KEY_BACKSPACE)) { + // trayWidget.minimizeWidget(widgetRenderer.selectedWidget); } - - return super.keyPressed(keyCode, scanCode, modifiers); + return super.keyPressed(event); } @Override - public boolean keyReleased(int keyCode, int scanCode, int modifiers) { - widgetRenderer.keyReleased(keyCode, scanCode, modifiers); - ContextMenuManager.getInstance().keyReleased(keyCode, scanCode, modifiers); - return super.keyReleased(keyCode, scanCode, modifiers); + public boolean keyReleased(KeyEvent event) { + widgetRenderer.keyReleased(event.key(), event.scancode(), event.modifiers()); + ContextMenuManager.getInstance().keyReleased(event.key(), event.scancode(), event.modifiers()); + return super.keyReleased(event); } @Override - public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { - widgetRenderer.mouseScrolled(mouseX, mouseY, verticalAmount, horizontalAmount); - ContextMenuManager.getInstance().mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); - return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); + public boolean mouseScrolled(double x, double y, double horizontalAmount, double verticalAmount) { + widgetRenderer.mouseScrolled(x, y, verticalAmount, horizontalAmount); + ContextMenuManager.getInstance().mouseScrolled(x, y, horizontalAmount, verticalAmount); + return super.mouseScrolled(x, y, horizontalAmount, verticalAmount); } /** * Renders this screen and its widgets on the screen. * - * @param drawContext The matrix stack used for rendering + * @param graphics The matrix stack used for rendering * @param mouseX The current x position of the mouse cursor * @param mouseY The current y position of the mouse cursor * @param delta The time elapsed since the last frame in seconds */ @Override - public void render(DrawContext drawContext, int mouseX, int mouseY, float delta) { - if (this.client.world == null) { - renderInGameBackground(drawContext); + public void render(@NonNull GuiGraphics graphics, int mouseX, int mouseY, float delta) { + if (this.minecraft.level == null) { + renderBackground(graphics,mouseX,mouseY,delta); } - drawContext.drawText(client.textRenderer, title, client.getWindow().getScaledWidth() / 2 - client.textRenderer.getWidth(title.getString()) / 2, textRenderer.fontHeight / 2, -1, true); + graphics.drawCenteredString(this.font, this.title, this.width / 2, this.font.lineHeight / 2,-1); // Draw each widget - widgetRenderer.renderWidgets(drawContext, mouseX, mouseY); + widgetRenderer.renderWidgets(graphics, mouseX, mouseY); - ContextMenuManager.getInstance().renderAll(drawContext, mouseX, mouseY); + ContextMenuManager.getInstance().renderAll(graphics, mouseX, mouseY); if (GlobalConfig.get().shouldDisplayDescriptions()) { for (Widget widget : widgetRenderer.getWidgets()) { if (widget == null || widget.isShiftDown) continue; if (widget.getWidgetBox().isMouseOver(mouseX, mouseY)) { - drawContext.drawTooltip(client.textRenderer, widget.tooltipText, mouseX, mouseY); + graphics.setTooltipForNextFrame(this.font, widget.tooltipText, mouseX, mouseY); break; } } @@ -122,16 +132,15 @@ public void handleClickOnWidget(Widget widget, double mouseX, double mouseY, int } @Override - public void close() { + public void onClose() { widgetRenderer.isInEditor = false; widgetRenderer.onCloseScreen(); ContextMenuManager.getInstance().onClose(); - super.close(); + super.onClose(); } @Override - public boolean shouldPause() { + public boolean isPauseScreen() { return false; } } - diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/CustomRenderLayers.java b/src/main/java/com/tanishisherewith/dynamichud/utils/CustomRenderLayers.java index df17c3d..5e395c3 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/CustomRenderLayers.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/CustomRenderLayers.java @@ -3,94 +3,116 @@ import com.mojang.blaze3d.pipeline.BlendFunction; import com.mojang.blaze3d.pipeline.RenderPipeline; import com.mojang.blaze3d.platform.DestFactor; -import com.mojang.blaze3d.platform.LogicOp; import com.mojang.blaze3d.platform.SourceFactor; +import com.mojang.blaze3d.shaders.UniformType; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.VertexFormat; import com.mojang.blaze3d.vertex.VertexFormatElement; -import com.tanishisherewith.dynamichud.internal.IRenderLayer; -import net.minecraft.client.gl.RenderPipelines; -import net.minecraft.client.gl.UniformType; -import net.minecraft.client.render.RenderLayer; -import net.minecraft.client.render.VertexFormats; -import net.minecraft.client.util.math.Vector2f; -import net.minecraft.util.Identifier; -import net.minecraft.util.Util; +import net.minecraft.client.renderer.RenderPipelines; +import net.minecraft.resources.Identifier; import org.joml.Vector4f; -import java.awt.*; -import java.util.function.Function; public class CustomRenderLayers { - public static RenderLayer QUADS_CUSTOM_BLEND = RenderLayer.of( - "dynamichud/quads_custom_blend", - 1536, - false, - true, - RenderPipelines.register(RenderPipeline.builder(RenderPipelines.POSITION_COLOR_SNIPPET) - .withLocation(Identifier.of("dynamichud", "pipeline/quad_custom_blend_func")) - .withVertexFormat(VertexFormats.POSITION_COLOR, VertexFormat.DrawMode.QUADS) - .withBlend(new BlendFunction(SourceFactor.DST_ALPHA, DestFactor.ONE_MINUS_DST_ALPHA)) - .build() - ), - RenderLayer.MultiPhaseParameters.builder().build(false) - ); + public static final RenderPipeline COLOR_LINE = RenderPipeline.builder() + .withLocation(Identifier.fromNamespaceAndPath("dynamichud", "color_line")) + .withVertexFormat(DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.DEBUG_LINES) + .withFragmentShader(Identifier.withDefaultNamespace("position_color")) + .withVertexShader(Identifier.withDefaultNamespace("position_color")) + .build(); + + // Width/Height in UV1 + public static final VertexFormatElement ELM_WIDTH_HEIGHT = + new VertexFormatElement(1, 2, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.UV, 8); + + // Roundness in UV2 + public static final VertexFormatElement ELM_ROUNDNESS = + new VertexFormatElement(2, 4, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.UV, 16); + + public static final VertexFormat ROUNDED_FORMAT = VertexFormat.builder() + .add("Position", VertexFormatElement.POSITION) + .add("Color", VertexFormatElement.COLOR) + .add("UV0", VertexFormatElement.UV0) + .add("WidthHeight", ELM_WIDTH_HEIGHT) + .add("Roundness", ELM_ROUNDNESS) + .build(); + - public static RenderLayer TRIANGLE_FAN_CUSTOM_BLEND = RenderLayer.of( - "dynamichud/triangle_fan_custom_blend", - 1536, - false, - true, - RenderPipelines.register(RenderPipeline.builder(RenderPipelines.POSITION_COLOR_SNIPPET) - .withLocation(Identifier.of("dynamichud", "pipeline/triangle_fan_custom_blend_func")) - .withVertexFormat(VertexFormats.POSITION_COLOR, VertexFormat.DrawMode.TRIANGLE_FAN) - .withBlend(new BlendFunction(SourceFactor.DST_ALPHA, DestFactor.ONE_MINUS_DST_ALPHA)) + public static final RenderPipeline ROUNDED_RECT = RenderPipelines.register( + RenderPipeline.builder() + .withVertexFormat(ROUNDED_FORMAT, VertexFormat.Mode.QUADS) + .withBlend(new BlendFunction(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA)) + .withFragmentShader(Identifier.fromNamespaceAndPath("dynamichud", "core/rounded")) + .withVertexShader(Identifier.fromNamespaceAndPath("dynamichud", "core/rounded")) + .withLocation(Identifier.fromNamespaceAndPath("dynamichud", "pipeline/rounded")) + .withUniform("Roundness", UniformType.UNIFORM_BUFFER) + .withUniform("widthHeight", UniformType.UNIFORM_BUFFER) .build() - ), - RenderLayer.MultiPhaseParameters.builder().build(false) ); - public static RenderLayer TRIANGLE_STRIP = RenderLayer.of( - "dynamichud/triangle_strip", - 1536, - false, - true, - RenderPipelines.register(RenderPipeline.builder(RenderPipelines.POSITION_COLOR_SNIPPET) - .withLocation(Identifier.of("dynamichud", "pipeline/triangle_strip")) - .withVertexFormat(VertexFormats.POSITION_COLOR, VertexFormat.DrawMode.TRIANGLE_STRIP) - .withBlend(BlendFunction.TRANSLUCENT) + + public static final RenderPipeline ROUNDED_RECT_OUTLINE = RenderPipelines.register( + RenderPipeline.builder() + .withVertexFormat(ROUNDED_FORMAT, VertexFormat.Mode.QUADS) + .withBlend(new BlendFunction(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA)) + .withFragmentShader(Identifier.fromNamespaceAndPath("dynamichud", "core/rounded_outline")) + .withVertexShader(Identifier.fromNamespaceAndPath("dynamichud", "core/rounded")) + .withLocation(Identifier.fromNamespaceAndPath("dynamichud", "pipeline/rounded_outline")) + .withUniform("Roundness", UniformType.UNIFORM_BUFFER) + .withUniform("widthHeight", UniformType.UNIFORM_BUFFER) + .withUniform("Thickness", UniformType.UNIFORM_BUFFER) .build() - ), - RenderLayer.MultiPhaseParameters.builder().build(false) ); - private static final RenderPipeline ROUNDED = RenderPipelines.register(RenderPipeline.builder(RenderPipelines.MATRICES_COLOR_SNIPPET) + public static RenderPipeline QUADS_CUSTOM_BLEND = RenderPipelines.register(RenderPipeline.builder(RenderPipelines.GUI_SNIPPET) + .withLocation(Identifier.fromNamespaceAndPath("dynamichud", "pipeline/quad_custom_blend_func")) + .withVertexFormat(DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.QUADS) + .withBlend(new BlendFunction(SourceFactor.DST_ALPHA, DestFactor.ONE_MINUS_DST_ALPHA)) + .build() + ); + + public static RenderPipeline TRIANGLE_FAN_CUSTOM_BLEND = RenderPipelines.register(RenderPipeline.builder(RenderPipelines.GUI_SNIPPET) + .withLocation(Identifier.fromNamespaceAndPath("dynamichud", "pipeline/triangle_fan_custom_blend_func")) + .withVertexFormat(DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.TRIANGLE_FAN) + .withBlend(new BlendFunction(SourceFactor.DST_ALPHA, DestFactor.ONE_MINUS_DST_ALPHA)) + .build() + ); + public static RenderPipeline TRIANGLE_STRIP = RenderPipelines.register(RenderPipeline.builder(RenderPipelines.GUI_SNIPPET) + .withLocation(Identifier.fromNamespaceAndPath("dynamichud", "pipeline/triangle_strip")) + .withVertexFormat(DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.TRIANGLE_STRIP) + .withBlend(BlendFunction.TRANSLUCENT) + .build() + ); + + /* + private static final RenderPipeline ROUNDED = RenderPipelines.register(RenderPipeline.builder(RenderPipelines.MATRICES_PROJECTION_SNIPPET) .withBlend(BlendFunction.TRANSLUCENT) .withVertexFormat(VertexFormat.builder() .add("Position", VertexFormatElement.POSITION) .add("UV0", VertexFormatElement.UV0) .add("Color", VertexFormatElement.COLOR) - .build(), VertexFormat.DrawMode.QUADS) + .build(), VertexFormat.Mode.QUADS) .withCull(true) .withColorLogic(LogicOp.NONE) - .withFragmentShader(Identifier.of("dynamichud", "core/rounded")) - .withVertexShader(Identifier.of("dynamichud", "core/rounded")) - .withLocation(Identifier.of("dynamichud", "pipeline/rounded")) - .withUniform("Roundness", UniformType.VEC4) - .withUniform("widthHeight", UniformType.VEC2) + .withFragmentShader(Identifier.fromNamespaceAndPath("dynamichud", "core/rounded")) + .withVertexShader(Identifier.fromNamespaceAndPath("dynamichud", "core/rounded")) + .withLocation(Identifier.fromNamespaceAndPath("dynamichud", "pipeline/rounded")) + .withUniform("Roundness", UniformType.UNIFORM_BUFFER) + .withUniform("widthHeight", UniformType.UNIFORM_BUFFER) .build()); - private static final RenderPipeline ROUNDED_OUTLINE = RenderPipelines.register(RenderPipeline.builder(RenderPipelines.MATRICES_COLOR_SNIPPET) + private static final RenderPipeline ROUNDED_OUTLINE = RenderPipelines.register(RenderPipeline.builder(RenderPipelines.MATRICES_PROJECTION_SNIPPET) .withBlend(BlendFunction.TRANSLUCENT) .withVertexFormat(VertexFormat.builder() .add("Position", VertexFormatElement.POSITION) .add("UV0", VertexFormatElement.UV0) .add("Color", VertexFormatElement.COLOR) - .build(), VertexFormat.DrawMode.QUADS) + .build(), VertexFormat.Mode.QUADS) .withCull(true) .withColorLogic(LogicOp.NONE) - .withFragmentShader(Identifier.of("dynamichud", "core/rounded_outline")) - .withVertexShader(Identifier.of("dynamichud", "core/rounded")) - .withLocation(Identifier.of("dynamichud", "pipeline/rounded_outline")) - .withUniform("Thickness", UniformType.VEC4) + .withFragmentShader(Identifier.fromNamespaceAndPath("dynamichud", "core/rounded_outline")) + .withVertexShader(Identifier.fromNamespaceAndPath("dynamichud", "core/rounded")) + .withLocation(Identifier.fromNamespaceAndPath("dynamichud", "pipeline/rounded_outline")) + .withUniform("Thickness", UniformType) .withUniform("Roundness", UniformType.VEC4) .withUniform("widthHeight", UniformType.VEC2) .build()); @@ -121,14 +143,15 @@ public class CustomRenderLayers { .build(false) ); ((IRenderLayer) rl).dynamichud$setUniform("Roundness", params.roundness); - ((IRenderLayer) rl).dynamichud$setUniform("Thickness", new Vector4f(params.thickness,0f,0f,0f)); + ((IRenderLayer) rl).dynamichud$setUniform("Thickness", new Vector4f(params.thickness, 0f, 0f, 0f)); ((IRenderLayer) rl).dynamichud$setUniform("widthHeight", params.widthHeight); return rl; }); + */ private static int getNewVertexFormatElementsId() { - for(int id = 0; id < 32; id++) { + for (int id = 0; id < 32; id++) { if (VertexFormatElement.byId(id) == null) { return id; } @@ -137,6 +160,9 @@ private static int getNewVertexFormatElementsId() { } - public record RoundedParameters(Vector4f roundness, float[] widthHeight){} - public record OutlineParameters(Vector4f roundness, float thickness, float[] widthHeight){} + public record RoundedParameters(Vector4f roundness, float[] widthHeight) { + } + + public record OutlineParameters(Vector4f roundness, float thickness, float[] widthHeight) { + } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/Util.java b/src/main/java/com/tanishisherewith/dynamichud/utils/Util.java index 4210d61..c6ae850 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/Util.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/Util.java @@ -4,8 +4,8 @@ public class Util { public static Quadrant getQuadrant(int x, int y) { - int screenWidth = DynamicHUD.MC.getWindow().getScaledWidth(); - int screenHeight = DynamicHUD.MC.getWindow().getScaledHeight(); + int screenWidth = DynamicHUD.MC.getWindow().getGuiScaledWidth(); + int screenHeight = DynamicHUD.MC.getWindow().getGuiScaledHeight(); if (x < screenWidth / 2) { if (y < screenHeight / 2) { @@ -35,4 +35,8 @@ public static boolean warnIfTrue(boolean expression, String message, Object... o if (expression) DynamicHUD.logger.warn(message, objects); return expression; } + + public static boolean isSafeToContinue() { + return DynamicHUD.MC.getWindow() != null && DynamicHUD.MC.font != null; + } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java index 48a2cf6..65da6a9 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java @@ -9,9 +9,8 @@ import com.tanishisherewith.dynamichud.utils.contextmenu.contextmenuscreen.DefaultContextMenuScreenFactory; import com.tanishisherewith.dynamichud.utils.contextmenu.options.Option; import com.tanishisherewith.dynamichud.widget.WidgetBox; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.util.math.MathHelper; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFW; @@ -72,7 +71,7 @@ public void addOption(Option option) { options.add(option); } - public void render(DrawContext drawContext, int x, int y, int mouseX, int mouseY) { + public void render(GuiGraphics graphics, int x, int y, int mouseX, int mouseY) { if (newScreenFlag && screenFactory != null) { DynamicHUD.MC.setScreen(screenFactory.create(this, properties)); return; @@ -83,12 +82,12 @@ public void render(DrawContext drawContext, int x, int y, int mouseX, int mouseY update(); if (scale <= 0.0f || newScreenFlag) return; - DrawHelper.scaleAndPosition(drawContext.getMatrices(), x, y, scale); + DrawHelper.scaleAndPosition(graphics.pose(), x, y, scale); properties.getSkin().setContextMenu(this); - properties.getSkin().renderContextMenu(drawContext, this, mouseX, mouseY); + properties.getSkin().renderContextMenu(graphics, this, mouseX, mouseY); - DrawHelper.stopScaling(drawContext.getMatrices()); + DrawHelper.stopScaling(graphics.pose()); } public void update() { @@ -104,7 +103,7 @@ public void update() { scale -= 0.1f; } - scale = MathHelper.clamp(scale, 0, 1.0f); + scale = Math.clamp(scale, 0, 1.0f); } public void close() { @@ -121,7 +120,7 @@ public void close() { public void open() { shouldDisplay = true; update(); - parentScreen = DynamicHUD.MC.currentScreen; + parentScreen = DynamicHUD.MC.screen; if (properties.getSkin().shouldCreateNewScreen()) { newScreenFlag = true; } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenuManager.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenuManager.java index 70edde9..c2b05f7 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenuManager.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenuManager.java @@ -1,7 +1,7 @@ package com.tanishisherewith.dynamichud.utils.contextmenu; import com.tanishisherewith.dynamichud.utils.Input; -import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.GuiGraphics; import java.util.ArrayList; import java.util.List; @@ -21,11 +21,11 @@ public void registerProvider(ContextMenuProvider provider) { providers.add(provider); } - public void renderAll(DrawContext drawContext, int mouseX, int mouseY) { + public void renderAll(GuiGraphics graphics, int mouseX, int mouseY) { for (ContextMenuProvider provider : providers) { ContextMenu contextMenu = provider.getContextMenu(); if (contextMenu != null) { - contextMenu.render(drawContext, contextMenu.getX(), contextMenu.getY(), mouseX, mouseY); + contextMenu.render(graphics, contextMenu.getX(), contextMenu.getY(), mouseX, mouseY); } } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/ContextMenuScreen.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/ContextMenuScreen.java index 1ccfce4..eeba531 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/ContextMenuScreen.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/ContextMenuScreen.java @@ -3,35 +3,37 @@ import com.tanishisherewith.dynamichud.helpers.DrawHelper; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenu; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenuProperties; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.text.Text; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.input.KeyEvent; +import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.network.chat.Component; public class ContextMenuScreen extends Screen { ContextMenu contextMenu; ContextMenuProperties properties; protected ContextMenuScreen(ContextMenu menu, ContextMenuProperties properties) { - super(Text.of("ContextMenu screen")); + super(Component.literal("ContextMenu screen")); this.contextMenu = menu; this.properties = properties; } @Override - public void onDisplayed() { - super.onDisplayed(); + public void added() { + super.added(); contextMenu.setVisible(true); } @Override - public void render(DrawContext drawContext, int mouseX, int mouseY, float delta) { + public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) { contextMenu.update(); - DrawHelper.scaleAndPosition(drawContext.getMatrices(), (float) width / 2, (float) height / 2, contextMenu.getScale()); + DrawHelper.scaleAndPosition(graphics.pose(), (float) width / 2, (float) height / 2, contextMenu.getScale()); properties.getSkin().setContextMenu(contextMenu); - properties.getSkin().renderContextMenu(drawContext, contextMenu, mouseX, mouseY); + properties.getSkin().renderContextMenu(graphics, contextMenu, mouseX, mouseY); - DrawHelper.stopScaling(drawContext.getMatrices()); + DrawHelper.stopScaling(graphics.pose()); if (contextMenu.getScale() <= 0 && !contextMenu.isVisible()) { contextMenu.close(); @@ -39,48 +41,48 @@ public void render(DrawContext drawContext, int mouseX, int mouseY, float delta) } @Override - protected void renderDarkening(DrawContext context) { + public void renderBackground(GuiGraphics guiGraphics, int i, int j, float f) { } @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - contextMenu.mouseClicked(mouseX, mouseY, button); - return super.mouseClicked(mouseX, mouseY, button); + public boolean mouseClicked(MouseButtonEvent event, boolean bl) { + contextMenu.mouseClicked(event.x(), event.y(), event.button()); + return super.mouseClicked(event, bl); } @Override - public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { - contextMenu.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); - return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); + public boolean mouseDragged(MouseButtonEvent event, double dx, double dy) { + contextMenu.mouseDragged(event.x(), event.y(), event.button(), dx, dy); + return super.mouseDragged(event, dx, dy); } @Override - public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { - contextMenu.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); - return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); + public boolean mouseScrolled(double x, double y, double horizontalAmount, double verticalAmount) { + contextMenu.mouseScrolled(x, y, horizontalAmount, verticalAmount); + return super.mouseScrolled(x, y, horizontalAmount, verticalAmount); } @Override - public boolean mouseReleased(double mouseX, double mouseY, int button) { - contextMenu.mouseReleased(mouseX, mouseY, button); - return super.mouseReleased(mouseX, mouseY, button); + public boolean mouseReleased(MouseButtonEvent event) { + contextMenu.mouseReleased(event.x(), event.y(), event.button()); + return super.mouseReleased(event); } @Override - public boolean keyReleased(int keyCode, int scanCode, int modifiers) { - contextMenu.keyReleased(keyCode, scanCode, modifiers); - return super.keyReleased(keyCode, scanCode, modifiers); + public boolean keyReleased(KeyEvent event) { + contextMenu.keyReleased(event.key(), event.scancode(), event.modifiers()); + return super.keyReleased(event); } @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - contextMenu.keyPressed(keyCode, scanCode, modifiers); - return super.keyPressed(keyCode, scanCode, modifiers); + public boolean keyPressed(KeyEvent event) { + contextMenu.keyPressed(event.key(), event.scancode(), event.modifiers()); + return super.keyPressed(event); } @Override - public void close() { + public void onClose() { contextMenu.close(); contextMenu.setVisible(false); } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/ContextMenuScreenFactory.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/ContextMenuScreenFactory.java index 6dea3ec..b66b0c7 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/ContextMenuScreenFactory.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/ContextMenuScreenFactory.java @@ -2,7 +2,7 @@ import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenu; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenuProperties; -import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screens.Screen; /** * We will use this interface to provide the context menu with the screen required by its skins. diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/ContextMenuScreenRegistry.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/ContextMenuScreenRegistry.java index 3bd3646..3e8ee1d 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/ContextMenuScreenRegistry.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/ContextMenuScreenRegistry.java @@ -1,6 +1,6 @@ package com.tanishisherewith.dynamichud.utils.contextmenu.contextmenuscreen; -import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screens.Screen; public class ContextMenuScreenRegistry { public Class screenKlass; diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/DefaultContextMenuScreenFactory.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/DefaultContextMenuScreenFactory.java index b156347..1b0bbc9 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/DefaultContextMenuScreenFactory.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/DefaultContextMenuScreenFactory.java @@ -2,7 +2,7 @@ import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenu; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenuProperties; -import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screens.Screen; /** * Default implementation of the {@link ContextMenuScreenFactory} providing a {@link ContextMenuScreen} diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/layout/LayoutContext.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/layout/LayoutContext.java index fb3d782..a20ce5f 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/layout/LayoutContext.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/layout/LayoutContext.java @@ -3,27 +3,11 @@ import com.tanishisherewith.dynamichud.utils.contextmenu.options.Option; //This was supposed to be used for something bigger but that got scraped. -public class LayoutContext { - private final Offset indent; - private final Option parentOption; - +public record LayoutContext(Offset indent, Option parentOption) { public LayoutContext() { this(Offset.zero(), null); } - public LayoutContext(Offset margin, Option parentOption) { - this.indent = margin; - this.parentOption = parentOption; - } - - public Offset getIndent() { - return indent; - } - - public Option getParentOption() { - return parentOption; - } - // Builder-style methods for creating new contexts public LayoutContext withIndent(Offset indent) { return new LayoutContext(indent, this.parentOption); @@ -57,28 +41,20 @@ public int getEffectiveHeight(int baseHeight) { return baseHeight + indent.top; } - public static class Offset { - public final int left; - public final int top; - - public Offset(int all) { - this(all, all); - } - - public Offset(int horizontal, int vertical) { - this.left = horizontal; - this.top = vertical; - } + public record Offset(int left, int top) { + public Offset(int all) { + this(all, all); + } public static Offset zero() { - return new Offset(0); + return new Offset(0); + } + + public Offset add(Offset other) { + return new Offset( + this.left + other.left, + this.top + other.top + ); + } } - - public Offset add(Offset other) { - return new Offset( - this.left + other.left, - this.top + other.top - ); - } - } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/BooleanOption.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/BooleanOption.java index d5f3b55..a4764d8 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/BooleanOption.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/BooleanOption.java @@ -1,8 +1,8 @@ package com.tanishisherewith.dynamichud.utils.contextmenu.options; import com.tanishisherewith.dynamichud.utils.BooleanPool; -import net.minecraft.screen.ScreenTexts; -import net.minecraft.text.Text; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.network.chat.Component; import org.lwjgl.glfw.GLFW; import java.util.function.Consumer; @@ -12,21 +12,21 @@ public class BooleanOption extends Option { private final BooleanType booleanType; - public BooleanOption(Text name, Supplier getter, Consumer setter, BooleanType booleanType) { + public BooleanOption(Component name, Supplier getter, Consumer setter, BooleanType booleanType) { super(name, getter, setter); this.booleanType = booleanType; this.renderer.init(this); } - public BooleanOption(Text name, Supplier getter, Consumer setter) { + public BooleanOption(Component name, Supplier getter, Consumer setter) { this(name, getter, setter, BooleanType.TRUE_FALSE); } - public BooleanOption(Text name, boolean defaultValue) { + public BooleanOption(Component name, boolean defaultValue) { this(name, defaultValue, BooleanType.TRUE_FALSE); } - public BooleanOption(Text name, boolean defaultValue, BooleanType type) { + public BooleanOption(Component name, boolean defaultValue, BooleanType type) { this(name, () -> BooleanPool.get(name.getString()), value -> BooleanPool.put(name.getString(), value), type); BooleanPool.put(name.getString(), defaultValue); } @@ -46,17 +46,17 @@ public BooleanType getBooleanType() { } public enum BooleanType { - ON_OFF(ScreenTexts::onOrOff), - TRUE_FALSE(aBoolean -> aBoolean ? Text.of("True") : Text.of("False")), - YES_NO(aBoolean -> aBoolean ? ScreenTexts.YES : ScreenTexts.NO); + ON_OFF(aBoolean -> aBoolean ? CommonComponents.OPTION_ON : CommonComponents.OPTION_OFF), + TRUE_FALSE(aBoolean -> aBoolean ? Component.literal("True") : Component.literal("False")), + YES_NO(aBoolean -> aBoolean ? CommonComponents.GUI_YES : CommonComponents.GUI_NO); - private final Function function; + private final Function function; - BooleanType(Function function) { + BooleanType(Function function) { this.function = function; } - public Text getText(boolean val) { + public Component getText(boolean val) { return function.apply(val); } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ColorOption.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ColorOption.java index 9471f7c..c0f341d 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ColorOption.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ColorOption.java @@ -2,7 +2,7 @@ import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenu; import com.tanishisherewith.dynamichud.utils.contextmenu.options.coloroption.ColorGradient; -import net.minecraft.text.Text; +import net.minecraft.network.chat.Component; import java.awt.*; import java.util.function.Consumer; @@ -13,7 +13,7 @@ public class ColorOption extends Option { private ContextMenu parentMenu = null; private ColorGradient colorGradient = null; - public ColorOption(Text name, Supplier getter, Consumer setter, ContextMenu parentMenu) { + public ColorOption(Component name, Supplier getter, Consumer setter, ContextMenu parentMenu) { super(name, getter, setter); this.parentMenu = parentMenu; this.colorGradient = new ColorGradient(x + this.parentMenu.getWidth(), y - 10, get(), this::set, 50, 100); diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/DoubleOption.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/DoubleOption.java index 27d8ec6..14208f4 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/DoubleOption.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/DoubleOption.java @@ -2,8 +2,8 @@ import com.tanishisherewith.dynamichud.helpers.DrawHelper; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenu; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.text.Text; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.network.chat.Component; import org.apache.commons.lang3.Validate; import org.lwjgl.glfw.GLFW; @@ -18,7 +18,7 @@ public class DoubleOption extends Option { ContextMenu parentMenu; private boolean isDragging = false; - public DoubleOption(Text name, double minValue, double maxValue, float step, Supplier getter, Consumer setter, ContextMenu parentMenu) { + public DoubleOption(Component name, double minValue, double maxValue, float step, Supplier getter, Consumer setter, ContextMenu parentMenu) { super(name, getter, setter); this.value = get(); this.minValue = minValue; @@ -31,10 +31,10 @@ public DoubleOption(Text name, double minValue, double maxValue, float step, Sup this.renderer.init(this); } - public void drawSlider(DrawContext drawContext, int sliderX, int sliderY, int sliderWidth, double handleX) { - DrawHelper.drawRectangle(drawContext, sliderX, sliderY, sliderWidth, 2, 0xFFFFFFFF); + public void drawSlider(GuiGraphics graphics, int sliderX, int sliderY, int sliderWidth, double handleX) { + DrawHelper.drawRectangle(graphics, sliderX, sliderY, sliderWidth, 2, 0xFFFFFFFF); if (handleX - sliderX > 0) { - DrawHelper.drawRectangle(drawContext, (float) sliderX, (float) sliderY, (float) ((value - minValue) / (maxValue - minValue) * (width - 3)), 2, Color.ORANGE.getRGB()); + DrawHelper.drawRectangle(graphics, (float) sliderX, (float) sliderY, (float) ((value - minValue) / (maxValue - minValue) * (width - 3)), 2, Color.ORANGE.getRGB()); } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/EnumOption.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/EnumOption.java index 1eab358..f71cee2 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/EnumOption.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/EnumOption.java @@ -1,6 +1,6 @@ package com.tanishisherewith.dynamichud.utils.contextmenu.options; -import net.minecraft.text.Text; +import net.minecraft.network.chat.Component; import java.util.function.Consumer; import java.util.function.Supplier; @@ -9,7 +9,7 @@ public class EnumOption> extends Option { private final E[] values; private int currentIndex = 0; - public EnumOption(Text name, Supplier getter, Consumer setter, E[] values) { + public EnumOption(Component name, Supplier getter, Consumer setter, E[] values) { super(name, getter, setter); this.values = values; this.value = get(); diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ListOption.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ListOption.java index d407242..d948664 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ListOption.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ListOption.java @@ -1,6 +1,6 @@ package com.tanishisherewith.dynamichud.utils.contextmenu.options; -import net.minecraft.text.Text; +import net.minecraft.network.chat.Component; import java.util.List; import java.util.function.Consumer; @@ -10,7 +10,7 @@ public class ListOption extends Option { private final List values; private int currentIndex = 0; - public ListOption(Text name, Supplier getter, Consumer setter, List values) { + public ListOption(Component name, Supplier getter, Consumer setter, List values) { super(name, getter, setter); this.values = values; this.value = getter.get(); diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/Option.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/Option.java index be4bf94..137b4c6 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/Option.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/Option.java @@ -5,15 +5,15 @@ import com.tanishisherewith.dynamichud.utils.Input; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenuProperties; import com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.interfaces.SkinRenderer; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.text.Text; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.network.chat.Component; import java.util.function.Consumer; import java.util.function.Supplier; public abstract class Option implements Input { - public Text name, description = Text.empty(); + public Component name, description = Component.empty(); public T value = null; protected int x, y; protected int width = 0; @@ -22,16 +22,16 @@ public abstract class Option implements Input { protected Supplier getter; protected Consumer setter; protected T defaultValue = null; - protected MinecraftClient mc = MinecraftClient.getInstance(); + protected Minecraft mc = Minecraft.getInstance(); protected ContextMenuProperties properties; protected SkinRenderer> renderer; protected Complexity complexity = Complexity.Simple; - public Option(Text name, Supplier getter, Consumer setter) { + public Option(Component name, Supplier getter, Consumer setter) { this(name, getter, setter, () -> true); } - public Option(Text name, Supplier getter, Consumer setter, Supplier shouldRender, ContextMenuProperties properties) { + public Option(Component name, Supplier getter, Consumer setter, Supplier shouldRender, ContextMenuProperties properties) { this.name = name; this.getter = getter; this.setter = setter; @@ -41,7 +41,7 @@ public Option(Text name, Supplier getter, Consumer setter, Supplier getter, Consumer setter, Supplier shouldRender) { + public Option(Component name, Supplier getter, Consumer setter, Supplier shouldRender) { this(name, getter, setter, shouldRender, ContextMenuProperties.createGenericSimplified()); } @@ -63,13 +63,13 @@ public void updateProperties(ContextMenuProperties properties) { } } - public void render(DrawContext drawContext, int x, int y, int mouseX, int mouseY) { + public void render(GuiGraphics graphics, int x, int y, int mouseX, int mouseY) { this.x = x; this.y = y; this.value = get(); // Retrieve the renderer and ensure it is not null - renderer.render(drawContext, this, x, y, mouseX, mouseY); + renderer.render(graphics, this, x, y, mouseX, mouseY); } public boolean mouseClicked(double mouseX, double mouseY, int button) { @@ -163,7 +163,7 @@ public void setPosition(int x, int y) { this.y = y; } - public Option description(Text description) { + public Option description(Component description) { this.description = description; return this; } @@ -177,11 +177,11 @@ public SkinRenderer> getRenderer() { return renderer; } - public Text getName() { + public Component getName() { return name; } - public Text getDescription() { + public Component getDescription() { return description; } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/OptionGroup.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/OptionGroup.java index 99097fd..ec68a50 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/OptionGroup.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/OptionGroup.java @@ -2,8 +2,8 @@ import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenuProperties; import com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.interfaces.SkinRenderer; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.text.Text; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.network.chat.Component; import java.util.ArrayList; import java.util.Collections; @@ -14,7 +14,7 @@ public class OptionGroup extends Option { private final List> groupOptions = new ArrayList<>(); protected boolean expanded; // Skins can choose to use this or ignore it - public OptionGroup(Text name) { + public OptionGroup(Component name) { super(name, () -> null, (v) -> {}, () -> true); this.expanded = false; } @@ -38,8 +38,8 @@ public void updateProperties(ContextMenuProperties properties) { } @Override - public void render(DrawContext drawContext, int x, int y, int mouseX, int mouseY) { - super.render(drawContext,x,y,mouseX,mouseY); + public void render(GuiGraphics graphics, int x, int y, int mouseX, int mouseY) { + super.render(graphics,x,y,mouseX,mouseY); } public boolean isExpanded() { @@ -65,7 +65,7 @@ public int getHeight() { public static class OptionGroupRenderer implements SkinRenderer> { @Override - public void render(DrawContext drawContext, Option option, int x, int y, int mouseX, int mouseY) {} + public void render(GuiGraphics graphics, Option option, int x, int y, int mouseX, int mouseY) {} @Override public boolean mouseClicked(Option option2, double mouseX, double mouseY, int button) { diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/RunnableOption.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/RunnableOption.java index 8bc80a1..ce18f5e 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/RunnableOption.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/RunnableOption.java @@ -2,7 +2,7 @@ import com.tanishisherewith.dynamichud.DynamicHUD; import com.tanishisherewith.dynamichud.utils.BooleanPool; -import net.minecraft.text.Text; +import net.minecraft.network.chat.Component; import java.util.function.Consumer; import java.util.function.Supplier; @@ -18,14 +18,14 @@ public class RunnableOption extends Option { * @param setter Return a boolean based on if the task is running or not. * @param task The task to run */ - public RunnableOption(Text name, Supplier getter, Consumer setter, Runnable task) { + public RunnableOption(Component name, Supplier getter, Consumer setter, Runnable task) { super(name, getter, setter); this.name = name; this.task = task; this.renderer.init(this); } - public RunnableOption(Text name, boolean defaultValue, Runnable task) { + public RunnableOption(Component name, boolean defaultValue, Runnable task) { this(name, () -> BooleanPool.get(name.getString()), value -> BooleanPool.put(name.getString(), value), task); BooleanPool.put(name.getString(), defaultValue); } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/SubMenuOption.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/SubMenuOption.java index 36f7f9b..0b65c86 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/SubMenuOption.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/SubMenuOption.java @@ -3,7 +3,7 @@ import com.tanishisherewith.dynamichud.utils.BooleanPool; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenu; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenuProperties; -import net.minecraft.text.Text; +import net.minecraft.network.chat.Component; import java.util.Objects; import java.util.function.Consumer; @@ -19,7 +19,7 @@ public class SubMenuOption extends Option { private final ContextMenu subMenu; - public SubMenuOption(Text name, ContextMenu parentMenu, Supplier getter, Consumer setter, T properties) { + public SubMenuOption(Component name, ContextMenu parentMenu, Supplier getter, Consumer setter, T properties) { super(name, getter, setter); Objects.requireNonNull(parentMenu, "Parent Context Menu cannot be null in [" + name + "] SubMenu option"); this.subMenu = parentMenu.createSubMenu(parentMenu.x + parentMenu.getWidth(), this.y, properties.cloneSkin()); @@ -28,15 +28,15 @@ public SubMenuOption(Text name, ContextMenu this.renderer.init(this); } - public SubMenuOption(Text name, ContextMenu parentMenu, T properties) { + public SubMenuOption(Component name, ContextMenu parentMenu, T properties) { this(name, parentMenu, () -> BooleanPool.get(name.getString()), value -> BooleanPool.put(name.getString(), value), properties); } - public SubMenuOption(Text name, ContextMenu parentMenu, Supplier getter, Consumer setter) { + public SubMenuOption(Component name, ContextMenu parentMenu, Supplier getter, Consumer setter) { this(name, parentMenu, getter, setter, parentMenu.getProperties().cloneWithSkin()); } - public SubMenuOption(Text name, ContextMenu parentMenu) { + public SubMenuOption(Component name, ContextMenu parentMenu) { this(name, parentMenu, () -> BooleanPool.get(name.getString()), value -> BooleanPool.put(name.getString(), value), parentMenu.getProperties().cloneWithSkin()); } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/AlphaSlider.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/AlphaSlider.java index ef71488..5c37cfd 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/AlphaSlider.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/AlphaSlider.java @@ -2,7 +2,7 @@ import com.tanishisherewith.dynamichud.helpers.ColorHelper; import com.tanishisherewith.dynamichud.helpers.DrawHelper; -import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.GuiGraphics; import java.awt.*; @@ -25,13 +25,13 @@ public AlphaSlider(int x, int y, int width, int height, Color color) { this.alpha = color.getAlpha() / 255f; } - public void render(DrawContext drawContext, int x, int y) { + public void render(GuiGraphics graphics, int x, int y) { this.x = x; this.y = y; - DrawHelper.drawOutlinedBox(drawContext, x - 2, y - 2, x + width + 2, y + height + 2, Color.WHITE.getRGB()); - DrawHelper.drawGradient(drawContext, x, y, width, height, color.getRGB(), ColorHelper.changeAlpha(color, 0).getRGB(), DrawHelper.Direction.TOP_BOTTOM); - drawContext.fill(x - 2, y + alphaHandleY - 1, x + width + 2, y + alphaHandleY + 1, Color.WHITE.getRGB()); + DrawHelper.drawOutlinedBox(graphics, x - 2, y - 2, x + width + 2, y + height + 2, Color.WHITE.getRGB()); + DrawHelper.drawGradient(graphics, x, y, width, height, color.getRGB(), ColorHelper.changeAlpha(color, 0).getRGB(), DrawHelper.Direction.TOP_BOTTOM); + graphics.fill(x - 2, y + alphaHandleY - 1, x + width + 2, y + alphaHandleY + 1, Color.WHITE.getRGB()); } public Color getColor() { diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/ColorGradient.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/ColorGradient.java index 067c45c..14379a8 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/ColorGradient.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/ColorGradient.java @@ -3,14 +3,14 @@ import com.tanishisherewith.dynamichud.config.GlobalConfig; import com.tanishisherewith.dynamichud.helpers.ColorHelper; import com.tanishisherewith.dynamichud.helpers.MouseColorQuery; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; import java.awt.*; import java.util.function.Consumer; public class ColorGradient { - final MinecraftClient client = MinecraftClient.getInstance(); + final Minecraft client = Minecraft.getInstance(); private final Consumer onColorSelected; // The callback to call when a color is selected private final HueSlider gradientSlider; private final SaturationHueBox gradientBox; @@ -52,15 +52,15 @@ public void close() { display = false; } - public void render(DrawContext drawContext, int x1, int y1, int mouseX, int mouseY) { + public void render(GuiGraphics graphics, int x1, int y1, int mouseX, int mouseY) { setPos(x1, y1); if (!display) { return; } - gradientSlider.render(drawContext, x, y + client.textRenderer.fontHeight + 4); - gradientBox.render(drawContext, x, y + client.textRenderer.fontHeight + gradientSlider.getHeight() + 10); - // colorPickerButton.render(drawContext, x + 24 + boxSize, y + client.textRenderer.fontHeight + gradientSlider.getHeight() + 8); - alphaSlider.render(drawContext, x + 10 + boxSize, y + client.textRenderer.fontHeight + gradientSlider.getHeight() + 10); + gradientSlider.render(graphics, x, y + client.font.lineHeight + 4); + gradientBox.render(graphics, x, y + client.font.lineHeight + gradientSlider.getHeight() + 10); + // colorPickerButton.render(graphics, x + 24 + boxSize, y + client.font.lineHeight + gradientSlider.getHeight() + 8); + alphaSlider.render(graphics, x + 10 + boxSize, y + client.font.lineHeight + gradientSlider.getHeight() + 10); if (colorPickerButton.isPicking() && GlobalConfig.get().showColorPickerPreview()) { MouseColorQuery.request(mouseX, mouseY, colors -> { @@ -70,11 +70,8 @@ public void render(DrawContext drawContext, int x1, int y1, int mouseX, int mous int blue = colors[2]; //Draw the preview box near the mouse pointer - drawContext.getMatrices().push(); - drawContext.getMatrices().translate(0, 0, 2500); - drawContext.fill(mouseX + 10, mouseY, mouseX + 26, mouseY + 16, -1); - drawContext.fill(mouseX + 11, mouseY + 1, mouseX + 25, mouseY + 15, (red << 16) | (green << 8) | blue | 0xFF000000); - drawContext.getMatrices().pop(); + graphics.fill(mouseX + 10, mouseY, mouseX + 26, mouseY + 16, -1); + graphics.fill(mouseX + 11, mouseY + 1, mouseX + 25, mouseY + 15, (red << 16) | (green << 8) | blue | 0xFF000000); } }); } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/ColorPickerButton.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/ColorPickerButton.java index 4d9b711..c4807bc 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/ColorPickerButton.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/ColorPickerButton.java @@ -1,7 +1,7 @@ package com.tanishisherewith.dynamichud.utils.contextmenu.options.coloroption; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; import java.awt.*; @@ -19,15 +19,12 @@ public ColorPickerButton(int x, int y, int width, int height) { this.height = height; } - public void render(DrawContext drawContext, int x, int y) { + public void render(GuiGraphics graphics, int x, int y) { this.x = x; this.y = y; - drawContext.getMatrices().push(); - drawContext.getMatrices().translate(0, 0, 404); // Draw the button - drawContext.fill(x + 2, y + 2, x + width - 2, y + height - 2, isPicking() ? Color.GREEN.getRGB() : 0xFFAAAAAA); - drawContext.drawCenteredTextWithShadow(MinecraftClient.getInstance().textRenderer, "Pick", x + width / 2, y + (height - 8) / 2, 0xFFFFFFFF); - drawContext.getMatrices().pop(); + graphics.fill(x + 2, y + 2, x + width - 2, y + height - 2, isPicking() ? Color.GREEN.getRGB() : 0xFFAAAAAA); + graphics.drawCenteredString(Minecraft.getInstance().font, "Pick", x + width / 2, y + (height - 8) / 2, 0xFFFFFFFF); } public int getHeight() { diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/HueSlider.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/HueSlider.java index 1c5097d..7d8c009 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/HueSlider.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/HueSlider.java @@ -1,7 +1,7 @@ package com.tanishisherewith.dynamichud.utils.contextmenu.options.coloroption; import com.tanishisherewith.dynamichud.helpers.DrawHelper; -import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.GuiGraphics; import java.awt.*; @@ -31,20 +31,17 @@ public void setPosition(int x, int y) { this.y = y; } - public void render(DrawContext drawContext, int x, int y) { + public void render(GuiGraphics graphics, int x, int y) { setPosition(x, y); - drawContext.getMatrices().push(); - drawContext.getMatrices().translate(0, 0, 401); - DrawHelper.drawOutlinedBox(drawContext, x - 2, y - 2, x + width + 2, y + height + 2, -1); + DrawHelper.drawOutlinedBox(graphics, x - 2, y - 2, x + width + 2, y + height + 2, -1); // Draw the gradient for (int i = 0; i < width; i++) { float hue = (float) i / width; int color = Color.HSBtoRGB(hue, 1.0f, 1.0f); color = (color & 0x00FFFFFF) | (255 << 24); - drawContext.fill(x + i, y, x + i + 1, y + height, color); + graphics.fill(x + i, y, x + i + 1, y + height, color); } - drawContext.draw(); // Draw the handle @@ -53,8 +50,7 @@ public void render(DrawContext drawContext, int x, int y) { float handleX = x + hue * width - handleWidth / 2.0f; float handleY = y - (handleHeight - height) / 2.0f; - DrawHelper.drawRectangle(drawContext, handleX, handleY, handleWidth, handleHeight, -1); - drawContext.getMatrices().pop(); + DrawHelper.drawRectangle(graphics, handleX, handleY, handleWidth, handleHeight, -1); } public int getHeight() { diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/SaturationHueBox.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/SaturationHueBox.java index 53b8238..348459b 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/SaturationHueBox.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/SaturationHueBox.java @@ -1,7 +1,7 @@ package com.tanishisherewith.dynamichud.utils.contextmenu.options.coloroption; import com.tanishisherewith.dynamichud.helpers.DrawHelper; -import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.GuiGraphics; import java.awt.*; @@ -21,22 +21,19 @@ public SaturationHueBox(int x, int y, int size) { this.size = size; } - public void render(DrawContext drawContext, int x, int y) { + public void render(GuiGraphics graphics, int x, int y) { setPosition(x, y); - drawContext.getMatrices().push(); - drawContext.getMatrices().translate(0, 0, 406); - DrawHelper.drawOutlinedBox(drawContext, x - 2, y - 2, x + size + 2, y + size + 2, -1); + DrawHelper.drawOutlinedBox(graphics, x - 2, y - 2, x + size + 2, y + size + 2, -1); // Draw the gradient - DrawHelper.drawRoundedGradientRectangle(drawContext, Color.WHITE, Color.getHSBColor(hue, 1.0f, 1.0f),Color.BLACK, Color.BLACK, x, y, size, size, 3); + DrawHelper.drawRoundedGradientRectangle(graphics, Color.WHITE, Color.getHSBColor(hue, 1.0f, 1.0f),Color.BLACK, Color.BLACK, x, y, size, size, 3); // Draw the handle float handleSize = 1f; float handleX = x + 2 + saturation * size - handleSize / 2.0f; float handleY = y + 2 + (1.0f - value) * size - handleSize / 2.0f; - DrawHelper.drawFilledCircle(drawContext, handleX, handleY, handleSize, -1); - drawContext.getMatrices().pop(); + DrawHelper.drawFilledCircle(graphics, handleX, handleY, handleSize, -1); } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ClassicSkin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ClassicSkin.java index 36ec017..1298a56 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ClassicSkin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ClassicSkin.java @@ -5,10 +5,11 @@ import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenuProperties; import com.tanishisherewith.dynamichud.utils.contextmenu.options.*; import com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.interfaces.SkinRenderer; -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.text.Text; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.network.chat.Component; +import org.apache.logging.log4j.core.pattern.TextRenderer; +import org.joml.Matrix3x2fStack; import java.awt.*; @@ -32,14 +33,14 @@ public ClassicSkin() { } @Override - public void renderContextMenu(DrawContext drawContext, ContextMenu contextMenu, int mouseX, int mouseY) { + public void renderContextMenu(GuiGraphics graphics, ContextMenu contextMenu, int mouseX, int mouseY) { this.contextMenu = contextMenu; - MatrixStack matrices = drawContext.getMatrices(); + Matrix3x2fStack matrices = graphics.pose(); ContextMenuProperties properties = contextMenu.getProperties(); // Draw the background - drawBackground(drawContext, contextMenu, properties); + drawBackground(graphics, contextMenu, properties); int yOffset = contextMenu.y + 3; int width = 10; @@ -48,10 +49,10 @@ public void renderContextMenu(DrawContext drawContext, ContextMenu contextMen // Adjust mouse coordinates based on the scale if (contextMenu.getProperties().hoverEffect() && contextMenu.isMouseOver(mouseX, mouseY, contextMenu.x + 1, yOffset - 1, contextMenu.getWidth() - 2, option.getHeight())) { - drawBackground(drawContext, contextMenu, properties, yOffset - 1, contextMenu.getWidth(), option.getHeight() + 1, contextMenu.getProperties().getHoverColor().getRGB(), false); + drawBackground(graphics, contextMenu, properties, yOffset - 1, contextMenu.getWidth(), option.getHeight() + 1, contextMenu.getProperties().getHoverColor().getRGB(), false); } - option.render(drawContext, contextMenu.x + 4, yOffset, mouseX, mouseY); + option.render(graphics, contextMenu.x + 4, yOffset, mouseX, mouseY); width = Math.max(width, option.getWidth()); yOffset += option.getHeight() + 1; } @@ -60,19 +61,19 @@ public void renderContextMenu(DrawContext drawContext, ContextMenu contextMen // Draw the border if needed if (properties.shouldDrawBorder()) { - drawBorder(drawContext, contextMenu, properties); + drawBorder(graphics, contextMenu, properties); } } - private void drawBackground(DrawContext drawContext, ContextMenu contextMenu, ContextMenuProperties properties) { - drawBackground(drawContext, contextMenu, properties, contextMenu.y, contextMenu.getWidth(), contextMenu.getHeight(), properties.getBackgroundColor().getRGB(), properties.shadow()); + private void drawBackground(GuiGraphics graphics, ContextMenu contextMenu, ContextMenuProperties properties) { + drawBackground(graphics, contextMenu, properties, contextMenu.y, contextMenu.getWidth(), contextMenu.getHeight(), properties.getBackgroundColor().getRGB(), properties.shadow()); } - private void drawBackground(DrawContext drawContext, ContextMenu contextMenu, ContextMenuProperties properties, int yOffset, int width, int height, int color, boolean shadow) { + private void drawBackground(GuiGraphics graphics, ContextMenu contextMenu, ContextMenuProperties properties, int yOffset, int width, int height, int color, boolean shadow) { if (properties.roundedCorners()) { // Rounded if (shadow) { - DrawHelper.drawRoundedRectangleWithShadowBadWay(drawContext, + DrawHelper.drawRoundedRectangleWithShadowBadWay(graphics, contextMenu.x, yOffset, width, @@ -84,7 +85,7 @@ private void drawBackground(DrawContext drawContext, ContextMenu contextMenu, 1 ); } else { - DrawHelper.drawRoundedRectangle(drawContext, + DrawHelper.drawRoundedRectangle(graphics, contextMenu.x, yOffset, width, @@ -96,7 +97,7 @@ private void drawBackground(DrawContext drawContext, ContextMenu contextMenu, } else { // Normal if (shadow) { - DrawHelper.drawRectangleWithShadowBadWay(drawContext, + DrawHelper.drawRectangleWithShadowBadWay(graphics, contextMenu.x, yOffset, width, @@ -107,7 +108,7 @@ private void drawBackground(DrawContext drawContext, ContextMenu contextMenu, 1 ); } else { - DrawHelper.drawRectangle(drawContext, + DrawHelper.drawRectangle(graphics, contextMenu.x, yOffset, width, @@ -118,9 +119,9 @@ private void drawBackground(DrawContext drawContext, ContextMenu contextMenu, } } - private void drawBorder(DrawContext drawContext, ContextMenu contextMenu, ContextMenuProperties properties) { + private void drawBorder(GuiGraphics graphics, ContextMenu contextMenu, ContextMenuProperties properties) { if (properties.roundedCorners()) { - DrawHelper.drawOutlineRoundedBox(drawContext, + DrawHelper.drawOutlineRoundedBox(graphics, contextMenu.x, contextMenu.y, contextMenu.getWidth(), @@ -130,7 +131,7 @@ private void drawBorder(DrawContext drawContext, ContextMenu contextMenu, Con properties.getBorderColor().getRGB() ); } else { - DrawHelper.drawOutlineBox(drawContext, + DrawHelper.drawOutlineBox(graphics, contextMenu.x, contextMenu.y, contextMenu.getWidth(), @@ -148,24 +149,24 @@ public Skin clone() { public static class ClassicBooleanRenderer implements SkinRenderer { @Override - public void render(DrawContext drawContext, BooleanOption option, int x, int y, int mouseX, int mouseY) { + public void render(GuiGraphics graphics, BooleanOption option, int x, int y, int mouseX, int mouseY) { int color = option.value ? Color.GREEN.getRGB() : Color.RED.getRGB(); - drawContext.drawText(mc.textRenderer, option.name, x, y, color, false); - option.setHeight(mc.textRenderer.fontHeight); - option.setWidth(mc.textRenderer.getWidth(option.name) + 1); + graphics.drawString(mc.font, option.name, x, y, color, false); + option.setHeight(mc.font.lineHeight); + option.setWidth(mc.font.width(option.name) + 1); } } public static class ClassicColorOptionRenderer implements SkinRenderer { @Override - public void render(DrawContext drawContext, ColorOption option, int x, int y, int mouseX, int mouseY) { + public void render(GuiGraphics graphics, ColorOption option, int x, int y, int mouseX, int mouseY) { int color = option.isVisible ? Color.GREEN.getRGB() : Color.RED.getRGB(); - drawContext.drawText(mc.textRenderer, option.name, x, y, color, false); - option.setHeight(mc.textRenderer.fontHeight); - option.setWidth(mc.textRenderer.getWidth(option.name) + 10); + graphics.drawString(mc.font, option.name, x, y, color, false); + option.setHeight(mc.font.lineHeight); + option.setWidth(mc.font.width(option.name) + 10); int shadowOpacity = Math.min(option.value.getAlpha(), 90); - DrawHelper.drawRoundedRectangleWithShadowBadWay(drawContext, + DrawHelper.drawRoundedRectangleWithShadowBadWay(graphics, x + option.getWidth() - 10 + 1, y - 1, 8, @@ -176,32 +177,32 @@ public void render(DrawContext drawContext, ColorOption option, int x, int y, in 1, 1); - option.getColorGradient().render(drawContext, x + option.getParentMenu().getWidth() + 7, y - 10, mouseX, mouseY); + option.getColorGradient().render(graphics, x + option.getParentMenu().getWidth() + 7, y - 10, mouseX, mouseY); } } public static class ClassicEnumRenderer> implements SkinRenderer> { @Override - public void render(DrawContext drawContext, EnumOption option, int x, int y, int mouseX, int mouseY) { - option.setHeight(mc.textRenderer.fontHeight + 1); - option.setWidth(mc.textRenderer.getWidth(option.name + ": " + option.value.name()) + 1); + public void render(GuiGraphics graphics, EnumOption option, int x, int y, int mouseX, int mouseY) { + option.setHeight(mc.font.lineHeight + 1); + option.setWidth(mc.font.width(option.name + ": " + option.value.name()) + 1); - drawContext.drawText(mc.textRenderer, option.name.copy().append(": "), x, y, Color.WHITE.getRGB(), false); - drawContext.drawText(mc.textRenderer, option.value.name(), x + mc.textRenderer.getWidth(option.name + ": ") + 1, y, Color.CYAN.getRGB(), false); + graphics.drawString(mc.font, option.name.copy().append(": "), x, y, Color.WHITE.getRGB(), false); + graphics.drawString(mc.font, option.value.name(), x + mc.font.width(option.name + ": ") + 1, y, Color.CYAN.getRGB(), false); } } public static class ClassicSubMenuRenderer implements SkinRenderer { @Override - public void render(DrawContext drawContext, SubMenuOption option, int x, int y, int mouseX, int mouseY) { + public void render(GuiGraphics graphics, SubMenuOption option, int x, int y, int mouseX, int mouseY) { int color = option.value ? Color.GREEN.getRGB() : Color.RED.getRGB(); - drawContext.drawText(mc.textRenderer, option.name, x, y, color, false); - drawContext.drawText(mc.textRenderer, option.getSubMenu().isVisible() ? "-" : "+", x + Math.max(option.getParentMenu().getWidth() - 12, mc.textRenderer.getWidth(option.name) + 2), y, color, false); + graphics.drawString(mc.font, option.name, x, y, color, false); + graphics.drawString(mc.font, option.getSubMenu().isVisible() ? "-" : "+", x + Math.max(option.getParentMenu().getWidth() - 12, mc.font.width(option.name) + 2), y, color, false); - option.setHeight(mc.textRenderer.fontHeight); - option.setWidth(mc.textRenderer.getWidth(option.name) + 4); + option.setHeight(mc.font.lineHeight); + option.setWidth(mc.font.width(option.name) + 4); - option.getSubMenu().render(drawContext, x + option.getParentMenu().getWidth(), y - 1, mouseX, mouseY); + option.getSubMenu().render(graphics, x + option.getParentMenu().getWidth(), y - 1, mouseX, mouseY); } } @@ -210,41 +211,41 @@ public static class ClassicRunnableRenderer implements SkinRenderer { @Override - public void render(DrawContext drawContext, DoubleOption option, int x, int y, int mouseX, int mouseY) { + public void render(GuiGraphics graphics, DoubleOption option, int x, int y, int mouseX, int mouseY) { option.setWidth(Math.max(35, contextMenu != null ? contextMenu.getWidth() - option.getProperties().getPadding() - 2 : 0)); option.setHeight(16); // Draw the label - TextRenderer textRenderer = mc.textRenderer; - DrawHelper.scaleAndPosition(drawContext.getMatrices(), x, y, 0.7f); - Text labelText = option.name.copy().append(": " + String.format("%.1f", option.value)); - int labelWidth = textRenderer.getWidth(labelText); + Font font = mc.font; + DrawHelper.scaleAndPosition(graphics.pose(), x, y, 0.7f); + Component labelText = option.name.copy().append(": " + String.format("%.1f", option.value)); + int labelWidth = font.width(labelText); option.setWidth(Math.max(option.getWidth(), labelWidth)); - drawContext.drawTextWithShadow(textRenderer, labelText, x, y + 1, 0xFFFFFFFF); - DrawHelper.stopScaling(drawContext.getMatrices()); + graphics.drawString(font, labelText, x, y + 1, 0xFFFFFFFF,true); + DrawHelper.stopScaling(graphics.pose()); float handleWidth = 3; float handleHeight = 8; double handleX = x + (option.value - option.minValue) / (option.maxValue - option.minValue) * (option.getWidth() - handleWidth); - double handleY = y + textRenderer.fontHeight + 1 + ((2 - handleHeight) / 2); + double handleY = y + font.lineHeight + 1 + ((2 - handleHeight) / 2); // Draw the slider - option.drawSlider(drawContext, x, y + textRenderer.fontHeight + 1, option.getWidth(), handleX); + option.drawSlider(graphics, x, y + font.lineHeight + 1, option.getWidth(), handleX); // Draw the handle - DrawHelper.drawRoundedRectangleWithShadowBadWay(drawContext, + DrawHelper.drawRoundedRectangleWithShadowBadWay(graphics, (float) handleX, (float) handleY, handleWidth, @@ -260,12 +261,12 @@ public void render(DrawContext drawContext, DoubleOption option, int x, int y, i public static class ClassicListRenderer implements SkinRenderer> { @Override - public void render(DrawContext drawContext, ListOption option, int x, int y, int mouseX, int mouseY) { - option.setHeight(mc.textRenderer.fontHeight + 1); - option.setWidth(mc.textRenderer.getWidth(option.name + ": " + option.value.toString()) + 1); + public void render(GuiGraphics graphics, ListOption option, int x, int y, int mouseX, int mouseY) { + option.setHeight(mc.font.lineHeight + 1); + option.setWidth(mc.font.width(option.name + ": " + option.value.toString()) + 1); - drawContext.drawText(mc.textRenderer, option.name.copy().append(": "), x, y + 1, Color.WHITE.getRGB(), false); - drawContext.drawText(mc.textRenderer, option.value.toString(), x + mc.textRenderer.getWidth(option.name + ": ") + 1, y + 1, Color.CYAN.getRGB(), false); + graphics.drawString(mc.font, option.name.copy().append(": "), x, y + 1, Color.WHITE.getRGB(), false); + graphics.drawString(mc.font, option.value.toString(), x + mc.font.width(option.name + ": ") + 1, y + 1, Color.CYAN.getRGB(), false); } } } \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java index 0593ed0..9aeb548 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java @@ -1,6 +1,5 @@ package com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem; -import com.mojang.blaze3d.systems.RenderSystem; import com.tanishisherewith.dynamichud.DynamicHUD; import com.tanishisherewith.dynamichud.helpers.DrawHelper; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenu; @@ -9,13 +8,13 @@ import com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.interfaces.GroupableSkin; import com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.interfaces.SkinRenderer; import com.tanishisherewith.dynamichud.utils.handlers.ScrollHandler; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.screen.ButtonTextures; -import net.minecraft.client.render.RenderLayer; -import net.minecraft.client.sound.PositionedSoundInstance; -import net.minecraft.sound.SoundEvents; -import net.minecraft.text.Text; -import net.minecraft.util.Identifier; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.WidgetSprites; +import net.minecraft.client.renderer.RenderPipelines; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.resources.Identifier; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.network.chat.Component; import org.lwjgl.glfw.GLFW; import java.awt.*; @@ -29,18 +28,18 @@ * It tries to imitate the minecraft look and provides various form of panel shades {@link PanelColor} */ public class MinecraftSkin extends Skin implements GroupableSkin { - public static final ButtonTextures TEXTURES = new ButtonTextures( - Identifier.ofVanilla("widget/button"), - Identifier.ofVanilla("widget/button_disabled"), - Identifier.ofVanilla("widget/button_highlighted") + public static final WidgetSprites TEXTURES = new WidgetSprites( + Identifier.withDefaultNamespace("widget/button"), + Identifier.withDefaultNamespace("widget/button_disabled"), + Identifier.withDefaultNamespace("widget/button_highlighted") ); public static final int DEFAULT_SCROLLBAR_WIDTH = 8; public static final int DEFAULT_PANEL_WIDTH = 248; public static final int DEFAULT_PANEL_HEIGHT = 165; - public static final Identifier DEFAULT_BACKGROUND_PANEL = Identifier.ofVanilla("textures/gui/demo_background.png"); - public static final Identifier SCROLLER_TEXTURE = Identifier.ofVanilla("widget/scroller"); - public static final Identifier SCROLL_BAR_BACKGROUND = Identifier.ofVanilla("widget/scroller_background"); - public static final Identifier GROUP_BACKGROUND = Identifier.of(DynamicHUD.MOD_ID, "textures/minecraftskin/group_panel.png"); + public static final Identifier DEFAULT_BACKGROUND_PANEL = Identifier.withDefaultNamespace("textures/gui/demo_background.png"); + public static final Identifier SCROLLER_TEXTURE = Identifier.withDefaultNamespace("widget/scroller"); + public static final Identifier SCROLL_BAR_BACKGROUND = Identifier.withDefaultNamespace("widget/scroller_background"); + public static final Identifier GROUP_BACKGROUND = Identifier.fromNamespaceAndPath(DynamicHUD.MOD_ID, "textures/minecraftskin/group_panel.png"); private final Identifier BACKGROUND_PANEL; private final int panelWidth; @@ -76,12 +75,12 @@ public MinecraftSkin(PanelColor color) { setCreateNewScreen(true); } - private void enableContextMenuScissor() { - DrawHelper.enableScissor(0, imageY + 3, mc.getWindow().getScaledWidth(), panelHeight - 8); + private void enableContextMenuScissor(GuiGraphics graphics) { + DrawHelper.enableScissor(0, imageY + 3, mc.getWindow().getGuiScaledWidth(), panelHeight - 8,graphics); } private void createGroups() { - OptionGroup generalGroup = new OptionGroup(Text.of("General")); + OptionGroup generalGroup = new OptionGroup(Component.literal("General")); for (Option option : getOptions(contextMenu)) { if (option instanceof OptionGroup og) { optionGroups.add(og); @@ -104,13 +103,13 @@ private void initOptionGroups() { } @Override - public void renderContextMenu(DrawContext drawContext, ContextMenu contextMenu, int mouseX, int mouseY) { + public void renderContextMenu(GuiGraphics graphics, ContextMenu contextMenu, int mouseX, int mouseY) { this.contextMenu = contextMenu; initOptionGroups(); - int screenWidth = mc.getWindow().getScaledWidth(); - int screenHeight = mc.getWindow().getScaledHeight(); + int screenWidth = mc.getWindow().getGuiScaledWidth(); + int screenHeight = mc.getWindow().getGuiScaledHeight(); int centerX = screenWidth / 2; int centerY = screenHeight / 2; @@ -121,64 +120,60 @@ public void renderContextMenu(DrawContext drawContext, ContextMenu contextMen imageX = (screenWidth - panelWidth + 25) / 2; imageY = (screenHeight - panelHeight) / 2; - drawContext.drawTexture(RenderLayer::getGuiTextured, BACKGROUND_PANEL, imageX, imageY, 0, 0, panelWidth, panelHeight, 256, 254,panelColor.getColor()); + graphics.blit(RenderPipelines.GUI_TEXTURED, BACKGROUND_PANEL, imageX, imageY, 0, 0, panelWidth, panelHeight, 256, 254,panelColor.getColor()); - drawSingularButton(drawContext, "X", mouseX, mouseY, imageX + 3, imageY + 3, 14, 14); + drawSingularButton(graphics, "X", mouseX, mouseY, imageX + 3, imageY + 3, 14, 14); //Up and down arrows near the group panel int size = (int) (groupPanelWidth * 0.5f); - drawSingularButton(drawContext, "^", mouseX, mouseY, groupPanelX.getAsInt() + groupPanelWidth / 2 - size / 2, imageY - 14, size, 14, groupScrollHandler.isOffsetWithinBounds(-10)); - drawSingularButton(drawContext, "v", mouseX, mouseY, groupPanelX.getAsInt() + groupPanelWidth / 2 - size / 2, imageY + panelHeight - 2, size, 14, groupScrollHandler.isOffsetWithinBounds(10)); - drawContext.draw(); - // drawContext.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURES.get(true, isMouseOver(mouseX, mouseY, imageX + 3, imageY + 3, 14, 14)), imageX + 3, imageY + 3, 14, 14); - // drawContext.drawText(mc.textRenderer, "X", imageX + 10 - mc.textRenderer.getWidth("X") / 2, imageY + 6, -1, true); + drawSingularButton(graphics, "^", mouseX, mouseY, groupPanelX.getAsInt() + groupPanelWidth / 2 - size / 2, imageY - 14, size, 14, groupScrollHandler.isOffsetWithinBounds(-10)); + drawSingularButton(graphics, "v", mouseX, mouseY, groupPanelX.getAsInt() + groupPanelWidth / 2 - size / 2, imageY + panelHeight - 2, size, 14, groupScrollHandler.isOffsetWithinBounds(10)); + // graphics.blitSprite(RenderPipelines.GUI_TEXTURED, TEXTURES.get(true, isMouseOver(mouseX, mouseY, imageX + 3, imageY + 3, 14, 14)), imageX + 3, imageY + 3, 14, 14); + // graphics.drawString(mc.font, "X", imageX + 10 - mc.font.width("X") / 2, imageY + 6, -1, true); - this.enableContextMenuScissor(); + this.enableContextMenuScissor(graphics); contextMenu.setWidth(panelWidth - 4); contextMenu.y = imageY; - renderOptionGroups(drawContext, mouseX, mouseY); - renderSelectedGroupOptions(drawContext, mouseX, mouseY); + renderOptionGroups(graphics, mouseX, mouseY); + renderSelectedGroupOptions(graphics, mouseX, mouseY); contextMenu.setHeight(getContentHeight() + 15); - drawScrollbar(drawContext); + drawScrollbar(graphics); scrollHandler.updateScrollOffset(getMaxScrollOffset()); // Disable scissor after rendering - DrawHelper.disableScissor(); + DrawHelper.disableScissor(graphics); } - public void drawSingularButton(DrawContext drawContext, String text, int mouseX, int mouseY, int x, int y, int width, int height, boolean enabled) { - RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f); - drawContext.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURES.get(enabled, isMouseOver(mouseX, mouseY, x, y, width, height)), x, y, width, height); - drawContext.drawText(mc.textRenderer, text, x + width / 2 - mc.textRenderer.getWidth(text) / 2, y + mc.textRenderer.fontHeight / 2 - 1, Color.WHITE.getRGB(), true); + public void drawSingularButton(GuiGraphics graphics, String Component, int mouseX, int mouseY, int x, int y, int width, int height, boolean enabled) { + graphics.blitSprite(RenderPipelines.GUI_TEXTURED, TEXTURES.get(enabled, isMouseOver(mouseX, mouseY, x, y, width, height)), x, y, width, height); + graphics.drawString(mc.font, Component, x + width / 2 - mc.font.width(Component) / 2, y + mc.font.lineHeight / 2 - 1, Color.WHITE.getRGB(), true); } - public void drawSingularButton(DrawContext drawContext, String text, int mouseX, int mouseY, int x, int y, int width, int height) { - this.drawSingularButton(drawContext, text, mouseX, mouseY, x, y, width, height, true); + public void drawSingularButton(GuiGraphics graphics, String Component, int mouseX, int mouseY, int x, int y, int width, int height) { + this.drawSingularButton(graphics, Component, mouseX, mouseY, x, y, width, height, true); } - private void renderOptionGroups(DrawContext drawContext, int mouseX, int mouseY) { + private void renderOptionGroups(GuiGraphics graphics, int mouseX, int mouseY) { int groupX = groupPanelX.getAsInt(); int groupY = imageY; - RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f); - drawContext.drawTexture(RenderLayer::getGuiTextured, GROUP_BACKGROUND, groupX - 10, groupY + 2, 0,0,groupPanelWidth + 20, panelHeight, 80, 158); - RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f); + graphics.blit(RenderPipelines.GUI_TEXTURED, GROUP_BACKGROUND, groupX - 10, groupY + 2, 0,0,groupPanelWidth + 20, panelHeight - 2, groupPanelWidth + 20, panelHeight - 3); int yOffset = groupY + 12 - groupScrollHandler.getScrollOffset(); for (OptionGroup group : optionGroups) { if (yOffset >= groupY + 12 && yOffset <= groupY + panelHeight - 15) { - drawContext.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURES.get(!group.isExpanded(), isMouseOver(mouseX, mouseY, groupX, yOffset, groupPanelWidth, 20)), groupX, yOffset, groupPanelWidth, 20); + graphics.blitSprite(RenderPipelines.GUI_TEXTURED, TEXTURES.get(!group.isExpanded(), isMouseOver(mouseX, mouseY, groupX, yOffset, groupPanelWidth, 20)), groupX, yOffset, groupPanelWidth, 20); - DrawHelper.drawScrollableText(drawContext, mc.textRenderer, group.getName(), groupX + groupPanelWidth / 2, groupX + 2, yOffset, groupX + groupPanelWidth - 2, yOffset + 20, -1); + DrawHelper.drawScrollableText(graphics, mc.font, group.getName(), groupX + groupPanelWidth / 2, groupX + 2, yOffset, groupX + groupPanelWidth - 2, yOffset + 20, -1); - //Scrollable text uses scissor, so we need to enable the context menu scissor again - this.enableContextMenuScissor(); + //Scrollable Component uses scissor, so we need to enable the context menu scissor again + this.enableContextMenuScissor(graphics); yOffset += 20; // Space for the header } @@ -186,24 +181,22 @@ private void renderOptionGroups(DrawContext drawContext, int mouseX, int mouseY) } groupScrollHandler.updateScrollOffset(yOffset - groupY - 12 + groupScrollHandler.getScrollOffset() - panelHeight); - - RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f); } - private int renderSelectedGroupOptions(DrawContext drawContext, int mouseX, int mouseY) { + private int renderSelectedGroupOptions(GuiGraphics graphics, int mouseX, int mouseY) { int yOffset = imageY + 12 - scrollHandler.getScrollOffset(); for (Option option : selectedGroup.getGroupOptions()) { if (!option.shouldRender()) continue; if (yOffset >= imageY - option.getHeight() && yOffset <= imageY + option.getHeight() + panelHeight) { - option.render(drawContext, imageX + 4, yOffset, mouseX, mouseY); + option.render(graphics, imageX + 4, yOffset, mouseX, mouseY); } yOffset += option.getHeight() + 1; } return yOffset; } - private void drawScrollbar(DrawContext drawContext) { + private void drawScrollbar(GuiGraphics graphics) { if (getMaxScrollOffset() > 0) { int scrollbarX = imageX + panelWidth + 10; int scrollbarY = imageY; @@ -211,8 +204,8 @@ private void drawScrollbar(DrawContext drawContext) { double handleHeight = panelHeight * ratio; int handleY = (int) (scrollbarY + (panelHeight - handleHeight) * ((double) scrollHandler.getScrollOffset() / getMaxScrollOffset())); - drawContext.drawGuiTexture(RenderLayer::getGuiTextured, SCROLL_BAR_BACKGROUND, scrollbarX, scrollbarY, DEFAULT_SCROLLBAR_WIDTH, panelHeight); - drawContext.drawGuiTexture(RenderLayer::getGuiTextured, SCROLLER_TEXTURE, scrollbarX, handleY, DEFAULT_SCROLLBAR_WIDTH, (int) handleHeight); + graphics.blitSprite(RenderPipelines.GUI_TEXTURED, SCROLL_BAR_BACKGROUND, scrollbarX, scrollbarY, DEFAULT_SCROLLBAR_WIDTH, panelHeight); + graphics.blitSprite(RenderPipelines.GUI_TEXTURED, SCROLLER_TEXTURE, scrollbarX, handleY, DEFAULT_SCROLLBAR_WIDTH, (int) handleHeight); } } @@ -238,7 +231,7 @@ public void mouseScrolled(ContextMenu menu, double mouseX, double mouseY, dou public boolean mouseClicked(ContextMenu menu, double mouseX, double mouseY, int button) { if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { if (isMouseOver(mouseX, mouseY, imageX + 3, imageY + 3, 14, 14)) { - mc.getSoundManager().play(PositionedSoundInstance.master( + mc.getSoundManager().play(SimpleSoundInstance.forUI( SoundEvents.UI_BUTTON_CLICK, 1.0F)); contextMenu.close(); @@ -248,12 +241,12 @@ public boolean mouseClicked(ContextMenu menu, double mouseX, double mouseY, i int size = (int) (groupPanelWidth * 0.5f); //Up and down button if (groupScrollHandler.isOffsetWithinBounds(-10) && isMouseOver(mouseX, mouseY, groupPanelX.getAsInt() + (double) groupPanelWidth / 2 - size / 2, imageY - 14, size, 14)) { - mc.getSoundManager().play(PositionedSoundInstance.master( + mc.getSoundManager().play(SimpleSoundInstance.forUI( SoundEvents.UI_BUTTON_CLICK, 1.0F)); groupScrollHandler.addOffset(-10); } if (groupScrollHandler.isOffsetWithinBounds(10) && isMouseOver(mouseX, mouseY, groupPanelX.getAsInt() + (double) groupPanelWidth / 2 - size / 2, imageY + panelHeight - 2, size, 14)) { - mc.getSoundManager().play(PositionedSoundInstance.master( + mc.getSoundManager().play(SimpleSoundInstance.forUI( SoundEvents.UI_BUTTON_CLICK, 1.0F)); groupScrollHandler.addOffset(10); } @@ -336,7 +329,7 @@ public int getImageY() { * Group rendering handled already */ @Override - public void renderGroup(DrawContext drawContext, OptionGroup group, int groupX, int groupY, int mouseX, int mouseY) { + public void renderGroup(GuiGraphics graphics, OptionGroup group, int groupX, int groupY, int mouseX, int mouseY) { } public enum PanelColor { @@ -378,9 +371,6 @@ public static PanelColor custom(float red, float green, float blue, float alpha) return custom; } - public void applyColor() { - RenderSystem.setShaderColor(red, green, blue, alpha); - } public int getColor() { return new Color(red,green,blue,alpha).getRGB(); } @@ -388,19 +378,17 @@ public int getColor() { public class MinecraftBooleanRenderer implements SkinRenderer { @Override - public void render(DrawContext drawContext, BooleanOption option, int x, int y, int mouseX, int mouseY) { - drawContext.drawText(mc.textRenderer, option.name, x + 15, y + 25 / 2 - 5, -1, true); + public void render(GuiGraphics graphics, BooleanOption option, int x, int y, int mouseX, int mouseY) { + graphics.drawString(mc.font, option.name, x + 15, y + 25 / 2 - 5, -1, true); option.setPosition(x + panelWidth - 75, y); int width = 50; - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - drawContext.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURES.get(true, option.isMouseOver(mouseX, mouseY)), option.getX(), y, width, 20); + graphics.blitSprite(RenderPipelines.GUI_TEXTURED, TEXTURES.get(true, option.isMouseOver(mouseX, mouseY)), option.getX(), y, width, 20); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - Text text = option.getBooleanType().getText(option.value); + Component Component = option.getBooleanType().getText(option.value); int color = option.value ? Color.GREEN.getRGB() : Color.RED.getRGB(); - drawContext.drawText(mc.textRenderer, text, (int) (option.getX() + (width / 2.0f) - (mc.textRenderer.getWidth(text) / 2.0f)), y + 5, color, true); + graphics.drawString(mc.font, Component, (int) (option.getX() + (width / 2.0f) - (mc.font.width(Component) / 2.0f)), y + 5, color, true); option.setHeight(25); @@ -416,19 +404,16 @@ public boolean mouseClicked(BooleanOption option, double mouseX, double mouseY, public class MinecraftColorOptionRenderer implements SkinRenderer { @Override - public void render(DrawContext drawContext, ColorOption option, int x, int y, int mouseX, int mouseY) { - drawContext.drawText(mc.textRenderer, option.name, x + 15, y + 25 / 2 - 5, -1, true); + public void render(GuiGraphics graphics, ColorOption option, int x, int y, int mouseX, int mouseY) { + graphics.drawString(mc.font, option.name, x + 15, y + 25 / 2 - 5, -1, true); option.setPosition(x + panelWidth - 45, y); int width = 20; - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - drawContext.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURES.get(!option.isVisible, option.isMouseOver(mouseX, mouseY)), option.getX(), y, width, 20); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); + graphics.blitSprite(RenderPipelines.GUI_TEXTURED, TEXTURES.get(!option.isVisible, option.isMouseOver(mouseX, mouseY)), option.getX(), y, width, 20); int shadowOpacity = Math.min(option.value.getAlpha(), 45); - drawContext.draw(); - DrawHelper.drawRectangleWithShadowBadWay(drawContext, + DrawHelper.drawRectangleWithShadowBadWay(graphics, option.getX() + 4, y + 4, width - 8, @@ -437,18 +422,17 @@ public void render(DrawContext drawContext, ColorOption option, int x, int y, in shadowOpacity, 1, 1); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); option.setHeight(25); option.setWidth(width); if (option.getColorGradient().getColorPickerButton().isPicking()) { - DrawHelper.disableScissor(); // Disable scissor test for the colorpicker + DrawHelper.disableScissor(graphics); // Disable scissor test for the colorpicker } //TODO: WHAT IS THISSSSS int colorGradientWidth = option.getColorGradient().getBoxSize() + option.getColorGradient().getAlphaSlider().getWidth() + option.getColorGradient().getColorPickerButton().getWidth(); - option.getColorGradient().render(drawContext, x + panelWidth / 2 - colorGradientWidth / 2, y + 12, mouseX, mouseY); + option.getColorGradient().render(graphics, x + panelWidth / 2 - colorGradientWidth / 2, y + 12, mouseX, mouseY); if (option.getColorGradient().shouldDisplay()) { int colorGradientHeight = option.getColorGradient().getBoxSize() + 10 + option.getColorGradient().getGradientSlider().getHeight(); @@ -456,16 +440,16 @@ public void render(DrawContext drawContext, ColorOption option, int x, int y, in } if (option.getColorGradient().getColorPickerButton().isPicking()) { - DrawHelper.enableScissor(imageX, imageY + 2, panelWidth, panelHeight - 4); + DrawHelper.enableScissor(imageX, imageY + 2, panelWidth, panelHeight - 4, graphics); } } } public class MinecraftDoubleRenderer implements SkinRenderer { - private static final Identifier TEXTURE = Identifier.ofVanilla("widget/slider"); - private static final Identifier HIGHLIGHTED_TEXTURE = Identifier.ofVanilla("widget/slider_highlighted"); - private static final Identifier HANDLE_TEXTURE = Identifier.ofVanilla("widget/slider_handle"); - private static final Identifier HANDLE_HIGHLIGHTED_TEXTURE = Identifier.ofVanilla("widget/slider_handle_highlighted"); + private static final Identifier TEXTURE = Identifier.withDefaultNamespace("widget/slider"); + private static final Identifier HIGHLIGHTED_TEXTURE = Identifier.withDefaultNamespace("widget/slider_highlighted"); + private static final Identifier HANDLE_TEXTURE = Identifier.withDefaultNamespace("widget/slider_handle"); + private static final Identifier HANDLE_HIGHLIGHTED_TEXTURE = Identifier.withDefaultNamespace("widget/slider_handle_highlighted"); @Override public void init(DoubleOption option) { @@ -473,8 +457,8 @@ public void init(DoubleOption option) { } @Override - public void render(DrawContext drawContext, DoubleOption option, int x, int y, int mouseX, int mouseY) { - drawContext.drawText(mc.textRenderer, option.name, x + 15, y + 25 / 2 - 5, -1, true); + public void render(GuiGraphics graphics, DoubleOption option, int x, int y, int mouseX, int mouseY) { + graphics.drawString(mc.font, option.name, x + 15, y + 25 / 2 - 5, -1, true); option.setWidth(panelWidth - 150); option.setHeight(25); @@ -483,16 +467,15 @@ public void render(DrawContext drawContext, DoubleOption option, int x, int y, i double sliderX = option.getX() + ((option.value - option.minValue) / (option.maxValue - option.minValue)) * (option.getWidth() - 8); boolean isMouseOverHandle = isMouseOver(mouseX, mouseY, sliderX, y, 10, 20); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - drawContext.drawGuiTexture(RenderLayer::getGuiTextured, option.isMouseOver(mouseX, mouseY) ? HIGHLIGHTED_TEXTURE : TEXTURE, option.getX(), y, option.getWidth(), 20); - drawContext.drawGuiTexture(RenderLayer::getGuiTextured, isMouseOverHandle ? HANDLE_HIGHLIGHTED_TEXTURE : HANDLE_TEXTURE, (int) Math.round(sliderX), y, 8, 20); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - // Determine the number of decimal places in option.step + graphics.blitSprite(RenderPipelines.GUI_TEXTURED, option.isMouseOver(mouseX, mouseY) ? HIGHLIGHTED_TEXTURE : TEXTURE, option.getX(), y, option.getWidth(), 20); + graphics.blitSprite(RenderPipelines.GUI_TEXTURED, isMouseOverHandle ? HANDLE_HIGHLIGHTED_TEXTURE : HANDLE_TEXTURE, (int) Math.round(sliderX), y, 8, 20); + + // Determine the number of decimal places in option.step int decimalPlaces = String.valueOf(option.step).split("\\.")[1].length(); // Format option.value to the determined number of decimal places String formattedValue = String.format("%." + decimalPlaces + "f", option.value); - drawContext.drawText(mc.textRenderer, formattedValue, option.getX() + option.getWidth() / 2 - mc.textRenderer.getWidth(formattedValue) / 2, y + 5, 16777215, false); + graphics.drawCenteredString(mc.font, formattedValue, option.getX() + option.getWidth() / 2, y + Math.round((float) mc.font.lineHeight /2), -1); } @Override @@ -506,7 +489,7 @@ public class MinecraftEnumRenderer> implements SkinRenderer option) { for (E enumConstant : option.getValues()) { - int width = mc.textRenderer.getWidth(enumConstant.name()) + 5; + int width = mc.font.width(enumConstant.name()) + 5; if (width > maxWidth) { maxWidth = width; } @@ -514,20 +497,18 @@ private void calculateMaxWidth(EnumOption option) { } @Override - public void render(DrawContext drawContext, EnumOption option, int x, int y, int mouseX, int mouseY) { + public void render(GuiGraphics graphics, EnumOption option, int x, int y, int mouseX, int mouseY) { calculateMaxWidth(option); option.setHeight(25); option.setWidth(maxWidth); - drawContext.drawText(mc.textRenderer, option.name.copy().append(": "), x + 15, y + 25 / 2 - 5, -1, true); + graphics.drawString(mc.font, option.name.copy().append(": "), x + 15, y + 25 / 2 - 5, -1, true); option.setPosition(x + panelWidth - maxWidth - 25, y); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - drawContext.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURES.get(true, option.isMouseOver(mouseX, mouseY)), option.getX(), y, maxWidth, 20); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - String text = option.get().toString(); - drawContext.drawText(mc.textRenderer, text, option.getX() + maxWidth / 2 - mc.textRenderer.getWidth(text) / 2, y + 5, Color.CYAN.getRGB(), true); + graphics.blitSprite(RenderPipelines.GUI_TEXTURED, TEXTURES.get(true, option.isMouseOver(mouseX, mouseY)), option.getX(), y, maxWidth, 20); + String Component = option.get().toString(); + graphics.drawString(mc.font, Component, option.getX() + maxWidth / 2 - mc.font.width(Component) / 2, y + 5, Color.CYAN.getRGB(), true); } } @@ -536,7 +517,7 @@ public class MinecraftListRenderer implements SkinRenderer> { private void calculateMaxWidth(ListOption option) { for (E listValues : option.getValues()) { - int width = mc.textRenderer.getWidth(listValues.toString()) + 5; + int width = mc.font.width(listValues.toString()) + 5; if (width > maxWidth) { maxWidth = width; } @@ -544,40 +525,36 @@ private void calculateMaxWidth(ListOption option) { } @Override - public void render(DrawContext drawContext, ListOption option, int x, int y, int mouseX, int mouseY) { + public void render(GuiGraphics graphics, ListOption option, int x, int y, int mouseX, int mouseY) { calculateMaxWidth(option); option.setHeight(25); option.setWidth(maxWidth); - drawContext.drawText(mc.textRenderer, option.name.copy().append(": "), x + 15, y + 25 / 2 - 5, -1, true); + graphics.drawString(mc.font, option.name.copy().append(": "), x + 15, y + 25 / 2 - 5, -1, true); option.setPosition(x + panelWidth - maxWidth - 25, y); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - drawContext.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURES.get(true, option.isMouseOver(mouseX, mouseY)), option.getX(), y, maxWidth, 20); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - String text = option.get().toString(); - drawContext.drawText(mc.textRenderer, text, option.getX() + maxWidth / 2 - mc.textRenderer.getWidth(text) / 2, y + 5, Color.CYAN.getRGB(), true); + graphics.blitSprite(RenderPipelines.GUI_TEXTURED, TEXTURES.get(true, option.isMouseOver(mouseX, mouseY)), option.getX(), y, maxWidth, 20); + String Component = option.get().toString(); + graphics.drawString(mc.font, Component, option.getX() + maxWidth / 2 - mc.font.width(Component) / 2, y + 5, Color.CYAN.getRGB(), true); } } public class MinecraftSubMenuRenderer implements SkinRenderer { @Override - public void render(DrawContext drawContext, SubMenuOption option, int x, int y, int mouseX, int mouseY) { + public void render(GuiGraphics graphics, SubMenuOption option, int x, int y, int mouseX, int mouseY) { option.setHeight(20); option.setWidth(30); - drawContext.drawText(mc.textRenderer, option.name, x + 15, y + 25 / 2 - 5, -1, true); + graphics.drawString(mc.font, option.name, x + 15, y + 25 / 2 - 5, -1, true); option.setPosition(x + panelWidth - 55, y); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - drawContext.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURES.get(true, option.isMouseOver(mouseX, mouseY)), option.getX(), y, option.getWidth(), 20); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - String text = "Open"; - drawContext.drawText(mc.textRenderer, text, option.getX() + option.getWidth() / 2 - mc.textRenderer.getWidth(text) / 2, y + 5, Color.YELLOW.getRGB(), true); + graphics.blitSprite(RenderPipelines.GUI_TEXTURED, TEXTURES.get(true, option.isMouseOver(mouseX, mouseY)), option.getX(), y, option.getWidth(), 20); + String Component = "Open"; + graphics.drawString(mc.font, Component, option.getX() + option.getWidth() / 2 - mc.font.width(Component) / 2, y + 5, Color.YELLOW.getRGB(), true); - option.getSubMenu().render(drawContext, x + option.getParentMenu().getWidth(), y, mouseX, mouseY); + option.getSubMenu().render(graphics, x + option.getParentMenu().getWidth(), y, mouseX, mouseY); } } @@ -586,18 +563,16 @@ public class MinecraftRunnableRenderer implements SkinRenderer { Color DARK_GREEN = new Color(24, 132, 0, 226); @Override - public void render(DrawContext drawContext, RunnableOption option, int x, int y, int mouseX, int mouseY) { + public void render(GuiGraphics graphics, RunnableOption option, int x, int y, int mouseX, int mouseY) { option.setHeight(25); option.setWidth(26); - drawContext.drawText(mc.textRenderer, option.name.copy().append(": "), x + 15, y + 25 / 2 - 5, -1, true); + graphics.drawString(mc.font, option.name.copy().append(": "), x + 15, y + 25 / 2 - 5, -1, true); option.setPosition(x + panelWidth - 51, y); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - drawContext.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURES.get(!option.value, option.isMouseOver(mouseX, mouseY)), option.getX(), y, option.getWidth(), 20); - drawContext.drawText(mc.textRenderer, "Run", option.getX() + option.getWidth() / 2 - mc.textRenderer.getWidth("Run") / 2, y + 5, option.value ? DARK_GREEN.getRGB() : DARK_RED.getRGB(), true); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); + graphics.blitSprite(RenderPipelines.GUI_TEXTURED, TEXTURES.get(!option.value, option.isMouseOver(mouseX, mouseY)), option.getX(), y, option.getWidth(), 20); + graphics.drawString(mc.font, "Run", option.getX() + option.getWidth() / 2 - mc.font.width("Run") / 2, y + 5, option.value ? DARK_GREEN.getRGB() : DARK_RED.getRGB(), true); } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java index 17fc98d..6d3b809 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java @@ -1,6 +1,5 @@ package com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem; -import com.mojang.blaze3d.systems.RenderSystem; import com.tanishisherewith.dynamichud.helpers.ColorHelper; import com.tanishisherewith.dynamichud.helpers.DrawHelper; import com.tanishisherewith.dynamichud.helpers.animationhelper.EasingType; @@ -11,14 +10,12 @@ import com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.interfaces.GroupableSkin; import com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.interfaces.SkinRenderer; import com.tanishisherewith.dynamichud.utils.handlers.ScrollHandler; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.sound.PositionedSoundInstance; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.sound.SoundEvents; -import net.minecraft.text.OrderedText; -import net.minecraft.text.StringVisitable; -import net.minecraft.text.Text; -import net.minecraft.util.math.MathHelper; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.network.chat.Component; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.util.Mth; import org.lwjgl.glfw.GLFW; import java.awt.*; @@ -32,18 +29,18 @@ public class ModernSkin extends Skin implements GroupableSkin { private final Color themeColor; private final float radius; - private final Text defaultToolTipHeader; - private final Text defaultToolTipText; + private final Component defaultToolTipHeader; + private final Component defaultToolTipText; private int contextMenuX = 0, contextMenuY = 0; private int width = 0, height = 0; private float scaledWidth = 0, scaledHeight = 0; - private Text TOOLTIP_TEXT; - private Text TOOLTIP_HEAD; + private Component TOOLTIP_TEXT; + private Component TOOLTIP_HEAD; private static int SCALE_FACTOR = 4; private final ScrollHandler scrollHandler; - public ModernSkin(Color themeColor, float radius, Text defaultToolTipHeader, Text defaultToolTipText) { + public ModernSkin(Color themeColor, float radius, Component defaultToolTipHeader, Component defaultToolTipText) { this.themeColor = themeColor; this.radius = radius; TOOLTIP_TEXT = defaultToolTipText; @@ -65,7 +62,7 @@ public ModernSkin(Color themeColor, float radius, Text defaultToolTipHeader, Tex } public ModernSkin(Color themeColor, float radius) { - this(themeColor, radius, Text.of("Example Tip"), Text.of("Hover over a setting to see its tool-tip (if present) here!")); + this(themeColor, radius, Component.literal("Example Tip"), Component.literal("Hover over a setting to see its tool-tip (if present) here!")); } public ModernSkin(Color themeColor) { @@ -81,33 +78,33 @@ public LayoutContext.Offset getGroupIndent() { return new LayoutContext.Offset(2, 2); } - public void enableSkinScissor() { - DrawHelper.enableScissor(contextMenuX + (int) (width * 0.2f) + 10, contextMenuY + 19, (int) (width * 0.8f - 14), height - 23, SCALE_FACTOR); + public void enableSkinScissor(GuiGraphics graphics) { + DrawHelper.enableScissor(contextMenuX + (int) (width * 0.2f) + 10, contextMenuY + 19, (int) (width * 0.8f - 14), height - 23, SCALE_FACTOR, graphics); } @Override - public void renderGroup(DrawContext drawContext, OptionGroup group, int groupX, int groupY, int mouseX, int mouseY) { - mouseX = (int) (mc.mouse.getX() / SCALE_FACTOR); - mouseY = (int) (mc.mouse.getY() / SCALE_FACTOR); + public void renderGroup(GuiGraphics graphics, OptionGroup group, int groupX, int groupY, int mouseX, int mouseY) { + mouseX = (int) (mc.mouseHandler.xpos() / SCALE_FACTOR); + mouseY = (int) (mc.mouseHandler.ypos() / SCALE_FACTOR); if (group.isExpanded() && group.getHeight() > 20) { - DrawHelper.drawRoundedRectangle(drawContext, + DrawHelper.drawRoundedRectangle(graphics, groupX + 1, groupY + 14, width - groupX - 8 + contextMenuX, group.getHeight() - 16, radius, DARKER_GRAY_2.getRGB()); } - Text groupText = group.name.copy().append(" " + (group.isExpanded() ? "-" : "+")); + Component groupText = group.name.copy().append(" " + (group.isExpanded() ? "-" : "+")); - DrawHelper.drawRoundedRectangle(drawContext, - groupX + 1, groupY + 1, true, true, !group.isExpanded(), !group.isExpanded(), mc.textRenderer.getWidth(groupText) + 6, 16, radius, DARKER_GRAY_2.getRGB()); + DrawHelper.drawRoundedRectangle(graphics, + groupX + 1, groupY + 1, true, true, !group.isExpanded(), !group.isExpanded(), mc.font.width(groupText) + 6, 16, radius, DARKER_GRAY_2.getRGB()); - drawContext.drawText(mc.textRenderer, groupText, groupX + 4, groupY + 4, -1, true); + graphics.drawString(mc.font, groupText, groupX + 4, groupY + 4, -1, true); if (group.isExpanded()) { - int yOffset = groupY + 16 + getGroupIndent().top; + int yOffset = groupY + 16 + getGroupIndent().top(); for (Option option : group.getGroupOptions()) { if (!option.shouldRender()) continue; - option.render(drawContext, groupX + getGroupIndent().left, yOffset, mouseX, mouseY); + option.render(graphics, groupX + getGroupIndent().left(), yOffset, mouseX, mouseY); yOffset += option.getHeight() + 1; } @@ -117,25 +114,25 @@ public void renderGroup(DrawContext drawContext, OptionGroup group, int groupX, } } - private void drawScrollbar(DrawContext drawContext) { + private void drawScrollbar(GuiGraphics graphics) { if (getMaxScrollOffset() > 0) { int scrollbarX = contextMenuX + width + 5; // Position at the right of the panel int scrollbarY = contextMenuY + 19; // Position below the header int handleHeight = (int) ((float) (height - 23) * ((height - 23) / (float) contextMenu.getHeight())); int handleY = scrollbarY + (int) ((float) ((height - 23) - handleHeight) * ((float) scrollHandler.getScrollOffset() / getMaxScrollOffset())); - DrawHelper.drawRoundedRectangle(drawContext, scrollbarX, scrollbarY, 2, height - 23, 1, DARKER_GRAY.getRGB()); - DrawHelper.drawRoundedRectangle(drawContext, scrollbarX, handleY, 2, handleHeight, 1, Color.LIGHT_GRAY.getRGB()); + DrawHelper.drawRoundedRectangle(graphics, scrollbarX, scrollbarY, 2, height - 23, 1, DARKER_GRAY.getRGB()); + DrawHelper.drawRoundedRectangle(graphics, scrollbarX, handleY, 2, handleHeight, 1, Color.LIGHT_GRAY.getRGB()); } } @Override - public void renderContextMenu(DrawContext drawContext, ContextMenu contextMenu, int mouseX, int mouseY) { + public void renderContextMenu(GuiGraphics graphics, ContextMenu contextMenu, int mouseX, int mouseY) { //This is equivalent to "Auto" GUI scale in minecraft options - SCALE_FACTOR = mc.getWindow().calculateScaleFactor(0, mc.forcesUnicodeFont()); + SCALE_FACTOR = mc.getWindow().calculateScale(0, mc.isEnforceUnicode()); - mouseX = (int) (mc.mouse.getX() / SCALE_FACTOR); - mouseY = (int) (mc.mouse.getY() / SCALE_FACTOR); + mouseX = (int) (mc.mouseHandler.xpos() / SCALE_FACTOR); + mouseY = (int) (mc.mouseHandler.ypos() / SCALE_FACTOR); // Apply custom scaling to counteract Minecraft's default scaling DrawHelper.customScaledProjection(SCALE_FACTOR); @@ -144,19 +141,19 @@ public void renderContextMenu(DrawContext drawContext, ContextMenu contextMen contextMenu.set(contextMenuX, contextMenuY, 0); //Background - DrawHelper.drawRoundedRectangle(drawContext, + DrawHelper.drawRoundedRectangle(graphics, contextMenuX, contextMenuY, width, height, radius, DARKER_GRAY.getRGB()); - drawBackButton(drawContext, mouseX, mouseY); + drawBackButton(graphics, mouseX, mouseY); //OptionStartX = Tool-Tip width + padding int optionStartX = contextMenu.x + (int) (width * 0.2f) + 10; //Background behind the options - DrawHelper.drawRoundedRectangle(drawContext, + DrawHelper.drawRoundedRectangle(graphics, optionStartX, contextMenuY + 19, width * 0.8f - 14, height - 23, radius, DARK_GRAY.getRGB()); - enableSkinScissor(); + enableSkinScissor(graphics); int yOffset = contextMenu.y + 19 + 3 - scrollHandler.getScrollOffset(); for (Option option : getOptions(contextMenu)) { if (!option.shouldRender()) continue; @@ -166,59 +163,57 @@ public void renderContextMenu(DrawContext drawContext, ContextMenu contextMen } if (option instanceof OptionGroup group) { - this.renderGroup(drawContext, group, optionStartX + 2, yOffset, mouseX, mouseY); + this.renderGroup(graphics, group, optionStartX + 2, yOffset, mouseX, mouseY); } else { - option.render(drawContext, optionStartX + 2, yOffset, mouseX, mouseY); + option.render(graphics, optionStartX + 2, yOffset, mouseX, mouseY); } yOffset += option.getHeight() + 1; } - drawContext.draw(); - RenderSystem.disableScissor(); + DrawHelper.disableScissor(graphics); contextMenu.setWidth(width); contextMenu.setHeight(yOffset - (contextMenu.y + 19 + 3 - scrollHandler.getScrollOffset()) + 4); scrollHandler.updateScrollOffset(getMaxScrollOffset()); - drawScrollbar(drawContext); + drawScrollbar(graphics); - renderToolTipText(drawContext, mouseX, mouseY); + renderToolTipText(graphics, mouseX, mouseY); //Reset our scaling so minecraft runs normally\ DrawHelper.scaledProjection(); } private void updateContextDimensions() { - scaledWidth = (float) mc.getWindow().getFramebufferWidth() / SCALE_FACTOR; - scaledHeight = (float) mc.getWindow().getFramebufferHeight() / SCALE_FACTOR; + scaledWidth = (float) mc.getWindow().getWidth() / SCALE_FACTOR; + scaledHeight = (float) mc.getWindow().getHeight() / SCALE_FACTOR; contextMenuX = (int) (scaledWidth * 0.1f); contextMenuY = (int) (scaledHeight * 0.1f); width = (int) (scaledWidth * 0.8f); height = (int) (scaledHeight * 0.8f); } - public void drawBackButton(DrawContext drawContext, int mouseX, int mouseY) { + public void drawBackButton(GuiGraphics graphics, int mouseX, int mouseY) { String backText = "< Back"; - int textWidth = mc.textRenderer.getWidth(backText); + int textWidth = mc.font.width(backText); boolean isHoveringOver = isMouseOver(mouseX, mouseY, contextMenuX + 2, contextMenuY + 2, textWidth + 8, 14); int color = isHoveringOver ? themeColor.darker().getRGB() : themeColor.getRGB(); - DrawHelper.drawRoundedRectangleWithShadowBadWay(drawContext, + DrawHelper.drawRoundedRectangleWithShadowBadWay(graphics, contextMenuX + 2, contextMenuY + 2, textWidth + 8, 14, radius, color, 125, 2, 2); - drawContext.drawText(mc.textRenderer, backText, contextMenuX + 6, contextMenuY + 5, -1, true); - drawContext.draw(); + graphics.drawString(mc.font, backText, contextMenuX + 6, contextMenuY + 5, -1, true); } - public void renderToolTipText(DrawContext drawContext, int mouseX, int mouseY) { + public void renderToolTipText(GuiGraphics graphics, int mouseX, int mouseY) { int tooltipY = contextMenuY + 19; int toolTipWidth = (int) (width * 0.2f) + 4; int toolTipHeight = (int) (height * 0.16f); if (!TOOLTIP_TEXT.getString().isEmpty()) { - toolTipHeight = Math.max(toolTipHeight, mc.textRenderer.getWrappedLinesHeight(TOOLTIP_TEXT, toolTipWidth)) + 18; + toolTipHeight = Math.max(toolTipHeight, mc.font.wordWrapHeight(TOOLTIP_TEXT, toolTipWidth)) + 18; toolTipHeight = Math.min(height - 23, toolTipHeight); } @@ -226,7 +221,7 @@ public void renderToolTipText(DrawContext drawContext, int mouseX, int mouseY) { // Draw background DrawHelper.drawRoundedRectangle( - drawContext, + graphics, contextMenuX + 2, tooltipY, toolTipWidth, @@ -235,7 +230,7 @@ public void renderToolTipText(DrawContext drawContext, int mouseX, int mouseY) { DARK_GRAY.getRGB() ); DrawHelper.drawHorizontalLine( - drawContext, + graphics, contextMenuX + 2, toolTipWidth, tooltipY + 16, @@ -248,9 +243,9 @@ public void renderToolTipText(DrawContext drawContext, int mouseX, int mouseY) { return; } - //Draw the head text - drawContext.drawText( - mc.textRenderer, + //Draw the head Component + graphics.drawString( + mc.font, TOOLTIP_HEAD, contextMenuX + 4, tooltipY + 4, @@ -258,31 +253,30 @@ public void renderToolTipText(DrawContext drawContext, int mouseX, int mouseY) { true ); - List wrappedText = mc.textRenderer.wrapLines(StringVisitable.styled(TOOLTIP_TEXT.getString(), TOOLTIP_TEXT.getStyle()), toolTipWidth); + List wrappedText = mc.font.split(TOOLTIP_TEXT, toolTipWidth); - DrawHelper.scaleAndPosition(drawContext.getMatrices(), contextMenuX + 4, tooltipY + 19, textScale); + DrawHelper.scaleAndPosition(graphics.pose(), contextMenuX + 4, tooltipY + 19, textScale); - // Draw text + // Draw Component int textY = tooltipY + 19; - for (OrderedText line : wrappedText) { - drawContext.drawText( - mc.textRenderer, + for (FormattedCharSequence line : wrappedText) { + graphics.drawString( + mc.font, line, contextMenuX + 2 + 2, textY, -1, false ); - textY += mc.textRenderer.fontHeight; + textY += mc.font.lineHeight; } - drawContext.draw(); - DrawHelper.stopScaling(drawContext.getMatrices()); + DrawHelper.stopScaling(graphics.pose()); setTooltipText(defaultToolTipHeader, defaultToolTipText); } - public void setTooltipText(Text head_text, Text tooltip_text) { + public void setTooltipText(Component head_text, Component tooltip_text) { TOOLTIP_TEXT = tooltip_text; TOOLTIP_HEAD = head_text; } @@ -305,8 +299,8 @@ public boolean mouseReleased(ContextMenu menu, double mouseX, double mouseY, @Override public boolean mouseClicked(ContextMenu menu, double mouseX, double mouseY, int button) { - mouseX = mc.mouse.getX() / SCALE_FACTOR; - mouseY = mc.mouse.getY() / SCALE_FACTOR; + mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; + mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && isMouseOver(mouseX, mouseY, contextMenuX + width - 5, contextMenuY, 7, height)) { scrollHandler.startDragging(mouseY); @@ -320,7 +314,7 @@ public boolean mouseClicked(ContextMenu menu, double mouseX, double mouseY, i if (option instanceof OptionGroup group) { if (isMouseOver(mouseX, mouseY, optionStartX + 2, yOffset, - mc.textRenderer.getWidth(group.name + " " + (group.isExpanded() ? "-" : "+")) + 6, + mc.font.width(group.name + " " + (group.isExpanded() ? "-" : "+")) + 6, 16)) { group.setExpanded(!group.isExpanded()); break; @@ -330,8 +324,8 @@ public boolean mouseClicked(ContextMenu menu, double mouseX, double mouseY, i yOffset += option.getHeight() + 1; } } - if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && isMouseOver(mouseX, mouseY, contextMenuX + 2, contextMenuY + 2, mc.textRenderer.getWidth("< Back") + 8, 14)) { - mc.getSoundManager().play(PositionedSoundInstance.master( + if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && isMouseOver(mouseX, mouseY, contextMenuX + 2, contextMenuY + 2, mc.font.width("< Back") + 8, 14)) { + mc.getSoundManager().play(SimpleSoundInstance.forUI( SoundEvents.UI_BUTTON_CLICK, 1.0F)); contextMenu.close(); } @@ -340,8 +334,8 @@ public boolean mouseClicked(ContextMenu menu, double mouseX, double mouseY, i @Override public boolean mouseDragged(ContextMenu menu, double mouseX, double mouseY, int button, double deltaX, double deltaY) { - mouseX = mc.mouse.getX() / SCALE_FACTOR; - mouseY = mc.mouse.getY() / SCALE_FACTOR; + mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; + mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && isMouseOver(mouseX, mouseY, contextMenuX + width - 5, contextMenuY, 7, height)) { scrollHandler.updateScrollPosition(mouseY); @@ -357,15 +351,13 @@ public class ModernBooleanRenderer implements SkinRenderer { private long animationStartTime; @Override - public void render(DrawContext drawContext, BooleanOption option, int x, int y, int mouseX, int mouseY) { + public void render(GuiGraphics graphics, BooleanOption option, int x, int y, int mouseX, int mouseY) { int backgroundWidth = (int) (width * 0.8f - 14); option.setHeight(14); option.setPosition(x, y); option.setWidth(backgroundWidth); - MatrixStack matrices = drawContext.getMatrices(); - // Calculate the current progress of the animation int toggleBgX = x + backgroundWidth - 30; // Background @@ -374,7 +366,7 @@ public void render(DrawContext drawContext, BooleanOption option, int x, int y, Color hoveredColor = isMouseOver(mouseX, mouseY, toggleBgX, y + 2, 14, 7) ? backgroundColor.darker() : backgroundColor; DrawHelper.drawRoundedRectangleWithShadowBadWay( - drawContext, + graphics, toggleBgX, y + 2, 14, 7, 3, hoveredColor.getRGB(), @@ -387,11 +379,11 @@ public void render(DrawContext drawContext, BooleanOption option, int x, int y, EasingType easingType = active ? EasingType.EASE_IN_CUBIC : EasingType.EASE_OUT_QUAD; float toggleX = MathAnimations.lerp(startX, endX, animationStartTime, 200f, easingType); - DrawHelper.drawFilledCircle(drawContext, toggleX, y + 2 + 3.3f, 2.8f, Color.WHITE.getRGB()); + DrawHelper.drawFilledCircle(graphics, toggleX, y + 2 + 3.3f, 2.8f, Color.WHITE.getRGB()); // Draw option name - drawContext.drawText( - mc.textRenderer, + graphics.drawString( + mc.font, option.name, x + 2, y + 4, @@ -402,8 +394,8 @@ public void render(DrawContext drawContext, BooleanOption option, int x, int y, @Override public boolean mouseClicked(BooleanOption option, double mouseX, double mouseY, int button) { - mouseX = mc.mouse.getX() / SCALE_FACTOR; - mouseY = mc.mouse.getY() / SCALE_FACTOR; + mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; + mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; int backgroundWidth = (int) (width * 0.8f - 14); int toggleBgX = option.getX() + backgroundWidth - 30; @@ -430,21 +422,21 @@ public void update(ColorOption option) { if (!display) { scale -= ANIMATION_SPEED; } - scale = MathHelper.clamp(scale, 0, 1.0f); + scale = Math.clamp(scale, 0, 1.0f); if (scale <= 0) { option.getColorGradient().close(); } } @Override - public void render(DrawContext drawContext, ColorOption option, int x, int y, int mouseX, int mouseY) { + public void render(GuiGraphics graphics, ColorOption option, int x, int y, int mouseX, int mouseY) { update(option); int backgroundWidth = (int) (width * 0.8f - 14); // Draw option name - drawContext.drawText( - mc.textRenderer, + graphics.drawString( + mc.font, option.name, x + 2, y + 5, @@ -461,7 +453,7 @@ public void render(DrawContext drawContext, ColorOption option, int x, int y, in //The shape behind the preview Color behindColor = isMouseOver(mouseX, mouseY, x + backgroundWidth - width - 17, y + 1, width + 2, 14) ? getThemeColor().darker().darker() : getThemeColor(); - DrawHelper.drawRoundedRectangleWithShadowBadWay(drawContext, + DrawHelper.drawRoundedRectangleWithShadowBadWay(graphics, x + backgroundWidth - width - 17, y + 1, width + 2, @@ -473,8 +465,8 @@ public void render(DrawContext drawContext, ColorOption option, int x, int y, in 1); //The letter above the shape behind the preview - drawContext.drawText( - mc.textRenderer, + graphics.drawString( + mc.font, option.getColorGradient().shouldDisplay() ? "^" : "v", x + backgroundWidth - 21, y + 4, @@ -483,7 +475,7 @@ public void render(DrawContext drawContext, ColorOption option, int x, int y, in ); //Preview - DrawHelper.drawRoundedRectangleWithShadowBadWay(drawContext, + DrawHelper.drawRoundedRectangleWithShadowBadWay(graphics, x + backgroundWidth - width - 15, y + 2, width - 8, @@ -499,22 +491,22 @@ public void render(DrawContext drawContext, ColorOption option, int x, int y, in option.setWidth(width); if (option.getColorGradient().getColorPickerButton().isPicking()) { - RenderSystem.disableScissor(); //Disable scissor so the color picker preview works + DrawHelper.disableScissor(graphics); //Disable scissor so the color picker preview works } - DrawHelper.scaleAndPosition(drawContext.getMatrices(), x + backgroundWidth / 2.0f, y, scale); - option.getColorGradient().render(drawContext, x + backgroundWidth / 2 - 50, y + 6, mouseX, mouseY); - DrawHelper.stopScaling(drawContext.getMatrices()); + DrawHelper.scaleAndPosition(graphics.pose(), x + backgroundWidth / 2.0f, y, scale); + option.getColorGradient().render(graphics, x + backgroundWidth / 2 - 50, y + 6, mouseX, mouseY); + DrawHelper.stopScaling(graphics.pose()); if (option.getColorGradient().getColorPickerButton().isPicking()) { - enableSkinScissor(); // re-enable the scissor + enableSkinScissor(graphics); // re-enable the scissor } } @Override public boolean mouseClicked(ColorOption option, double mouseX, double mouseY, int button) { - mouseX = mc.mouse.getX() / SCALE_FACTOR; - mouseY = mc.mouse.getY() / SCALE_FACTOR; + mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; + mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && isMouseOver(mouseX, mouseY, option.getX() + (int) (width * 0.8f - 14) - 37, option.getY(), 22, 16)) { option.isVisible = !option.isVisible; if (option.isVisible) { @@ -531,16 +523,16 @@ public boolean mouseClicked(ColorOption option, double mouseX, double mouseY, in @Override public boolean mouseDragged(ColorOption option, double mouseX, double mouseY, int button, double deltaX, double deltaY) { - mouseX = mc.mouse.getX() / SCALE_FACTOR; - mouseY = mc.mouse.getY() / SCALE_FACTOR; + mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; + mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; option.getColorGradient().mouseDragged(mouseX, mouseY, button); return SkinRenderer.super.mouseDragged(option, mouseX, mouseY, button, deltaX, deltaY); } @Override public boolean mouseReleased(ColorOption option, double mouseX, double mouseY, int button) { - mouseX = mc.mouse.getX() / SCALE_FACTOR; - mouseY = mc.mouse.getY() / SCALE_FACTOR; + mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; + mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; option.getColorGradient().mouseReleased(mouseX, mouseY, button); return SkinRenderer.super.mouseReleased(option, mouseX, mouseY, button); @@ -552,10 +544,10 @@ public class ModernDoubleRenderer implements SkinRenderer { private static final float ANIMATION_SPEED = 0.1f; @Override - public void render(DrawContext drawContext, DoubleOption option, int x, int y, int mouseX, int mouseY) { + public void render(GuiGraphics graphics, DoubleOption option, int x, int y, int mouseX, int mouseY) { // Draw option name - drawContext.drawText( - mc.textRenderer, + graphics.drawString( + mc.font, option.name, x + 2, y, @@ -573,11 +565,11 @@ public void render(DrawContext drawContext, DoubleOption option, int x, int y, i option.setHeight(14); // Smoothly interpolate to the new value - displayValue = MathHelper.lerp(ANIMATION_SPEED, displayValue, option.get()); + displayValue = Mth.lerp(ANIMATION_SPEED, displayValue, option.get()); // Background DrawHelper.drawRoundedRectangle( - drawContext, + graphics, sliderX, y, sliderBackgroundWidth, sliderBackgroundHeight, 1, DARKER_GRAY.getRGB() ); @@ -585,32 +577,32 @@ public void render(DrawContext drawContext, DoubleOption option, int x, int y, i int activeFillWidth = (int) ((displayValue - option.minValue) / (option.maxValue - option.minValue) * option.getWidth()); Color fillColor = isMouseOver(mouseX, mouseY, sliderX, y, sliderBackgroundWidth, sliderBackgroundHeight + 4) ? getThemeColor().darker().darker() : getThemeColor(); DrawHelper.drawRoundedRectangle( - drawContext, + graphics, sliderX, y, activeFillWidth, sliderBackgroundHeight, 2, fillColor.getRGB() ); // Draw slider handle float sliderHandleX = sliderX + activeFillWidth - 5; - DrawHelper.drawFilledCircle(drawContext, sliderHandleX + 5, y + 1, 2, Color.WHITE.getRGB()); - - // Draw value text - String text = String.format("%.2f", displayValue); - DrawHelper.scaleAndPosition(drawContext.getMatrices(), sliderX + 120 - mc.textRenderer.getWidth(text), y + 7, 0.6f); - drawContext.drawText( - mc.textRenderer, - text, - sliderX + sliderBackgroundWidth + 10 - mc.textRenderer.getWidth(text), + DrawHelper.drawFilledCircle(graphics, sliderHandleX + 5, y + 1, 2, Color.WHITE.getRGB()); + + // Draw value Component + String Component = String.format("%.2f", displayValue); + DrawHelper.scaleAndPosition(graphics.pose(), sliderX + 120 - mc.font.width(Component), y + 7, 0.6f); + graphics.drawString( + mc.font, + Component, + sliderX + sliderBackgroundWidth + 10 - mc.font.width(Component), y + 2, -1, true ); - drawContext.getMatrices().pop(); + graphics.pose().popMatrix(); } @Override public boolean mouseClicked(DoubleOption option, double mouseX, double mouseY, int button) { - mouseX = mc.mouse.getX() / SCALE_FACTOR; - mouseY = mc.mouse.getY() / SCALE_FACTOR; + mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; + mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && isMouseOver(mouseX, mouseY, option.getX() + (int) (width * 0.8f - 14) - 125, option.getY() - 1, option.getWidth() + 2, option.getHeight() + 1)) { option.setDragging(true); return true; @@ -621,7 +613,7 @@ public boolean mouseClicked(DoubleOption option, double mouseX, double mouseY, i @Override public boolean mouseDragged(DoubleOption option, double mouseX, double mouseY, int button, double deltaX, double deltaY) { if (option.isDragging()) { - mouseX = mc.mouse.getX() / SCALE_FACTOR; + mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; int backgroundWidth = (int) (width * 0.8f - 14); int sliderBackgroundWidth = 120; int sliderX = option.getX() + backgroundWidth - sliderBackgroundWidth - 10; @@ -643,66 +635,66 @@ public boolean mouseReleased(DoubleOption option, double mouseX, double mouseY, public class ModernEnumRenderer> implements SkinRenderer> { @Override - public void render(DrawContext drawContext, EnumOption option, int x, int y, int mouseX, int mouseY) { + public void render(GuiGraphics graphics, EnumOption option, int x, int y, int mouseX, int mouseY) { // Set dimensions for the main label and dropdown area - option.setHeight(mc.textRenderer.fontHeight + 2); + option.setHeight(mc.font.lineHeight + 2); // Draw main option name and selected option - Text mainLabel = option.name.copy().append(": "); + Component mainLabel = option.name.copy().append(": "); String selectedOption = option.get().toString(); - drawContext.drawText(mc.textRenderer, mainLabel, x + 4, y + 2, -1, false); - Color fillColor = isMouseOver(mouseX, mouseY, x + 4 + mc.textRenderer.getWidth(mainLabel), y, mc.textRenderer.getWidth(selectedOption) + 5, mc.textRenderer.fontHeight + 2) ? getThemeColor().darker().darker() : getThemeColor(); + graphics.drawString(mc.font, mainLabel, x + 4, y + 2, -1, false); + Color fillColor = isMouseOver(mouseX, mouseY, x + 4 + mc.font.width(mainLabel), y, mc.font.width(selectedOption) + 5, mc.font.lineHeight + 2) ? getThemeColor().darker().darker() : getThemeColor(); DrawHelper.drawRoundedRectangle( - drawContext, - x + 4 + mc.textRenderer.getWidth(mainLabel), y, mc.textRenderer.getWidth(selectedOption) + 5, mc.textRenderer.fontHeight + 2, 2, + graphics, + x + 4 + mc.font.width(mainLabel), y, mc.font.width(selectedOption) + 5, mc.font.lineHeight + 2, 2, fillColor.getRGB() ); // "<" and ">" buttons int contextMenuWidth = (int) (width * 0.8f - 14); int leftX = x + contextMenuWidth - 30; - boolean hoveredOverLeft = isMouseOver(mouseX, mouseY, leftX, y, mc.textRenderer.getWidth("<") + 5, mc.textRenderer.fontHeight); - boolean hoveredOverRight = isMouseOver(mouseX, mouseY, leftX + mc.textRenderer.getWidth("<") + 6, y, mc.textRenderer.getWidth(">") + 5, mc.textRenderer.fontHeight); + boolean hoveredOverLeft = isMouseOver(mouseX, mouseY, leftX, y, mc.font.width("<") + 5, mc.font.lineHeight); + boolean hoveredOverRight = isMouseOver(mouseX, mouseY, leftX + mc.font.width("<") + 6, y, mc.font.width(">") + 5, mc.font.lineHeight); // Shadow DrawHelper.drawRoundedRectangle( - drawContext, + graphics, leftX + 1, y + 3, - (mc.textRenderer.getWidth("<") * 2) + 10, mc.textRenderer.fontHeight, 2, + (mc.font.width("<") * 2) + 10, mc.font.lineHeight, 2, ColorHelper.changeAlpha(Color.BLACK, 128).getRGB() ); DrawHelper.drawRoundedRectangle( - drawContext, + graphics, leftX, y + 2, true, false, true, false, - mc.textRenderer.getWidth("<") + 5, mc.textRenderer.fontHeight, 2, + mc.font.width("<") + 5, mc.font.lineHeight, 2, hoveredOverLeft ? getThemeColor().darker().darker().getRGB() : getThemeColor().getRGB() ); DrawHelper.drawRoundedRectangle( - drawContext, - leftX + mc.textRenderer.getWidth("<") + 6, y + 2, + graphics, + leftX + mc.font.width("<") + 6, y + 2, false, true, false, true, - mc.textRenderer.getWidth(">") + 5, mc.textRenderer.fontHeight, 2, + mc.font.width(">") + 5, mc.font.lineHeight, 2, hoveredOverRight ? getThemeColor().darker().darker().getRGB() : getThemeColor().getRGB() ); DrawHelper.drawVerticalLine( - drawContext, - leftX + mc.textRenderer.getWidth("<") + 5, + graphics, + leftX + mc.font.width("<") + 5, y + 2, - mc.textRenderer.fontHeight, + mc.font.lineHeight, 0.7f, Color.WHITE.getRGB() ); - drawContext.drawText(mc.textRenderer, "<", leftX + mc.textRenderer.getWidth("<") / 2 + 1, y + 3, -1, false); - drawContext.drawText(mc.textRenderer, ">", leftX + mc.textRenderer.getWidth("<") + 7 + mc.textRenderer.getWidth(">") / 2, y + 3, -1, false); + graphics.drawString(mc.font, "<", leftX + mc.font.width("<") / 2 + 1, y + 3, -1, false); + graphics.drawString(mc.font, ">", leftX + mc.font.width("<") + 7 + mc.font.width(">") / 2, y + 3, -1, false); - drawContext.drawText(mc.textRenderer, selectedOption, x + 6 + mc.textRenderer.getWidth(mainLabel), y + 2, Color.LIGHT_GRAY.getRGB(), false); + graphics.drawString(mc.font, selectedOption, x + 6 + mc.font.width(mainLabel), y + 2, Color.LIGHT_GRAY.getRGB(), false); } @Override public boolean mouseClicked(EnumOption option, double mouseX, double mouseY, int button) { if (option.getValues().length == 0) return false; - mouseX = mc.mouse.getX() / SCALE_FACTOR; - mouseY = mc.mouse.getY() / SCALE_FACTOR; + mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; + mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; int x = option.getX(); int y = option.getY(); @@ -713,9 +705,9 @@ public boolean mouseClicked(EnumOption option, double mouseX, double mouseY, // "<" and ">" buttons int contextMenuWidth = (int) (width * 0.8f - 14); int leftX = x + contextMenuWidth - 30; - boolean hoveredOverLeft = isMouseOver(mouseX, mouseY, leftX, y, mc.textRenderer.getWidth("<") + 5, mc.textRenderer.fontHeight); - boolean hoveredOverRight = isMouseOver(mouseX, mouseY, leftX + mc.textRenderer.getWidth("<") + 6, y, mc.textRenderer.getWidth(">") + 5, mc.textRenderer.fontHeight); - boolean hoveredOverMainLabel = isMouseOver(mouseX, mouseY, x + 4 + mc.textRenderer.getWidth(mainLabel), y, mc.textRenderer.getWidth(selectedOption) + 5, mc.textRenderer.fontHeight + 2); + boolean hoveredOverLeft = isMouseOver(mouseX, mouseY, leftX, y, mc.font.width("<") + 5, mc.font.lineHeight); + boolean hoveredOverRight = isMouseOver(mouseX, mouseY, leftX + mc.font.width("<") + 6, y, mc.font.width(">") + 5, mc.font.lineHeight); + boolean hoveredOverMainLabel = isMouseOver(mouseX, mouseY, x + 4 + mc.font.width(mainLabel), y, mc.font.width(selectedOption) + 5, mc.font.lineHeight + 2); if (hoveredOverLeft || hoveredOverRight || hoveredOverMainLabel) { E[] values = option.getValues(); @@ -741,60 +733,60 @@ public boolean mouseClicked(EnumOption option, double mouseX, double mouseY, public class ModernListRenderer implements SkinRenderer> { @Override - public void render(DrawContext drawContext, ListOption option, int x, int y, int mouseX, int mouseY) { + public void render(GuiGraphics graphics, ListOption option, int x, int y, int mouseX, int mouseY) { // Set dimensions for the main label and dropdown area - option.setHeight(mc.textRenderer.fontHeight + 2); + option.setHeight(mc.font.lineHeight + 2); // Draw main option name and selected option - Text mainLabel = option.name.copy().append(": "); + Component mainLabel = option.name.copy().append(": "); String selectedOption = option.get().toString(); - drawContext.drawText(mc.textRenderer, mainLabel, x + 4, y + 2, -1, false); - Color fillColor = isMouseOver(mouseX, mouseY, x + 4 + mc.textRenderer.getWidth(mainLabel), y, mc.textRenderer.getWidth(selectedOption) + 5, mc.textRenderer.fontHeight + 2) ? getThemeColor().darker().darker() : getThemeColor(); + graphics.drawString(mc.font, mainLabel, x + 4, y + 2, -1, false); + Color fillColor = isMouseOver(mouseX, mouseY, x + 4 + mc.font.width(mainLabel), y, mc.font.width(selectedOption) + 5, mc.font.lineHeight + 2) ? getThemeColor().darker().darker() : getThemeColor(); DrawHelper.drawRoundedRectangle( - drawContext, - x + 4 + mc.textRenderer.getWidth(mainLabel), y, mc.textRenderer.getWidth(selectedOption) + 5, mc.textRenderer.fontHeight + 2, 2, + graphics, + x + 4 + mc.font.width(mainLabel), y, mc.font.width(selectedOption) + 5, mc.font.lineHeight + 2, 2, fillColor.getRGB() ); // "<" and ">" buttons int contextMenuWidth = (int) (width * 0.8f - 14); int leftX = x + contextMenuWidth - 30; - boolean hoveredOverLeft = isMouseOver(mouseX, mouseY, leftX, y, mc.textRenderer.getWidth("<") + 5, mc.textRenderer.fontHeight); - boolean hoveredOverRight = isMouseOver(mouseX, mouseY, leftX + mc.textRenderer.getWidth("<") + 6, y, mc.textRenderer.getWidth(">") + 5, mc.textRenderer.fontHeight); + boolean hoveredOverLeft = isMouseOver(mouseX, mouseY, leftX, y, mc.font.width("<") + 5, mc.font.lineHeight); + boolean hoveredOverRight = isMouseOver(mouseX, mouseY, leftX + mc.font.width("<") + 6, y, mc.font.width(">") + 5, mc.font.lineHeight); // Shadow DrawHelper.drawRoundedRectangle( - drawContext, + graphics, leftX + 1, y + 3, - (mc.textRenderer.getWidth("<") * 2) + 10, mc.textRenderer.fontHeight, 2, + (mc.font.width("<") * 2) + 10, mc.font.lineHeight, 2, ColorHelper.changeAlpha(Color.BLACK, 128).getRGB() ); DrawHelper.drawRoundedRectangle( - drawContext, + graphics, leftX, y + 2, true, false, true, false, - mc.textRenderer.getWidth("<") + 5, mc.textRenderer.fontHeight, 2, + mc.font.width("<") + 5, mc.font.lineHeight, 2, hoveredOverLeft ? getThemeColor().darker().darker().getRGB() : getThemeColor().getRGB() ); DrawHelper.drawRoundedRectangle( - drawContext, - leftX + mc.textRenderer.getWidth("<") + 6, y + 2, + graphics, + leftX + mc.font.width("<") + 6, y + 2, false, true, false, true, - mc.textRenderer.getWidth(">") + 5, mc.textRenderer.fontHeight, 2, + mc.font.width(">") + 5, mc.font.lineHeight, 2, hoveredOverRight ? getThemeColor().darker().darker().getRGB() : getThemeColor().getRGB() ); DrawHelper.drawVerticalLine( - drawContext, - leftX + mc.textRenderer.getWidth("<") + 5, + graphics, + leftX + mc.font.width("<") + 5, y + 2, - mc.textRenderer.fontHeight, + mc.font.lineHeight, 0.7f, Color.WHITE.getRGB() ); - drawContext.drawText(mc.textRenderer, "<", leftX + mc.textRenderer.getWidth("<") / 2 + 1, y + 3, -1, false); - drawContext.drawText(mc.textRenderer, ">", leftX + mc.textRenderer.getWidth("<") + 7 + mc.textRenderer.getWidth(">") / 2, y + 3, -1, false); + graphics.drawString(mc.font, "<", leftX + mc.font.width("<") / 2 + 1, y + 3, -1, false); + graphics.drawString(mc.font, ">", leftX + mc.font.width("<") + 7 + mc.font.width(">") / 2, y + 3, -1, false); - drawContext.drawText(mc.textRenderer, selectedOption, x + 6 + mc.textRenderer.getWidth(mainLabel), y + 2, Color.LIGHT_GRAY.getRGB(), false); + graphics.drawString(mc.font, selectedOption, x + 6 + mc.font.width(mainLabel), y + 2, Color.LIGHT_GRAY.getRGB(), false); } @Override @@ -806,7 +798,7 @@ public boolean mouseClicked(ListOption option, double mouseX, double mouseY, int x = option.getX(); int y = option.getY(); - Text mainLabel = option.name.copy().append(": "); + Component mainLabel = option.name.copy().append(": "); String selectedOption = option.get().toString(); // Calculate positions @@ -814,9 +806,9 @@ public boolean mouseClicked(ListOption option, double mouseX, double mouseY, int leftX = x + contextMenuWidth - 30; // Check hover states - boolean hoveredOverLeft = isMouseOver(mouseX, mouseY, leftX, y, mc.textRenderer.getWidth("<") + 5, mc.textRenderer.fontHeight); - boolean hoveredOverRight = isMouseOver(mouseX, mouseY, leftX + mc.textRenderer.getWidth("<") + 6, y, mc.textRenderer.getWidth(">") + 5, mc.textRenderer.fontHeight); - boolean hoveredOverMainLabel = isMouseOver(mouseX, mouseY, x + 4 + mc.textRenderer.getWidth(mainLabel), y, mc.textRenderer.getWidth(selectedOption) + 5, mc.textRenderer.fontHeight + 2); + boolean hoveredOverLeft = isMouseOver(mouseX, mouseY, leftX, y, mc.font.width("<") + 5, mc.font.lineHeight); + boolean hoveredOverRight = isMouseOver(mouseX, mouseY, leftX + mc.font.width("<") + 6, y, mc.font.width(">") + 5, mc.font.lineHeight); + boolean hoveredOverMainLabel = isMouseOver(mouseX, mouseY, x + 4 + mc.font.width(mainLabel), y, mc.font.width(selectedOption) + 5, mc.font.lineHeight + 2); // Check if any area is clicked if (hoveredOverLeft || hoveredOverRight || hoveredOverMainLabel) { @@ -843,28 +835,28 @@ public boolean mouseClicked(ListOption option, double mouseX, double mouseY, public class ModernSubMenuRenderer implements SkinRenderer { @Override - public void render(DrawContext drawContext, SubMenuOption option, int x, int y, int mouseX, int mouseY) { - mouseX = (int) (mc.mouse.getX() / SCALE_FACTOR); - mouseY = (int) (mc.mouse.getY() / SCALE_FACTOR); + public void render(GuiGraphics graphics, SubMenuOption option, int x, int y, int mouseX, int mouseY) { + mouseX = (int) (mc.mouseHandler.xpos() / SCALE_FACTOR); + mouseY = (int) (mc.mouseHandler.ypos() / SCALE_FACTOR); - String text = "Open"; + String Component = "Open"; int contextMenuWidth = (int) (width * 0.8f - 14); int xPos = x + 4 + contextMenuWidth - 40; option.setPosition(xPos - 1, y); - option.setWidth(mc.textRenderer.getWidth(text) + 5); + option.setWidth(mc.font.width(Component) + 5); option.setHeight(16); - drawContext.drawText(mc.textRenderer, option.name, x + 4, y + 4, -1, false); + graphics.drawString(mc.font, option.name, x + 4, y + 4, -1, false); - drawContext.drawText(mc.textRenderer, text, xPos + 2, y + 4, Color.WHITE.getRGB(), true); + graphics.drawString(mc.font, Component, xPos + 2, y + 4, Color.WHITE.getRGB(), true); - Color fillColor = isMouseOver(mouseX, mouseY, xPos + 2, y + 4, mc.textRenderer.getWidth(text) + 5, mc.textRenderer.fontHeight + 4) ? getThemeColor().darker().darker() : getThemeColor(); + Color fillColor = isMouseOver(mouseX, mouseY, xPos + 2, y + 4, mc.font.width(Component) + 5, mc.font.lineHeight + 4) ? getThemeColor().darker().darker() : getThemeColor(); DrawHelper.drawRoundedRectangleWithShadowBadWay( - drawContext, + graphics, xPos - 1, y + 1, - mc.textRenderer.getWidth(text) + 5, mc.textRenderer.fontHeight + 4, + mc.font.width(Component) + 5, mc.font.lineHeight + 4, 2, fillColor.getRGB(), 180, @@ -872,42 +864,42 @@ public void render(DrawContext drawContext, SubMenuOption option, int x, int y, 1 ); DrawHelper.drawOutlineRoundedBox( - drawContext, + graphics, xPos - 1, y + 1, - mc.textRenderer.getWidth(text) + 5, mc.textRenderer.fontHeight + 4, + mc.font.width(Component) + 5, mc.font.lineHeight + 4, 2, 0.7f, Color.WHITE.getRGB() ); - option.getSubMenu().render(drawContext, x + option.getParentMenu().getWidth(), y, mouseX, mouseY); + option.getSubMenu().render(graphics, x + option.getParentMenu().getWidth(), y, mouseX, mouseY); } @Override public void mouseScrolled(SubMenuOption option, double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { - mouseX = mc.mouse.getX() / SCALE_FACTOR; - mouseY = mc.mouse.getY() / SCALE_FACTOR; + mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; + mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; SkinRenderer.super.mouseScrolled(option, mouseX, mouseY, horizontalAmount, verticalAmount); } @Override public boolean mouseDragged(SubMenuOption option, double mouseX, double mouseY, int button, double deltaX, double deltaY) { - mouseX = mc.mouse.getX() / SCALE_FACTOR; - mouseY = mc.mouse.getY() / SCALE_FACTOR; + mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; + mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; return SkinRenderer.super.mouseDragged(option, mouseX, mouseY, button, deltaX, deltaY); } @Override public boolean mouseReleased(SubMenuOption option, double mouseX, double mouseY, int button) { - mouseX = mc.mouse.getX() / SCALE_FACTOR; - mouseY = mc.mouse.getY() / SCALE_FACTOR; + mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; + mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; return SkinRenderer.super.mouseReleased(option, mouseX, mouseY, button); } @Override public boolean mouseClicked(SubMenuOption option, double mouseX, double mouseY, int button) { - mouseX = mc.mouse.getX() / SCALE_FACTOR; - mouseY = mc.mouse.getY() / SCALE_FACTOR; + mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; + mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; return SkinRenderer.super.mouseClicked(option, mouseX, mouseY, button); } } @@ -917,25 +909,25 @@ public class ModernRunnableRenderer implements SkinRenderer { Color DARK_GREEN = new Color(24, 132, 0, 226); @Override - public void render(DrawContext drawContext, RunnableOption option, int x, int y, int mouseX, int mouseY) { - String text = "Run â–¶"; + public void render(GuiGraphics graphics, RunnableOption option, int x, int y, int mouseX, int mouseY) { + String Component = "Run â–¶"; int contextMenuWidth = (int) (width * 0.8f - 14); int xPos = x + 4 + contextMenuWidth - 45; option.setPosition(xPos - 1, y); - option.setWidth(mc.textRenderer.getWidth(text) + 5); - option.setHeight(mc.textRenderer.fontHeight + 6); + option.setWidth(mc.font.width(Component) + 5); + option.setHeight(mc.font.lineHeight + 6); - drawContext.drawText(mc.textRenderer, option.name, x + 4, y + 4, -1, false); + graphics.drawString(mc.font, option.name, x + 4, y + 4, -1, false); - drawContext.drawText(mc.textRenderer, text, xPos + 2, y + 4, option.value ? DARK_GREEN.getRGB() : DARK_RED.getRGB(), true); + graphics.drawString(mc.font, Component, xPos + 2, y + 4, option.value ? DARK_GREEN.getRGB() : DARK_RED.getRGB(), true); - Color fillColor = isMouseOver(mouseX, mouseY, xPos + 2, y + 4, mc.textRenderer.getWidth(text) + 5, mc.textRenderer.fontHeight + 4) ? getThemeColor().darker().darker() : getThemeColor(); + Color fillColor = isMouseOver(mouseX, mouseY, xPos + 2, y + 4, mc.font.width(Component) + 5, mc.font.lineHeight + 4) ? getThemeColor().darker().darker() : getThemeColor(); DrawHelper.drawRoundedRectangleWithShadowBadWay( - drawContext, + graphics, xPos - 1, y + 1, - mc.textRenderer.getWidth(text) + 5, mc.textRenderer.fontHeight + 4, + mc.font.width(Component) + 5, mc.font.lineHeight + 4, 2, fillColor.getRGB(), 180, @@ -946,8 +938,8 @@ public void render(DrawContext drawContext, RunnableOption option, int x, int y, @Override public boolean mouseClicked(RunnableOption option, double mouseX, double mouseY, int button) { - mouseX = mc.mouse.getX() / SCALE_FACTOR; - mouseY = mc.mouse.getY() / SCALE_FACTOR; + mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; + mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; return SkinRenderer.super.mouseClicked(option, mouseX, mouseY, button); } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/Skin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/Skin.java index 5c8e86b..03f8a60 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/Skin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/Skin.java @@ -5,8 +5,8 @@ import com.tanishisherewith.dynamichud.utils.contextmenu.options.OptionGroup; import com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.interfaces.GroupableSkin; import com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.interfaces.SkinRenderer; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; import java.util.ArrayList; import java.util.HashMap; @@ -15,7 +15,7 @@ import java.util.function.Supplier; public abstract class Skin { - protected static final MinecraftClient mc = MinecraftClient.getInstance(); + protected static final Minecraft mc = Minecraft.getInstance(); protected ContextMenu contextMenu; protected Map>, Supplier>>> renderers = new HashMap<>(); private boolean createNewScreen; @@ -82,7 +82,7 @@ public void setRenderers(Map>, Supplier contextMenu, int mouseX, int mouseY); + public abstract void renderContextMenu(GuiGraphics graphics, ContextMenu contextMenu, int mouseX, int mouseY); public boolean mouseClicked(ContextMenu menu, double mouseX, double mouseY, int button) { return false; @@ -113,7 +113,7 @@ public void setCreateNewScreen(boolean createNewScreen) { this.createNewScreen = createNewScreen; } - protected boolean isMouseOver(double mouseX, double mouseY, double x, double y, double width, double height) { + public static boolean isMouseOver(double mouseX, double mouseY, double x, double y, double width, double height) { return mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height; } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/interfaces/GroupableSkin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/interfaces/GroupableSkin.java index c93dd52..6319f77 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/interfaces/GroupableSkin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/interfaces/GroupableSkin.java @@ -2,11 +2,11 @@ import com.tanishisherewith.dynamichud.utils.contextmenu.layout.LayoutContext; import com.tanishisherewith.dynamichud.utils.contextmenu.options.OptionGroup; -import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.GuiGraphics; public interface GroupableSkin { LayoutContext.Offset getGroupIndent(); - void renderGroup(DrawContext drawContext, OptionGroup group, int groupX, int groupY, int mouseX, int mouseY); + void renderGroup(GuiGraphics graphics, OptionGroup group, int groupX, int groupY, int mouseX, int mouseY); } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/interfaces/SkinRenderer.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/interfaces/SkinRenderer.java index 89fa741..671c9b1 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/interfaces/SkinRenderer.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/interfaces/SkinRenderer.java @@ -1,10 +1,10 @@ package com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.interfaces; import com.tanishisherewith.dynamichud.utils.contextmenu.options.Option; -import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.GuiGraphics; public interface SkinRenderer> { - void render(DrawContext drawContext, T option, int x, int y, int mouseX, int mouseY); + void render(GuiGraphics graphics, T option, int x, int y, int mouseX, int mouseY); default boolean mouseClicked(T option, double mouseX, double mouseY, int button) { return option.mouseClicked(mouseX, mouseY, button); diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/handlers/ScrollHandler.java b/src/main/java/com/tanishisherewith/dynamichud/utils/handlers/ScrollHandler.java index 2bd9d98..4d10ae4 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/handlers/ScrollHandler.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/handlers/ScrollHandler.java @@ -1,6 +1,5 @@ package com.tanishisherewith.dynamichud.utils.handlers; -import net.minecraft.util.math.MathHelper; public class ScrollHandler { protected int scrollOffset; @@ -23,7 +22,7 @@ public void updateScrollOffset(int maxYOffset) { this.maxScrollOffset = maxYOffset; applyMomentum(); - scrollOffset = MathHelper.clamp(scrollOffset, 0, maxScrollOffset); + scrollOffset = Math.clamp(scrollOffset, 0, maxScrollOffset); } public void mouseScrolled(double deltaY) { @@ -41,7 +40,7 @@ public void stopDragging() { } public void addOffset(int offset) { - this.scrollOffset = MathHelper.clamp(scrollOffset + offset, 0, maxScrollOffset); + this.scrollOffset = Math.clamp(scrollOffset + offset, 0, maxScrollOffset); } public void updateScrollPosition(double mouseY) { @@ -50,7 +49,7 @@ public void updateScrollPosition(double mouseY) { double deltaY = lastMouseY - mouseY; // Update the scroll offset based on the mouse movement - scrollOffset = MathHelper.clamp(scrollOffset - (int) (deltaY * SCROLL_SPEED), 0, maxScrollOffset); + scrollOffset = Math.clamp(scrollOffset - (int) (deltaY * SCROLL_SPEED), 0, maxScrollOffset); // Update the last mouse position lastMouseY = mouseY; @@ -62,7 +61,7 @@ private void applyMomentum() { double timeDelta = (currentTime - lastScrollTime) / 1000.0; scrollOffset += (int) (scrollVelocity * timeDelta); scrollVelocity *= 0.9; // Decay factor - scrollOffset = MathHelper.clamp(scrollOffset, 0, maxScrollOffset); + scrollOffset = Math.clamp(scrollOffset, 0, maxScrollOffset); } public int getScrollOffset() { diff --git a/src/main/java/com/tanishisherewith/dynamichud/widget/DynamicValueWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widget/DynamicValueWidget.java index 1e8630f..18cc7b9 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widget/DynamicValueWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widget/DynamicValueWidget.java @@ -4,7 +4,7 @@ import com.tanishisherewith.dynamichud.utils.Util; import com.tanishisherewith.dynamichud.widgets.GraphWidget; import com.tanishisherewith.dynamichud.widgets.TextWidget; -import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.CompoundTag; import java.util.function.Supplier; @@ -36,14 +36,14 @@ protected void initializeValueSupplier() { } @Override - public void writeToTag(NbtCompound tag) { + public void writeToTag(CompoundTag tag) { super.writeToTag(tag); tag.putString("RegistryID", registryID); tag.putString("RegistryKey", registryKey); } @Override - public void readFromTag(NbtCompound tag) { + public void readFromTag(CompoundTag tag) { super.readFromTag(tag); registryID = tag.getString("RegistryID").orElse(DynamicValueRegistry.GLOBAL_ID); registryKey = tag.getString("RegistryKey").orElse("null"); diff --git a/src/main/java/com/tanishisherewith/dynamichud/widget/UserManageable.java b/src/main/java/com/tanishisherewith/dynamichud/widget/UserManageable.java deleted file mode 100644 index b719d15..0000000 --- a/src/main/java/com/tanishisherewith/dynamichud/widget/UserManageable.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.tanishisherewith.dynamichud.widget; - -//unused -public interface UserManageable { - // Marker interface that a widget is add-able and removable. -} \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/widget/Widget.java b/src/main/java/com/tanishisherewith/dynamichud/widget/Widget.java index a385042..74d4c56 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widget/Widget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widget/Widget.java @@ -4,15 +4,14 @@ import com.tanishisherewith.dynamichud.helpers.DrawHelper; import com.tanishisherewith.dynamichud.internal.UID; import com.tanishisherewith.dynamichud.utils.Input; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.text.Text; -import net.minecraft.util.math.MathHelper; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; import org.lwjgl.glfw.GLFW; public abstract class Widget implements Input { - public static MinecraftClient mc = MinecraftClient.getInstance(); + public static Minecraft mc = Minecraft.getInstance(); public WidgetData DATA; /** * This is the UID of the widget used to identify during loading and saving. @@ -39,7 +38,7 @@ public abstract class Widget implements Input { */ public String modId = "unknown"; - public Text tooltipText; + public Component tooltipText; // Boolean to know if the widget is currently being displayed in an instance of AbstractMoveableScreen protected boolean isInEditor = false; @@ -66,7 +65,7 @@ public Widget(WidgetData DATA, String modId, Anchor anchor) { widgetBox = new WidgetBox(0, 0, 0, 0); this.modId = modId; this.anchor = anchor; - this.tooltipText = Text.of(DATA.description()); + this.tooltipText = Component.literal(DATA.description()); init(); } @@ -128,7 +127,7 @@ private int getAnchorY(int screenHeight) { // Update position based on anchor and offset void updatePosition(int screenWidth, int screenHeight) { if (offsetX == 0 || offsetY == 0) { - calculateOffset(x, y, mc.getWindow().getScaledWidth(), mc.getWindow().getScaledHeight()); + calculateOffset(x, y, mc.getWindow().getGuiScaledWidth(), mc.getWindow().getGuiScaledHeight()); } int anchorX = getAnchorX(screenWidth); @@ -141,9 +140,9 @@ void updatePosition(int screenWidth, int screenHeight) { public void setPosition(int x, int y) { this.x = x; this.y = y; - if (mc.getWindow() != null) { - calculateOffset(x, y, mc.getWindow().getScaledWidth(), mc.getWindow().getScaledHeight()); - updatePosition(mc.getWindow().getScaledWidth(), mc.getWindow().getScaledHeight()); + if(mc.getWindow() != null) { + calculateOffset(x, y, mc.getWindow().getGuiScaledWidth(), mc.getWindow().getGuiScaledHeight()); + updatePosition(mc.getWindow().getGuiScaledWidth(), mc.getWindow().getGuiScaledHeight()); } } @@ -159,17 +158,17 @@ public boolean isOverlapping(Widget other) { /** * Renders the widget on the screen. */ - public final void render(DrawContext drawContext, int mouseX, int mouseY) { + public final void render(GuiGraphics graphics, int mouseX, int mouseY) { if (!isVisible()) return; if (shouldScale) { - DrawHelper.scaleAndPosition(drawContext.getMatrices(), getX(), getY(), GlobalConfig.get().getScale()); + DrawHelper.scaleAndPosition(graphics.pose(), getX(), getY(), GlobalConfig.get().getScale()); } - renderWidget(drawContext, mouseX, mouseY); + renderWidget(graphics, mouseX, mouseY); if (shouldScale) { - DrawHelper.stopScaling(drawContext.getMatrices()); + DrawHelper.stopScaling(graphics.pose()); } clampPosition(); } @@ -177,18 +176,18 @@ public final void render(DrawContext drawContext, int mouseX, int mouseY) { /** * Renders the widget on the editor screen. */ - public final void renderInEditor(DrawContext drawContext, int mouseX, int mouseY) { + public final void renderInEditor(GuiGraphics graphics, int mouseX, int mouseY) { if (!isInEditor) return; - drawWidgetBackground(drawContext); + drawWidgetBackground(graphics); if (shouldScale) { - DrawHelper.scaleAndPosition(drawContext.getMatrices(), getX(), getY(), GlobalConfig.get().getScale()); + DrawHelper.scaleAndPosition(graphics.pose(), getX(), getY(), GlobalConfig.get().getScale()); } - renderWidgetInEditor(drawContext, mouseX, mouseY); + renderWidgetInEditor(graphics, mouseX, mouseY); if (shouldScale) { - DrawHelper.stopScaling(drawContext.getMatrices()); + DrawHelper.stopScaling(graphics.pose()); } clampPosition(); } @@ -199,21 +198,21 @@ public final void renderInEditor(DrawContext drawContext, int mouseX, int mouseY * The mouse position values are only passed when in a {@link com.tanishisherewith.dynamichud.screens.AbstractMoveableScreen} screen. *

* - * @param context DrawContext Object + * @param graphics GuiGraphics Object * @param mouseX X position of mouse. * @param mouseY Y position of mouse */ - public abstract void renderWidget(DrawContext context, int mouseX, int mouseY); + public abstract void renderWidget(GuiGraphics graphics, int mouseX, int mouseY); /** * Renders the widget in the editor screen with a background. * Override this method without super call to remove the background. * Could also be used to display placeholder values. */ - private void renderWidgetInEditor(DrawContext context, int mouseX, int mouseY) { - //drawWidgetBackground(context); + private void renderWidgetInEditor(GuiGraphics graphics, int mouseX, int mouseY) { + //drawWidgetBackground(graphics); - renderWidget(context, mouseX, mouseY); + renderWidget(graphics, mouseX, mouseY); } @Override @@ -233,8 +232,8 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { /* Input related methods. Override with **super call** to add your own input-based code like contextMenu */ public void clampPosition() { - this.x = (int) MathHelper.clamp(this.x, 0, mc.getWindow().getScaledWidth() - getWidth()); - this.y = (int) MathHelper.clamp(this.y, 0, mc.getWindow().getScaledHeight() - getHeight()); + this.x = (int) org.joml.Math.clamp(this.x, 0, mc.getWindow().getGuiScaledWidth() - getWidth()); + this.y = (int) org.joml.Math.clamp(this.y, 0, mc.getWindow().getGuiScaledHeight() - getHeight()); } @Override @@ -252,8 +251,8 @@ public boolean mouseDragged(double mouseX, double mouseY, int button, double del // Higher the snapSize, more the grid boxes if (this.isShiftDown) { // Calculate the size of each snap box - int snapBoxWidth = mc.getWindow().getScaledWidth() / snapSize; - int snapBoxHeight = mc.getWindow().getScaledHeight() / snapSize; + int snapBoxWidth = mc.getWindow().getGuiScaledWidth() / snapSize; + int snapBoxHeight = mc.getWindow().getGuiScaledHeight() / snapSize; // Calculate the index of the snap box that the new position would be in and // snap the new position to the top-left corner of the snap box @@ -261,10 +260,10 @@ public boolean mouseDragged(double mouseX, double mouseY, int button, double del newY = (newY / snapBoxHeight) * snapBoxHeight; } - this.x = (int) MathHelper.clamp(newX, 0, mc.getWindow().getScaledWidth() - getWidth()); - this.y = (int) MathHelper.clamp(newY, 0, mc.getWindow().getScaledHeight() - getHeight()); + this.x = (int) org.joml.Math.clamp(newX, 0, mc.getWindow().getGuiScaledWidth() - getWidth()); + this.y = (int) org.joml.Math.clamp(newY, 0, mc.getWindow().getGuiScaledHeight() - getHeight()); - calculateOffset(x, y, mc.getWindow().getScaledWidth(), mc.getWindow().getScaledHeight()); // Set initial offset + calculateOffset(x, y, mc.getWindow().getGuiScaledWidth(), mc.getWindow().getGuiScaledHeight()); // Set initial offset return true; } @@ -311,11 +310,11 @@ public void onClose() { * Displays a faint grayish background if enabled or faint reddish background if disabled. * Drawn with 2 pixel offset to all sides */ - protected void drawWidgetBackground(DrawContext context) { + protected void drawWidgetBackground(GuiGraphics graphics) { int backgroundColor = this.isVisible() ? GlobalConfig.get().getHudActiveColor().getRGB() : GlobalConfig.get().getHudInactiveColor().getRGB(); WidgetBox box = this.getWidgetBox(); - DrawHelper.drawRectangle(context, + DrawHelper.drawRectangle(graphics, box.x, box.y, box.getWidth(), @@ -324,13 +323,13 @@ protected void drawWidgetBackground(DrawContext context) { } /** - * Set the tooltip text of the widget + * Set the tooltip Component of the widget */ - protected void setTooltipText(Text text) { - this.tooltipText = text; + protected void setTooltipText(Component Component) { + this.tooltipText = Component; } - public void readFromTag(NbtCompound tag) { + public void readFromTag(CompoundTag tag) { modId = tag.getString("modId").orElse("unknown"); uid = tag.contains("UID") ? new UID(tag.getString("UID").get()) : UID.generate(); // x = tag.getInt("x"); @@ -348,7 +347,7 @@ public void readFromTag(NbtCompound tag) { * * @param tag The tag to write to */ - public void writeToTag(NbtCompound tag) { + public void writeToTag(CompoundTag tag) { tag.putString("name", DATA.name()); tag.putString("modId", modId); tag.putString("UID", uid.getUniqueID()); diff --git a/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetManager.java b/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetManager.java index 1f0f05e..1e1aab6 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetManager.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetManager.java @@ -2,10 +2,9 @@ import com.tanishisherewith.dynamichud.DynamicHUD; import com.tanishisherewith.dynamichud.mixins.ScreenMixin; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtElement; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtIo; -import net.minecraft.nbt.NbtList; import java.io.DataOutputStream; import java.io.File; @@ -128,8 +127,8 @@ public static void onScreenResized(int newWidth, int newHeight, int previousWidt * @param file The file to save to */ public static void saveWidgets(File file, List widgets) throws IOException { - NbtCompound rootTag = new NbtCompound(); - NbtList widgetList = new NbtList(); + CompoundTag rootTag = new CompoundTag(); + ListTag widgetList = new ListTag(); printInfo("Saving widgets"); @@ -140,7 +139,7 @@ public static void saveWidgets(File file, List widgets) throws IOExcepti Set widgetSet = new HashSet<>(); for (Widget widget : widgets) { - NbtCompound widgetTag = new NbtCompound(); + CompoundTag widgetTag = new CompoundTag(); //I faced this exception once and had to spend 10 minutes trying to find it. P.S. It leaves 0 stacktrace message try { widget.writeToTag(widgetTag); @@ -190,20 +189,20 @@ public static List loadWidgets(File file) throws IOException { file = new File(file.getAbsolutePath() + ".backup"); } - NbtCompound rootTag = NbtIo.read(file.toPath()); + CompoundTag rootTag = NbtIo.read(file.toPath()); if (rootTag == null) { printWarn("RootTag is null. File is either empty or corrupted: " + file); return Collections.emptyList(); } - NbtList widgetList = rootTag.getList("widgets").orElse(null); + ListTag widgetList = rootTag.getList("widgets").orElse(null); if (widgetList == null) { printWarn("WidgetList is null. File is empty: " + file); return Collections.emptyList(); } List widgetsToAdd = new ArrayList<>(); for (int i = 0; i < widgetList.size(); i++) { - NbtCompound widgetTag = widgetList.getCompound(i).orElse(null); + CompoundTag widgetTag = widgetList.getCompound(i).orElse(null); if(widgetTag == null) continue; WidgetData widgetData = widgetDataMap.get(widgetTag.getString("name").orElse("unknown")); if (widgetData == null) { diff --git a/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetRenderer.java b/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetRenderer.java index d0bc2f1..cd6df72 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetRenderer.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetRenderer.java @@ -6,10 +6,9 @@ import com.tanishisherewith.dynamichud.screens.AbstractMoveableScreen; import com.tanishisherewith.dynamichud.utils.Input; import com.tanishisherewith.dynamichud.utils.contextmenu.contextmenuscreen.ContextMenuScreenRegistry; -import dev.isxander.yacl3.gui.YACLScreen; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.screen.GameMenuScreen; -import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.PauseScreen; +import net.minecraft.client.gui.screens.Screen; import org.lwjgl.glfw.GLFW; import java.util.List; @@ -21,19 +20,19 @@ public class WidgetRenderer implements Input { public Widget selectedWidget = null; List widgets; private boolean renderInGameHud = true; - private int Z_Index = -1; + //private int Z_Index = -1; /** * Add the list of widgets the widgetRenderer should render *

- * By default, it adds the {@link GameMenuScreen} to allow rendering of the widgets in the pause/main menu screen. + * By default, it adds the {@link PauseScreen} to allow rendering of the widgets in the pause/main menu screen. * * @param widgets List of widgets to render */ public WidgetRenderer(List widgets) { this.widgets = widgets; // Render in GameMenuScreen - this.allowedScreens = screen -> screen.getClass() == GameMenuScreen.class || + this.allowedScreens = screen -> screen.getClass() == PauseScreen.class || System.getInstances(ContextMenuScreenRegistry.class, DynamicHUD.MOD_ID).stream().anyMatch(registry -> registry.screenKlass == screen.getClass()); } @@ -88,22 +87,22 @@ private boolean renderInDebugScreen() { if (GlobalConfig.get().renderInDebugScreen()) { return true; } - return !DynamicHUD.MC.getDebugHud().shouldShowDebugHud(); + return !DynamicHUD.MC.getDebugOverlay().showDebugScreen(); } - public void renderWidgets(DrawContext context, int mouseX, int mouseY) { + public void renderWidgets(GuiGraphics graphics, int mouseX, int mouseY) { if (WidgetManager.getWidgets().isEmpty() || !renderInDebugScreen()) return; - Screen currentScreen = DynamicHUD.MC.currentScreen; + Screen currentScreen = DynamicHUD.MC.screen; - context.getMatrices().push(); - context.getMatrices().translate(0, 0, Z_Index); + // graphics.pose().pushMatrix(); + // graphics.pose().translate(0, 0,Z_Index); //Render in editing screen if (currentScreen instanceof AbstractMoveableScreen) { for (Widget widget : widgets) { widget.isInEditor = true; - widget.renderInEditor(context, mouseX, mouseY); + widget.renderInEditor(graphics, mouseX, mouseY); } return; } @@ -111,15 +110,15 @@ public void renderWidgets(DrawContext context, int mouseX, int mouseY) { if ((currentScreen == null && renderInGameHud) || allowedScreens.test(currentScreen)) { for (Widget widget : widgets) { widget.isInEditor = false; - widget.render(context, 0, 0); + widget.render(graphics, 0, 0); } } - context.getMatrices().pop(); + //graphics.pose().popMatrix(); } @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { - Screen currentScreen = DynamicHUD.MC.currentScreen; + Screen currentScreen = DynamicHUD.MC.screen; if (currentScreen == null) { return false; } @@ -139,7 +138,7 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { @Override public void mouseScrolled(double mouseX, double mouseY, double vAmount, double hAmount) { - Screen currentScreen = DynamicHUD.MC.currentScreen; + Screen currentScreen = DynamicHUD.MC.screen; if (currentScreen == null) { return; } @@ -155,7 +154,7 @@ public void charTyped(char c, int modifiers) { } public void onCloseScreen() { - if (DynamicHUD.MC.currentScreen instanceof AbstractMoveableScreen) { + if (DynamicHUD.MC.screen instanceof AbstractMoveableScreen) { for (Widget widget : widgets) { widget.onClose(); } @@ -168,7 +167,7 @@ public List getWidgets() { @Override public boolean mouseReleased(double mouseX, double mouseY, int button) { - Screen currentScreen = DynamicHUD.MC.currentScreen; + Screen currentScreen = DynamicHUD.MC.screen; if (currentScreen == null) { return false; } @@ -186,7 +185,7 @@ public final boolean mouseDragged(double mouseX, double mouseY, int button, doub } public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY, int snapSize) { - Screen currentScreen = DynamicHUD.MC.currentScreen; + Screen currentScreen = DynamicHUD.MC.screen; if (currentScreen == null) { return false; } @@ -206,7 +205,7 @@ public boolean mouseDragged(double mouseX, double mouseY, int button, double del @Override public void keyPressed(int key, int scanCode, int modifiers) { - Screen currentScreen = DynamicHUD.MC.currentScreen; + Screen currentScreen = DynamicHUD.MC.screen; if (currentScreen instanceof AbstractMoveableScreen && (key == GLFW.GLFW_KEY_LEFT_SHIFT || key == GLFW.GLFW_KEY_RIGHT_SHIFT)) { for (Widget widget : widgets) { widget.isShiftDown = true; @@ -216,7 +215,7 @@ public void keyPressed(int key, int scanCode, int modifiers) { @Override public void keyReleased(int key, int scanCode, int modifiers) { - Screen currentScreen = DynamicHUD.MC.currentScreen; + Screen currentScreen = DynamicHUD.MC.screen; if (currentScreen instanceof AbstractMoveableScreen && (key == GLFW.GLFW_KEY_LEFT_SHIFT || key == GLFW.GLFW_KEY_RIGHT_SHIFT)) { for (Widget widget : widgets) { widget.isShiftDown = false; @@ -224,8 +223,8 @@ public void keyReleased(int key, int scanCode, int modifiers) { } } - public WidgetRenderer withZIndex(int z_Index) { - this.Z_Index = z_Index; - return this; - } + // public WidgetRenderer withZIndex(int z_Index) { + // this.Z_Index = z_Index; + // return this; + // } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java index e2e0d44..574ae6c 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java @@ -3,9 +3,11 @@ import com.tanishisherewith.dynamichud.config.GlobalConfig; import com.tanishisherewith.dynamichud.helpers.ColorHelper; import com.tanishisherewith.dynamichud.helpers.DrawHelper; -import com.tanishisherewith.dynamichud.helpers.animationhelper.animations.MathAnimations; +import com.tanishisherewith.dynamichud.renderstates.GradientShadowRenderState; +import com.tanishisherewith.dynamichud.renderstates.InterpolatedCurveRenderState; import com.tanishisherewith.dynamichud.utils.CustomRenderLayers; import com.tanishisherewith.dynamichud.utils.DynamicValueRegistry; +import com.tanishisherewith.dynamichud.utils.Util; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenu; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenuManager; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenuProperties; @@ -18,12 +20,11 @@ import com.tanishisherewith.dynamichud.widget.WidgetBox; import com.tanishisherewith.dynamichud.widget.WidgetData; import com.twelvemonkeys.lang.Validate; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.text.Text; -import net.minecraft.util.math.MathHelper; -import org.joml.Matrix4f; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.render.TextureSetup; +import net.minecraft.client.renderer.RenderPipelines; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; import java.awt.*; import java.util.ArrayList; @@ -86,10 +87,11 @@ private void internal_init() { this.widgetBox = new WidgetBox(x, y, (int) width, (int) height); this.stepY = height / (gridLines + 1); this.valueStep = (maxValue - minValue) / (gridLines + 1); - this.scale = (float) MathHelper.clamp((stepY / 9.5), 0.0f, 1.0f); + this.scale = (float) Math.clamp((stepY / 9.5), 0.0f, 1.0f); + computeOffset(); - setTooltipText(Text.of("Graph displaying: " + label)); + setTooltipText(Component.literal("Graph displaying: " + label)); } public GraphWidget() { @@ -126,7 +128,7 @@ public void addDataPoint(Float value) { } int index = (head) % maxDataPoints; - dataPoints[index] = MathHelper.clamp(value, minValue, maxValue); + dataPoints[index] = Math.clamp(value, minValue, maxValue); head = (head + 1) % maxDataPoints; // Buffer full, overwrite oldest and move head } @@ -161,53 +163,26 @@ private List getInterpolatedPoints() { } // draw a continuous interpolated curve - private void drawInterpolatedCurve(DrawContext drawContext, List points, int color, float thickness) { + private void drawInterpolatedCurve(GuiGraphics graphics, List points, int color, float thickness) { if (points.size() < 2) return; - drawContext.draw(vcp -> { - Matrix4f matrix = drawContext.getMatrices().peek().getPositionMatrix(); - VertexConsumer consumer = vcp.getBuffer(CustomRenderLayers.TRIANGLE_STRIP); - - for (int i = 0; i < points.size(); i++) { - float[] point = points.get(i); - float x = point[0]; - float y = point[1]; - - // Create a thick line by offsetting vertices perpendicular to the curve - float dx = (i < points.size() - 1) ? points.get(i + 1)[0] - x : x - points.get(i - 1)[0]; - float dy = (i < points.size() - 1) ? points.get(i + 1)[1] - y : y - points.get(i - 1)[1]; - float length = (float) Math.sqrt(dx * dx + dy * dy); - if (length == 0) continue; - - float offsetX = (thickness * 0.5f * dy) / length; - float offsetY = (thickness * 0.5f * -dx) / length; - - consumer.vertex(matrix, x + offsetX, y + offsetY, 0).color(color); - consumer.vertex(matrix, x - offsetX, y - offsetY, 0).color(color); - } - }); + graphics.guiRenderState.submitGuiElement( + new InterpolatedCurveRenderState(points, thickness, color, graphics.pose(), CustomRenderLayers.QUADS_CUSTOM_BLEND, graphics.scissorStack.peek()) + ); } + // draw a gradient shadow under the curve - private void drawGradientShadow(DrawContext context, List points, float bottomY, int startColor, int endColor) { + private void drawGradientShadow(GuiGraphics graphics, List points, float bottomY, int startColor, int endColor) { if (points.size() < 2) return; - context.draw(vcp -> { - Matrix4f matrix = context.getMatrices().peek().getPositionMatrix(); - VertexConsumer consumer = vcp.getBuffer(CustomRenderLayers.TRIANGLE_STRIP); - - for (float[] point : points) { - float x = point[0]; - float y = point[1]; - - consumer.vertex(matrix, x, y, 0).color(startColor); - consumer.vertex(matrix, x, bottomY, 0).color(endColor); - } - }); + graphics.guiRenderState.submitGuiElement( + new GradientShadowRenderState(points,bottomY, startColor, endColor, graphics.pose(), CustomRenderLayers.TRIANGLE_STRIP, graphics.scissorStack.peek()) + ); } @Override - public void renderWidget(DrawContext context, int mouseX, int mouseY) { + public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { if (valueSupplier != null) { addDataPoint(getValue()); } @@ -217,12 +192,12 @@ public void renderWidget(DrawContext context, int mouseX, int mouseY) { if(graphColorRainbow) graphColor = ColorHelper.getRainbowColor(100); - DrawHelper.enableScissor(widgetBox); + // DrawHelper.enableScissor(widgetBox); // Draw gradient background with rounded.fsh corners if (!isInEditor) { DrawHelper.drawRoundedRectangle( - context, + graphics, x + offset, y, false, @@ -242,18 +217,18 @@ public void renderWidget(DrawContext context, int mouseX, int mouseY) { for (int i = 1; i <= gridLines; i++) { float yPos = y + stepY * i; - DrawHelper.drawHorizontalLine(context, x + offset, width, yPos, 0.5f, 0x4DFFFFFF); // Semi-transparent white + DrawHelper.drawHorizontalLine(graphics, x + offset, width, yPos, 0.5f, 0x4DFFFFFF); // Semi-transparent white // Draw value labels on the left axis float value = maxValue - (i * valueStep); String valueText = formatValue(value); - float texWidth = mc.textRenderer.getWidth(valueText) * scale; + float texWidth = mc.font.width(valueText) * scale; - //Scale the text to its proper position and size with grid lines - DrawHelper.scaleAndPosition(context.getMatrices(), x - 2, yPos, scale); - context.drawText(mc.textRenderer, valueText, Math.round(x + offset - texWidth), (int) (yPos - (mc.textRenderer.fontHeight * scale) / 2.0f), 0xFFFFFFFF, true); - DrawHelper.stopScaling(context.getMatrices()); + //Scale the Component to its proper position and size with grid lines + DrawHelper.scaleAndPosition(graphics.pose(), x - 2, yPos, scale); + graphics.drawString(mc.font, valueText, Math.round(x + offset - texWidth), (int) (yPos - (mc.font.lineHeight * scale) / 2.0f), 0xFFFFFFFF, true); + DrawHelper.stopScaling(graphics.pose()); } // Update the offsets for the rest of the elements drawn. @@ -263,50 +238,49 @@ public void renderWidget(DrawContext context, int mouseX, int mouseY) { float stepX = width / 5; // 5 vertical lines for (int i = 1; i < 5; i++) { float xPos = x + stepX * i; - DrawHelper.drawVerticalLine(context, xPos, y, height, 0.5f, 0x4DFFFFFF); + DrawHelper.drawVerticalLine(graphics, xPos, y, height, 0.5f, 0x4DFFFFFF); } } // Draw interpolated graph curve List points = getInterpolatedPoints(); - drawInterpolatedCurve(context, points, graphColor.getRGB(), lineThickness); + drawInterpolatedCurve(graphics, points, graphColor.getRGB(), lineThickness); // Draw shadow effect under the graph drawGradientShadow( - context, points, y + height, + graphics, points, y + height, ColorHelper.changeAlpha(graphColor, 50).getRGB(), 0x00000000 ); - DrawHelper.drawChromaText( - context, label, + graphics, label, x + 5, y + 5, 1.0f, 0.8f, 1.0f, 0.05f, true ); // Draw axes - DrawHelper.drawHorizontalLine(context, x, width, y + height - 1, 1.0f, 0xFFFFFFFF); // X-axis - DrawHelper.drawVerticalLine(context, x, y, height, 1.0f, 0xFFFFFFFF); // Y-axis + DrawHelper.drawHorizontalLine(graphics, x, width, y + height - 1, 1.0f, 0xFFFFFFFF); // X-axis + DrawHelper.drawVerticalLine(graphics, x, y, height, 1.0f, 0xFFFFFFFF); // Y-axis // Draw min and max value labels with formatted values /* DrawHelper.scaleAndPosition(context.getMatrices(),x - 5,y,0.5f); String formattedMaxVal = formatValue(maxValue); - context.drawText(mc.textRenderer, formattedMaxVal, x - 5 - mc.textRenderer.getWidth(formattedMaxVal), y - 4, 0xFFFFFFFF, true); + context.drawText(mc.font, formattedMaxVal, x - 5 - mc.font.width(formattedMaxVal), y - 4, 0xFFFFFFFF, true); DrawHelper.stopScaling(context.getMatrices()); */ - DrawHelper.scaleAndPosition(context.getMatrices(), x - 5, y + height, 0.5f); + DrawHelper.scaleAndPosition(graphics.pose(), x - 5, y + height, 0.5f); String formattedMinVal = formatValue(minValue); - context.drawText(mc.textRenderer, formattedMinVal, x - mc.textRenderer.getWidth(formattedMinVal), (int) (y + height - 4), 0xFFFFFFFF, true); - DrawHelper.stopScaling(context.getMatrices()); + graphics.drawString(mc.font, formattedMinVal, x - mc.font.width(formattedMinVal), (int) (y + height - 4), 0xFFFFFFFF, true); + DrawHelper.stopScaling(graphics.pose()); if(showGrid) x -= offset; this.widgetBox.setDimensions(x, y, width + offset, height, shouldScale, GlobalConfig.get().getScale()); - DrawHelper.disableScissor(); + // DrawHelper.disableScissor(); if (menu != null) menu.set(getX(), getY(), (int) Math.ceil(getHeight())); } @@ -332,12 +306,12 @@ public void createMenu() { ContextMenuProperties properties = ContextMenuProperties.builder().build(); menu = new ContextMenu<>(getX(), (int) (getY() + widgetBox.getHeight()), properties); - menu.addOption(new BooleanOption(Text.of("Show Grid"), + menu.addOption(new BooleanOption(Component.literal("Show Grid"), () -> this.showGrid, value -> this.showGrid = value, BooleanOption.BooleanType.YES_NO) - .description(Text.of("Shows a grid and Y axis values")) + .description(Component.literal("Shows a grid and Y axis values")) ); - menu.addOption(new DoubleOption(Text.of("Number of Grid Lines"), + menu.addOption(new DoubleOption(Component.literal("Number of Grid Lines"), 1, 25, 1, () -> (double) this.gridLines, value -> { this.setGridLines(value.intValue()); @@ -345,36 +319,35 @@ public void createMenu() { }, menu) .renderWhen(() -> this.showGrid) ); - menu.addOption(new ColorOption(Text.of("Graph Line Color"), + menu.addOption(new ColorOption(Component.literal("Graph Line Color"), () -> this.graphColor, value -> this.graphColor = value, menu) - .description(Text.of("Specify the color you want for the graph's lines")) + .description(Component.literal("Specify the color you want for the graph's lines")) ); - menu.addOption(new BooleanOption(Text.of("Rainbow Graph Line Color"), + menu.addOption(new BooleanOption(Component.literal("Rainbow Graph Line Color"), () -> this.graphColorRainbow, value -> this.graphColorRainbow = value) - .description(Text.of("Color your graph line with funny rainbow")) + .description(Component.literal("Color your graph line with funny rainbow")) .withComplexity(Option.Complexity.Pro) ); - menu.addOption(new ColorOption(Text.of("Graph Background Color"), + menu.addOption(new ColorOption(Component.literal("Graph Background Color"), () -> this.backgroundColor, value -> this.backgroundColor = value, menu) - .description(Text.of("Specify the color you want for the graph's background")) + .description(Component.literal("Specify the color you want for the graph's background")) ); - menu.addOption(new DoubleOption(Text.of("Line Thickness"), + menu.addOption(new DoubleOption(Component.literal("Line Thickness"), 0.5f, 5.0f, 0.1f, () -> (double) this.lineThickness, value -> this.lineThickness = value.floatValue(), menu) ); } private void computeOffset(){ - // The first text is usually the largest but a negative value may occupy more width so we check the first and last text. + // The first Component is usually the largest but a negative value may occupy more width so we check the first and last Component. // Idk how this will break. - if(mc.textRenderer == null) return; String firstText = formatValue(maxValue - valueStep); String lastText = formatValue(maxValue - (gridLines * valueStep)); offset = Math.max( - (int) Math.ceil(mc.textRenderer.getWidth(firstText) * this.scale), - (int) Math.ceil(mc.textRenderer.getWidth(lastText) * this.scale) + (int) Math.ceil(mc.font.width(firstText) * this.scale), + (int) Math.ceil(mc.font.width(lastText) * this.scale) ); } @@ -456,7 +429,7 @@ public void setGridLines(int gridLines) { this.gridLines = gridLines; this.stepY = height / (gridLines + 1); this.valueStep = (maxValue - minValue) / (gridLines + 1); - this.scale = (float) MathHelper.clamp((stepY / 9.5), 0.0f, 1.0f); + this.scale = (float) Math.clamp((stepY / 9.5), 0.0f, 1.0f); } public boolean isShowGrid() { @@ -490,7 +463,7 @@ public void onClose() { } @Override - public void writeToTag(NbtCompound tag) { + public void writeToTag(CompoundTag tag) { super.writeToTag(tag); tag.putFloat("width", width); tag.putFloat("height", height); @@ -508,7 +481,7 @@ public void writeToTag(NbtCompound tag) { } @Override - public void readFromTag(NbtCompound tag) { + public void readFromTag(CompoundTag tag) { super.readFromTag(tag); this.width = tag.getFloat("width").orElse(100f); this.height = tag.getFloat("height").orElse(50f); diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/ItemWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/ItemWidget.java index 9140d2c..48bd7ac 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/ItemWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/ItemWidget.java @@ -3,10 +3,10 @@ import com.tanishisherewith.dynamichud.config.GlobalConfig; import com.tanishisherewith.dynamichud.widget.Widget; import com.tanishisherewith.dynamichud.widget.WidgetData; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NbtCompound; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; /** * This is just an example widget, not supposed to be used. @@ -25,21 +25,21 @@ public ItemWidget() { } @Override - public void renderWidget(DrawContext context, int mouseX, int mouseY) { - context.drawItem(item, x, y); + public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { + graphics.renderItem(item, x, y); widgetBox.setDimensions(getX(), getY(), 16, 16, this.shouldScale, GlobalConfig.get().getScale()); } @Override - public void writeToTag(NbtCompound tag) { + public void writeToTag(CompoundTag tag) { super.writeToTag(tag); - tag.putInt("ItemID", Item.getRawId(item.getItem())); + tag.putInt("ItemID", Item.getId(item.getItem())); } @Override - public void readFromTag(NbtCompound tag) { + public void readFromTag(CompoundTag tag) { super.readFromTag(tag); - item = Item.byRawId(tag.getInt("ItemID").orElse(0)).getDefaultStack(); + item = Item.byId(tag.getInt("ItemID").orElse(0)).getDefaultInstance(); } public void setItemStack(ItemStack item) { diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java index f85a8d7..a286d51 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java @@ -8,21 +8,28 @@ import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenuProperties; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenuProvider; import com.tanishisherewith.dynamichud.utils.contextmenu.options.*; +import com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.MinecraftSkin; +import com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.ModernSkin; import com.tanishisherewith.dynamichud.widget.DynamicValueWidget; import com.tanishisherewith.dynamichud.widget.WidgetData; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.text.Text; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import javax.swing.*; import java.awt.Color; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; public class TextWidget extends DynamicValueWidget implements ContextMenuProvider { - public static WidgetData DATA = new WidgetData<>("TextWidget", "Display Text on screen", TextWidget::new); + public static WidgetData DATA = new WidgetData<>("TextWidget", "Display Component on screen", TextWidget::new); private ContextMenu menu; public Color textColor; - protected boolean shadow; // Whether to draw a shadow behind the text - protected boolean rainbow; // Whether to apply a rainbow effect to the text + protected boolean shadow; // Whether to draw a shadow behind the Component + protected boolean rainbow; // Whether to apply a rainbow effect to the Component protected int rainbowSpeed = 2; //Speed of the rainbow effect protected float rainbowSpread = 0.01f, rainbowSaturation = 1.0f, rainbowBrightness = 1.0f; @@ -44,62 +51,98 @@ public TextWidget(String registryID, String registryKey, boolean shadow, boolean } public void createMenu() { - menu = new ContextMenu<>(getX(), getY(),ContextMenuProperties.createGenericSimplified()); + menu = new ContextMenu<>(getX(), getY(),ContextMenuProperties.builder().skin(new ModernSkin()).build()); - menu.addOption(new BooleanOption(Text.of("Shadow"), + menu.addOption(new BooleanOption(Component.literal("Shadow"), () -> this.shadow, value -> this.shadow = value, BooleanOption.BooleanType.ON_OFF) - .description(Text.of("Adds shadow to your text")) + .description(Component.literal("Adds shadow to your Component")) ); - menu.addOption(new BooleanOption(Text.of("Rainbow"), + menu.addOption(new BooleanOption(Component.literal("Rainbow"), () -> this.rainbow, value -> this.rainbow = value, BooleanOption.BooleanType.ON_OFF) - .description(Text.of("Adds rainbow effect to your text")) + .description(Component.literal("Adds rainbow effect to your Component")) ); - menu.addOption(new ColorOption(Text.of("Text Color"), + menu.addOption(new ColorOption(Component.literal("Component Color"), () -> this.textColor, value -> this.textColor = value, menu) - .description(Text.of("Specify the color you want to add to your text")) + .description(Component.literal("Specify the color you want to add to your Component")) .renderWhen(() -> !this.rainbow) ); - menu.addOption(new DoubleOption(Text.of("Rainbow Speed"), + menu.addOption(new DoubleOption(Component.literal("Rainbow Speed"), 1, 5.0f, 1, () -> (double) this.rainbowSpeed, value -> this.rainbowSpeed = value.intValue(), menu) .renderWhen(() -> this.rainbow) ); - menu.addOption(new DoubleOption(Text.of("Rainbow Spread"), + menu.addOption(new DoubleOption(Component.literal("Rainbow Spread"), 0.001f, 0.15f, 0.001f, () -> (double) this.rainbowSpread, value -> this.rainbowSpread = value.floatValue(), menu) .renderWhen(() -> this.rainbow) .withComplexity(Option.Complexity.Enhanced) ); - menu.addOption(new DoubleOption(Text.of("Rainbow Saturation"), + menu.addOption(new DoubleOption(Component.literal("Rainbow Saturation"), 0, 1.0f, 0.1f, () -> (double) this.rainbowSaturation, value -> this.rainbowSaturation = value.floatValue(), menu) .renderWhen(() -> this.rainbow) .withComplexity(Option.Complexity.Pro) ); - menu.addOption(new DoubleOption(Text.of("Rainbow Brightness"), + menu.addOption(new DoubleOption(Component.literal("Rainbow Brightness"), 0, 1.0f, 0.01f, () -> (double) this.rainbowBrightness, value -> this.rainbowBrightness = value.floatValue(), menu) .renderWhen(() -> this.rainbow) .withComplexity(Option.Complexity.Pro) ); + // Runnable Option + AtomicBoolean ran = new AtomicBoolean(false); + menu.addOption(new RunnableOption(Component.literal("Reset Position"), + ran::get, ran::set, + () -> this.setPosition(0, 0)) + .description(Component.literal("Reset widget to default position"))); + + // List Option + AtomicReference style = new AtomicReference<>("Style1"); + List styles = Arrays.asList("Style1", "Style2", "Style3"); + menu.addOption(new ListOption<>(Component.literal("Text Style"), + style::get, style::set, styles) + .description(Component.literal("Choose a text style"))); + + // Enum Option + menu.addOption(new EnumOption<>(Component.literal("Alignment"), + () -> GroupLayout.Alignment.CENTER, value -> {}, GroupLayout.Alignment.values()) + .description(Component.literal("Set text alignment"))); + + // Option Group + OptionGroup group = new OptionGroup(Component.literal("Display Options")); + group.addOption(new BooleanOption(Component.literal("Bold Text"), + () -> false, value -> {}, BooleanOption.BooleanType.YES_NO) + .description(Component.literal("Enable bold text"))); + group.addOption(new DoubleOption(Component.literal("Font Size"), + 8.0, 24.0, 1.0f, + () -> 12.0, value -> {}, menu) + .description(Component.literal("Adjust font size"))); + menu.addOption(group); + + // SubMenu Option + SubMenuOption subMenu = (SubMenuOption) new SubMenuOption(Component.literal("Advanced Settings"), menu) + .description(Component.literal("Open advanced settings")); + subMenu.getSubMenu().addOption(new BooleanOption(Component.literal("Some Boolean"), + () -> false, value -> {}, BooleanOption.BooleanType.TRUE_FALSE) + .description(Component.literal("True/False"))); + menu.addOption(subMenu); } @Override - public void renderWidget(DrawContext drawContext, int mouseX, int mouseY) { + public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { if (menu == null) return; //int color = rainbow ? ColorHelper.getColorFromHue((System.currentTimeMillis() % (5000 * rainbowSpeed) / (5000f * rainbowSpeed))) : textColor.getRGB(); int color = textColor.getRGB(); if (valueSupplier != null) { - String text = getValue(); + String Component = getValue(); if (rainbow) { - DrawHelper.drawChromaText(drawContext, text, getX() + 2, getY() + 2, rainbowSpeed / 2f, rainbowSaturation, rainbowBrightness, rainbowSpread, shadow); + DrawHelper.drawChromaText(graphics, Component, getX() + 2, getY() + 2, rainbowSpeed / 2f, rainbowSaturation, rainbowBrightness, rainbowSpread, shadow); } else { - drawContext.drawText(mc.textRenderer, text, getX() + 2, getY() + 2, color, shadow); + graphics.drawString(mc.font, Component, getX() + 2, getY() + 2, color, shadow); } - drawContext.draw(); - widgetBox.setDimensions(getX(), getY(), mc.textRenderer.getWidth(text) + 3, mc.textRenderer.fontHeight + 2, this.shouldScale, GlobalConfig.get().getScale()); + widgetBox.setDimensions(getX(), getY(), mc.font.width(Component) + 3, mc.font.lineHeight + 2, this.shouldScale, GlobalConfig.get().getScale()); } menu.set(getX(), getY(), (int) Math.ceil(getHeight())); @@ -118,7 +161,7 @@ public void onClose() { } @Override - public void writeToTag(NbtCompound tag) { + public void writeToTag(CompoundTag tag) { super.writeToTag(tag); tag.putBoolean("Shadow", shadow); tag.putBoolean("Rainbow", rainbow); @@ -130,7 +173,7 @@ public void writeToTag(NbtCompound tag) { } @Override - public void readFromTag(NbtCompound tag) { + public void readFromTag(CompoundTag tag) { super.readFromTag(tag); shadow = tag.getBoolean("Shadow").orElse(false); rainbow = tag.getBoolean("Rainbow").orElse(false); diff --git a/src/main/resources/dynamichud.mixins.json b/src/main/resources/dynamichud.mixins.json index f60e286..caa9633 100644 --- a/src/main/resources/dynamichud.mixins.json +++ b/src/main/resources/dynamichud.mixins.json @@ -1,6 +1,5 @@ { "required": true, - "minVersion": "0.8", "package": "com.tanishisherewith.dynamichud.mixins", "compatibilityLevel": "JAVA_21", "mixins": [ @@ -10,7 +9,11 @@ "defaultRequire": 1 }, "client": [ - "OptionsScreenMixin", - "RenderLayerMixin" - ] + "BufferBuilderMixin", + "MinecraftMixin", + "OptionsScreenMixin" + ], + "overwrites": { + "requireAnnotations": true + } } diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index a6ef3cf..a416a25 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -26,7 +26,10 @@ ] }, "mixins": [ - "dynamichud.mixins.json" + { + "config": "dynamichud.mixins.json", + "environment": "client" + } ], "depends": { "fabricloader": ">=${loader_version}", From a4e81749c18bd53e000ad74f798f5b0c928648e9 Mon Sep 17 00:00:00 2001 From: tanishisherewith <120117618+tanishisherewithhh@users.noreply.github.com> Date: Sat, 11 Apr 2026 00:59:39 +0530 Subject: [PATCH 02/22] Fixed dynamicHUD button position --- .../dynamichud/helpers/DrawHelper.java | 53 +++--- .../dynamichud/mixins/OptionsScreenMixin.java | 34 ++-- .../renderstates/GeometryRenderState.java | 3 +- .../GradientShadowRenderState.java | 12 +- .../InterpolatedCurveRenderState.java | 23 ++- .../QuadColorRectRenderState.java | 8 +- .../renderstates/RoundedRectRenderState.java | 168 +++++++++++++++--- .../dynamichud/utils/CustomRenderLayers.java | 24 ++- .../contextmenu/skinsystem/ModernSkin.java | 4 +- .../dynamichud/widgets/GraphWidget.java | 7 +- 10 files changed, 241 insertions(+), 95 deletions(-) diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java index e089219..5373dc4 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java +++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java @@ -1,7 +1,5 @@ package com.tanishisherewith.dynamichud.helpers; -import com.mojang.blaze3d.systems.RenderSystem; -import com.tanishisherewith.dynamichud.DynamicHUD; import com.tanishisherewith.dynamichud.renderstates.GeometryRenderState; import com.tanishisherewith.dynamichud.renderstates.QuadColorRectRenderState; import com.tanishisherewith.dynamichud.renderstates.RoundedRectRenderState; @@ -9,7 +7,6 @@ import com.tanishisherewith.dynamichud.widget.WidgetBox; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.gui.navigation.ScreenPosition; import net.minecraft.client.gui.navigation.ScreenRectangle; import net.minecraft.client.renderer.RenderPipelines; import net.minecraft.network.chat.Component; @@ -29,6 +26,12 @@ * Credits: HeliosClient */ public class DrawHelper { + public static final float[] SINA = {0,0.1736482f,0.3420201f,0.5f,0.6427876f,0.7660444f,0.8660254f,0.9396926f,0.9848077f,1,0.9848078f,0.9396927f,0.8660255f,0.7660446f,0.6427878f,0.5000002f,0.3420205f,0.1736485f,3.894144E-07f,-0.1736478f,-0.3420197f,-0.4999996f,-0.6427872f,-0.7660443f,-0.8660252f,-0.9396925f,-0.9848077f,-1,-0.9848078f,-0.9396928f,-0.8660257f,-0.7660449f,-0.6427881f,-0.5000006f,-0.3420208f,-0.1736489f,0,0.1736482f,0.3420201f,0.5f,0.6427876f,0.7660444f,0.8660254f,0.9396926f,0.9848077f}; + public static final float[] COSA = new float[45]; + static { + // Cosa is simply Sina shifted by 90 degrees (9 steps) + System.arraycopy(SINA, 9, COSA, 0, 36); + } /** * Draws a singular gradient rectangle on screen with the given parameters @@ -51,7 +54,6 @@ public static void drawGradient(GuiGraphics g, float x, float y, float width, fl g.guiRenderState.submitGuiElement( new QuadColorRectRenderState(RenderPipelines.GUI,g.pose(),x,y,width,height,c, - new ScreenRectangle((int) x, (int) y,(int)width,(int) height), g.scissorStack.peek()) ); } @@ -64,16 +66,24 @@ public static void enableScissor(WidgetBox box,GuiGraphics graphics) { enableScissor((int) box.x, (int) box.y, (int) box.getWidth(), (int) box.getHeight(), mc.getWindow().getGuiScale(),graphics); } - public static void enableScissor(int x, int y, int width, int height, double scaleFactor, GuiGraphics graphics) { + public static void enableScissor(int x, int y, int width, int height, float scaleFactor, GuiGraphics graphics) { + scaleFactor = scaleFactor / mc.getWindow().getGuiScale(); int scissorX = (int) (x * scaleFactor); int scissorY = (int) (y * scaleFactor); int scissorWidth = (int) (width * scaleFactor); int scissorHeight = (int) (height * scaleFactor); - ScreenRectangle rect = new ScreenRectangle(x, y, width, height); + ScreenRectangle rect = new ScreenRectangle(scissorX, scissorY, scissorWidth, scissorHeight); graphics.scissorStack.push(rect); } + /** + * All coordinates by minecraft need to unscaled first and then scaled by our factor. + */ + public static float scaleFactor(float scale) { + return scale / mc.getWindow().getGuiScale(); + } + public static void disableScissor(GuiGraphics graphics) { graphics.disableScissor(); @@ -158,10 +168,9 @@ public static void drawOutlineRoundedBox(GuiGraphics graphics, float x, float y, int[] intColors = {tl.getRGB(),tr.getRGB(),br.getRGB(),bl.getRGB()}; graphics.guiRenderState.submitGuiElement(new RoundedRectRenderState( - CustomRenderLayers.ROUNDED_RECT_OUTLINE, + CustomRenderLayers.TRIANGLE_FAN_CUSTOM_BLEND, graphics.pose(), - x, y, width, height, thickness, intColors, radii, graphics.scissorStack.peek(), - new ScreenRectangle(new ScreenPosition((int) x, (int) y), (int) width, (int) height) + x, y, width, height, thickness, intColors, radii, graphics.scissorStack.peek() )); } @@ -486,10 +495,9 @@ public static void drawRoundedRectangle(GuiGraphics graphics, float x, float y, int[] intColors = {tl.getRGB(),tr.getRGB(),br.getRGB(),bl.getRGB()}; graphics.guiRenderState.submitGuiElement(new RoundedRectRenderState( - CustomRenderLayers.ROUNDED_RECT, + CustomRenderLayers.TRIANGLE_FAN_CUSTOM_BLEND, graphics.pose(), - x, y, width, height, 0f, intColors, radii, graphics.scissorStack.peek(), - new ScreenRectangle(new ScreenPosition((int) x, (int) y), (int) width, (int) height) + x, y, width, height, -1f, intColors, radii, graphics.scissorStack.peek() )); } @@ -593,16 +601,9 @@ public static void drawOutlinedBox(GuiGraphics graphics, int x1, int y1, int x2, graphics.fill(x2 - 1, y1 + 1, x2, y2 - 1, color); } - public static void unscaledProjection() { - //RenderSystem.setProjectionMatrix(new Matrix4f().setOrtho(0, mc.getWindow().getWidth(), mc.getWindow().getHeight(), 0, 1000, 21000), ProjectionType.ORTHOGRAPHIC); - } - - public static void scaledProjection() { - //RenderSystem.setProjectionMatrix(new Matrix4f().setOrtho(0, (float) (mc.getWindow().getWidth() / mc.getWindow().getGuiScale()), (float) (mc.getWindow().getFramebufferHeight() / mc.getWindow().getScaleFactor()), 0, 1000, 21000), ProjectionType.ORTHOGRAPHIC); - } - - public static void customScaledProjection(float scale) { - //RenderSystem.setProjectionMatrix(new Matrix4f().setOrtho(0, mc.getWindow().getWidth() / scale, mc.getWindow().getHeight() / scale, 0, 1000, 21000), ProjectionType.ORTHOGRAPHIC); + public static void scaledProjection(float scale, GuiGraphics graphics) { + graphics.pose().pushMatrix(); + graphics.pose().scale(scale/mc.getWindow().getGuiScale()); } /** @@ -624,6 +625,14 @@ public static void scaleAndPosition(Matrix3x2fStack matrices, float x, float y, matrices.translate(-x, -y); } + /** + * Creating bounds for Render states + */ + public static ScreenRectangle createBounds(Matrix3x2fStack pose, ScreenRectangle scissor, float x, float y, float w, float h) { + ScreenRectangle bounds = new ScreenRectangle((int) x, (int) y, (int) w, (int) h).transformAxisAligned(pose); + return scissor == null ? bounds : scissor.intersection(bounds); + } + /** * This method scales the matrices by the centre of the widget * diff --git a/src/main/java/com/tanishisherewith/dynamichud/mixins/OptionsScreenMixin.java b/src/main/java/com/tanishisherewith/dynamichud/mixins/OptionsScreenMixin.java index ba6887b..b778b05 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/mixins/OptionsScreenMixin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/mixins/OptionsScreenMixin.java @@ -4,14 +4,15 @@ import com.tanishisherewith.dynamichud.config.GlobalConfig; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.layouts.HeaderAndFooterLayout; -import net.minecraft.client.gui.layouts.LayoutSettings; import net.minecraft.client.gui.layouts.LinearLayout; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.TitleScreen; import net.minecraft.client.gui.screens.options.OptionsScreen; import net.minecraft.network.chat.Component; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -23,28 +24,41 @@ public abstract class OptionsScreenMixin extends Screen { @Shadow protected abstract Button openScreenButton(Component component, Supplier supplier); - @Shadow - @Final - private HeaderAndFooterLayout layout; - protected OptionsScreenMixin(Component title) { super(title); } + @Unique + private LinearLayout header; + + @Unique + private Button dhButton; + @Inject( method = "init", at = @At( value = "INVOKE", target = "Lnet/minecraft/client/gui/layouts/LinearLayout;addChild(Lnet/minecraft/client/gui/layouts/LayoutElement;)Lnet/minecraft/client/gui/layouts/LayoutElement;", - ordinal = 1 // this is where the FOV row is added + ordinal = 1, // this is where the FOV row is added + shift = At.Shift.AFTER ) ) private void injectDHLayout(CallbackInfo ci, @Local(ordinal = 0) LinearLayout header) { - LinearLayout dhLayout = header.addChild(LinearLayout.vertical(), layoutSettings -> layoutSettings.paddingLeft(-20)); + this.header = header; + dhButton = openScreenButton(Component.literal("DH"), () -> GlobalConfig.get().createYACLGUI()); + dhButton.setPosition(this.width / 2 - 150 - 24 - 8, header.getY() + header.getHeight() - 20); + dhButton.setSize(20,20); + this.addRenderableWidget(dhButton); + } - Button dhButton = openScreenButton(Component.literal("DH"), () -> GlobalConfig.get().createYACLGUI()); - dhButton.setWidth(20); - dhLayout.addChild(dhButton); + @Inject( + method = "repositionElements", + at = @At(value = "TAIL") + ) + private void repositionElements(CallbackInfo ci) { + if(dhButton != null && header != null) { + dhButton.setPosition(this.width / 2 - 150 - 24 - 8, header.getY() + header.getHeight() - 20); + } } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/renderstates/GeometryRenderState.java b/src/main/java/com/tanishisherewith/dynamichud/renderstates/GeometryRenderState.java index 8926ee4..eb2106b 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/renderstates/GeometryRenderState.java +++ b/src/main/java/com/tanishisherewith/dynamichud/renderstates/GeometryRenderState.java @@ -17,8 +17,6 @@ public record GeometryRenderState( @Nullable ScreenRectangle scissorArea ) implements GuiElementRenderState { - public record VertexData(float x, float y, int color) {} - @Override public void buildVertices(VertexConsumer consumer) { for (int i = 0; i < vertices.length / 2; i++) { @@ -31,6 +29,7 @@ public void buildVertices(VertexConsumer consumer) { public TextureSetup textureSetup() { return TextureSetup.noTexture(); } + @Override public @Nullable ScreenRectangle bounds() { return null; diff --git a/src/main/java/com/tanishisherewith/dynamichud/renderstates/GradientShadowRenderState.java b/src/main/java/com/tanishisherewith/dynamichud/renderstates/GradientShadowRenderState.java index 1e4af63..7a1375a 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/renderstates/GradientShadowRenderState.java +++ b/src/main/java/com/tanishisherewith/dynamichud/renderstates/GradientShadowRenderState.java @@ -2,10 +2,12 @@ import com.mojang.blaze3d.pipeline.RenderPipeline; import com.mojang.blaze3d.vertex.VertexConsumer; +import com.tanishisherewith.dynamichud.helpers.DrawHelper; import net.minecraft.client.gui.navigation.ScreenRectangle; import net.minecraft.client.gui.render.TextureSetup; import net.minecraft.client.gui.render.state.GuiElementRenderState; import org.jetbrains.annotations.Nullable; +import org.joml.Matrix3x2fStack; import org.joml.Matrix3x2fc; import org.jspecify.annotations.NonNull; @@ -17,8 +19,10 @@ public record GradientShadowRenderState( float bottomY, int startColor, int endColor, - Matrix3x2fc pose, + Matrix3x2fStack pose, RenderPipeline pipeline, + int width, + int height, @Nullable ScreenRectangle scissorArea ) implements GuiElementRenderState { @@ -33,12 +37,12 @@ public void buildVertices(@NonNull VertexConsumer consumer) { } } @Override - public TextureSetup textureSetup() { + public @NonNull TextureSetup textureSetup() { return TextureSetup.noTexture(); } @Override - public @org.jspecify.annotations.Nullable ScreenRectangle bounds() { - return null; + public @Nullable ScreenRectangle bounds() { + return DrawHelper.createBounds(pose,scissorArea,points.getFirst()[0],points.getFirst()[1],width,height); } } \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/renderstates/InterpolatedCurveRenderState.java b/src/main/java/com/tanishisherewith/dynamichud/renderstates/InterpolatedCurveRenderState.java index 96031ee..78d4dbc 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/renderstates/InterpolatedCurveRenderState.java +++ b/src/main/java/com/tanishisherewith/dynamichud/renderstates/InterpolatedCurveRenderState.java @@ -2,11 +2,12 @@ import com.mojang.blaze3d.pipeline.RenderPipeline; import com.mojang.blaze3d.vertex.VertexConsumer; +import com.tanishisherewith.dynamichud.helpers.DrawHelper; import net.minecraft.client.gui.navigation.ScreenRectangle; import net.minecraft.client.gui.render.TextureSetup; import net.minecraft.client.gui.render.state.GuiElementRenderState; import org.jetbrains.annotations.Nullable; -import org.joml.Matrix3x2fc; +import org.joml.Matrix3x2fStack; import org.jspecify.annotations.NonNull; import java.util.List; @@ -15,18 +16,16 @@ public record InterpolatedCurveRenderState( List points, float thickness, int color, - Matrix3x2fc pose, + Matrix3x2fStack pose, RenderPipeline pipeline, + int width, + int height, @Nullable ScreenRectangle scissorArea ) implements GuiElementRenderState { @Override public void buildVertices(@NonNull VertexConsumer consumer) { - consumer.addVertexWith2DPose(pose, 10, 10).setColor(color); - consumer.addVertexWith2DPose(pose, 100, 10).setColor(color); - consumer.addVertexWith2DPose(pose, 10, 20).setColor(color); - consumer.addVertexWith2DPose(pose, 100, 20).setColor(color); - /* + consumer.setLineWidth(thickness); for (int i = 0; i < points.size(); i++) { float[] point = points.get(i); float x = point[0]; @@ -37,23 +36,21 @@ public void buildVertices(@NonNull VertexConsumer consumer) { float length = (float) Math.sqrt(dx * dx + dy * dy); if (length == 0) continue; - float offsetX = (thickness * 0.5f * dy) / length; - float offsetY = (thickness * 0.5f * -dx) / length; + float offsetX = (dy) / length; + float offsetY = (-dx) / length; consumer.addVertexWith2DPose(pose, x + offsetX, y + offsetY).setColor(color); consumer.addVertexWith2DPose(pose, x - offsetX, y - offsetY).setColor(color); } - - */ } @Override - public TextureSetup textureSetup() { + public @NonNull TextureSetup textureSetup() { return TextureSetup.noTexture(); } @Override public @Nullable ScreenRectangle bounds() { - return null; + return DrawHelper.createBounds(pose,scissorArea,points.getFirst()[0],points.getFirst()[1],width,height); } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/renderstates/QuadColorRectRenderState.java b/src/main/java/com/tanishisherewith/dynamichud/renderstates/QuadColorRectRenderState.java index 4921a73..4485440 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/renderstates/QuadColorRectRenderState.java +++ b/src/main/java/com/tanishisherewith/dynamichud/renderstates/QuadColorRectRenderState.java @@ -2,23 +2,23 @@ import com.mojang.blaze3d.pipeline.RenderPipeline; import com.mojang.blaze3d.vertex.VertexConsumer; +import com.tanishisherewith.dynamichud.helpers.DrawHelper; import net.minecraft.client.gui.navigation.ScreenRectangle; import net.minecraft.client.gui.render.TextureSetup; import net.minecraft.client.gui.render.state.GuiElementRenderState; -import org.joml.Matrix3x2f; +import org.joml.Matrix3x2fStack; import org.jspecify.annotations.Nullable; import java.awt.*; public record QuadColorRectRenderState( RenderPipeline pipeline, - Matrix3x2f pose, + Matrix3x2fStack pose, float x, float y, float width, float height, int[] color, - ScreenRectangle bounds, ScreenRectangle scissorArea ) implements GuiElementRenderState { @@ -37,6 +37,6 @@ public TextureSetup textureSetup() { @Override public @Nullable ScreenRectangle bounds() { - return this.scissorArea != null ? this.scissorArea.intersection(bounds) : this.bounds; + return DrawHelper.createBounds(pose,scissorArea,x,y,width,height); } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/renderstates/RoundedRectRenderState.java b/src/main/java/com/tanishisherewith/dynamichud/renderstates/RoundedRectRenderState.java index 01a6788..f7141c3 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/renderstates/RoundedRectRenderState.java +++ b/src/main/java/com/tanishisherewith/dynamichud/renderstates/RoundedRectRenderState.java @@ -2,56 +2,172 @@ import com.mojang.blaze3d.pipeline.RenderPipeline; import com.mojang.blaze3d.vertex.VertexConsumer; -import com.tanishisherewith.dynamichud.internal.IBufferBuilder; -import com.tanishisherewith.dynamichud.utils.CustomRenderLayers; +import com.tanishisherewith.dynamichud.helpers.DrawHelper; import net.minecraft.client.gui.navigation.ScreenRectangle; import net.minecraft.client.gui.render.TextureSetup; import net.minecraft.client.gui.render.state.GuiElementRenderState; import org.jetbrains.annotations.Nullable; -import org.joml.Matrix3x2fc; +import org.joml.Matrix3x2fStack; import org.joml.Vector4f; import org.jspecify.annotations.NonNull; +import static com.tanishisherewith.dynamichud.helpers.DrawHelper.COSA; +import static com.tanishisherewith.dynamichud.helpers.DrawHelper.SINA; + public record RoundedRectRenderState( RenderPipeline pipeline, - Matrix3x2fc pose, - float x, - float y, - float width, - float height, + Matrix3x2fStack pose, // Using Matrix3x2fc for 2D optimization + float x, float y, + float width, float height, float thickness, - int[] colors, - Vector4f roundness, - @Nullable ScreenRectangle scissorArea, - @Nullable ScreenRectangle bounds + int[] colors, // [TL, BL, BR, TR] + Vector4f roundness, // [x=TL, y=TR, z=BR, w=BL] + @Nullable ScreenRectangle scissorArea ) implements GuiElementRenderState { - @Override + @Override public void buildVertices(@NonNull VertexConsumer consumer) { - if (consumer instanceof IBufferBuilder builder) { - float[][] uvs = {{0, 0}, {0, 1}, {1, 1}, {1, 0}}; - float[][] coords = {{x, y}, {x, y + height}, {x + width, y + height}, {x + width, y}}; + if (thickness > 0) { + drawContinuousOutline(consumer); + } else { + drawFill(consumer); + } + } + + private int averageColors(int[] c) { + int r = 0, g = 0, b = 0, a = 0; + for (int color : c) { + a += (color >> 24) & 0xFF; + r += (color >> 16) & 0xFF; + g += (color >> 8) & 0xFF; + b += color & 0xFF; + } + return (a / 4 << 24) | (r / 4 << 16) | (g / 4 << 8) | (b / 4); + } + + private void drawFill(VertexConsumer consumer) { + float cx = x + (width / 2.0f); + float cy = y + (height / 2.0f); + float halfWidth = width * 0.5f; + float halfHeight = height * 0.5f; - for (int i = 0; i < 4; i++) { - consumer.addVertexWith2DPose(pose, coords[i][0], coords[i][1]) - .setColor(colors[i % colors.length]) - .setUv(uvs[i][0], uvs[i][1]); + // Start Fan at center + consumer.addVertexWith2DPose(pose, cx, cy).setColor(averageColors(colors)); + + // 1. Bottom-Right (Original i=0-9) + // Original logic: x0 = cx + (0.5f * dx), y0 = cy + (0.5f * dy) + float brRadius = roundness.z; + float dx = width - (brRadius * 2); // This is localized for the specific corner + float dy = height - (brRadius * 2); + + float x0 = cx + (0.5f * (width - brRadius * 2)); + float y0 = cy + (0.5f * (height - brRadius * 2)); + + if (brRadius > 0) { + for (int i = 0; i < 9; i++) { + // Using + for SINA to match your original: y = y0 + (r * sina[i]) + consumer.addVertexWith2DPose(pose, x0 + (brRadius * COSA[i]), y0 + (brRadius * SINA[i])).setColor(colors[2]); + } + } else { + consumer.addVertexWith2DPose(pose, cx + halfWidth, cy + halfHeight).setColor(colors[2]); + } + + // 2. Bottom-Left (Original i=9-18) + float blRadius = roundness.w; + x0 = cx - (0.5f * (width - blRadius * 2)); + y0 = cy + (0.5f * (height - blRadius * 2)); + if (blRadius > 0) { + for (int i = 9; i < 18; i++) { + consumer.addVertexWith2DPose(pose, x0 + (blRadius * COSA[i]), y0 + (blRadius * SINA[i])).setColor(colors[1]); + } + } else { + consumer.addVertexWith2DPose(pose, cx - halfWidth, cy + halfHeight).setColor(colors[1]); + } - builder.dynamicHUD$writeGenericFloats(CustomRenderLayers.ELM_WIDTH_HEIGHT, width, height); + // 3. Top-Left (Original i=18-27) + float tlRadius = roundness.x; + x0 = cx - (0.5f * (width - tlRadius * 2)); + y0 = cy - (0.5f * (height - tlRadius * 2)); + if (tlRadius > 0) { + for (int i = 18; i < 27; i++) { + consumer.addVertexWith2DPose(pose, x0 + (tlRadius * COSA[i]), y0 + (tlRadius * SINA[i])).setColor(colors[0]); + } + } else { + consumer.addVertexWith2DPose(pose, cx - halfWidth, cy - halfHeight).setColor(colors[0]); + } - builder.dynamicHUD$writeGenericFloats(CustomRenderLayers.ELM_ROUNDNESS, - roundness.x, roundness.y, roundness.z, roundness.w); + // 4. Top-Right (Original i=27-36) + float trRadius = roundness.y; + x0 = cx + (0.5f * (width - trRadius * 2)); + y0 = cy - (0.5f * (height - trRadius * 2)); + if (trRadius > 0) { + for (int i = 27; i < 36; i++) { + consumer.addVertexWith2DPose(pose, x0 + (trRadius * COSA[i]), y0 + (trRadius * SINA[i])).setColor(colors[3]); } + } else { + consumer.addVertexWith2DPose(pose, cx + halfWidth, cy - halfHeight).setColor(colors[3]); + } + + // 5. Final Closing Vertex (Matches your specific !BR logic) + if (roundness.z <= 0) { + consumer.addVertexWith2DPose(pose, cx + halfWidth, cy + halfHeight).setColor(colors[2]); + } else { + // Your original: buf.vertex(ma, x, cy + (0.5f * dy), 0) + // x here was the last calculated x (cx + halfWidth) + consumer.addVertexWith2DPose(pose, cx + halfWidth, cy + (0.5f * (height - brRadius * 2))).setColor(colors[2]); + } + } + + private void drawContinuousOutline(VertexConsumer consumer) { + consumer.setLineWidth(thickness); + float innerShift = thickness; + + // Quadrant 1: Top-Right (i=0-9) + float cx = x + width - roundness.y; + float cy = y + roundness.y; + walkArc(consumer, cx, cy, roundness.y, roundness.y - innerShift, colors[3], 0, 9); + + // Quadrant 2: Top-Left (i=9-18) + cx = x + roundness.x; + cy = y + roundness.x; + walkArc(consumer, cx, cy, roundness.x, roundness.x - innerShift, colors[0], 9, 18); + + // Quadrant 3: Bottom-Left (i=18-27) + cx = x + roundness.w; + cy = y + height - roundness.w; + walkArc(consumer, cx, cy, roundness.w, roundness.w - innerShift, colors[1], 18, 27); + + // Quadrant 4: Bottom-Right (i=27-36) + cx = x + width - roundness.z; + cy = y + height - roundness.z; + walkArc(consumer, cx, cy, roundness.z, roundness.z - innerShift, colors[2], 27, 36); + + // Close the loop back to the start of Quadrant 1 + float startX = x + width; + float startY = y + roundness.y; + consumer.addVertexWith2DPose(pose, startX, startY).setColor(colors[3]); + consumer.addVertexWith2DPose(pose, startX - innerShift, startY).setColor(colors[3]); + } + + /** + * Walks a specific corner arc, pushing vertices for both outer and inner radii. + */ + private void walkArc(VertexConsumer c, float cx, float cy, float outerR, float innerR, int color, int start, int end) { + for (int i = start; i <= end; i++) { + // Outer Ring Vertex + c.addVertexWith2DPose(pose, cx + (outerR * COSA[i]), cy - (outerR * SINA[i])).setColor(color); + // Inner Ring Vertex + c.addVertexWith2DPose(pose, cx + (innerR * COSA[i]), cy - (innerR * SINA[i])).setColor(color); } } @Override - public TextureSetup textureSetup() { + public @NonNull TextureSetup textureSetup() { return TextureSetup.noTexture(); } @Override - public @org.jspecify.annotations.Nullable ScreenRectangle bounds() { - return this.scissorArea != null ? this.scissorArea.intersection(this.bounds) : this.bounds; + public @Nullable ScreenRectangle bounds() { + return DrawHelper.createBounds(pose,scissorArea,x,y,width,height); } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/CustomRenderLayers.java b/src/main/java/com/tanishisherewith/dynamichud/utils/CustomRenderLayers.java index 5e395c3..d98fa06 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/CustomRenderLayers.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/CustomRenderLayers.java @@ -17,10 +17,24 @@ public class CustomRenderLayers { public static final RenderPipeline COLOR_LINE = RenderPipeline.builder() .withLocation(Identifier.fromNamespaceAndPath("dynamichud", "color_line")) .withVertexFormat(DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.DEBUG_LINES) - .withFragmentShader(Identifier.withDefaultNamespace("position_color")) - .withVertexShader(Identifier.withDefaultNamespace("position_color")) + .withFragmentShader(Identifier.withDefaultNamespace("core/position_color")) + .withVertexShader(Identifier.withDefaultNamespace("core/position_color")) .build(); + public static final RenderPipeline COLOR_TRIANGLES = RenderPipeline.builder() + .withLocation(Identifier.fromNamespaceAndPath("dynamichud", "color_triangles")) + .withVertexFormat(DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.TRIANGLES) + .withVertexShader(Identifier.withDefaultNamespace("core/position_color")) + .withFragmentShader(Identifier.withDefaultNamespace("core/position_color")) + .build(); + + public static RenderPipeline TRIANGLE_STRIP = RenderPipelines.register(RenderPipeline.builder(RenderPipelines.GUI_SNIPPET) + .withLocation(Identifier.fromNamespaceAndPath("dynamichud", "pipeline/triangle_strip")) + .withVertexFormat(DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.TRIANGLE_STRIP) + .withBlend(BlendFunction.TRANSLUCENT) + .build() + ); + // Width/Height in UV1 public static final VertexFormatElement ELM_WIDTH_HEIGHT = new VertexFormatElement(1, 2, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.UV, 8); @@ -76,12 +90,6 @@ public class CustomRenderLayers { .withBlend(new BlendFunction(SourceFactor.DST_ALPHA, DestFactor.ONE_MINUS_DST_ALPHA)) .build() ); - public static RenderPipeline TRIANGLE_STRIP = RenderPipelines.register(RenderPipeline.builder(RenderPipelines.GUI_SNIPPET) - .withLocation(Identifier.fromNamespaceAndPath("dynamichud", "pipeline/triangle_strip")) - .withVertexFormat(DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.TRIANGLE_STRIP) - .withBlend(BlendFunction.TRANSLUCENT) - .build() - ); /* private static final RenderPipeline ROUNDED = RenderPipelines.register(RenderPipeline.builder(RenderPipelines.MATRICES_PROJECTION_SNIPPET) diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java index 6d3b809..ae2f21b 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java @@ -135,7 +135,7 @@ public void renderContextMenu(GuiGraphics graphics, ContextMenu contextMenu, mouseY = (int) (mc.mouseHandler.ypos() / SCALE_FACTOR); // Apply custom scaling to counteract Minecraft's default scaling - DrawHelper.customScaledProjection(SCALE_FACTOR); + DrawHelper.scaledProjection(SCALE_FACTOR, graphics); updateContextDimensions(); contextMenu.set(contextMenuX, contextMenuY, 0); @@ -182,7 +182,7 @@ public void renderContextMenu(GuiGraphics graphics, ContextMenu contextMenu, renderToolTipText(graphics, mouseX, mouseY); //Reset our scaling so minecraft runs normally\ - DrawHelper.scaledProjection(); + DrawHelper.stopScaling(graphics.pose()); } private void updateContextDimensions() { diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java index 574ae6c..f17a7b8 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java @@ -167,17 +167,16 @@ private void drawInterpolatedCurve(GuiGraphics graphics, List points, i if (points.size() < 2) return; graphics.guiRenderState.submitGuiElement( - new InterpolatedCurveRenderState(points, thickness, color, graphics.pose(), CustomRenderLayers.QUADS_CUSTOM_BLEND, graphics.scissorStack.peek()) + new InterpolatedCurveRenderState(points, thickness, color, graphics.pose(), CustomRenderLayers.TRIANGLE_STRIP, (int) width, (int) height, graphics.scissorStack.peek()) ); } - // draw a gradient shadow under the curve private void drawGradientShadow(GuiGraphics graphics, List points, float bottomY, int startColor, int endColor) { if (points.size() < 2) return; - graphics.guiRenderState.submitGuiElement( - new GradientShadowRenderState(points,bottomY, startColor, endColor, graphics.pose(), CustomRenderLayers.TRIANGLE_STRIP, graphics.scissorStack.peek()) + graphics.guiRenderState.submitGuiElement( + new GradientShadowRenderState(points,bottomY, startColor, endColor, graphics.pose(), CustomRenderLayers.TRIANGLE_STRIP, (int) width, (int) height, graphics.scissorStack.peek()) ); } From 823921e573185b50cc02c0d949dc0227866574e9 Mon Sep 17 00:00:00 2001 From: tanishisherewith <120117618+tanishisherewithhh@users.noreply.github.com> Date: Sun, 12 Apr 2026 16:49:30 +0530 Subject: [PATCH 03/22] Finally got rounded rectangles to work. --- .../dynamichud/IntegrationTest.java | 1 + .../dynamichud/helpers/DrawHelper.java | 6 +- .../GradientShadowRenderState.java | 14 +- .../InterpolatedCurveRenderState.java | 39 ++-- .../QuadColorRectRenderState.java | 5 +- .../renderstates/RoundedRectRenderState.java | 195 ++++++------------ .../dynamichud/utils/CustomRenderLayers.java | 5 +- .../dynamichud/widgets/GraphWidget.java | 104 +++++++--- 8 files changed, 187 insertions(+), 182 deletions(-) diff --git a/src/main/java/com/tanishisherewith/dynamichud/IntegrationTest.java b/src/main/java/com/tanishisherewith/dynamichud/IntegrationTest.java index 1dd92c6..8b260b0 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/IntegrationTest.java +++ b/src/main/java/com/tanishisherewith/dynamichud/IntegrationTest.java @@ -87,6 +87,7 @@ public void init() { .setDraggable(true) .setDisplay(true) .showGrid(true) + .shouldScale(true) .registryKey("FPS") .registryID(registry.getId()) .build() diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java index 5373dc4..1e7790c 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java +++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java @@ -168,7 +168,7 @@ public static void drawOutlineRoundedBox(GuiGraphics graphics, float x, float y, int[] intColors = {tl.getRGB(),tr.getRGB(),br.getRGB(),bl.getRGB()}; graphics.guiRenderState.submitGuiElement(new RoundedRectRenderState( - CustomRenderLayers.TRIANGLE_FAN_CUSTOM_BLEND, + RenderPipelines.DEBUG_QUADS, graphics.pose(), x, y, width, height, thickness, intColors, radii, graphics.scissorStack.peek() )); @@ -465,7 +465,7 @@ public static void drawRoundedRectangle(GuiGraphics graphics, float x, float y, * @param color Color of the rounded.fsh rectangle */ public static void drawRoundedRectangle(GuiGraphics graphics, float x, float y, boolean TL, boolean TR, boolean BL, boolean BR, float width, float height, float radius, int color) { - Vector4f radii = new Vector4f(TR ? radius : 0.0f, BR ? radius : 0.0f, TL ? radius : 0.0f, BL ? radius : 0.0f); + Vector4f radii = new Vector4f(TL ? radius : 0.0f, TR ? radius : 0.0f, BR ? radius : 0.0f, BL ? radius : 0.0f); // Turns out Color class takes rgb by default not rgba Color c = new Color(color, true); @@ -495,7 +495,7 @@ public static void drawRoundedRectangle(GuiGraphics graphics, float x, float y, int[] intColors = {tl.getRGB(),tr.getRGB(),br.getRGB(),bl.getRGB()}; graphics.guiRenderState.submitGuiElement(new RoundedRectRenderState( - CustomRenderLayers.TRIANGLE_FAN_CUSTOM_BLEND, + RenderPipelines.DEBUG_QUADS, graphics.pose(), x, y, width, height, -1f, intColors, radii, graphics.scissorStack.peek() )); diff --git a/src/main/java/com/tanishisherewith/dynamichud/renderstates/GradientShadowRenderState.java b/src/main/java/com/tanishisherewith/dynamichud/renderstates/GradientShadowRenderState.java index 7a1375a..1c177d8 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/renderstates/GradientShadowRenderState.java +++ b/src/main/java/com/tanishisherewith/dynamichud/renderstates/GradientShadowRenderState.java @@ -28,12 +28,16 @@ public record GradientShadowRenderState( @Override public void buildVertices(@NonNull VertexConsumer consumer) { - for (float[] point : points) { - float x = point[0]; - float y = point[1]; + for (int i = 0; i < points.size() - 1; i++) { + float x1 = points.get(i)[0]; + float y1 = points.get(i)[1]; + float x2 = points.get(i + 1)[0]; + float y2 = points.get(i + 1)[1]; - consumer.addVertexWith2DPose(pose, x, y).setColor(startColor); - consumer.addVertexWith2DPose(pose, x, bottomY).setColor(endColor); + consumer.addVertexWith2DPose(pose, x1, y1).setColor(startColor); // Topleft + consumer.addVertexWith2DPose(pose, x1, bottomY).setColor(endColor); // Bottomleft + consumer.addVertexWith2DPose(pose, x2, bottomY).setColor(endColor); // Bottomright + consumer.addVertexWith2DPose(pose, x2, y2).setColor(startColor); // Topright } } @Override diff --git a/src/main/java/com/tanishisherewith/dynamichud/renderstates/InterpolatedCurveRenderState.java b/src/main/java/com/tanishisherewith/dynamichud/renderstates/InterpolatedCurveRenderState.java index 78d4dbc..07a9e7f 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/renderstates/InterpolatedCurveRenderState.java +++ b/src/main/java/com/tanishisherewith/dynamichud/renderstates/InterpolatedCurveRenderState.java @@ -26,21 +26,35 @@ public record InterpolatedCurveRenderState( @Override public void buildVertices(@NonNull VertexConsumer consumer) { consumer.setLineWidth(thickness); - for (int i = 0; i < points.size(); i++) { - float[] point = points.get(i); - float x = point[0]; - float y = point[1]; + if (points.size() < 2) return; - float dx = (i < points.size() - 1) ? points.get(i + 1)[0] - x : x - points.get(i - 1)[0]; - float dy = (i < points.size() - 1) ? points.get(i + 1)[1] - y : y - points.get(i - 1)[1]; + // build individual QUADS + for (int i = 0; i < points.size() - 1; i++) { + float[] p1 = points.get(i); + float[] p2 = points.get(i + 1); + + float x1 = p1[0]; + float y1 = p1[1]; + float x2 = p2[0]; + float y2 = p2[1]; + + float dx = x2 - x1; + float dy = y2 - y1; float length = (float) Math.sqrt(dx * dx + dy * dy); if (length == 0) continue; - float offsetX = (dy) / length; - float offsetY = (-dx) / length; + // normals for line thickness + float offsetX = (thickness * 0.5f * dy) / length; + float offsetY = (thickness * 0.5f * -dx) / length; - consumer.addVertexWith2DPose(pose, x + offsetX, y + offsetY).setColor(color); - consumer.addVertexWith2DPose(pose, x - offsetX, y - offsetY).setColor(color); + //Topleft + consumer.addVertexWith2DPose(pose, x1 + offsetX, y1 + offsetY).setColor(color); + //Bottomleft + consumer.addVertexWith2DPose(pose, x1 - offsetX, y1 - offsetY).setColor(color); + //Bottomright + consumer.addVertexWith2DPose(pose, x2 - offsetX, y2 - offsetY).setColor(color); + //Topright + consumer.addVertexWith2DPose(pose, x2 + offsetX, y2 + offsetY).setColor(color); } } @@ -51,6 +65,7 @@ public void buildVertices(@NonNull VertexConsumer consumer) { @Override public @Nullable ScreenRectangle bounds() { - return DrawHelper.createBounds(pose,scissorArea,points.getFirst()[0],points.getFirst()[1],width,height); + if (points.isEmpty()) return null; + return DrawHelper.createBounds(pose, scissorArea, points.getFirst()[0], points.getFirst()[1], width, height); } -} +} \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/renderstates/QuadColorRectRenderState.java b/src/main/java/com/tanishisherewith/dynamichud/renderstates/QuadColorRectRenderState.java index 4485440..e02892e 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/renderstates/QuadColorRectRenderState.java +++ b/src/main/java/com/tanishisherewith/dynamichud/renderstates/QuadColorRectRenderState.java @@ -7,10 +7,9 @@ import net.minecraft.client.gui.render.TextureSetup; import net.minecraft.client.gui.render.state.GuiElementRenderState; import org.joml.Matrix3x2fStack; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; -import java.awt.*; - public record QuadColorRectRenderState( RenderPipeline pipeline, Matrix3x2fStack pose, @@ -31,7 +30,7 @@ public void buildVertices(VertexConsumer vertices) { } @Override - public TextureSetup textureSetup() { + public @NonNull TextureSetup textureSetup() { return TextureSetup.noTexture(); } diff --git a/src/main/java/com/tanishisherewith/dynamichud/renderstates/RoundedRectRenderState.java b/src/main/java/com/tanishisherewith/dynamichud/renderstates/RoundedRectRenderState.java index f7141c3..4e39e3b 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/renderstates/RoundedRectRenderState.java +++ b/src/main/java/com/tanishisherewith/dynamichud/renderstates/RoundedRectRenderState.java @@ -16,149 +16,90 @@ public record RoundedRectRenderState( RenderPipeline pipeline, - Matrix3x2fStack pose, // Using Matrix3x2fc for 2D optimization + Matrix3x2fStack pose, float x, float y, float width, float height, float thickness, - int[] colors, // [TL, BL, BR, TR] - Vector4f roundness, // [x=TL, y=TR, z=BR, w=BL] + int[] colors, + Vector4f roundness, @Nullable ScreenRectangle scissorArea ) implements GuiElementRenderState { - @Override + @Override public void buildVertices(@NonNull VertexConsumer consumer) { - if (thickness > 0) { - drawContinuousOutline(consumer); - } else { - drawFill(consumer); - } - } - - private int averageColors(int[] c) { - int r = 0, g = 0, b = 0, a = 0; - for (int color : c) { - a += (color >> 24) & 0xFF; - r += (color >> 16) & 0xFF; - g += (color >> 8) & 0xFF; - b += color & 0xFF; - } - return (a / 4 << 24) | (r / 4 << 16) | (g / 4 << 8) | (b / 4); - } - - private void drawFill(VertexConsumer consumer) { - float cx = x + (width / 2.0f); - float cy = y + (height / 2.0f); - float halfWidth = width * 0.5f; - float halfHeight = height * 0.5f; - - // Start Fan at center - consumer.addVertexWith2DPose(pose, cx, cy).setColor(averageColors(colors)); - - // 1. Bottom-Right (Original i=0-9) - // Original logic: x0 = cx + (0.5f * dx), y0 = cy + (0.5f * dy) - float brRadius = roundness.z; - float dx = width - (brRadius * 2); // This is localized for the specific corner - float dy = height - (brRadius * 2); - - float x0 = cx + (0.5f * (width - brRadius * 2)); - float y0 = cy + (0.5f * (height - brRadius * 2)); - - if (brRadius > 0) { - for (int i = 0; i < 9; i++) { - // Using + for SINA to match your original: y = y0 + (r * sina[i]) - consumer.addVertexWith2DPose(pose, x0 + (brRadius * COSA[i]), y0 + (brRadius * SINA[i])).setColor(colors[2]); + float fX = 0, fY = 0, fIX = 0, fIY = 0; + int fC = 0; + float pX = 0, pY = 0, pIX = 0, pIY = 0; + int pC = 0; + + float midX = x + (width * 0.5f); + float midY = y + (height * 0.5f); + int midC = (thickness <= 0) ? averageColors(colors) : 0; + + // 9 steps per quadrant to match the 360 precomputed tables + for (int k = 0; k <= 36; k++) { + int i = k % 36; + float r, cx, cy; + int color; + + // Quadrants:- 0-8:BR, 9-17:BL, 18-26:TL, 27-35:TR + if (i < 9) { + r = roundness.z; cx = x + width - r; cy = y + height - r; color = colors[2]; + } else if (i < 18) { + r = roundness.w; cx = x + r; cy = y + height - r; color = colors[3]; + } else if (i < 27) { + r = roundness.x; cx = x + r; cy = y + r; color = colors[0]; + } else { + r = roundness.y; cx = x + width - r; cy = y + r; color = colors[1]; } - } else { - consumer.addVertexWith2DPose(pose, cx + halfWidth, cy + halfHeight).setColor(colors[2]); - } - // 2. Bottom-Left (Original i=9-18) - float blRadius = roundness.w; - x0 = cx - (0.5f * (width - blRadius * 2)); - y0 = cy + (0.5f * (height - blRadius * 2)); - if (blRadius > 0) { - for (int i = 9; i < 18; i++) { - consumer.addVertexWith2DPose(pose, x0 + (blRadius * COSA[i]), y0 + (blRadius * SINA[i])).setColor(colors[1]); - } - } else { - consumer.addVertexWith2DPose(pose, cx - halfWidth, cy + halfHeight).setColor(colors[1]); - } + float cX = cx + (r * COSA[i]); + float cY = cy + (r * SINA[i]); + float cIX = 0, cIY = 0; - // 3. Top-Left (Original i=18-27) - float tlRadius = roundness.x; - x0 = cx - (0.5f * (width - tlRadius * 2)); - y0 = cy - (0.5f * (height - tlRadius * 2)); - if (tlRadius > 0) { - for (int i = 18; i < 27; i++) { - consumer.addVertexWith2DPose(pose, x0 + (tlRadius * COSA[i]), y0 + (tlRadius * SINA[i])).setColor(colors[0]); + if (thickness > 0) { + // clamping inner radius to 0 + float ir = Math.max(0, r - thickness); + cIX = cx + (ir * COSA[i]); + cIY = cy + (ir * SINA[i]); } - } else { - consumer.addVertexWith2DPose(pose, cx - halfWidth, cy - halfHeight).setColor(colors[0]); - } - // 4. Top-Right (Original i=27-36) - float trRadius = roundness.y; - x0 = cx + (0.5f * (width - trRadius * 2)); - y0 = cy - (0.5f * (height - trRadius * 2)); - if (trRadius > 0) { - for (int i = 27; i < 36; i++) { - consumer.addVertexWith2DPose(pose, x0 + (trRadius * COSA[i]), y0 + (trRadius * SINA[i])).setColor(colors[3]); + if (k == 0) { + // Cache the first vertex set to ensure pixel-perfect loop closure + fX = cX; fY = cY; fIX = cIX; fIY = cIY; fC = color; + } else { + float tX = (k == 36) ? fX : cX; + float tY = (k == 36) ? fY : cY; + float tIX = (k == 36) ? fIX : cIX; + float tIY = (k == 36) ? fIY : cIY; + int tC = (k == 36) ? fC : color; + + if (thickness > 0) { + consumer.addVertexWith2DPose(pose, pX, pY).setColor(pC); + consumer.addVertexWith2DPose(pose, pIX, pIY).setColor(pC); + consumer.addVertexWith2DPose(pose, tIX, tIY).setColor(tC); + consumer.addVertexWith2DPose(pose, tX, tY).setColor(tC); + } else { + consumer.addVertexWith2DPose(pose, midX, midY).setColor(midC); + consumer.addVertexWith2DPose(pose, pX, pY).setColor(pC); + consumer.addVertexWith2DPose(pose, tX, tY).setColor(tC); + consumer.addVertexWith2DPose(pose, tX, tY).setColor(tC); + } } - } else { - consumer.addVertexWith2DPose(pose, cx + halfWidth, cy - halfHeight).setColor(colors[3]); - } - // 5. Final Closing Vertex (Matches your specific !BR logic) - if (roundness.z <= 0) { - consumer.addVertexWith2DPose(pose, cx + halfWidth, cy + halfHeight).setColor(colors[2]); - } else { - // Your original: buf.vertex(ma, x, cy + (0.5f * dy), 0) - // x here was the last calculated x (cx + halfWidth) - consumer.addVertexWith2DPose(pose, cx + halfWidth, cy + (0.5f * (height - brRadius * 2))).setColor(colors[2]); + pX = cX; pY = cY; pIX = cIX; pIY = cIY; pC = color; } } - private void drawContinuousOutline(VertexConsumer consumer) { - consumer.setLineWidth(thickness); - float innerShift = thickness; - - // Quadrant 1: Top-Right (i=0-9) - float cx = x + width - roundness.y; - float cy = y + roundness.y; - walkArc(consumer, cx, cy, roundness.y, roundness.y - innerShift, colors[3], 0, 9); - - // Quadrant 2: Top-Left (i=9-18) - cx = x + roundness.x; - cy = y + roundness.x; - walkArc(consumer, cx, cy, roundness.x, roundness.x - innerShift, colors[0], 9, 18); - - // Quadrant 3: Bottom-Left (i=18-27) - cx = x + roundness.w; - cy = y + height - roundness.w; - walkArc(consumer, cx, cy, roundness.w, roundness.w - innerShift, colors[1], 18, 27); - - // Quadrant 4: Bottom-Right (i=27-36) - cx = x + width - roundness.z; - cy = y + height - roundness.z; - walkArc(consumer, cx, cy, roundness.z, roundness.z - innerShift, colors[2], 27, 36); - - // Close the loop back to the start of Quadrant 1 - float startX = x + width; - float startY = y + roundness.y; - consumer.addVertexWith2DPose(pose, startX, startY).setColor(colors[3]); - consumer.addVertexWith2DPose(pose, startX - innerShift, startY).setColor(colors[3]); - } - - /** - * Walks a specific corner arc, pushing vertices for both outer and inner radii. - */ - private void walkArc(VertexConsumer c, float cx, float cy, float outerR, float innerR, int color, int start, int end) { - for (int i = start; i <= end; i++) { - // Outer Ring Vertex - c.addVertexWith2DPose(pose, cx + (outerR * COSA[i]), cy - (outerR * SINA[i])).setColor(color); - // Inner Ring Vertex - c.addVertexWith2DPose(pose, cx + (innerR * COSA[i]), cy - (innerR * SINA[i])).setColor(color); + private int averageColors(int[] c) { + int r = 0, g = 0, b = 0, a = 0; + for (int color : c) { + a += (color >> 24) & 0xFF; + r += (color >> 16) & 0xFF; + g += (color >> 8) & 0xFF; + b += color & 0xFF; } + return ((a / 4) << 24) | ((r / 4) << 16) | ((g / 4) << 8) | (b / 4); } @Override @@ -168,6 +109,6 @@ private void walkArc(VertexConsumer c, float cx, float cy, float outerR, float i @Override public @Nullable ScreenRectangle bounds() { - return DrawHelper.createBounds(pose,scissorArea,x,y,width,height); + return DrawHelper.createBounds(pose, scissorArea, x, y, width, height); } -} +} \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/CustomRenderLayers.java b/src/main/java/com/tanishisherewith/dynamichud/utils/CustomRenderLayers.java index d98fa06..8291909 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/CustomRenderLayers.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/CustomRenderLayers.java @@ -30,8 +30,7 @@ public class CustomRenderLayers { public static RenderPipeline TRIANGLE_STRIP = RenderPipelines.register(RenderPipeline.builder(RenderPipelines.GUI_SNIPPET) .withLocation(Identifier.fromNamespaceAndPath("dynamichud", "pipeline/triangle_strip")) - .withVertexFormat(DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.TRIANGLE_STRIP) - .withBlend(BlendFunction.TRANSLUCENT) + .withVertexFormat(DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.TRIANGLES) .build() ); @@ -87,7 +86,7 @@ public class CustomRenderLayers { public static RenderPipeline TRIANGLE_FAN_CUSTOM_BLEND = RenderPipelines.register(RenderPipeline.builder(RenderPipelines.GUI_SNIPPET) .withLocation(Identifier.fromNamespaceAndPath("dynamichud", "pipeline/triangle_fan_custom_blend_func")) .withVertexFormat(DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.TRIANGLE_FAN) - .withBlend(new BlendFunction(SourceFactor.DST_ALPHA, DestFactor.ONE_MINUS_DST_ALPHA)) + // .withBlend(new BlendFunction(SourceFactor.DST_ALPHA, DestFactor.ONE_MINUS_DST_ALPHA)) .build() ); diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java index f17a7b8..a9b0ac3 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java @@ -7,7 +7,6 @@ import com.tanishisherewith.dynamichud.renderstates.InterpolatedCurveRenderState; import com.tanishisherewith.dynamichud.utils.CustomRenderLayers; import com.tanishisherewith.dynamichud.utils.DynamicValueRegistry; -import com.tanishisherewith.dynamichud.utils.Util; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenu; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenuManager; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenuProperties; @@ -21,7 +20,6 @@ import com.tanishisherewith.dynamichud.widget.WidgetData; import com.twelvemonkeys.lang.Validate; import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.gui.render.TextureSetup; import net.minecraft.client.renderer.RenderPipelines; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; @@ -57,7 +55,7 @@ public class GraphWidget extends DynamicValueWidget implements ContextMenuProvid private boolean autoUpdateRange = false; private float stepY; private float valueStep; - private float scale; + private float valueScale; int offset = -2; public GraphWidget(String registryID, String registryKey, String modId, Anchor anchor, float width, float height, int maxDataPoints, float minValue, float maxValue, Color graphColor, Color backgroundColor, float lineThickness, boolean showGrid, int gridLines, String label) { @@ -87,7 +85,7 @@ private void internal_init() { this.widgetBox = new WidgetBox(x, y, (int) width, (int) height); this.stepY = height / (gridLines + 1); this.valueStep = (maxValue - minValue) / (gridLines + 1); - this.scale = (float) Math.clamp((stepY / 9.5), 0.0f, 1.0f); + this.valueScale = (float) Math.clamp((stepY / 9.5), 0.0f, 1.0f); computeOffset(); @@ -137,26 +135,72 @@ private List getInterpolatedPoints() { if (dataPoints.length < 2) return points; float xStep = width / (dataPoints.length - 1); - for (int i = 0; i < dataPoints.length - 1; i++) { - int index1 = (head + i) % dataPoints.length; - int index2 = (head + i + 1) % dataPoints.length; + float range = Math.max(maxValue - minValue, 0.0001f); + + //Pre-calculate Y coordinates + float[] yVals = new float[dataPoints.length]; + for (int i = 0; i < dataPoints.length; i++) { + int index = (head + i) % dataPoints.length; + yVals[i] = y + height - ((dataPoints[index] - minValue) / range * height); + } + + // Monotone Cubic Spline (Fritsch-Carlson) calculation + float[] m = new float[dataPoints.length]; + for (int i = 0; i < dataPoints.length; i++) { + if (i == 0) { + m[i] = yVals[1] - yVals[0]; + } else if (i == dataPoints.length - 1) { + m[i] = yVals[dataPoints.length - 1] - yVals[dataPoints.length - 2]; + } else { + float sPrev = yVals[i] - yVals[i - 1]; + float sNext = yVals[i + 1] - yVals[i]; + + if (sPrev * sNext <= 0) { + m[i] = 0; // Local peak/valley so clamp tangent to prevent overshoot + } else { + m[i] = (sPrev + sNext) / 2.0f; + // Clamp tangent magnitude to max 3x of smallest secant + float maxMag = 3.0f * Math.min(Math.abs(sPrev), Math.abs(sNext)); + if (Math.abs(m[i]) > maxMag) { + m[i] = Math.signum(m[i]) * maxMag; + } + } + } + } - float x1 = x + i * xStep; - float y1 = y + height - ((dataPoints[index1] - minValue) / (maxValue - minValue) * height); - float x2 = x + (i + 1) * xStep; - float y2 = y + height - ((dataPoints[index2] - minValue) / (maxValue - minValue) * height); + //Generate curve with distance filtering to fix tearing + for (int i = 0; i < dataPoints.length - 1; i++) { + float y0 = yVals[i]; + float y1 = yVals[i + 1]; + float m0 = m[i]; + float m1 = m[i + 1]; + float x0 = x + i * xStep; - // Add interpolated points using hermite spline (simplified) - for (float t = 0; t <= 1; t += 0.03f) { + for (float t = 0; t <= 1.0f; t += 0.05f) { float t2 = t * t; float t3 = t2 * t; + + // Hermite basis functions float h00 = 2 * t3 - 3 * t2 + 1; float h10 = t3 - 2 * t2 + t; float h01 = -2 * t3 + 3 * t2; - - float px = h00 * x1 + h10 * xStep + h01 * x2; - float py = h00 * y1 + h10 * (y2 - y1) + h01 * y2; - points.add(new float[]{px, py}); + float h11 = t3 - t2; + + float px = x0 + t * xStep; + float py = h00 * y0 + h10 * m0 + h01 * y1 + h11 * m1; + + // Vertex Simplifier: Only add point if it moved a safe distance. + // This prevents float-precision "divide by zero" errors when normals are + if (points.isEmpty()) { + points.add(new float[]{px, py}); + } else { + float[] lastP = points.get(points.size() - 1); + float distSq = (px - lastP[0]) * (px - lastP[0]) + (py - lastP[1]) * (py - lastP[1]); + // Add only if distance is safe OR if it's the strict end of the segment + if (distSq > 0.5f || t >= 0.99f) { + points.add(new float[]{px, py}); + } + } } } return points; @@ -167,7 +211,7 @@ private void drawInterpolatedCurve(GuiGraphics graphics, List points, i if (points.size() < 2) return; graphics.guiRenderState.submitGuiElement( - new InterpolatedCurveRenderState(points, thickness, color, graphics.pose(), CustomRenderLayers.TRIANGLE_STRIP, (int) width, (int) height, graphics.scissorStack.peek()) + new InterpolatedCurveRenderState(points, thickness, color, graphics.pose(), CustomRenderLayers.QUADS_CUSTOM_BLEND, (int) width, (int) height, graphics.scissorStack.peek()) ); } @@ -176,7 +220,7 @@ private void drawGradientShadow(GuiGraphics graphics, List points, floa if (points.size() < 2) return; graphics.guiRenderState.submitGuiElement( - new GradientShadowRenderState(points,bottomY, startColor, endColor, graphics.pose(), CustomRenderLayers.TRIANGLE_STRIP, (int) width, (int) height, graphics.scissorStack.peek()) + new GradientShadowRenderState(points,bottomY, startColor, endColor, graphics.pose(), RenderPipelines.DEBUG_QUADS, (int) width, (int) height, graphics.scissorStack.peek()) ); } @@ -212,7 +256,7 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { // Draw grid lines and value markings if (showGrid) { - //TODO: The scale is too small when no. of grid lines is greater than 21 (20 is the barely visible threshold) + //TODO: The valueScale is too small when no. of grid lines is greater than 21 (20 is the barely visible threshold) for (int i = 1; i <= gridLines; i++) { float yPos = y + stepY * i; @@ -222,11 +266,11 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { float value = maxValue - (i * valueStep); String valueText = formatValue(value); - float texWidth = mc.font.width(valueText) * scale; + float texWidth = mc.font.width(valueText) * valueScale; //Scale the Component to its proper position and size with grid lines - DrawHelper.scaleAndPosition(graphics.pose(), x - 2, yPos, scale); - graphics.drawString(mc.font, valueText, Math.round(x + offset - texWidth), (int) (yPos - (mc.font.lineHeight * scale) / 2.0f), 0xFFFFFFFF, true); + DrawHelper.scaleAndPosition(graphics.pose(), x - 2, yPos, valueScale); + graphics.drawString(mc.font, valueText, Math.round(x + offset - texWidth), (int) (yPos - (mc.font.lineHeight * valueScale) / 2.0f), 0xFFFFFFFF, true); DrawHelper.stopScaling(graphics.pose()); } @@ -241,16 +285,18 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { } } - // Draw interpolated graph curve List points = getInterpolatedPoints(); - drawInterpolatedCurve(graphics, points, graphColor.getRGB(), lineThickness); // Draw shadow effect under the graph drawGradientShadow( graphics, points, y + height, - ColorHelper.changeAlpha(graphColor, 50).getRGB(), + ColorHelper.changeAlpha(graphColor, 100).getRGB(), 0x00000000 ); + + // Draw interpolated graph curve + drawInterpolatedCurve(graphics, points, graphColor.getRGB(), lineThickness); + DrawHelper.drawChromaText( graphics, label, x + 5, y + 5, @@ -345,8 +391,8 @@ private void computeOffset(){ String lastText = formatValue(maxValue - (gridLines * valueStep)); offset = Math.max( - (int) Math.ceil(mc.font.width(firstText) * this.scale), - (int) Math.ceil(mc.font.width(lastText) * this.scale) + (int) Math.ceil(mc.font.width(firstText) * this.valueScale), + (int) Math.ceil(mc.font.width(lastText) * this.valueScale) ); } @@ -428,7 +474,7 @@ public void setGridLines(int gridLines) { this.gridLines = gridLines; this.stepY = height / (gridLines + 1); this.valueStep = (maxValue - minValue) / (gridLines + 1); - this.scale = (float) Math.clamp((stepY / 9.5), 0.0f, 1.0f); + this.valueScale = (float) Math.clamp((stepY / 9.5), 0.0f, 1.0f); } public boolean isShowGrid() { From 4ca5a1d4ffad2b5956cd4648d774ac517b9c0226 Mon Sep 17 00:00:00 2001 From: tanishisherewith <120117618+tanishisherewithhh@users.noreply.github.com> Date: Sun, 12 Apr 2026 16:55:52 +0530 Subject: [PATCH 04/22] Refactor GlobalConfig.get().getScale() --- .../com/tanishisherewith/dynamichud/DynamicHUD.java | 10 ++++++++++ .../com/tanishisherewith/dynamichud/widget/Widget.java | 5 +++-- .../dynamichud/widgets/GraphWidget.java | 4 ++-- .../dynamichud/widgets/ItemWidget.java | 3 ++- .../dynamichud/widgets/TextWidget.java | 3 ++- 5 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/tanishisherewith/dynamichud/DynamicHUD.java b/src/main/java/com/tanishisherewith/dynamichud/DynamicHUD.java index 53dc955..43b9b99 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/DynamicHUD.java +++ b/src/main/java/com/tanishisherewith/dynamichud/DynamicHUD.java @@ -70,4 +70,14 @@ public void onInitializeClient() { ClientTickEvents.END_CLIENT_TICK.register(mc-> MouseColorQuery.processIfPending()); } + + /** + * Get applied scale on all widgets, modified by YACL. + *
+ * From {@link GlobalConfig#getScale()} + * @return scale in float + */ + public static float getGlobalScale() { + return GlobalConfig.get().getScale(); + } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/widget/Widget.java b/src/main/java/com/tanishisherewith/dynamichud/widget/Widget.java index 74d4c56..5c6a89c 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widget/Widget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widget/Widget.java @@ -1,5 +1,6 @@ package com.tanishisherewith.dynamichud.widget; +import com.tanishisherewith.dynamichud.DynamicHUD; import com.tanishisherewith.dynamichud.config.GlobalConfig; import com.tanishisherewith.dynamichud.helpers.DrawHelper; import com.tanishisherewith.dynamichud.internal.UID; @@ -163,7 +164,7 @@ public final void render(GuiGraphics graphics, int mouseX, int mouseY) { if (shouldScale) { - DrawHelper.scaleAndPosition(graphics.pose(), getX(), getY(), GlobalConfig.get().getScale()); + DrawHelper.scaleAndPosition(graphics.pose(), getX(), getY(), DynamicHUD.getGlobalScale()); } renderWidget(graphics, mouseX, mouseY); @@ -182,7 +183,7 @@ public final void renderInEditor(GuiGraphics graphics, int mouseX, int mouseY) { drawWidgetBackground(graphics); if (shouldScale) { - DrawHelper.scaleAndPosition(graphics.pose(), getX(), getY(), GlobalConfig.get().getScale()); + DrawHelper.scaleAndPosition(graphics.pose(), getX(), getY(), DynamicHUD.getGlobalScale()); } renderWidgetInEditor(graphics, mouseX, mouseY); diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java index a9b0ac3..4ccd082 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java @@ -1,6 +1,6 @@ package com.tanishisherewith.dynamichud.widgets; -import com.tanishisherewith.dynamichud.config.GlobalConfig; +import com.tanishisherewith.dynamichud.DynamicHUD; import com.tanishisherewith.dynamichud.helpers.ColorHelper; import com.tanishisherewith.dynamichud.helpers.DrawHelper; import com.tanishisherewith.dynamichud.renderstates.GradientShadowRenderState; @@ -324,7 +324,7 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { if(showGrid) x -= offset; - this.widgetBox.setDimensions(x, y, width + offset, height, shouldScale, GlobalConfig.get().getScale()); + this.widgetBox.setDimensions(x, y, width + offset, height, shouldScale, DynamicHUD.getGlobalScale()); // DrawHelper.disableScissor(); if (menu != null) menu.set(getX(), getY(), (int) Math.ceil(getHeight())); diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/ItemWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/ItemWidget.java index 48bd7ac..edb1c71 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/ItemWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/ItemWidget.java @@ -1,5 +1,6 @@ package com.tanishisherewith.dynamichud.widgets; +import com.tanishisherewith.dynamichud.DynamicHUD; import com.tanishisherewith.dynamichud.config.GlobalConfig; import com.tanishisherewith.dynamichud.widget.Widget; import com.tanishisherewith.dynamichud.widget.WidgetData; @@ -27,7 +28,7 @@ public ItemWidget() { @Override public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { graphics.renderItem(item, x, y); - widgetBox.setDimensions(getX(), getY(), 16, 16, this.shouldScale, GlobalConfig.get().getScale()); + widgetBox.setDimensions(getX(), getY(), 16, 16, this.shouldScale, DynamicHUD.getGlobalScale()); } @Override diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java index a286d51..25beeca 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java @@ -1,5 +1,6 @@ package com.tanishisherewith.dynamichud.widgets; +import com.tanishisherewith.dynamichud.DynamicHUD; import com.tanishisherewith.dynamichud.config.GlobalConfig; import com.tanishisherewith.dynamichud.helpers.DrawHelper; import com.tanishisherewith.dynamichud.utils.DynamicValueRegistry; @@ -142,7 +143,7 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { } else { graphics.drawString(mc.font, Component, getX() + 2, getY() + 2, color, shadow); } - widgetBox.setDimensions(getX(), getY(), mc.font.width(Component) + 3, mc.font.lineHeight + 2, this.shouldScale, GlobalConfig.get().getScale()); + widgetBox.setDimensions(getX(), getY(), mc.font.width(Component) + 3, mc.font.lineHeight + 2, this.shouldScale, DynamicHUD.getGlobalScale()); } menu.set(getX(), getY(), (int) Math.ceil(getHeight())); From a546a2ffa87ce74dbe3711f2562fdef406c32351 Mon Sep 17 00:00:00 2001 From: tanishisherewith <120117618+tanishisherewithhh@users.noreply.github.com> Date: Wed, 17 Jun 2026 00:10:45 +0530 Subject: [PATCH 05/22] Better animations to context menu Patches for 1.21.11 Refactor to improve package names Made rounded rectangles and circles work Fix mouse actions in context menu Improvements to library --- .../dynamichud/helpers/ColorHelper.java | 4 + .../dynamichud/helpers/DrawHelper.java | 59 ++-- .../animationhelper/AnimationProperty.java | 1 - .../animations/MathAnimations.java | 2 +- .../integration/IntegrationManager.java | 6 +- .../dynamichud/mixins/BufferBuilderMixin.java | 5 +- .../renderstates/GeometryRenderState.java | 24 +- .../GradientShadowRenderState.java | 4 +- .../InterpolatedCurveRenderState.java | 4 +- .../QuadColorRectRenderState.java | 4 +- .../renderstates/RoundedRectRenderState.java | 7 +- .../utils/contextmenu/ContextMenu.java | 119 +++++-- .../contextmenu/ContextMenuProperties.java | 10 + .../contextmenu/layout/LayoutEngine.java | 166 +++++++++ .../contextmenu/options/BooleanOption.java | 1 - .../contextmenu/options/ColorOption.java | 11 +- .../contextmenu/options/DoubleOption.java | 12 +- .../utils/contextmenu/options/EnumOption.java | 4 +- .../utils/contextmenu/options/ListOption.java | 4 +- .../utils/contextmenu/options/Option.java | 1 + .../contextmenu/options/OptionGroup.java | 18 +- .../contextmenu/options/RunnableOption.java | 20 +- .../contextmenu/options/SubMenuOption.java | 18 +- .../options/coloroption/ColorGradient.java | 9 +- .../ContextMenuScreen.java | 4 +- .../ContextMenuScreenRegistry.java | 2 +- .../factory}/ContextMenuScreenFactory.java | 2 +- .../DefaultContextMenuScreenFactory.java | 3 +- .../contextmenu/skinsystem/ClassicSkin.java | 150 ++------- .../contextmenu/skinsystem/MinecraftSkin.java | 150 ++++++--- .../contextmenu/skinsystem/ModernSkin.java | 314 ++++++++---------- .../utils/contextmenu/skinsystem/Skin.java | 2 +- .../dynamichud/widget/WidgetRenderer.java | 2 +- .../dynamichud/widgets/GraphWidget.java | 10 +- .../dynamichud/widgets/TextWidget.java | 82 ++--- 35 files changed, 740 insertions(+), 494 deletions(-) create mode 100644 src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/layout/LayoutEngine.java rename src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/{contextmenuscreen => screen}/ContextMenuScreen.java (94%) rename src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/{contextmenuscreen => screen}/ContextMenuScreenRegistry.java (77%) rename src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/{contextmenuscreen => screen/factory}/ContextMenuScreenFactory.java (89%) rename src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/{contextmenuscreen => screen/factory}/DefaultContextMenuScreenFactory.java (78%) diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/ColorHelper.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/ColorHelper.java index 1e59066..c6894ce 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/helpers/ColorHelper.java +++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/ColorHelper.java @@ -37,6 +37,10 @@ public class ColorHelper { public static int r, g, b, a; + // Used in [ClassicSkin.java] + public static Color DARK_RED = new Color(116, 0, 0); + public static Color DARK_GREEN = new Color(24, 132, 0, 226); + public ColorHelper(int r, int g, int b, int a) { ColorHelper.r = r; ColorHelper.g = g; diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java index 1e7790c..ffac337 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java +++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java @@ -5,6 +5,7 @@ import com.tanishisherewith.dynamichud.renderstates.RoundedRectRenderState; import com.tanishisherewith.dynamichud.utils.CustomRenderLayers; import com.tanishisherewith.dynamichud.widget.WidgetBox; +import net.fabricmc.fabric.api.renderer.v1.render.RenderLayerHelper; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.navigation.ScreenRectangle; @@ -13,6 +14,7 @@ import net.minecraft.util.ARGB; import net.minecraft.util.Util; import org.jetbrains.annotations.NotNull; +import org.joml.Matrix3x2f; import org.joml.Matrix3x2fStack; import org.joml.Vector4f; @@ -31,6 +33,7 @@ public class DrawHelper { static { // Cosa is simply Sina shifted by 90 degrees (9 steps) System.arraycopy(SINA, 9, COSA, 0, 36); + System.arraycopy(SINA, 9, COSA, 36, 9); } /** @@ -53,7 +56,7 @@ public static void drawGradient(GuiGraphics g, float x, float y, float width, fl }; g.guiRenderState.submitGuiElement( - new QuadColorRectRenderState(RenderPipelines.GUI,g.pose(),x,y,width,height,c, + new QuadColorRectRenderState(RenderPipelines.GUI,new Matrix3x2f(g.pose()),x,y,width,height,c, g.scissorStack.peek()) ); } @@ -169,7 +172,7 @@ public static void drawOutlineRoundedBox(GuiGraphics graphics, float x, float y, graphics.guiRenderState.submitGuiElement(new RoundedRectRenderState( RenderPipelines.DEBUG_QUADS, - graphics.pose(), + new Matrix3x2f(graphics.pose()), x, y, width, height, thickness, intColors, radii, graphics.scissorStack.peek() )); } @@ -236,7 +239,7 @@ public static void drawOutlineCircle(GuiGraphics graphics, float xCenter, float graphics.guiRenderState.submitGuiElement(new GeometryRenderState( CustomRenderLayers.TRIANGLE_STRIP, - graphics.pose(), + new Matrix3x2f(graphics.pose()), verts, colors, graphics.scissorStack.peek() )); } @@ -250,25 +253,33 @@ public static void drawOutlineCircle(GuiGraphics graphics, float xCenter, float * @param color color of the circle outline */ public static void drawFilledCircle(GuiGraphics graphics, float xCenter, float yCenter, float radius, int color) { - int segments = 72; // 5-degree steps for smoothness - float[] verts = new float[(segments + 2) * 2]; - int[] colors = new int[segments + 2]; - - // Center point - verts[0] = xCenter; verts[1] = yCenter; - colors[0] = color; - - for (int i = 0; i <= segments; i++) { - float rad = (float) Math.toRadians(i * 5); - int idx = (i + 1) * 2; - verts[idx] = xCenter + (float) Math.sin(rad) * radius; - verts[idx + 1] = yCenter + (float) Math.cos(rad) * radius; - colors[i + 1] = color; + int segments = 36; + float[] verts = new float[segments * 4 * 2]; + int[] colors = new int[segments * 4]; + + int vIdx = 0; + int cIdx = 0; + + for (int i = 0; i < segments; i++) { + float x1 = xCenter + SINA[i] * radius; + float y1 = yCenter + COSA[i] * radius; + float x2 = xCenter + SINA[i + 1] * radius; + float y2 = yCenter + COSA[i + 1] * radius; + + verts[vIdx++] = xCenter; verts[vIdx++] = yCenter; + verts[vIdx++] = x1; verts[vIdx++] = y1; + verts[vIdx++] = x2; verts[vIdx++] = y2; + verts[vIdx++] = x2; verts[vIdx++] = y2; + + colors[cIdx++] = color; + colors[cIdx++] = color; + colors[cIdx++] = color; + colors[cIdx++] = color; } graphics.guiRenderState.submitGuiElement(new GeometryRenderState( - CustomRenderLayers.TRIANGLE_FAN_CUSTOM_BLEND, - graphics.pose(), + CustomRenderLayers.QUADS_CUSTOM_BLEND, + new Matrix3x2f(graphics.pose()), verts, colors, graphics.scissorStack.peek() )); } @@ -324,7 +335,7 @@ public static void drawFilledGradientQuadrant(GuiGraphics graphics, float xCente graphics.guiRenderState.submitGuiElement(new GeometryRenderState( CustomRenderLayers.TRIANGLE_FAN_CUSTOM_BLEND, - graphics.pose(), + new Matrix3x2f(graphics.pose()), verts, colors, graphics.scissorStack.peek() )); } @@ -364,7 +375,7 @@ public static void drawArc(GuiGraphics graphics, float xCenter, float yCenter, f graphics.guiRenderState.submitGuiElement(new GeometryRenderState( CustomRenderLayers.TRIANGLE_FAN_CUSTOM_BLEND, - graphics.pose(), + new Matrix3x2f(graphics.pose()), verts, colors, graphics.scissorStack.peek() )); } @@ -399,7 +410,7 @@ public static void drawOutlineTriangle(GuiGraphics graphics, int x1, int y1, int graphics.guiRenderState.submitGuiElement(new GeometryRenderState( CustomRenderLayers.COLOR_LINE, - graphics.pose(), + new Matrix3x2f(graphics.pose()), vertices, colors, graphics.scissorStack.peek() @@ -496,7 +507,7 @@ public static void drawRoundedRectangle(GuiGraphics graphics, float x, float y, graphics.guiRenderState.submitGuiElement(new RoundedRectRenderState( RenderPipelines.DEBUG_QUADS, - graphics.pose(), + new Matrix3x2f(graphics.pose()), x, y, width, height, -1f, intColors, radii, graphics.scissorStack.peek() )); } @@ -628,7 +639,7 @@ public static void scaleAndPosition(Matrix3x2fStack matrices, float x, float y, /** * Creating bounds for Render states */ - public static ScreenRectangle createBounds(Matrix3x2fStack pose, ScreenRectangle scissor, float x, float y, float w, float h) { + public static ScreenRectangle createBounds(Matrix3x2f pose, ScreenRectangle scissor, float x, float y, float w, float h) { ScreenRectangle bounds = new ScreenRectangle((int) x, (int) y, (int) w, (int) h).transformAxisAligned(pose); return scissor == null ? bounds : scissor.intersection(bounds); } diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/AnimationProperty.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/AnimationProperty.java index 20a80b0..40a1b0b 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/AnimationProperty.java +++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/AnimationProperty.java @@ -3,6 +3,5 @@ // AnimationProperty.java public interface AnimationProperty { T get(); - void set(T value); } \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/MathAnimations.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/MathAnimations.java index 028e442..acdfccc 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/MathAnimations.java +++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/MathAnimations.java @@ -91,7 +91,7 @@ public static float lerp(float start, float end, long startTime, float duration) /// Linear interpolation between values over time with easing public static float lerp(float start, float end, long startTime, float duration, EasingType easing) { float progress = (System.currentTimeMillis() - startTime) / duration; - progress = Math.min(1, Math.max(0, progress)); // Clamp 0-1 + progress = Math.clamp(progress, 0, 1); return start + (end - start) * Easing.apply(easing, progress); } diff --git a/src/main/java/com/tanishisherewith/dynamichud/integration/IntegrationManager.java b/src/main/java/com/tanishisherewith/dynamichud/integration/IntegrationManager.java index fbaa215..a264c1b 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/integration/IntegrationManager.java +++ b/src/main/java/com/tanishisherewith/dynamichud/integration/IntegrationManager.java @@ -32,7 +32,7 @@ public final class IntegrationManager { public static final Map> FILE_MAP = new HashMap<>(); private static final List widgetRenderers = new ArrayList<>(); - private static boolean enableTestIntegration = false; + public static boolean IS_TEST_MODE = false; public static void addWidgetRenderer(WidgetRenderer widgetRenderer) { @@ -59,7 +59,7 @@ private static void checkToEnableTestIntegration() { String[] args = FabricLoader.getInstance().getLaunchArguments(true); for (int i = 0; i < args.length; i++) { if (args[i].equals("--dynamicHudTest") && i + 1 < args.length) { - enableTestIntegration = Boolean.parseBoolean(args[i + 1]); + IS_TEST_MODE = Boolean.parseBoolean(args[i + 1]); break; } } @@ -72,7 +72,7 @@ public static void integrate() { var integrations = new ArrayList<>(getRegisteredIntegrations()); - if (enableTestIntegration) { + if (IS_TEST_MODE) { EntrypointContainer testIntegration = getTestIntegration(); if (testIntegration != null) { integrations.add(testIntegration); diff --git a/src/main/java/com/tanishisherewith/dynamichud/mixins/BufferBuilderMixin.java b/src/main/java/com/tanishisherewith/dynamichud/mixins/BufferBuilderMixin.java index 8f2e442..0e25d22 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/mixins/BufferBuilderMixin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/mixins/BufferBuilderMixin.java @@ -15,10 +15,7 @@ public abstract class BufferBuilderMixin implements VertexConsumer, IBufferBuild @Shadow protected abstract long beginElement(VertexFormatElement element); - /** - * The "Library" secret sauce. - * This allows you to write N floats to a custom GENERIC element. - */ + @Unique public VertexConsumer dynamicHUD$writeGenericFloats(VertexFormatElement element, float... values) { long addr = this.beginElement(element); diff --git a/src/main/java/com/tanishisherewith/dynamichud/renderstates/GeometryRenderState.java b/src/main/java/com/tanishisherewith/dynamichud/renderstates/GeometryRenderState.java index eb2106b..2f5fbd8 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/renderstates/GeometryRenderState.java +++ b/src/main/java/com/tanishisherewith/dynamichud/renderstates/GeometryRenderState.java @@ -2,16 +2,17 @@ import com.mojang.blaze3d.pipeline.RenderPipeline; import com.mojang.blaze3d.vertex.VertexConsumer; +import com.tanishisherewith.dynamichud.helpers.DrawHelper; import net.minecraft.client.gui.navigation.ScreenRectangle; import net.minecraft.client.gui.render.TextureSetup; import net.minecraft.client.gui.render.state.GuiElementRenderState; import org.jetbrains.annotations.Nullable; -import org.joml.Matrix3x2fStack; +import org.joml.Matrix3x2f; // State for Geometric Shapes (Circles, Arcs, Fans) public record GeometryRenderState( RenderPipeline pipeline, - Matrix3x2fStack pose, + Matrix3x2f pose, float[] vertices, // Flat array: [x1, y1, x2, y2, ...] int[] colors, // Parallel array of ARGB colors @Nullable ScreenRectangle scissorArea @@ -32,6 +33,23 @@ public TextureSetup textureSetup() { @Override public @Nullable ScreenRectangle bounds() { - return null; + if (vertices == null || vertices.length < 2) return null; + + float minX = Float.MAX_VALUE; + float minY = Float.MAX_VALUE; + float maxX = -Float.MAX_VALUE; + float maxY = -Float.MAX_VALUE; + + for (int i = 0; i < vertices.length / 2; i++) { + float x = vertices[i * 2]; + float y = vertices[i * 2 + 1]; + + if (x < minX) minX = x; + if (y < minY) minY = y; + if (x > maxX) maxX = x; + if (y > maxY) maxY = y; + } + + return DrawHelper.createBounds(pose, scissorArea, minX, minY, maxX - minX, maxY - minY); } } \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/renderstates/GradientShadowRenderState.java b/src/main/java/com/tanishisherewith/dynamichud/renderstates/GradientShadowRenderState.java index 1c177d8..5a0c3de 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/renderstates/GradientShadowRenderState.java +++ b/src/main/java/com/tanishisherewith/dynamichud/renderstates/GradientShadowRenderState.java @@ -7,7 +7,7 @@ import net.minecraft.client.gui.render.TextureSetup; import net.minecraft.client.gui.render.state.GuiElementRenderState; import org.jetbrains.annotations.Nullable; -import org.joml.Matrix3x2fStack; +import org.joml.Matrix3x2f; import org.joml.Matrix3x2fc; import org.jspecify.annotations.NonNull; @@ -19,7 +19,7 @@ public record GradientShadowRenderState( float bottomY, int startColor, int endColor, - Matrix3x2fStack pose, + Matrix3x2f pose, RenderPipeline pipeline, int width, int height, diff --git a/src/main/java/com/tanishisherewith/dynamichud/renderstates/InterpolatedCurveRenderState.java b/src/main/java/com/tanishisherewith/dynamichud/renderstates/InterpolatedCurveRenderState.java index 07a9e7f..f1addda 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/renderstates/InterpolatedCurveRenderState.java +++ b/src/main/java/com/tanishisherewith/dynamichud/renderstates/InterpolatedCurveRenderState.java @@ -7,7 +7,7 @@ import net.minecraft.client.gui.render.TextureSetup; import net.minecraft.client.gui.render.state.GuiElementRenderState; import org.jetbrains.annotations.Nullable; -import org.joml.Matrix3x2fStack; +import org.joml.Matrix3x2f; import org.jspecify.annotations.NonNull; import java.util.List; @@ -16,7 +16,7 @@ public record InterpolatedCurveRenderState( List points, float thickness, int color, - Matrix3x2fStack pose, + Matrix3x2f pose, RenderPipeline pipeline, int width, int height, diff --git a/src/main/java/com/tanishisherewith/dynamichud/renderstates/QuadColorRectRenderState.java b/src/main/java/com/tanishisherewith/dynamichud/renderstates/QuadColorRectRenderState.java index e02892e..6edf7ca 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/renderstates/QuadColorRectRenderState.java +++ b/src/main/java/com/tanishisherewith/dynamichud/renderstates/QuadColorRectRenderState.java @@ -6,13 +6,13 @@ import net.minecraft.client.gui.navigation.ScreenRectangle; import net.minecraft.client.gui.render.TextureSetup; import net.minecraft.client.gui.render.state.GuiElementRenderState; -import org.joml.Matrix3x2fStack; +import org.joml.Matrix3x2f; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; public record QuadColorRectRenderState( RenderPipeline pipeline, - Matrix3x2fStack pose, + Matrix3x2f pose, float x, float y, float width, diff --git a/src/main/java/com/tanishisherewith/dynamichud/renderstates/RoundedRectRenderState.java b/src/main/java/com/tanishisherewith/dynamichud/renderstates/RoundedRectRenderState.java index 4e39e3b..daf15eb 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/renderstates/RoundedRectRenderState.java +++ b/src/main/java/com/tanishisherewith/dynamichud/renderstates/RoundedRectRenderState.java @@ -7,16 +7,19 @@ import net.minecraft.client.gui.render.TextureSetup; import net.minecraft.client.gui.render.state.GuiElementRenderState; import org.jetbrains.annotations.Nullable; -import org.joml.Matrix3x2fStack; +import org.joml.Matrix3x2f; import org.joml.Vector4f; import org.jspecify.annotations.NonNull; import static com.tanishisherewith.dynamichud.helpers.DrawHelper.COSA; import static com.tanishisherewith.dynamichud.helpers.DrawHelper.SINA; +/** + * Using Matrix3x2f is essential for these shapes to be affected by MatrixStack changes. + */ public record RoundedRectRenderState( RenderPipeline pipeline, - Matrix3x2fStack pose, + Matrix3x2f pose, float x, float y, float width, float height, float thickness, diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java index 65da6a9..f6b1860 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java @@ -2,11 +2,15 @@ import com.tanishisherewith.dynamichud.DynamicHUD; import com.tanishisherewith.dynamichud.helpers.DrawHelper; +import com.tanishisherewith.dynamichud.helpers.animationhelper.AnimationProperty; +import com.tanishisherewith.dynamichud.helpers.animationhelper.EasingType; +import com.tanishisherewith.dynamichud.helpers.animationhelper.animations.ValueAnimation; import com.tanishisherewith.dynamichud.internal.System; import com.tanishisherewith.dynamichud.utils.Input; -import com.tanishisherewith.dynamichud.utils.contextmenu.contextmenuscreen.ContextMenuScreenFactory; -import com.tanishisherewith.dynamichud.utils.contextmenu.contextmenuscreen.ContextMenuScreenRegistry; -import com.tanishisherewith.dynamichud.utils.contextmenu.contextmenuscreen.DefaultContextMenuScreenFactory; +import com.tanishisherewith.dynamichud.utils.contextmenu.layout.LayoutEngine; +import com.tanishisherewith.dynamichud.utils.contextmenu.screen.factory.ContextMenuScreenFactory; +import com.tanishisherewith.dynamichud.utils.contextmenu.screen.ContextMenuScreenRegistry; +import com.tanishisherewith.dynamichud.utils.contextmenu.screen.factory.DefaultContextMenuScreenFactory; import com.tanishisherewith.dynamichud.utils.contextmenu.options.Option; import com.tanishisherewith.dynamichud.widget.WidgetBox; import net.minecraft.client.gui.GuiGraphics; @@ -30,8 +34,9 @@ public class ContextMenu implements Input { protected final List> options = new ArrayList<>(); // The list of options in the context menu protected final ContextMenuScreenFactory screenFactory; public int x, y; - // Width is counted while the options are being rendered. - // FinalWidth is the width at the end of the count. + + protected LayoutEngine layoutEngine; + protected int width = 0; protected int height = 0, widgetHeight = 0; protected boolean shouldDisplay = false; @@ -39,6 +44,8 @@ public class ContextMenu implements Input { protected Screen parentScreen = null; protected boolean newScreenFlag = false; + private final ValueAnimation scaleAnimation; + @Nullable private final ContextMenu parentMenu; @@ -61,6 +68,27 @@ public ContextMenu(int x, int y, @NotNull T properties, ContextMenuScreenFactory this.darkerBackgroundColor = properties.getBackgroundColor().darker().darker().darker().darker().darker().darker(); this.parentMenu = parentMenu; this.properties.getSkin().setContextMenu(this); + this.layoutEngine = new LayoutEngine(); + + this.scaleAnimation = new ValueAnimation(new AnimationProperty<>() { + @Override + public Float get() { + return scale; + } + + @Override + public void set(Float value) { + scale = value; + } + }, 0.0f, 1.0f); + this.scaleAnimation.easing(EasingType.EASE_IN_CUBIC); + this.scaleAnimation.duration(280); + this.scaleAnimation.onComplete(() -> { + if (scale <= 0.0f && parentScreen != null && properties.getSkin().shouldCreateNewScreen()) { + DynamicHUD.MC.setScreen(parentScreen); + } + }); + Screen dummy = screenFactory.create(this, properties); System.registerInstance(new ContextMenuScreenRegistry(dummy.getClass()), DynamicHUD.MOD_ID); @@ -71,18 +99,20 @@ public void addOption(Option option) { options.add(option); } - public void render(GuiGraphics graphics, int x, int y, int mouseX, int mouseY) { + public void render(GuiGraphics graphics, int xPos, int yPos, int mouseX, int mouseY) { if (newScreenFlag && screenFactory != null) { DynamicHUD.MC.setScreen(screenFactory.create(this, properties)); return; } - this.x = x; - this.y = y + properties.getHeightOffset() + widgetHeight; + this.x = xPos; + this.y = yPos + properties.getHeightOffset() + widgetHeight; + update(); + if (scale <= 0.0f || newScreenFlag) return; - DrawHelper.scaleAndPosition(graphics.pose(), x, y, scale); + DrawHelper.scaleAndPosition(graphics.pose(), this.x + width/2.0f, this.y + height/2.0f, scale); properties.getSkin().setContextMenu(this); properties.getSkin().renderContextMenu(graphics, this, mouseX, mouseY); @@ -91,19 +121,15 @@ public void render(GuiGraphics graphics, int x, int y, int mouseX, int mouseY) { } public void update() { + if (layoutEngine != null) { + layoutEngine.applyLayout(this); + } if (!properties.enableAnimations()) { - scale = 1.0f; + scale = shouldDisplay ? 1.0f : 0.0f; return; } - // Update the scale - if (shouldDisplay) { - scale += 0.1f; - } else { - scale -= 0.1f; - } - - scale = Math.clamp(scale, 0, 1.0f); + scaleAnimation.update(); } public void close() { @@ -112,8 +138,15 @@ public void close() { for (Option option : options) { option.onClose(); } - if (properties.getSkin().shouldCreateNewScreen() && scale <= 0 && parentScreen != null) { - DynamicHUD.MC.setScreen(parentScreen); + if (properties.enableAnimations()) { + scaleAnimation.startValue(scale); + scaleAnimation.endValue(0.0f); + scaleAnimation.start(); + } else { + scale = 0.0f; + if (properties.getSkin().shouldCreateNewScreen() && parentScreen != null) { + DynamicHUD.MC.setScreen(parentScreen); + } } } @@ -124,6 +157,16 @@ public void open() { if (properties.getSkin().shouldCreateNewScreen()) { newScreenFlag = true; } + if (properties.enableAnimations()) { + scaleAnimation.startValue(scale); + scaleAnimation.endValue(1.0f); + scaleAnimation.start(); + } else { + scale = 0.0f; + if (properties.getSkin().shouldCreateNewScreen() && parentScreen != null) { + DynamicHUD.MC.setScreen(parentScreen); + } + } } public void toggleDisplay() { @@ -146,11 +189,21 @@ public void resetAllOptions() { } } + public LayoutEngine getLayoutEngine() { + return layoutEngine; + } + + public void setLayoutEngine(LayoutEngine layoutEngine) { + this.layoutEngine = layoutEngine; + } + @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { if (!shouldDisplay) return false; for (Option option : options) { - option.getRenderer().mouseClicked(option, mouseX, mouseY, button); + if (option.shouldRender() && option.getRenderer().mouseClicked(option ,mouseX, mouseY, button)) { + return true; + } } return properties.getSkin().mouseClicked(this, mouseX, mouseY, button); } @@ -159,7 +212,9 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { public boolean mouseReleased(double mouseX, double mouseY, int button) { if (!shouldDisplay) return false; for (Option option : options) { - option.getRenderer().mouseReleased(option, mouseX, mouseY, button); + if(option.shouldRender() && option.getRenderer().mouseReleased(option, mouseX, mouseY, button)){ + return true; + } } return properties.getSkin().mouseReleased(this, mouseX, mouseY, button); } @@ -168,7 +223,9 @@ public boolean mouseReleased(double mouseX, double mouseY, int button) { public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { if (!shouldDisplay) return false; for (Option option : options) { - option.getRenderer().mouseDragged(option, mouseX, mouseY, button, deltaX, deltaY); + if(option.shouldRender() && option.getRenderer().mouseDragged(option, mouseX, mouseY, button, deltaX, deltaY)){ + return true; + } } return properties.getSkin().mouseDragged(this, mouseX, mouseY, button, deltaX, deltaY); } @@ -177,7 +234,9 @@ public boolean mouseDragged(double mouseX, double mouseY, int button, double del public void keyPressed(int key, int scanCode, int modifiers) { if (!shouldDisplay) return; for (Option option : options) { - option.getRenderer().keyPressed(option, key, scanCode, modifiers); + if(option.shouldRender()){ + option.getRenderer().keyPressed(option, key, scanCode, modifiers); + } } properties.getSkin().keyPressed(this, key, scanCode, modifiers); @@ -187,7 +246,9 @@ public void keyPressed(int key, int scanCode, int modifiers) { public void keyReleased(int key, int scanCode, int modifiers) { if (!shouldDisplay) return; for (Option option : options) { - option.getRenderer().keyReleased(option, key, scanCode, modifiers); + if(option.shouldRender()) { + option.getRenderer().keyReleased(option, key, scanCode, modifiers); + } } properties.getSkin().keyReleased(this, key, scanCode, modifiers); @@ -197,7 +258,9 @@ public void keyReleased(int key, int scanCode, int modifiers) { public void mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { if (!shouldDisplay) return; for (Option option : options) { - option.getRenderer().mouseScrolled(option, mouseX, mouseY, horizontalAmount, verticalAmount); + if(option.shouldRender()) { + option.getRenderer().mouseScrolled(option, mouseX, mouseY, horizontalAmount, verticalAmount); + } } properties.getSkin().mouseScrolled(this, mouseX, mouseY, horizontalAmount, verticalAmount); } @@ -206,7 +269,9 @@ public void mouseScrolled(double mouseX, double mouseY, double horizontalAmount, public void charTyped(char c, int modifiers) { if (!shouldDisplay) return; for (Option option : options) { - option.charTyped(c, modifiers); + if(option.shouldRender()) { + option.charTyped(c, modifiers); + } } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenuProperties.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenuProperties.java index 3e45992..bbb23b9 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenuProperties.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenuProperties.java @@ -10,6 +10,7 @@ */ public class ContextMenuProperties { protected Color backgroundColor = new Color(107, 112, 126, 124); + protected Color accentColor = new Color(104, 151, 187, 255); // Color.CYAN.darker().darker(); protected Color borderColor = Color.BLACK; protected float borderWidth = 1f; protected int padding = 5; // The amount of padding around the rectangle @@ -91,6 +92,10 @@ public Skin getSkin() { return skin; } + public Color getAccentColor() { + return accentColor; + } + /** * @return Cloned object of every property except skin */ @@ -144,6 +149,11 @@ public Builder backgroundColor(Color backgroundColor) { return this; } + public Builder accentColor(Color accentColor) { + properties.accentColor = accentColor; + return this; + } + public Builder borderColor(Color borderColor) { properties.borderColor = borderColor; return this; diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/layout/LayoutEngine.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/layout/LayoutEngine.java new file mode 100644 index 0000000..4f1d5f1 --- /dev/null +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/layout/LayoutEngine.java @@ -0,0 +1,166 @@ +package com.tanishisherewith.dynamichud.utils.contextmenu.layout; +import com.tanishisherewith.dynamichud.DynamicHUD; +import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenu; +import com.tanishisherewith.dynamichud.utils.contextmenu.options.Option; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; + +import java.util.List; + +public class LayoutEngine { + private int horizontalPadding = 8; + private int verticalPadding = 4; + private int itemSpacing = 2; + private int minWidth = 80; + private LayoutStrategy activeStrategy = new VerticalFlowStrategy(); + + public LayoutEngine() {} + + public LayoutEngine(int horizontalPadding, int verticalPadding, int itemSpacing, int minWidth) { + this.horizontalPadding = horizontalPadding; + this.verticalPadding = verticalPadding; + this.itemSpacing = itemSpacing; + this.minWidth = minWidth; + } + + @FunctionalInterface + public interface LayoutStrategy { + /** + * Computes dimensions and positions options within the context menu. + */ + void layout(ContextMenu menu, LayoutEngine engine); + } + + + /** + * Executes the currently active layout strategy to position and size options dynamically. + */ + public void applyLayout(ContextMenu menu) { + if (activeStrategy != null) { + activeStrategy.layout(menu, this); + } + } + + /** + * Linear layout for skins that need to know their total dimensions + */ + public void performSimpleLayout(ContextMenu menu) { + if (menu == null) return; + + Font font = Minecraft.getInstance().font; + List> visibleOptions = menu.getProperties().getSkin().getOptions(menu); + int paddingValue = menu.getProperties().getPadding(); + + //width calculation + int maxInnerWidth = minWidth; + for (Option option : visibleOptions) { + if (!option.shouldRender()) continue; + + int preferredWidth = option.getWidth() > 0 ? option.getWidth() : font.width(option.getName()); + + maxInnerWidth = Math.max(maxInnerWidth, preferredWidth); + } + + int totalMenuWidth = maxInnerWidth + (horizontalPadding * 2) + paddingValue; + + int currentY = menu.getY() + verticalPadding + 3; + int currentX = menu.getX() + horizontalPadding; + + // height calculation + for (Option option : visibleOptions) { + if (!option.shouldRender()) continue; + + int itemHeight = option.getHeight() > 0 ? option.getHeight() : font.lineHeight; + + option.setWidth(totalMenuWidth - (horizontalPadding * 2) - paddingValue); + option.setHeight(itemHeight); + option.setPosition(currentX, currentY); + + currentY += itemHeight + itemSpacing; + } + + menu.setWidth(totalMenuWidth); + menu.setHeight(currentY - menu.getY()); + } + + /** + * Helper function for immediate layouts + * Automatically updates the option's dimensions and returns the updated Y position for the next element. + * + * @param option option to arrange. + * @param x start X coordinate. + * @param y start Y coordinate. + * @param targetWidth horizontal width for the option. + * @return next Y coordinate. + */ + public int layoutOption(Option option, int x, int y, int targetWidth) { + if (option == null || !option.shouldRender()) return y; + + int itemHeight = option.getHeight() > 0 ? option.getHeight() : DynamicHUD.MC.font.lineHeight; + + option.setPosition(x, y); + option.setWidth(targetWidth); + option.setHeight(itemHeight); + + return y + itemHeight + itemSpacing; + } + + + public LayoutStrategy getActiveStrategy() { + return activeStrategy; + } + + public void setActiveStrategy(LayoutStrategy activeStrategy) { + this.activeStrategy = activeStrategy; + } + + public int getHorizontalPadding() { return horizontalPadding; } + public void setHorizontalPadding(int horizontalPadding) { this.horizontalPadding = horizontalPadding; } + + public int getVerticalPadding() { return verticalPadding; } + public void setVerticalPadding(int verticalPadding) { this.verticalPadding = verticalPadding; } + + public int getItemSpacing() { return itemSpacing; } + public void setItemSpacing(int itemSpacing) { this.itemSpacing = itemSpacing; } + + public int getMinWidth() { return minWidth; } + public void setMinWidth(int minWidth) { this.minWidth = minWidth; } + + /** + * Default layout strategy that arranges items in a single vertical column. + * Automatically scales the menu width to match the longest option. + */ + public static class VerticalFlowStrategy implements LayoutStrategy { + @Override + public void layout(ContextMenu menu, LayoutEngine engine) { + if (menu == null || menu.getProperties() == null) return; + + Font font = Minecraft.getInstance().font; + List> visibleOptions = menu.getProperties().getSkin().getOptions(menu); + int paddingValue = menu.getProperties().getPadding(); + + // width calc + int maxInnerWidth = engine.getMinWidth(); + for (Option option : visibleOptions) { + if (!option.shouldRender()) continue; + int preferredWidth = option.getWidth() > 0 ? option.getWidth() : font.width(option.getName()); + maxInnerWidth = Math.max(maxInnerWidth, preferredWidth); + } + + int totalMenuWidth = maxInnerWidth + (engine.getHorizontalPadding() * 2) + paddingValue; + + // height calc + int currentY = menu.getY() + engine.getVerticalPadding() + 3; + int currentX = menu.getX() + engine.getHorizontalPadding(); + int targetWidth = totalMenuWidth - (engine.getHorizontalPadding() * 2) - paddingValue; + + for (Option option : visibleOptions) { + if (!option.shouldRender()) continue; + currentY = engine.layoutOption(option, currentX, currentY, targetWidth); + } + + menu.setWidth(totalMenuWidth); + menu.setHeight(currentY - menu.getY()); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/BooleanOption.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/BooleanOption.java index a4764d8..f0f0056 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/BooleanOption.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/BooleanOption.java @@ -15,7 +15,6 @@ public class BooleanOption extends Option { public BooleanOption(Component name, Supplier getter, Consumer setter, BooleanType booleanType) { super(name, getter, setter); this.booleanType = booleanType; - this.renderer.init(this); } public BooleanOption(Component name, Supplier getter, Consumer setter) { diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ColorOption.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ColorOption.java index c0f341d..9f4eb93 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ColorOption.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ColorOption.java @@ -17,7 +17,6 @@ public ColorOption(Component name, Supplier getter, Consumer sette super(name, getter, setter); this.parentMenu = parentMenu; this.colorGradient = new ColorGradient(x + this.parentMenu.getWidth(), y - 10, get(), this::set, 50, 100); - this.renderer.init(this); } @Override @@ -30,21 +29,19 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { } else { colorGradient.close(); } + return true; } - colorGradient.mouseClicked(mouseX, mouseY, button); - return super.mouseClicked(mouseX, mouseY, button); + return colorGradient.mouseClicked(mouseX, mouseY, button); } @Override public boolean mouseReleased(double mouseX, double mouseY, int button) { - colorGradient.mouseReleased(mouseX, mouseY, button); - return super.mouseReleased(mouseX, mouseY, button); + return colorGradient.mouseReleased(mouseX, mouseY, button); } @Override public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { - colorGradient.mouseDragged(mouseX, mouseY, button); - return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); + return colorGradient.mouseDragged(mouseX, mouseY, button); } public ColorGradient getColorGradient() { diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/DoubleOption.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/DoubleOption.java index 14208f4..e7e5d25 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/DoubleOption.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/DoubleOption.java @@ -28,7 +28,6 @@ public DoubleOption(Component name, double minValue, double maxValue, float step this.step = step; this.parentMenu = parentMenu; Validate.isTrue(this.step > 0.0f, "Step cannot be less than or equal to 0 (zero)"); - this.renderer.init(this); } public void drawSlider(GuiGraphics graphics, int sliderX, int sliderY, int sliderWidth, double handleX) { @@ -43,8 +42,9 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { if (super.mouseClicked(mouseX, mouseY, button) && button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { step(mouseX); isDragging = true; + return true; } - return true; + return false; } @Override @@ -57,7 +57,7 @@ private void step(double mouseX) { this.step(mouseX, x); } - public void step(double mouseX, double x) { + public void step(double mouseX, double x, double width) { double newValue = minValue + (float) (mouseX - x) / width * (maxValue - minValue); // Round the new value to the nearest step newValue = Math.round(newValue / step) * step; @@ -66,10 +66,16 @@ public void step(double mouseX, double x) { } + public void step(double mouseX, double x) { + this.step(mouseX, x, width); + } + + @Override public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { if (isMouseOver(mouseX, mouseY) && isDragging) { step(mouseX); + return true; } return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/EnumOption.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/EnumOption.java index f71cee2..ffb0350 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/EnumOption.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/EnumOption.java @@ -19,7 +19,6 @@ public EnumOption(Component name, Supplier getter, Consumer setter, E[] va break; } } - this.renderer.init(this); } @Override @@ -39,8 +38,9 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { value = values[currentIndex]; } set(value); + return true; } - return true; + return false; } public E[] getValues() { diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ListOption.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ListOption.java index d948664..f87a648 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ListOption.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ListOption.java @@ -20,7 +20,6 @@ public ListOption(Component name, Supplier getter, Consumer setter, List getValues() { diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/Option.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/Option.java index 137b4c6..2142ccc 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/Option.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/Option.java @@ -61,6 +61,7 @@ public void updateProperties(ContextMenuProperties properties) { DynamicHUD.logger.error("Renderer not found for class: {} in the following skin: {}", this.getClass().getName(), properties.getSkin()); throw new RuntimeException(); } + this.renderer.init(this); } public void render(GuiGraphics graphics, int x, int y, int mouseX, int mouseY) { diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/OptionGroup.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/OptionGroup.java index ec68a50..33b0c5a 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/OptionGroup.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/OptionGroup.java @@ -71,10 +71,14 @@ public void render(GuiGraphics graphics, Option option, int x, int public boolean mouseClicked(Option option2, double mouseX, double mouseY, int button) { OptionGroup option = (OptionGroup) option2; - for (Option subOption : option.getGroupOptions()) { - subOption.getRenderer().mouseClicked(subOption, mouseX, mouseY, button); + if (option.isExpanded()) { + for (Option subOption : option.getGroupOptions()) { + if (subOption.getRenderer().mouseClicked(subOption, mouseX, mouseY, button)) { + return true; + } + } } - return SkinRenderer.super.mouseClicked(option, mouseX, mouseY, button); + return false; } @Override @@ -82,9 +86,9 @@ public boolean mouseReleased(Option option2, double mouseX, double OptionGroup option = (OptionGroup) option2; for (Option subOption : option.getGroupOptions()) { - subOption.getRenderer().mouseReleased(subOption, mouseX, mouseY, button); + if(subOption.getRenderer().mouseReleased(subOption, mouseX, mouseY, button)) return true; } - return SkinRenderer.super.mouseReleased(option, mouseX, mouseY, button); + return false; } @Override @@ -92,9 +96,9 @@ public boolean mouseDragged(Option option2, double mouseX, double m OptionGroup option = (OptionGroup) option2; for (Option subOption : option.getGroupOptions()) { - subOption.getRenderer().mouseDragged(subOption, mouseX, mouseY, button, deltaX, deltaY); + if(subOption.getRenderer().mouseDragged(subOption, mouseX, mouseY, button, deltaX, deltaY)) return true; } - return SkinRenderer.super.mouseDragged(option, mouseX, mouseY, button, deltaX, deltaY); + return false; } @Override diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/RunnableOption.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/RunnableOption.java index ce18f5e..8605735 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/RunnableOption.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/RunnableOption.java @@ -22,7 +22,6 @@ public RunnableOption(Component name, Supplier getter, Consumer SubMenuOption(Component name, ContextMe this.subMenu = parentMenu.createSubMenu(parentMenu.x + parentMenu.getWidth(), this.y, properties.cloneSkin()); this.subMenu.getProperties().setHeightOffset(0); this.subMenu.setVisible(get()); - this.renderer.init(this); } public SubMenuOption(Component name, ContextMenu parentMenu, T properties) { @@ -43,24 +42,25 @@ public SubMenuOption(Component name, ContextMe @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { if (super.mouseClicked(mouseX, mouseY, button)) { - subMenu.toggleDisplay(); - set(subMenu.isVisible()); + toggle(); return true; } - subMenu.mouseClicked(mouseX, mouseY, button); - return false; + return subMenu.mouseClicked(mouseX, mouseY, button); + } + + public void toggle(){ + subMenu.toggleDisplay(); + set(subMenu.isVisible()); } @Override public boolean mouseReleased(double mouseX, double mouseY, int button) { - subMenu.mouseReleased(mouseX, mouseY, button); - return super.mouseReleased(mouseX, mouseY, button); + return subMenu.mouseReleased(mouseX, mouseY, button); } @Override public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { - subMenu.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); - return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); + return subMenu.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); } public SubMenuOption getOption() { diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/ColorGradient.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/ColorGradient.java index 14379a8..ed82651 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/ColorGradient.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/ColorGradient.java @@ -1,7 +1,6 @@ package com.tanishisherewith.dynamichud.utils.contextmenu.options.coloroption; import com.tanishisherewith.dynamichud.config.GlobalConfig; -import com.tanishisherewith.dynamichud.helpers.ColorHelper; import com.tanishisherewith.dynamichud.helpers.MouseColorQuery; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; @@ -111,15 +110,16 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { return true; } - public void mouseReleased(double mouseX, double mouseY, int button) { + public boolean mouseReleased(double mouseX, double mouseY, int button) { gradientSlider.onRelease(mouseX, mouseY, button); gradientBox.onRelease(mouseX, mouseY, button); alphaSlider.onRelease(mouseX, mouseY, button); + return false; } - public void mouseDragged(double mouseX, double mouseY, int button) { + public boolean mouseDragged(double mouseX, double mouseY, int button) { if (!display) { - return; + return false; } gradientSlider.onDrag(mouseX, mouseY, button); gradientBox.setHue(gradientSlider.getHue()); @@ -127,6 +127,7 @@ public void mouseDragged(double mouseX, double mouseY, int button) { alphaSlider.setColor(new Color(gradientBox.getColor(), true)); alphaSlider.onDrag(mouseX, mouseY, button); onColorSelected.accept(alphaSlider.getColor()); + return true; } public int getBoxSize() { diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/ContextMenuScreen.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/ContextMenuScreen.java similarity index 94% rename from src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/ContextMenuScreen.java rename to src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/ContextMenuScreen.java index eeba531..28c6cca 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/ContextMenuScreen.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/ContextMenuScreen.java @@ -1,4 +1,4 @@ -package com.tanishisherewith.dynamichud.utils.contextmenu.contextmenuscreen; +package com.tanishisherewith.dynamichud.utils.contextmenu.screen; import com.tanishisherewith.dynamichud.helpers.DrawHelper; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenu; @@ -13,7 +13,7 @@ public class ContextMenuScreen extends Screen { ContextMenu contextMenu; ContextMenuProperties properties; - protected ContextMenuScreen(ContextMenu menu, ContextMenuProperties properties) { + public ContextMenuScreen(ContextMenu menu, ContextMenuProperties properties) { super(Component.literal("ContextMenu screen")); this.contextMenu = menu; this.properties = properties; diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/ContextMenuScreenRegistry.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/ContextMenuScreenRegistry.java similarity index 77% rename from src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/ContextMenuScreenRegistry.java rename to src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/ContextMenuScreenRegistry.java index 3e8ee1d..058548f 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/ContextMenuScreenRegistry.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/ContextMenuScreenRegistry.java @@ -1,4 +1,4 @@ -package com.tanishisherewith.dynamichud.utils.contextmenu.contextmenuscreen; +package com.tanishisherewith.dynamichud.utils.contextmenu.screen; import net.minecraft.client.gui.screens.Screen; diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/ContextMenuScreenFactory.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/factory/ContextMenuScreenFactory.java similarity index 89% rename from src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/ContextMenuScreenFactory.java rename to src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/factory/ContextMenuScreenFactory.java index b66b0c7..66b60da 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/ContextMenuScreenFactory.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/factory/ContextMenuScreenFactory.java @@ -1,4 +1,4 @@ -package com.tanishisherewith.dynamichud.utils.contextmenu.contextmenuscreen; +package com.tanishisherewith.dynamichud.utils.contextmenu.screen.factory; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenu; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenuProperties; diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/DefaultContextMenuScreenFactory.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/factory/DefaultContextMenuScreenFactory.java similarity index 78% rename from src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/DefaultContextMenuScreenFactory.java rename to src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/factory/DefaultContextMenuScreenFactory.java index 1b0bbc9..589d38f 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/contextmenuscreen/DefaultContextMenuScreenFactory.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/factory/DefaultContextMenuScreenFactory.java @@ -1,7 +1,8 @@ -package com.tanishisherewith.dynamichud.utils.contextmenu.contextmenuscreen; +package com.tanishisherewith.dynamichud.utils.contextmenu.screen.factory; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenu; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenuProperties; +import com.tanishisherewith.dynamichud.utils.contextmenu.screen.ContextMenuScreen; import net.minecraft.client.gui.screens.Screen; /** diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ClassicSkin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ClassicSkin.java index 1298a56..89bbe7c 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ClassicSkin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ClassicSkin.java @@ -1,5 +1,6 @@ package com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem; +import com.tanishisherewith.dynamichud.helpers.ColorHelper; import com.tanishisherewith.dynamichud.helpers.DrawHelper; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenu; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenuProperties; @@ -8,26 +9,23 @@ import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.network.chat.Component; -import org.apache.logging.log4j.core.pattern.TextRenderer; -import org.joml.Matrix3x2fStack; import java.awt.*; - /** * This is one of the Skins provided by DynamicHUD featuring the classic rendering, * which should be used when you have a low amount of settings and want quicker way of changing the settings. */ public class ClassicSkin extends Skin { + public ClassicSkin() { super(); - addRenderer(BooleanOption.class, ClassicBooleanRenderer::new); - addRenderer(DoubleOption.class, ClassicDoubleRenderer::new); + addRenderer(ColorOption.class, ClassicColorOptionRenderer::new); addRenderer(EnumOption.class, ClassicEnumRenderer::new); addRenderer(ListOption.class, ClassicListRenderer::new); addRenderer(SubMenuOption.class, ClassicSubMenuRenderer::new); addRenderer(RunnableOption.class, ClassicRunnableRenderer::new); - addRenderer(ColorOption.class, ClassicColorOptionRenderer::new); + addRenderer(DoubleOption.class, ClassicDoubleRenderer::new); setCreateNewScreen(false); } @@ -35,31 +33,24 @@ public ClassicSkin() { @Override public void renderContextMenu(GuiGraphics graphics, ContextMenu contextMenu, int mouseX, int mouseY) { this.contextMenu = contextMenu; - - Matrix3x2fStack matrices = graphics.pose(); ContextMenuProperties properties = contextMenu.getProperties(); - // Draw the background + if (contextMenu.getLayoutEngine() != null) { + contextMenu.getLayoutEngine().applyLayout(contextMenu); + } + drawBackground(graphics, contextMenu, properties); - int yOffset = contextMenu.y + 3; - int width = 10; for (Option option : getOptions(contextMenu)) { if (!option.shouldRender()) continue; - // Adjust mouse coordinates based on the scale - if (contextMenu.getProperties().hoverEffect() && contextMenu.isMouseOver(mouseX, mouseY, contextMenu.x + 1, yOffset - 1, contextMenu.getWidth() - 2, option.getHeight())) { - drawBackground(graphics, contextMenu, properties, yOffset - 1, contextMenu.getWidth(), option.getHeight() + 1, contextMenu.getProperties().getHoverColor().getRGB(), false); + if (properties.hoverEffect() && contextMenu.isMouseOver(mouseX, mouseY, option.getX() - 3, option.getY() - 1, contextMenu.getWidth() - 2, option.getHeight())) { + drawBackground(graphics, contextMenu, properties, option.getY() - 1, contextMenu.getWidth(), option.getHeight() + 1, properties.getHoverColor().getRGB(), false); } - option.render(graphics, contextMenu.x + 4, yOffset, mouseX, mouseY); - width = Math.max(width, option.getWidth()); - yOffset += option.getHeight() + 1; + option.render(graphics, option.getX(), option.getY(), mouseX, mouseY); } - contextMenu.setWidth(width + properties.getPadding()); - contextMenu.setHeight(yOffset - contextMenu.y); - // Draw the border if needed if (properties.shouldDrawBorder()) { drawBorder(graphics, contextMenu, properties); } @@ -71,74 +62,25 @@ private void drawBackground(GuiGraphics graphics, ContextMenu contextMenu, Co private void drawBackground(GuiGraphics graphics, ContextMenu contextMenu, ContextMenuProperties properties, int yOffset, int width, int height, int color, boolean shadow) { if (properties.roundedCorners()) { - // Rounded if (shadow) { - DrawHelper.drawRoundedRectangleWithShadowBadWay(graphics, - contextMenu.x, - yOffset, - width, - height, - properties.getCornerRadius(), - color, - 150, - 1, - 1 - ); + DrawHelper.drawRoundedRectangleWithShadowBadWay(graphics, contextMenu.x, yOffset, width, height, properties.getCornerRadius(), color, 150, 1, 1); } else { - DrawHelper.drawRoundedRectangle(graphics, - contextMenu.x, - yOffset, - width, - height, - properties.getCornerRadius(), - color - ); + DrawHelper.drawRoundedRectangle(graphics, contextMenu.x, yOffset, width, height, properties.getCornerRadius(), color); } } else { - // Normal if (shadow) { - DrawHelper.drawRectangleWithShadowBadWay(graphics, - contextMenu.x, - yOffset, - width, - height, - color, - 150, - 1, - 1 - ); + DrawHelper.drawRectangleWithShadowBadWay(graphics, contextMenu.x, yOffset, width, height, color, 150, 1, 1); } else { - DrawHelper.drawRectangle(graphics, - contextMenu.x, - yOffset, - width, - height, - color - ); + DrawHelper.drawRectangle(graphics, contextMenu.x, yOffset, width, height, color); } } } private void drawBorder(GuiGraphics graphics, ContextMenu contextMenu, ContextMenuProperties properties) { if (properties.roundedCorners()) { - DrawHelper.drawOutlineRoundedBox(graphics, - contextMenu.x, - contextMenu.y, - contextMenu.getWidth(), - contextMenu.getHeight(), - properties.getCornerRadius(), - properties.getBorderWidth(), - properties.getBorderColor().getRGB() - ); + DrawHelper.drawOutlineRoundedBox(graphics, contextMenu.x, contextMenu.y, contextMenu.getWidth(), contextMenu.getHeight(), properties.getCornerRadius(), properties.getBorderWidth(), properties.getBorderColor().getRGB()); } else { - DrawHelper.drawOutlineBox(graphics, - contextMenu.x, - contextMenu.y, - contextMenu.getWidth(), - contextMenu.getHeight(), - properties.getBorderWidth(), - properties.getBorderColor().getRGB() - ); + DrawHelper.drawOutlineBox(graphics, contextMenu.x, contextMenu.y, contextMenu.getWidth(), contextMenu.getHeight(), properties.getBorderWidth(), properties.getBorderColor().getRGB()); } } @@ -147,13 +89,12 @@ public Skin clone() { return new ClassicSkin(); } + public static class ClassicBooleanRenderer implements SkinRenderer { @Override public void render(GuiGraphics graphics, BooleanOption option, int x, int y, int mouseX, int mouseY) { - int color = option.value ? Color.GREEN.getRGB() : Color.RED.getRGB(); + int color = option.get() ? Color.GREEN.getRGB() : Color.RED.getRGB(); graphics.drawString(mc.font, option.name, x, y, color, false); - option.setHeight(mc.font.lineHeight); - option.setWidth(mc.font.width(option.name) + 1); } } @@ -162,12 +103,10 @@ public static class ClassicColorOptionRenderer implements SkinRenderer> implements SkinRenderer> { @Override public void render(GuiGraphics graphics, EnumOption option, int x, int y, int mouseX, int mouseY) { - option.setHeight(mc.font.lineHeight + 1); - option.setWidth(mc.font.width(option.name + ": " + option.value.name()) + 1); - graphics.drawString(mc.font, option.name.copy().append(": "), x, y, Color.WHITE.getRGB(), false); - graphics.drawString(mc.font, option.value.name(), x + mc.font.width(option.name + ": ") + 1, y, Color.CYAN.getRGB(), false); + graphics.drawString(mc.font, option.get().name(), x + mc.font.width(option.name + ": ") + 1, y, Color.CYAN.getRGB(), false); + } + } + + public static class ClassicListRenderer implements SkinRenderer> { + @Override + public void render(GuiGraphics graphics, ListOption option, int x, int y, int mouseX, int mouseY) { + graphics.drawString(mc.font, option.name.copy().append(": "), x, y + 1, Color.WHITE.getRGB(), false); + graphics.drawString(mc.font, option.get().toString(), x + mc.font.width(option.name + ": ") + 1, y + 1, Color.CYAN.getRGB(), false); } } @@ -199,41 +143,25 @@ public void render(GuiGraphics graphics, SubMenuOption option, int x, int y, int graphics.drawString(mc.font, option.name, x, y, color, false); graphics.drawString(mc.font, option.getSubMenu().isVisible() ? "-" : "+", x + Math.max(option.getParentMenu().getWidth() - 12, mc.font.width(option.name) + 2), y, color, false); - option.setHeight(mc.font.lineHeight); - option.setWidth(mc.font.width(option.name) + 4); - option.getSubMenu().render(graphics, x + option.getParentMenu().getWidth(), y - 1, mouseX, mouseY); } } public static class ClassicRunnableRenderer implements SkinRenderer { - Color DARK_RED = new Color(116, 0, 0); - Color DARK_GREEN = new Color(24, 132, 0, 226); - @Override public void render(GuiGraphics graphics, RunnableOption option, int x, int y, int mouseX, int mouseY) { - option.setHeight(mc.font.lineHeight); - option.setWidth(mc.font.width("Run: " + option.name)); - int color = option.value ? DARK_GREEN.getRGB() : DARK_RED.getRGB(); + int color = option.value ? ColorHelper.DARK_GREEN.getRGB() : ColorHelper.DARK_RED.getRGB(); graphics.drawString(mc.font, Component.literal("Run: ").append(option.name), x, y, color, false); } } - public class ClassicDoubleRenderer implements SkinRenderer { + public static class ClassicDoubleRenderer implements SkinRenderer { @Override public void render(GuiGraphics graphics, DoubleOption option, int x, int y, int mouseX, int mouseY) { - option.setWidth(Math.max(35, contextMenu != null ? contextMenu.getWidth() - option.getProperties().getPadding() - 2 : 0)); - option.setHeight(16); - - // Draw the label Font font = mc.font; DrawHelper.scaleAndPosition(graphics.pose(), x, y, 0.7f); Component labelText = option.name.copy().append(": " + String.format("%.1f", option.value)); - int labelWidth = font.width(labelText); - - option.setWidth(Math.max(option.getWidth(), labelWidth)); - - graphics.drawString(font, labelText, x, y + 1, 0xFFFFFFFF,true); + graphics.drawString(font, labelText, x, y + 1, 0xFFFFFFFF, true); DrawHelper.stopScaling(graphics.pose()); float handleWidth = 3; @@ -241,10 +169,8 @@ public void render(GuiGraphics graphics, DoubleOption option, int x, int y, int double handleX = x + (option.value - option.minValue) / (option.maxValue - option.minValue) * (option.getWidth() - handleWidth); double handleY = y + font.lineHeight + 1 + ((2 - handleHeight) / 2); - // Draw the slider option.drawSlider(graphics, x, y + font.lineHeight + 1, option.getWidth(), handleX); - // Draw the handle DrawHelper.drawRoundedRectangleWithShadowBadWay(graphics, (float) handleX, (float) handleY, @@ -255,18 +181,6 @@ public void render(GuiGraphics graphics, DoubleOption option, int x, int y, int 90, 0.6f, 0.6f); - - } - } - - public static class ClassicListRenderer implements SkinRenderer> { - @Override - public void render(GuiGraphics graphics, ListOption option, int x, int y, int mouseX, int mouseY) { - option.setHeight(mc.font.lineHeight + 1); - option.setWidth(mc.font.width(option.name + ": " + option.value.toString()) + 1); - - graphics.drawString(mc.font, option.name.copy().append(": "), x, y + 1, Color.WHITE.getRGB(), false); - graphics.drawString(mc.font, option.value.toString(), x + mc.font.width(option.name + ": ") + 1, y + 1, Color.CYAN.getRGB(), false); } } } \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java index 9aeb548..9266750 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java @@ -2,6 +2,9 @@ import com.tanishisherewith.dynamichud.DynamicHUD; import com.tanishisherewith.dynamichud.helpers.DrawHelper; +import com.tanishisherewith.dynamichud.helpers.animationhelper.AnimationProperty; +import com.tanishisherewith.dynamichud.helpers.animationhelper.EasingType; +import com.tanishisherewith.dynamichud.helpers.animationhelper.animations.ValueAnimation; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenu; import com.tanishisherewith.dynamichud.utils.contextmenu.layout.LayoutContext; import com.tanishisherewith.dynamichud.utils.contextmenu.options.*; @@ -22,6 +25,9 @@ import java.util.List; import java.util.function.IntSupplier; +import static com.tanishisherewith.dynamichud.helpers.ColorHelper.DARK_GREEN; +import static com.tanishisherewith.dynamichud.helpers.ColorHelper.DARK_RED; + /** * This is one of the Skins provided by DynamicHUD featuring the minecraft-like style rendering. * It runs on a separate screen and provides more complex features like scrolling and larger dimension. @@ -33,26 +39,28 @@ public class MinecraftSkin extends Skin implements GroupableSkin { Identifier.withDefaultNamespace("widget/button_disabled"), Identifier.withDefaultNamespace("widget/button_highlighted") ); - public static final int DEFAULT_SCROLLBAR_WIDTH = 8; - public static final int DEFAULT_PANEL_WIDTH = 248; - public static final int DEFAULT_PANEL_HEIGHT = 165; public static final Identifier DEFAULT_BACKGROUND_PANEL = Identifier.withDefaultNamespace("textures/gui/demo_background.png"); public static final Identifier SCROLLER_TEXTURE = Identifier.withDefaultNamespace("widget/scroller"); public static final Identifier SCROLL_BAR_BACKGROUND = Identifier.withDefaultNamespace("widget/scroller_background"); public static final Identifier GROUP_BACKGROUND = Identifier.fromNamespaceAndPath(DynamicHUD.MOD_ID, "textures/minecraftskin/group_panel.png"); private final Identifier BACKGROUND_PANEL; + + public static final int DEFAULT_SCROLLBAR_WIDTH = 8; + public static final int DEFAULT_PANEL_WIDTH = 248; + public static final int DEFAULT_PANEL_HEIGHT = 165; private final int panelWidth; private final int panelHeight; - private PanelColor panelColor; + private final int groupPanelWidth = 60; // Width for the group panel private int imageX, imageY; private final ScrollHandler scrollHandler; private List optionGroups; private OptionGroup selectedGroup; + + private PanelColor panelColor; private final ScrollHandler groupScrollHandler; - private final int groupPanelWidth = 60; // Width for the group panel private final IntSupplier groupPanelX = () -> imageX - groupPanelWidth - 15; public MinecraftSkin(PanelColor color) { @@ -102,6 +110,19 @@ private void initOptionGroups() { } } + private int getOptionHeight(Option option) { + if (option instanceof SubMenuOption) return 20; + if (option instanceof ColorOption colorOption) { + int baseHeight = 25; + if (colorOption.getColorGradient().shouldDisplay()) { + int colorGradientHeight = colorOption.getColorGradient().getBoxSize() + 10 + colorOption.getColorGradient().getGradientSlider().getHeight(); + return baseHeight + colorGradientHeight; + } + return baseHeight; + } + return 25; + } + @Override public void renderContextMenu(GuiGraphics graphics, ContextMenu contextMenu, int mouseX, int mouseY) { this.contextMenu = contextMenu; @@ -185,13 +206,17 @@ private void renderOptionGroups(GuiGraphics graphics, int mouseX, int mouseY) { private int renderSelectedGroupOptions(GuiGraphics graphics, int mouseX, int mouseY) { int yOffset = imageY + 12 - scrollHandler.getScrollOffset(); + int targetWidth = panelWidth - 25; + for (Option option : selectedGroup.getGroupOptions()) { if (!option.shouldRender()) continue; - if (yOffset >= imageY - option.getHeight() && yOffset <= imageY + option.getHeight() + panelHeight) { - option.render(graphics, imageX + 4, yOffset, mouseX, mouseY); + option.setHeight(getOptionHeight(option)); + yOffset = contextMenu.getLayoutEngine().layoutOption(option, imageX + 4, yOffset, targetWidth); + + if (option.getY() >= imageY - option.getHeight() && option.getY() <= imageY + option.getHeight() + panelHeight) { + option.render(graphics, option.getX(), option.getY(), mouseX, mouseY); } - yOffset += option.getHeight() + 1; } return yOffset; } @@ -390,21 +415,44 @@ public void render(GuiGraphics graphics, BooleanOption option, int x, int y, int int color = option.value ? Color.GREEN.getRGB() : Color.RED.getRGB(); graphics.drawString(mc.font, Component, (int) (option.getX() + (width / 2.0f) - (mc.font.width(Component) / 2.0f)), y + 5, color, true); - option.setHeight(25); //Widths don't matter in this skin option.setWidth(width); } + } + + public class MinecraftColorOptionRenderer implements SkinRenderer { + private ValueAnimation scaleAnimation; + private float scale = 0.0f; @Override - public boolean mouseClicked(BooleanOption option, double mouseX, double mouseY, int button) { - return SkinRenderer.super.mouseClicked(option, mouseX, mouseY, button); + public void init(ColorOption option) { + this.scaleAnimation = new ValueAnimation(new AnimationProperty<>() { + @Override + public Float get() { + return scale; + } + + @Override + public void set(Float value) { + scale = value; + } + }, 0.0f, 1.0f); + scaleAnimation.easing(EasingType.EASE_OUT_BACK); + scaleAnimation.duration(200); + this.scaleAnimation.onComplete(() -> { + if (scale <= 0.0f) { + option.getColorGradient().close(); + } + }); } - } - public class MinecraftColorOptionRenderer implements SkinRenderer { @Override public void render(GuiGraphics graphics, ColorOption option, int x, int y, int mouseX, int mouseY) { + if (scaleAnimation != null) { + scaleAnimation.update(); + } + graphics.drawString(mc.font, option.name, x + 15, y + 25 / 2 - 5, -1, true); option.setPosition(x + panelWidth - 45, y); @@ -423,26 +471,71 @@ public void render(GuiGraphics graphics, ColorOption option, int x, int y, int m 1, 1); - - option.setHeight(25); option.setWidth(width); if (option.getColorGradient().getColorPickerButton().isPicking()) { - DrawHelper.disableScissor(graphics); // Disable scissor test for the colorpicker + DrawHelper.disableScissor(graphics); } - //TODO: WHAT IS THISSSSS + int colorGradientWidth = option.getColorGradient().getBoxSize() + option.getColorGradient().getAlphaSlider().getWidth() + option.getColorGradient().getColorPickerButton().getWidth(); - option.getColorGradient().render(graphics, x + panelWidth / 2 - colorGradientWidth / 2, y + 12, mouseX, mouseY); + int pickerX = x + panelWidth / 2 - colorGradientWidth / 2; + int pickerY = y + 12; - if (option.getColorGradient().shouldDisplay()) { + if (scale > 0.0f) { + DrawHelper.scaleAndPosition(graphics.pose(), pickerX + colorGradientWidth / 2.0f, pickerY, scale); + option.getColorGradient().render(graphics, pickerX, pickerY, mouseX, mouseY); + DrawHelper.stopScaling(graphics.pose()); + } + + int baseHeight = 25; + if (option.getColorGradient().shouldDisplay() || (scaleAnimation != null && !scaleAnimation.isFinished())) { int colorGradientHeight = option.getColorGradient().getBoxSize() + 10 + option.getColorGradient().getGradientSlider().getHeight(); - option.setHeight(option.getHeight() + colorGradientHeight); + option.setHeight(baseHeight + (int) (colorGradientHeight * scale)); + } else { + option.setHeight(baseHeight); } if (option.getColorGradient().getColorPickerButton().isPicking()) { DrawHelper.enableScissor(imageX, imageY + 2, panelWidth, panelHeight - 4, graphics); } } + + @Override + public boolean mouseClicked(ColorOption option, double mouseX, double mouseY, int button) { + if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && isMouseOver(mouseX, mouseY, option.getX(), option.getY(), 20, 20)) { + boolean isOpening = !option.getColorGradient().shouldDisplay(); + scaleAnimation.startValue(scale); + if (isOpening) { + option.getColorGradient().display(); + scaleAnimation.endValue(1.0f); + } else { + scaleAnimation.endValue(0.0f); + } + scaleAnimation.start(); + return true; + } + + if (option.getColorGradient().shouldDisplay()) { + option.getColorGradient().mouseClicked(mouseX, mouseY, button); + } + return false; + } + + @Override + public boolean mouseDragged(ColorOption option, double mouseX, double mouseY, int button, double deltaX, double deltaY) { + if (option.getColorGradient().shouldDisplay()) { + option.getColorGradient().mouseDragged(mouseX, mouseY, button); + } + return SkinRenderer.super.mouseDragged(option, mouseX, mouseY, button, deltaX, deltaY); + } + + @Override + public boolean mouseReleased(ColorOption option, double mouseX, double mouseY, int button) { + if (option.getColorGradient().shouldDisplay()) { + option.getColorGradient().mouseReleased(mouseX, mouseY, button); + } + return SkinRenderer.super.mouseReleased(option, mouseX, mouseY, button); + } } public class MinecraftDoubleRenderer implements SkinRenderer { @@ -451,17 +544,11 @@ public class MinecraftDoubleRenderer implements SkinRenderer { private static final Identifier HANDLE_TEXTURE = Identifier.withDefaultNamespace("widget/slider_handle"); private static final Identifier HANDLE_HIGHLIGHTED_TEXTURE = Identifier.withDefaultNamespace("widget/slider_handle_highlighted"); - @Override - public void init(DoubleOption option) { - SkinRenderer.super.init(option); - } - @Override public void render(GuiGraphics graphics, DoubleOption option, int x, int y, int mouseX, int mouseY) { graphics.drawString(mc.font, option.name, x + 15, y + 25 / 2 - 5, -1, true); option.setWidth(panelWidth - 150); - option.setHeight(25); option.setPosition(x + panelWidth - 122, y); double sliderX = option.getX() + ((option.value - option.minValue) / (option.maxValue - option.minValue)) * (option.getWidth() - 8); @@ -477,11 +564,6 @@ public void render(GuiGraphics graphics, DoubleOption option, int x, int y, int String formattedValue = String.format("%." + decimalPlaces + "f", option.value); graphics.drawCenteredString(mc.font, formattedValue, option.getX() + option.getWidth() / 2, y + Math.round((float) mc.font.lineHeight /2), -1); } - - @Override - public boolean mouseClicked(DoubleOption option, double mouseX, double mouseY, int button) { - return SkinRenderer.super.mouseClicked(option, mouseX, mouseY, button); - } } public class MinecraftEnumRenderer> implements SkinRenderer> { @@ -499,7 +581,6 @@ private void calculateMaxWidth(EnumOption option) { @Override public void render(GuiGraphics graphics, EnumOption option, int x, int y, int mouseX, int mouseY) { calculateMaxWidth(option); - option.setHeight(25); option.setWidth(maxWidth); graphics.drawString(mc.font, option.name.copy().append(": "), x + 15, y + 25 / 2 - 5, -1, true); @@ -527,7 +608,6 @@ private void calculateMaxWidth(ListOption option) { @Override public void render(GuiGraphics graphics, ListOption option, int x, int y, int mouseX, int mouseY) { calculateMaxWidth(option); - option.setHeight(25); option.setWidth(maxWidth); graphics.drawString(mc.font, option.name.copy().append(": "), x + 15, y + 25 / 2 - 5, -1, true); @@ -543,7 +623,6 @@ public void render(GuiGraphics graphics, ListOption option, int x, int y, int public class MinecraftSubMenuRenderer implements SkinRenderer { @Override public void render(GuiGraphics graphics, SubMenuOption option, int x, int y, int mouseX, int mouseY) { - option.setHeight(20); option.setWidth(30); graphics.drawString(mc.font, option.name, x + 15, y + 25 / 2 - 5, -1, true); @@ -559,12 +638,9 @@ public void render(GuiGraphics graphics, SubMenuOption option, int x, int y, int } public class MinecraftRunnableRenderer implements SkinRenderer { - Color DARK_RED = new Color(116, 0, 0); - Color DARK_GREEN = new Color(24, 132, 0, 226); @Override public void render(GuiGraphics graphics, RunnableOption option, int x, int y, int mouseX, int mouseY) { - option.setHeight(25); option.setWidth(26); graphics.drawString(mc.font, option.name.copy().append(": "), x + 15, y + 25 / 2 - 5, -1, true); diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java index ae2f21b..2ff9eec 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java @@ -22,12 +22,14 @@ import java.util.Arrays; import java.util.List; +import static com.tanishisherewith.dynamichud.helpers.ColorHelper.DARK_GREEN; +import static com.tanishisherewith.dynamichud.helpers.ColorHelper.DARK_RED; + public class ModernSkin extends Skin implements GroupableSkin { static Color DARK_GRAY = new Color(20, 20, 20, 229); static Color DARKER_GRAY = new Color(10, 10, 10, 243); static Color DARKER_GRAY_2 = new Color(12, 12, 12, 246); - private final Color themeColor; private final float radius; private final Component defaultToolTipHeader; private final Component defaultToolTipText; @@ -39,12 +41,10 @@ public class ModernSkin extends Skin implements GroupableSkin { private static int SCALE_FACTOR = 4; private final ScrollHandler scrollHandler; - - public ModernSkin(Color themeColor, float radius, Component defaultToolTipHeader, Component defaultToolTipText) { - this.themeColor = themeColor; + public ModernSkin(float radius, Component defaultToolTipHeader, Component defaultToolTipText) { this.radius = radius; - TOOLTIP_TEXT = defaultToolTipText; - TOOLTIP_HEAD = defaultToolTipHeader; + this.TOOLTIP_TEXT = defaultToolTipText; + this.TOOLTIP_HEAD = defaultToolTipHeader; this.defaultToolTipText = defaultToolTipText; this.defaultToolTipHeader = defaultToolTipHeader; @@ -61,21 +61,17 @@ public ModernSkin(Color themeColor, float radius, Component defaultToolTipHeader setCreateNewScreen(true); } - public ModernSkin(Color themeColor, float radius) { - this(themeColor, radius, Component.literal("Example Tip"), Component.literal("Hover over a setting to see its tool-tip (if present) here!")); - } - - public ModernSkin(Color themeColor) { - this(themeColor, 4); + public ModernSkin(float radius) { + this(radius, Component.literal("Example Tip"), Component.literal("Hover over a setting to see its tool-tip (if present) here!")); } public ModernSkin() { - this(Color.CYAN.darker().darker()); + this(4); } @Override public LayoutContext.Offset getGroupIndent() { - return new LayoutContext.Offset(2, 2); + return new LayoutContext.Offset(4, 4); } public void enableSkinScissor(GuiGraphics graphics) { @@ -84,6 +80,24 @@ public void enableSkinScissor(GuiGraphics graphics) { @Override public void renderGroup(GuiGraphics graphics, OptionGroup group, int groupX, int groupY, int mouseX, int mouseY) { + int targetWidth = (int) (width * 0.8f - 18); + renderGroup(graphics, group, groupX, groupY, targetWidth, mouseX, mouseY); + } + private int calcOptionHeight(Option option) { + if (option instanceof BooleanOption || option instanceof DoubleOption) return 14; + if (option instanceof EnumOption || option instanceof ListOption) return mc.font.lineHeight + 2; + if (option instanceof SubMenuOption) return 16; + if (option instanceof RunnableOption) return mc.font.lineHeight + 6; + if (option instanceof ColorOption colorOption) { + return colorOption.getHeight() > 0 ? colorOption.getHeight() : 20; + } + if (option instanceof OptionGroup group) { + return group.isExpanded() ? group.getHeight() : 20; + } + return option.getHeight() > 0 ? option.getHeight() : mc.font.lineHeight; + } + + public void renderGroup(GuiGraphics graphics, OptionGroup group, int groupX, int groupY, int targetWidth, int mouseX, int mouseY) { mouseX = (int) (mc.mouseHandler.xpos() / SCALE_FACTOR); mouseY = (int) (mc.mouseHandler.ypos() / SCALE_FACTOR); @@ -101,11 +115,16 @@ public void renderGroup(GuiGraphics graphics, OptionGroup group, int groupX, int if (group.isExpanded()) { int yOffset = groupY + 16 + getGroupIndent().top(); + int nestedIndent = getGroupIndent().left(); + int subWidth = targetWidth - nestedIndent - 8; + for (Option option : group.getGroupOptions()) { if (!option.shouldRender()) continue; - option.render(graphics, groupX + getGroupIndent().left(), yOffset, mouseX, mouseY); - yOffset += option.getHeight() + 1; + // Position child option with layout engine + option.setHeight(calcOptionHeight(option)); + yOffset = contextMenu.getLayoutEngine().layoutOption(option, groupX + nestedIndent, yOffset, subWidth); + option.render(graphics, option.getX(), option.getY(), mouseX, mouseY); } group.setHeight(yOffset - groupY); @@ -116,8 +135,8 @@ public void renderGroup(GuiGraphics graphics, OptionGroup group, int groupX, int private void drawScrollbar(GuiGraphics graphics) { if (getMaxScrollOffset() > 0) { - int scrollbarX = contextMenuX + width + 5; // Position at the right of the panel - int scrollbarY = contextMenuY + 19; // Position below the header + int scrollbarX = contextMenuX + width + 5; + int scrollbarY = contextMenuY + 19; int handleHeight = (int) ((float) (height - 23) * ((height - 23) / (float) contextMenu.getHeight())); int handleY = scrollbarY + (int) ((float) ((height - 23) - handleHeight) * ((float) scrollHandler.getScrollOffset() / getMaxScrollOffset())); @@ -128,33 +147,34 @@ private void drawScrollbar(GuiGraphics graphics) { @Override public void renderContextMenu(GuiGraphics graphics, ContextMenu contextMenu, int mouseX, int mouseY) { - //This is equivalent to "Auto" GUI scale in minecraft options SCALE_FACTOR = mc.getWindow().calculateScale(0, mc.isEnforceUnicode()); + this.contextMenu = contextMenu; mouseX = (int) (mc.mouseHandler.xpos() / SCALE_FACTOR); mouseY = (int) (mc.mouseHandler.ypos() / SCALE_FACTOR); - // Apply custom scaling to counteract Minecraft's default scaling DrawHelper.scaledProjection(SCALE_FACTOR, graphics); updateContextDimensions(); contextMenu.set(contextMenuX, contextMenuY, 0); - //Background + // Background DrawHelper.drawRoundedRectangle(graphics, contextMenuX, contextMenuY, width, height, radius, DARKER_GRAY.getRGB()); drawBackButton(graphics, mouseX, mouseY); - //OptionStartX = Tool-Tip width + padding int optionStartX = contextMenu.x + (int) (width * 0.2f) + 10; + int targetWidth = (int) (width * 0.8f - 18); - //Background behind the options + // Background behind the options scroll area DrawHelper.drawRoundedRectangle(graphics, optionStartX, contextMenuY + 19, width * 0.8f - 14, height - 23, radius, DARK_GRAY.getRGB()); enableSkinScissor(graphics); + int yOffset = contextMenu.y + 19 + 3 - scrollHandler.getScrollOffset(); + for (Option option : getOptions(contextMenu)) { if (!option.shouldRender()) continue; @@ -162,14 +182,18 @@ public void renderContextMenu(GuiGraphics graphics, ContextMenu contextMenu, setTooltipText(option.name, option.description); } + option.setHeight(calcOptionHeight(option)); + int nextY = contextMenu.getLayoutEngine().layoutOption(option, optionStartX + 2, yOffset, targetWidth); + if (option instanceof OptionGroup group) { - this.renderGroup(graphics, group, optionStartX + 2, yOffset, mouseX, mouseY); + this.renderGroup(graphics, group, optionStartX + 2, yOffset, targetWidth, mouseX, mouseY); + yOffset += group.getHeight() + contextMenu.getLayoutEngine().getItemSpacing(); } else { - option.render(graphics, optionStartX + 2, yOffset, mouseX, mouseY); + option.render(graphics, option.getX(), option.getY(), mouseX, mouseY); + yOffset = nextY; } - - yOffset += option.getHeight() + 1; } + DrawHelper.disableScissor(graphics); contextMenu.setWidth(width); @@ -181,7 +205,6 @@ public void renderContextMenu(GuiGraphics graphics, ContextMenu contextMenu, renderToolTipText(graphics, mouseX, mouseY); - //Reset our scaling so minecraft runs normally\ DrawHelper.stopScaling(graphics.pose()); } @@ -199,7 +222,7 @@ public void drawBackButton(GuiGraphics graphics, int mouseX, int mouseY) { int textWidth = mc.font.width(backText); boolean isHoveringOver = isMouseOver(mouseX, mouseY, contextMenuX + 2, contextMenuY + 2, textWidth + 8, 14); - int color = isHoveringOver ? themeColor.darker().getRGB() : themeColor.getRGB(); + int color = isHoveringOver ? getThemeColor().darker().getRGB() : getThemeColor().getRGB(); DrawHelper.drawRoundedRectangleWithShadowBadWay(graphics, contextMenuX + 2, contextMenuY + 2, textWidth + 8, 14, radius, color, 125, 2, 2); @@ -219,7 +242,6 @@ public void renderToolTipText(GuiGraphics graphics, int mouseX, int mouseY) { float textScale = 0.8f; - // Draw background DrawHelper.drawRoundedRectangle( graphics, contextMenuX + 2, @@ -243,7 +265,6 @@ public void renderToolTipText(GuiGraphics graphics, int mouseX, int mouseY) { return; } - //Draw the head Component graphics.drawString( mc.font, TOOLTIP_HEAD, @@ -257,7 +278,6 @@ public void renderToolTipText(GuiGraphics graphics, int mouseX, int mouseY) { DrawHelper.scaleAndPosition(graphics.pose(), contextMenuX + 4, tooltipY + 19, textScale); - // Draw Component int textY = tooltipY + 19; for (FormattedCharSequence line : wrappedText) { graphics.drawString( @@ -277,8 +297,8 @@ public void renderToolTipText(GuiGraphics graphics, int mouseX, int mouseY) { } public void setTooltipText(Component head_text, Component tooltip_text) { - TOOLTIP_TEXT = tooltip_text; - TOOLTIP_HEAD = head_text; + this.TOOLTIP_TEXT = tooltip_text; + this.TOOLTIP_HEAD = head_text; } private int getMaxScrollOffset() { @@ -309,19 +329,24 @@ public boolean mouseClicked(ContextMenu menu, double mouseX, double mouseY, i if (button == GLFW.GLFW_MOUSE_BUTTON_RIGHT) { int optionStartX = contextMenuX + (int) (width * 0.2f) + 10; int yOffset = contextMenu.y + 22 - scrollHandler.getScrollOffset(); + int spacing = contextMenu.getLayoutEngine().getItemSpacing(); + for (Option option : getOptions(contextMenu)) { if (!option.shouldRender()) continue; + int optHeight = calcOptionHeight(option); if (option instanceof OptionGroup group) { + Component groupText = group.name.copy().append(" " + (group.isExpanded() ? "-" : "+")); if (isMouseOver(mouseX, mouseY, optionStartX + 2, yOffset, - mc.font.width(group.name + " " + (group.isExpanded() ? "-" : "+")) + 6, + mc.font.width(groupText) + 6, 16)) { group.setExpanded(!group.isExpanded()); - break; + return true; } + yOffset += group.getHeight() + spacing; + } else { + yOffset += optHeight + spacing; } - - yOffset += option.getHeight() + 1; } } if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && isMouseOver(mouseX, mouseY, contextMenuX + 2, contextMenuY + 2, mc.font.width("< Back") + 8, 14)) { @@ -344,7 +369,7 @@ public boolean mouseDragged(ContextMenu menu, double mouseX, double mouseY, i } public Color getThemeColor() { - return themeColor; + return contextMenu.getProperties().getAccentColor(); } public class ModernBooleanRenderer implements SkinRenderer { @@ -352,15 +377,7 @@ public class ModernBooleanRenderer implements SkinRenderer { @Override public void render(GuiGraphics graphics, BooleanOption option, int x, int y, int mouseX, int mouseY) { - int backgroundWidth = (int) (width * 0.8f - 14); - - option.setHeight(14); - option.setPosition(x, y); - option.setWidth(backgroundWidth); - - // Calculate the current progress of the animation - int toggleBgX = x + backgroundWidth - 30; - // Background + int toggleBgX = x + option.getWidth() - 30; boolean active = option.get(); Color backgroundColor = active ? getThemeColor() : DARKER_GRAY; Color hoveredColor = isMouseOver(mouseX, mouseY, toggleBgX, y + 2, 14, 7) ? backgroundColor.darker() : backgroundColor; @@ -373,7 +390,6 @@ public void render(GuiGraphics graphics, BooleanOption option, int x, int y, int 125, 1, 1 ); - // Draw toggle circle float startX = active ? toggleBgX + 4 : toggleBgX + 10; float endX = active ? toggleBgX + 10 : toggleBgX + 4; EasingType easingType = active ? EasingType.EASE_IN_CUBIC : EasingType.EASE_OUT_QUAD; @@ -381,7 +397,6 @@ public void render(GuiGraphics graphics, BooleanOption option, int x, int y, int DrawHelper.drawFilledCircle(graphics, toggleX, y + 2 + 3.3f, 2.8f, Color.WHITE.getRGB()); - // Draw option name graphics.drawString( mc.font, option.name, @@ -397,8 +412,7 @@ public boolean mouseClicked(BooleanOption option, double mouseX, double mouseY, mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; - int backgroundWidth = (int) (width * 0.8f - 14); - int toggleBgX = option.getX() + backgroundWidth - 30; + int toggleBgX = option.getX() + option.getWidth() - 30; if (isMouseOver(mouseX, mouseY, toggleBgX, option.getY(), 14, option.getHeight())) { option.set(!option.get()); @@ -409,7 +423,6 @@ public boolean mouseClicked(BooleanOption option, double mouseX, double mouseY, } } - public class ModernColorOptionRenderer implements SkinRenderer { private static final float ANIMATION_SPEED = 0.1f; private float scale = 0f; @@ -432,9 +445,6 @@ public void update(ColorOption option) { public void render(GuiGraphics graphics, ColorOption option, int x, int y, int mouseX, int mouseY) { update(option); - int backgroundWidth = (int) (width * 0.8f - 14); - - // Draw option name graphics.drawString( mc.font, option.name, @@ -444,17 +454,12 @@ public void render(GuiGraphics graphics, ColorOption option, int x, int y, int m false ); - option.setWidth(20); - option.setPosition(x, y); - - int width = 20; int shadowOpacity = Math.min(option.value.getAlpha(), 45); - //The shape behind the preview - Color behindColor = isMouseOver(mouseX, mouseY, x + backgroundWidth - width - 17, y + 1, width + 2, 14) ? getThemeColor().darker().darker() : getThemeColor(); + Color behindColor = isMouseOver(mouseX, mouseY, x + option.getWidth() - width - 17, y + 1, width + 2, 14) ? getThemeColor().darker().darker() : getThemeColor(); DrawHelper.drawRoundedRectangleWithShadowBadWay(graphics, - x + backgroundWidth - width - 17, + x + option.getWidth() - width - 17, y + 1, width + 2, 14, @@ -464,19 +469,17 @@ public void render(GuiGraphics graphics, ColorOption option, int x, int y, int m 1, 1); - //The letter above the shape behind the preview graphics.drawString( mc.font, option.getColorGradient().shouldDisplay() ? "^" : "v", - x + backgroundWidth - 21, + x + option.getWidth() - 21, y + 4, -1, false ); - //Preview DrawHelper.drawRoundedRectangleWithShadowBadWay(graphics, - x + backgroundWidth - width - 15, + x + option.getWidth() - width - 15, y + 2, width - 8, 12, @@ -488,18 +491,17 @@ public void render(GuiGraphics graphics, ColorOption option, int x, int y, int m int targetHeight = (int) (option.getColorGradient().getBoxSize() + option.getColorGradient().getGradientBox().getSize() * scale); option.setHeight(option.getColorGradient().shouldDisplay() ? targetHeight : 20); - option.setWidth(width); if (option.getColorGradient().getColorPickerButton().isPicking()) { - DrawHelper.disableScissor(graphics); //Disable scissor so the color picker preview works + DrawHelper.disableScissor(graphics); } - DrawHelper.scaleAndPosition(graphics.pose(), x + backgroundWidth / 2.0f, y, scale); - option.getColorGradient().render(graphics, x + backgroundWidth / 2 - 50, y + 6, mouseX, mouseY); + DrawHelper.scaleAndPosition(graphics.pose(), x + option.getWidth() / 2.0f, y, scale); + option.getColorGradient().render(graphics, x + option.getWidth() / 2 - 50, y + 6, mouseX, mouseY); DrawHelper.stopScaling(graphics.pose()); if (option.getColorGradient().getColorPickerButton().isPicking()) { - enableSkinScissor(graphics); // re-enable the scissor + enableSkinScissor(graphics); } } @@ -507,7 +509,7 @@ public void render(GuiGraphics graphics, ColorOption option, int x, int y, int m public boolean mouseClicked(ColorOption option, double mouseX, double mouseY, int button) { mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; - if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && isMouseOver(mouseX, mouseY, option.getX() + (int) (width * 0.8f - 14) - 37, option.getY(), 22, 16)) { + if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && isMouseOver(mouseX, mouseY, option.getX() + option.getWidth() - 37, option.getY(), 22, 16)) { option.isVisible = !option.isVisible; if (option.isVisible) { option.getColorGradient().display(); @@ -517,35 +519,32 @@ public boolean mouseClicked(ColorOption option, double mouseX, double mouseY, in } return true; } - option.getColorGradient().mouseClicked(mouseX, mouseY, button); - return false; + return option.getColorGradient().mouseClicked(mouseX, mouseY, button); } @Override public boolean mouseDragged(ColorOption option, double mouseX, double mouseY, int button, double deltaX, double deltaY) { mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; - option.getColorGradient().mouseDragged(mouseX, mouseY, button); - return SkinRenderer.super.mouseDragged(option, mouseX, mouseY, button, deltaX, deltaY); + return option.getColorGradient().mouseDragged(mouseX, mouseY, button) && SkinRenderer.super.mouseDragged(option, mouseX, mouseY, button, deltaX, deltaY); } @Override public boolean mouseReleased(ColorOption option, double mouseX, double mouseY, int button) { mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; - option.getColorGradient().mouseReleased(mouseX, mouseY, button); - - return SkinRenderer.super.mouseReleased(option, mouseX, mouseY, button); + return option.getColorGradient().mouseReleased(mouseX, mouseY, button) && SkinRenderer.super.mouseReleased(option, mouseX, mouseY, button); } } public class ModernDoubleRenderer implements SkinRenderer { private double displayValue; private static final float ANIMATION_SPEED = 0.1f; + int sliderBackgroundWidth = 120; + int sliderBackgroundHeight = 2; @Override public void render(GuiGraphics graphics, DoubleOption option, int x, int y, int mouseX, int mouseY) { - // Draw option name graphics.drawString( mc.font, option.name, @@ -554,44 +553,31 @@ public void render(GuiGraphics graphics, DoubleOption option, int x, int y, int -1, false ); + int sliderX = x + option.getWidth() - sliderBackgroundWidth - 10; - int backgroundWidth = (int) (width * 0.8f - 14); - int sliderBackgroundWidth = 120; - int sliderBackgroundHeight = 2; - int sliderX = x + backgroundWidth - sliderBackgroundWidth - 10; - - option.setPosition(x, y); - option.setWidth(sliderBackgroundWidth); - option.setHeight(14); - - // Smoothly interpolate to the new value displayValue = Mth.lerp(ANIMATION_SPEED, displayValue, option.get()); - // Background DrawHelper.drawRoundedRectangle( graphics, sliderX, y, sliderBackgroundWidth, sliderBackgroundHeight, 1, DARKER_GRAY.getRGB() ); - // Active fill - int activeFillWidth = (int) ((displayValue - option.minValue) / (option.maxValue - option.minValue) * option.getWidth()); + int activeFillWidth = (int) ((displayValue - option.minValue) / (option.maxValue - option.minValue) * sliderBackgroundWidth); Color fillColor = isMouseOver(mouseX, mouseY, sliderX, y, sliderBackgroundWidth, sliderBackgroundHeight + 4) ? getThemeColor().darker().darker() : getThemeColor(); DrawHelper.drawRoundedRectangle( graphics, sliderX, y, activeFillWidth, sliderBackgroundHeight, 2, fillColor.getRGB() ); - // Draw slider handle float sliderHandleX = sliderX + activeFillWidth - 5; DrawHelper.drawFilledCircle(graphics, sliderHandleX + 5, y + 1, 2, Color.WHITE.getRGB()); - // Draw value Component - String Component = String.format("%.2f", displayValue); - DrawHelper.scaleAndPosition(graphics.pose(), sliderX + 120 - mc.font.width(Component), y + 7, 0.6f); + String label = String.format("%.2f", displayValue); + DrawHelper.scaleAndPosition(graphics.pose(), sliderX + sliderBackgroundWidth - mc.font.width(label), y + 7, 0.6f); graphics.drawString( mc.font, - Component, - sliderX + sliderBackgroundWidth + 10 - mc.font.width(Component), + label, + sliderX + sliderBackgroundWidth + 10 - mc.font.width(label), y + 2, -1, true @@ -603,7 +589,8 @@ public void render(GuiGraphics graphics, DoubleOption option, int x, int y, int public boolean mouseClicked(DoubleOption option, double mouseX, double mouseY, int button) { mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; - if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && isMouseOver(mouseX, mouseY, option.getX() + (int) (width * 0.8f - 14) - 125, option.getY() - 1, option.getWidth() + 2, option.getHeight() + 1)) { + int sliderX = option.getX() + option.getWidth() - sliderBackgroundWidth - 10; + if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && isMouseOver(mouseX, mouseY, sliderX - 2, option.getY() - 1, sliderBackgroundWidth + 4, option.getHeight() + 1)) { option.setDragging(true); return true; } @@ -614,10 +601,8 @@ public boolean mouseClicked(DoubleOption option, double mouseX, double mouseY, i public boolean mouseDragged(DoubleOption option, double mouseX, double mouseY, int button, double deltaX, double deltaY) { if (option.isDragging()) { mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; - int backgroundWidth = (int) (width * 0.8f - 14); - int sliderBackgroundWidth = 120; - int sliderX = option.getX() + backgroundWidth - sliderBackgroundWidth - 10; - option.step(mouseX, sliderX); + int sliderX = option.getX() + option.getWidth() - sliderBackgroundWidth - 10; + option.step(mouseX, sliderX, sliderBackgroundWidth); return true; } return false; @@ -636,25 +621,23 @@ public boolean mouseReleased(DoubleOption option, double mouseX, double mouseY, public class ModernEnumRenderer> implements SkinRenderer> { @Override public void render(GuiGraphics graphics, EnumOption option, int x, int y, int mouseX, int mouseY) { - // Set dimensions for the main label and dropdown area option.setHeight(mc.font.lineHeight + 2); - // Draw main option name and selected option Component mainLabel = option.name.copy().append(": "); String selectedOption = option.get().toString(); graphics.drawString(mc.font, mainLabel, x + 4, y + 2, -1, false); - Color fillColor = isMouseOver(mouseX, mouseY, x + 4 + mc.font.width(mainLabel), y, mc.font.width(selectedOption) + 5, mc.font.lineHeight + 2) ? getThemeColor().darker().darker() : getThemeColor(); + boolean isMouseOverText = isMouseOver(mouseX, mouseY, x + 4 + mc.font.width(mainLabel), y, mc.font.width(selectedOption) + 5, mc.font.lineHeight + 2); + Color fillColor = isMouseOverText ? getThemeColor().darker().darker() : getThemeColor(); DrawHelper.drawRoundedRectangle( graphics, x + 4 + mc.font.width(mainLabel), y, mc.font.width(selectedOption) + 5, mc.font.lineHeight + 2, 2, fillColor.getRGB() ); - // "<" and ">" buttons - int contextMenuWidth = (int) (width * 0.8f - 14); - int leftX = x + contextMenuWidth - 30; + + int leftX = x + option.getWidth() - 30; boolean hoveredOverLeft = isMouseOver(mouseX, mouseY, leftX, y, mc.font.width("<") + 5, mc.font.lineHeight); boolean hoveredOverRight = isMouseOver(mouseX, mouseY, leftX + mc.font.width("<") + 6, y, mc.font.width(">") + 5, mc.font.lineHeight); - // Shadow + DrawHelper.drawRoundedRectangle( graphics, leftX + 1, y + 3, @@ -686,7 +669,7 @@ public void render(GuiGraphics graphics, EnumOption option, int x, int y, int graphics.drawString(mc.font, "<", leftX + mc.font.width("<") / 2 + 1, y + 3, -1, false); graphics.drawString(mc.font, ">", leftX + mc.font.width("<") + 7 + mc.font.width(">") / 2, y + 3, -1, false); - graphics.drawString(mc.font, selectedOption, x + 6 + mc.font.width(mainLabel), y + 2, Color.LIGHT_GRAY.getRGB(), false); + graphics.drawString(mc.font, selectedOption, x + 6 + mc.font.width(mainLabel), y + 2, Color.LIGHT_GRAY.getRGB(), isMouseOverText); } @Override @@ -698,13 +681,10 @@ public boolean mouseClicked(EnumOption option, double mouseX, double mouseY, int x = option.getX(); int y = option.getY(); - String mainLabel = option.name + ": "; + Component mainLabel = option.name.copy().append(": "); String selectedOption = option.get().toString(); - // Check if the main label is clicked to cycle - // "<" and ">" buttons - int contextMenuWidth = (int) (width * 0.8f - 14); - int leftX = x + contextMenuWidth - 30; + int leftX = x + option.getWidth() - 30; boolean hoveredOverLeft = isMouseOver(mouseX, mouseY, leftX, y, mc.font.width("<") + 5, mc.font.lineHeight); boolean hoveredOverRight = isMouseOver(mouseX, mouseY, leftX + mc.font.width("<") + 6, y, mc.font.width(">") + 5, mc.font.lineHeight); boolean hoveredOverMainLabel = isMouseOver(mouseX, mouseY, x + 4 + mc.font.width(mainLabel), y, mc.font.width(selectedOption) + 5, mc.font.lineHeight + 2); @@ -714,47 +694,41 @@ public boolean mouseClicked(EnumOption option, double mouseX, double mouseY, int index = Arrays.asList(values).indexOf(option.value); if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT || hoveredOverLeft) { - // Cycle forward E nextVal = values[(index + 1) % values.length]; option.set(nextVal); } else if (button == GLFW.GLFW_MOUSE_BUTTON_RIGHT || hoveredOverRight) { - // Cycle backward with wrap-around E nextVal = values[(index - 1 + values.length) % values.length]; option.set(nextVal); + } else { + return false; } return true; } - return SkinRenderer.super.mouseClicked(option, mouseX, mouseY, button); + return false; } - } public class ModernListRenderer implements SkinRenderer> { - @Override public void render(GuiGraphics graphics, ListOption option, int x, int y, int mouseX, int mouseY) { - - // Set dimensions for the main label and dropdown area option.setHeight(mc.font.lineHeight + 2); - // Draw main option name and selected option Component mainLabel = option.name.copy().append(": "); String selectedOption = option.get().toString(); graphics.drawString(mc.font, mainLabel, x + 4, y + 2, -1, false); - Color fillColor = isMouseOver(mouseX, mouseY, x + 4 + mc.font.width(mainLabel), y, mc.font.width(selectedOption) + 5, mc.font.lineHeight + 2) ? getThemeColor().darker().darker() : getThemeColor(); + boolean isMouseOverText = isMouseOver(mouseX, mouseY, x + 4 + mc.font.width(mainLabel), y, mc.font.width(selectedOption) + 5, mc.font.lineHeight + 2); + Color fillColor = isMouseOverText ? getThemeColor().darker().darker() : getThemeColor(); DrawHelper.drawRoundedRectangle( graphics, x + 4 + mc.font.width(mainLabel), y, mc.font.width(selectedOption) + 5, mc.font.lineHeight + 2, 2, fillColor.getRGB() ); - // "<" and ">" buttons - int contextMenuWidth = (int) (width * 0.8f - 14); - int leftX = x + contextMenuWidth - 30; + int leftX = x + option.getWidth() - 30; boolean hoveredOverLeft = isMouseOver(mouseX, mouseY, leftX, y, mc.font.width("<") + 5, mc.font.lineHeight); boolean hoveredOverRight = isMouseOver(mouseX, mouseY, leftX + mc.font.width("<") + 6, y, mc.font.width(">") + 5, mc.font.lineHeight); - // Shadow + DrawHelper.drawRoundedRectangle( graphics, leftX + 1, y + 3, @@ -786,77 +760,62 @@ public void render(GuiGraphics graphics, ListOption option, int x, int y, int graphics.drawString(mc.font, "<", leftX + mc.font.width("<") / 2 + 1, y + 3, -1, false); graphics.drawString(mc.font, ">", leftX + mc.font.width("<") + 7 + mc.font.width(">") / 2, y + 3, -1, false); - graphics.drawString(mc.font, selectedOption, x + 6 + mc.font.width(mainLabel), y + 2, Color.LIGHT_GRAY.getRGB(), false); + graphics.drawString(mc.font, selectedOption, x + 6 + mc.font.width(mainLabel), y + 2, Color.LIGHT_GRAY.getRGB(), isMouseOverText); } @Override public boolean mouseClicked(ListOption option, double mouseX, double mouseY, int button) { if (option.getValues().isEmpty()) return false; - mouseX /= SCALE_FACTOR; - mouseY /= SCALE_FACTOR; + mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; + mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; int x = option.getX(); int y = option.getY(); Component mainLabel = option.name.copy().append(": "); String selectedOption = option.get().toString(); - // Calculate positions - int contextMenuWidth = (int) (width * 0.8f - 14); - int leftX = x + contextMenuWidth - 30; - - // Check hover states + int leftX = x + option.getWidth() - 30; boolean hoveredOverLeft = isMouseOver(mouseX, mouseY, leftX, y, mc.font.width("<") + 5, mc.font.lineHeight); boolean hoveredOverRight = isMouseOver(mouseX, mouseY, leftX + mc.font.width("<") + 6, y, mc.font.width(">") + 5, mc.font.lineHeight); boolean hoveredOverMainLabel = isMouseOver(mouseX, mouseY, x + 4 + mc.font.width(mainLabel), y, mc.font.width(selectedOption) + 5, mc.font.lineHeight + 2); - // Check if any area is clicked if (hoveredOverLeft || hoveredOverRight || hoveredOverMainLabel) { List values = option.getValues(); int currentIndex = values.indexOf(option.value); int nextIndex; - // Determine the next index based on the button clicked if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT || hoveredOverLeft) { - nextIndex = (currentIndex + 1) % values.size(); // Cycle forward + nextIndex = (currentIndex + 1) % values.size(); } else if (button == GLFW.GLFW_MOUSE_BUTTON_RIGHT || hoveredOverRight) { - nextIndex = (currentIndex - 1 + values.size()) % values.size(); // Cycle backward + nextIndex = (currentIndex - 1 + values.size()) % values.size(); } else { - return false; // No valid click + return false; } option.set(values.get(nextIndex)); return true; } - return SkinRenderer.super.mouseClicked(option, mouseX, mouseY, button); + return false; } } public class ModernSubMenuRenderer implements SkinRenderer { @Override public void render(GuiGraphics graphics, SubMenuOption option, int x, int y, int mouseX, int mouseY) { - mouseX = (int) (mc.mouseHandler.xpos() / SCALE_FACTOR); - mouseY = (int) (mc.mouseHandler.ypos() / SCALE_FACTOR); - - String Component = "Open"; - int contextMenuWidth = (int) (width * 0.8f - 14); - int xPos = x + 4 + contextMenuWidth - 40; + String textLabel = "Open"; + int xPos = x + option.getWidth() - 40; - option.setPosition(xPos - 1, y); - option.setWidth(mc.font.width(Component) + 5); option.setHeight(16); graphics.drawString(mc.font, option.name, x + 4, y + 4, -1, false); - - graphics.drawString(mc.font, Component, xPos + 2, y + 4, Color.WHITE.getRGB(), true); - - Color fillColor = isMouseOver(mouseX, mouseY, xPos + 2, y + 4, mc.font.width(Component) + 5, mc.font.lineHeight + 4) ? getThemeColor().darker().darker() : getThemeColor(); + Color fillColor = isMouseOver(mouseX, mouseY, xPos + 2, y + 4, mc.font.width(textLabel) + 5, mc.font.lineHeight + 4) ? getThemeColor().darker().darker() : getThemeColor(); DrawHelper.drawRoundedRectangleWithShadowBadWay( graphics, xPos - 1, y + 1, - mc.font.width(Component) + 5, mc.font.lineHeight + 4, + mc.font.width(textLabel) + 5, mc.font.lineHeight + 4, 2, fillColor.getRGB(), 180, @@ -866,12 +825,14 @@ public void render(GuiGraphics graphics, SubMenuOption option, int x, int y, int DrawHelper.drawOutlineRoundedBox( graphics, xPos - 1, y + 1, - mc.font.width(Component) + 5, mc.font.lineHeight + 4, + mc.font.width(textLabel) + 5, mc.font.lineHeight + 4, 2, 0.7f, Color.WHITE.getRGB() ); + graphics.drawString(mc.font, textLabel, xPos + 2, y + 4, Color.WHITE.getRGB(), true); + option.getSubMenu().render(graphics, x + option.getParentMenu().getWidth(), y, mouseX, mouseY); } @@ -893,58 +854,61 @@ public boolean mouseDragged(SubMenuOption option, double mouseX, double mouseY, public boolean mouseReleased(SubMenuOption option, double mouseX, double mouseY, int button) { mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; - return SkinRenderer.super.mouseReleased(option, mouseX, mouseY, button); + return isMouseOver(mouseX, mouseY, option.getX() + option.getWidth() - 40 + 2, option.getY() + 4, mc.font.width("Open") + 5, mc.font.lineHeight + 4); } @Override public boolean mouseClicked(SubMenuOption option, double mouseX, double mouseY, int button) { mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; - return SkinRenderer.super.mouseClicked(option, mouseX, mouseY, button); + if(isMouseOver(mouseX, mouseY, option.getX() + option.getWidth() - 40 + 2, option.getY() + 4, mc.font.width("Open") + 5, mc.font.lineHeight + 4)){ + option.toggle(); + return true; + } + return false; } } public class ModernRunnableRenderer implements SkinRenderer { - Color DARK_RED = new Color(116, 0, 0); - Color DARK_GREEN = new Color(24, 132, 0, 226); - @Override public void render(GuiGraphics graphics, RunnableOption option, int x, int y, int mouseX, int mouseY) { - String Component = "Run â–¶"; - int contextMenuWidth = (int) (width * 0.8f - 14); - int xPos = x + 4 + contextMenuWidth - 45; + String labelText = "Run â–¶"; + int xPos = x + option.getWidth() - 45; - option.setPosition(xPos - 1, y); - option.setWidth(mc.font.width(Component) + 5); option.setHeight(mc.font.lineHeight + 6); graphics.drawString(mc.font, option.name, x + 4, y + 4, -1, false); - graphics.drawString(mc.font, Component, xPos + 2, y + 4, option.value ? DARK_GREEN.getRGB() : DARK_RED.getRGB(), true); - - Color fillColor = isMouseOver(mouseX, mouseY, xPos + 2, y + 4, mc.font.width(Component) + 5, mc.font.lineHeight + 4) ? getThemeColor().darker().darker() : getThemeColor(); + Color fillColor = isMouseOver(mouseX, mouseY, xPos + 2, y + 4, mc.font.width(labelText) + 5, mc.font.lineHeight + 4) ? getThemeColor().darker().darker() : getThemeColor(); DrawHelper.drawRoundedRectangleWithShadowBadWay( graphics, xPos - 1, y + 1, - mc.font.width(Component) + 5, mc.font.lineHeight + 4, + mc.font.width(labelText) + 5, mc.font.lineHeight + 4, 2, fillColor.getRGB(), 180, 1, 1 ); + + graphics.drawString(mc.font, labelText, xPos + 2, y + 4, option.value ? DARK_GREEN.getRGB() : DARK_RED.getRGB(), true); } @Override public boolean mouseClicked(RunnableOption option, double mouseX, double mouseY, int button) { mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; - return SkinRenderer.super.mouseClicked(option, mouseX, mouseY, button); + if(isMouseOver(mouseX, mouseY, option.getX() + option.getWidth() - 45 + 2, option.getY() + 4, mc.font.width("Run â–¶") + 5, mc.font.lineHeight + 4)){ + option.toggle(); + return true; + } + return false; } } + @Override public Skin clone() { - return new ModernSkin(themeColor,radius,defaultToolTipHeader,defaultToolTipText); + return new ModernSkin(radius, defaultToolTipHeader, defaultToolTipText); } } \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/Skin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/Skin.java index 03f8a60..dc4997d 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/Skin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/Skin.java @@ -70,7 +70,7 @@ protected List> flattenOptions(List> options) { return flattened; } - protected List> getOptions(ContextMenu menu) { + public List> getOptions(ContextMenu menu) { return supportsGroups() ? menu.getOptions() : flattenOptions(menu.getOptions()); } diff --git a/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetRenderer.java b/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetRenderer.java index cd6df72..05d10a7 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetRenderer.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetRenderer.java @@ -5,7 +5,7 @@ import com.tanishisherewith.dynamichud.internal.System; import com.tanishisherewith.dynamichud.screens.AbstractMoveableScreen; import com.tanishisherewith.dynamichud.utils.Input; -import com.tanishisherewith.dynamichud.utils.contextmenu.contextmenuscreen.ContextMenuScreenRegistry; +import com.tanishisherewith.dynamichud.utils.contextmenu.screen.ContextMenuScreenRegistry; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screens.PauseScreen; import net.minecraft.client.gui.screens.Screen; diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java index 4ccd082..58d568f 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java @@ -15,6 +15,7 @@ import com.tanishisherewith.dynamichud.utils.contextmenu.options.ColorOption; import com.tanishisherewith.dynamichud.utils.contextmenu.options.DoubleOption; import com.tanishisherewith.dynamichud.utils.contextmenu.options.Option; +import com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.MinecraftSkin; import com.tanishisherewith.dynamichud.widget.DynamicValueWidget; import com.tanishisherewith.dynamichud.widget.WidgetBox; import com.tanishisherewith.dynamichud.widget.WidgetData; @@ -23,6 +24,7 @@ import net.minecraft.client.renderer.RenderPipelines; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; +import org.joml.Matrix3x2f; import java.awt.*; import java.util.ArrayList; @@ -211,7 +213,7 @@ private void drawInterpolatedCurve(GuiGraphics graphics, List points, i if (points.size() < 2) return; graphics.guiRenderState.submitGuiElement( - new InterpolatedCurveRenderState(points, thickness, color, graphics.pose(), CustomRenderLayers.QUADS_CUSTOM_BLEND, (int) width, (int) height, graphics.scissorStack.peek()) + new InterpolatedCurveRenderState(points, thickness, color, new Matrix3x2f(graphics.pose()), CustomRenderLayers.QUADS_CUSTOM_BLEND, (int) width, (int) height, graphics.scissorStack.peek()) ); } @@ -220,7 +222,7 @@ private void drawGradientShadow(GuiGraphics graphics, List points, floa if (points.size() < 2) return; graphics.guiRenderState.submitGuiElement( - new GradientShadowRenderState(points,bottomY, startColor, endColor, graphics.pose(), RenderPipelines.DEBUG_QUADS, (int) width, (int) height, graphics.scissorStack.peek()) + new GradientShadowRenderState(points,bottomY, startColor, endColor, new Matrix3x2f(graphics.pose()), RenderPipelines.DEBUG_QUADS, (int) width, (int) height, graphics.scissorStack.peek()) ); } @@ -274,7 +276,6 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { DrawHelper.stopScaling(graphics.pose()); } - // Update the offsets for the rest of the elements drawn. x += offset; // Draw vertical grid lines (time axis) @@ -294,7 +295,6 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { 0x00000000 ); - // Draw interpolated graph curve drawInterpolatedCurve(graphics, points, graphColor.getRGB(), lineThickness); DrawHelper.drawChromaText( @@ -348,7 +348,7 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { } public void createMenu() { - ContextMenuProperties properties = ContextMenuProperties.builder().build(); + ContextMenuProperties properties = ContextMenuProperties.builder().skin(new MinecraftSkin(MinecraftSkin.PanelColor.FOREST_GREEN)).build(); menu = new ContextMenu<>(getX(), (int) (getY() + widgetBox.getHeight()), properties); menu.addOption(new BooleanOption(Component.literal("Show Grid"), diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java index 25beeca..2ad95fb 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java @@ -3,6 +3,7 @@ import com.tanishisherewith.dynamichud.DynamicHUD; import com.tanishisherewith.dynamichud.config.GlobalConfig; import com.tanishisherewith.dynamichud.helpers.DrawHelper; +import com.tanishisherewith.dynamichud.integration.IntegrationManager; import com.tanishisherewith.dynamichud.utils.DynamicValueRegistry; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenu; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenuManager; @@ -92,43 +93,50 @@ public void createMenu() { .renderWhen(() -> this.rainbow) .withComplexity(Option.Complexity.Pro) ); - // Runnable Option - AtomicBoolean ran = new AtomicBoolean(false); - menu.addOption(new RunnableOption(Component.literal("Reset Position"), - ran::get, ran::set, - () -> this.setPosition(0, 0)) - .description(Component.literal("Reset widget to default position"))); - - // List Option - AtomicReference style = new AtomicReference<>("Style1"); - List styles = Arrays.asList("Style1", "Style2", "Style3"); - menu.addOption(new ListOption<>(Component.literal("Text Style"), - style::get, style::set, styles) - .description(Component.literal("Choose a text style"))); - - // Enum Option - menu.addOption(new EnumOption<>(Component.literal("Alignment"), - () -> GroupLayout.Alignment.CENTER, value -> {}, GroupLayout.Alignment.values()) - .description(Component.literal("Set text alignment"))); - - // Option Group - OptionGroup group = new OptionGroup(Component.literal("Display Options")); - group.addOption(new BooleanOption(Component.literal("Bold Text"), - () -> false, value -> {}, BooleanOption.BooleanType.YES_NO) - .description(Component.literal("Enable bold text"))); - group.addOption(new DoubleOption(Component.literal("Font Size"), - 8.0, 24.0, 1.0f, - () -> 12.0, value -> {}, menu) - .description(Component.literal("Adjust font size"))); - menu.addOption(group); - - // SubMenu Option - SubMenuOption subMenu = (SubMenuOption) new SubMenuOption(Component.literal("Advanced Settings"), menu) - .description(Component.literal("Open advanced settings")); - subMenu.getSubMenu().addOption(new BooleanOption(Component.literal("Some Boolean"), - () -> false, value -> {}, BooleanOption.BooleanType.TRUE_FALSE) - .description(Component.literal("True/False"))); - menu.addOption(subMenu); + if(IntegrationManager.IS_TEST_MODE) { + // Runnable Option + AtomicBoolean ran = new AtomicBoolean(false); + menu.addOption(new RunnableOption(Component.literal("Reset Position"), + ran::get, ran::set, + () -> this.setPosition(0, 0)) + .description(Component.literal("Reset widget to default position"))); + + // List Option + AtomicReference style = new AtomicReference<>("Style1"); + List styles = Arrays.asList("Style1", "Style2", "Style3"); + menu.addOption(new ListOption<>(Component.literal("Text Style"), + style::get, style::set, styles) + .description(Component.literal("Choose a text style"))); + + // Enum Option + AtomicReference align = new AtomicReference<>(GroupLayout.Alignment.CENTER); + + menu.addOption(new EnumOption<>(Component.literal("Alignment"), + align::get, align::set, GroupLayout.Alignment.values()) + .description(Component.literal("Set text alignment"))); + + // Option Group + OptionGroup group = new OptionGroup(Component.literal("Display Options")); + group.addOption(new BooleanOption(Component.literal("Bold Text"), + () -> false, value -> { + }, BooleanOption.BooleanType.YES_NO) + .description(Component.literal("Enable bold text"))); + group.addOption(new DoubleOption(Component.literal("Font Size"), + 8.0, 24.0, 1.0f, + () -> 12.0, value -> { + }, menu).description(Component.literal("Adjust font size"))); + + menu.addOption(group); + + // SubMenu Option + SubMenuOption subMenu = (SubMenuOption) new SubMenuOption(Component.literal("Advanced Settings"), menu) + .description(Component.literal("Open advanced settings")); + subMenu.getSubMenu().addOption(new BooleanOption(Component.literal("Some Boolean"), + () -> false, value -> { + }, BooleanOption.BooleanType.TRUE_FALSE) + .description(Component.literal("True/False"))); + menu.addOption(subMenu); + } } @Override From a2a9665cf8f6f331916a1d6081544f40b3496129 Mon Sep 17 00:00:00 2001 From: tanishisherewith <120117618+tanishisherewithhh@users.noreply.github.com> Date: Wed, 17 Jun 2026 17:00:06 +0530 Subject: [PATCH 06/22] Replaced ListOption and EnumOption with CycleOption Removed LayoutContext Added animations in ModernSkin New SquishAnimator Fixed some issues in GraphWidget --- .../dynamichud/helpers/DrawHelper.java | 6 +- .../animations/SquishAnimator.java | 41 +++ .../animations/ValueAnimation.java | 5 + .../utils/contextmenu/ContextMenu.java | 7 +- .../contextmenu/layout/LayoutContext.java | 60 ----- .../contextmenu/layout/LayoutEngine.java | 73 ++---- .../contextmenu/options/CycleOption.java | 60 +++++ .../utils/contextmenu/options/EnumOption.java | 49 ---- .../utils/contextmenu/options/ListOption.java | 50 ---- .../contextmenu/options/OptionGroup.java | 1 + .../contextmenu/screen/ContextMenuScreen.java | 3 +- .../contextmenu/skinsystem/ClassicSkin.java | 21 +- .../contextmenu/skinsystem/MinecraftSkin.java | 50 +--- .../contextmenu/skinsystem/ModernSkin.java | 243 +++++++++--------- .../skinsystem/interfaces/GroupableSkin.java | 4 +- .../utils/handlers/ScrollHandler.java | 4 +- .../dynamichud/widgets/GraphWidget.java | 15 +- .../dynamichud/widgets/TextWidget.java | 19 +- 18 files changed, 297 insertions(+), 414 deletions(-) create mode 100644 src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/SquishAnimator.java delete mode 100644 src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/layout/LayoutContext.java create mode 100644 src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/CycleOption.java delete mode 100644 src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/EnumOption.java delete mode 100644 src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ListOption.java diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java index ffac337..139d632 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java +++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java @@ -625,12 +625,11 @@ public static void scaledProjection(float scale, GuiGraphics graphics) { * @param scale Scale the matrices */ public static void scaleAndPosition(Matrix3x2fStack matrices, float x, float y, float scale) { - matrices.pushMatrix(); // Save the current transformation state + matrices.pushMatrix(); // Translate the origin back to the desired position matrices.translate(x, y); - // Scale the matrix matrices.scale(scale, scale); matrices.translate(-x, -y); @@ -654,12 +653,11 @@ public static ScreenRectangle createBounds(Matrix3x2f pose, ScreenRectangle scis * @param scale Scale the matrices */ public static void scaleAndPosition(Matrix3x2fStack matrices, float x, float y, float width, float height, float scale) { - matrices.pushMatrix(); // Save the current transformation state + matrices.pushMatrix(); // Translate the origin back to the desired position matrices.translate(x + width / 2.0f, y + height / 2.0f); - // Scale the matrix matrices.scale(scale, scale); matrices.translate(-(x + width / 2.0f), -(y + height / 2.0f)); diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/SquishAnimator.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/SquishAnimator.java new file mode 100644 index 0000000..9f9e403 --- /dev/null +++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/SquishAnimator.java @@ -0,0 +1,41 @@ +package com.tanishisherewith.dynamichud.helpers.animationhelper.animations; + +import com.tanishisherewith.dynamichud.helpers.animationhelper.AnimationProperty; +import com.tanishisherewith.dynamichud.helpers.animationhelper.EasingType; + +public class SquishAnimator { + private final ValueAnimation animation; + private final AnimationProperty property; + private boolean isPressed = false; + private float normalScale; + private float pressedScale; + + public SquishAnimator(float normalScale, float pressedScale) { + this.normalScale = normalScale; + this.pressedScale = pressedScale; + this.property = new AnimationProperty<>() { + private float val = normalScale; + public Float get() { return val; } + public void set(Float v) { val = v; } + }; + + this.animation = new ValueAnimation(property, normalScale, pressedScale); + this.animation.easing(EasingType.EASE_OUT_BACK); + this.animation.duration(125); + } + public SquishAnimator(){ + this(1.0f,0.95f); + } + + public void update(boolean pressed) { + if (this.isPressed != pressed) { + this.isPressed = pressed; + animation.startValue(property.get()); + animation.endValue(pressed ? pressedScale : normalScale); + animation.start(); + } + animation.update(); + } + + public float getScale() { return property.get(); } +} \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/ValueAnimation.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/ValueAnimation.java index 9d19d3b..c984e44 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/ValueAnimation.java +++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/ValueAnimation.java @@ -17,6 +17,7 @@ public ValueAnimation(AnimationProperty property, float start, float end, this.startValue = start; this.endValue = end; this.easing = easingType; + this.value = startValue; } public ValueAnimation(AnimationProperty property, float start, float end) { @@ -44,6 +45,10 @@ public ValueAnimation endValue(float endValue) { return this; } + public void setValue(float value) { + this.value = value; + } + public float getValue() { return value; } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java index f6b1860..b75fe93 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java @@ -112,7 +112,7 @@ public void render(GuiGraphics graphics, int xPos, int yPos, int mouseX, int mou if (scale <= 0.0f || newScreenFlag) return; - DrawHelper.scaleAndPosition(graphics.pose(), this.x + width/2.0f, this.y + height/2.0f, scale); + DrawHelper.scaleAndPosition(graphics.pose(), this.x, this.y,this.width,this.height, scale); properties.getSkin().setContextMenu(this); properties.getSkin().renderContextMenu(graphics, this, mouseX, mouseY); @@ -124,6 +124,7 @@ public void update() { if (layoutEngine != null) { layoutEngine.applyLayout(this); } + if (!properties.enableAnimations()) { scale = shouldDisplay ? 1.0f : 0.0f; return; @@ -212,8 +213,8 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { public boolean mouseReleased(double mouseX, double mouseY, int button) { if (!shouldDisplay) return false; for (Option option : options) { - if(option.shouldRender() && option.getRenderer().mouseReleased(option, mouseX, mouseY, button)){ - return true; + if(option.shouldRender()){ + option.getRenderer().mouseReleased(option, mouseX, mouseY, button); } } return properties.getSkin().mouseReleased(this, mouseX, mouseY, button); diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/layout/LayoutContext.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/layout/LayoutContext.java deleted file mode 100644 index a20ce5f..0000000 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/layout/LayoutContext.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.tanishisherewith.dynamichud.utils.contextmenu.layout; - -import com.tanishisherewith.dynamichud.utils.contextmenu.options.Option; - -//This was supposed to be used for something bigger but that got scraped. -public record LayoutContext(Offset indent, Option parentOption) { - public LayoutContext() { - this(Offset.zero(), null); - } - - // Builder-style methods for creating new contexts - public LayoutContext withIndent(Offset indent) { - return new LayoutContext(indent, this.parentOption); - } - - public LayoutContext withParent(Option parent) { - return new LayoutContext(this.indent, parent); - } - - public LayoutContext addIndent(Offset additionalIndent) { - return new LayoutContext( - this.indent.add(additionalIndent), - this.parentOption - ); - } - - // Utility methods for calculating positions - public int getEffectiveX(int baseX) { - return baseX + indent.left; - } - - public int getEffectiveY(int baseY) { - return baseY + indent.top; - } - - public int getEffectiveWidth(int baseWidth) { - return baseWidth + indent.left; - } - - public int getEffectiveHeight(int baseHeight) { - return baseHeight + indent.top; - } - - public record Offset(int left, int top) { - public Offset(int all) { - this(all, all); - } - - public static Offset zero() { - return new Offset(0); - } - - public Offset add(Offset other) { - return new Offset( - this.left + other.left, - this.top + other.top - ); - } - } -} diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/layout/LayoutEngine.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/layout/LayoutEngine.java index 4f1d5f1..7009c54 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/layout/LayoutEngine.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/layout/LayoutEngine.java @@ -1,9 +1,13 @@ package com.tanishisherewith.dynamichud.utils.contextmenu.layout; import com.tanishisherewith.dynamichud.DynamicHUD; +import com.tanishisherewith.dynamichud.helpers.DrawHelper; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenu; import com.tanishisherewith.dynamichud.utils.contextmenu.options.Option; +import com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.Skin; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import org.joml.Vector2d; import java.util.List; @@ -12,15 +16,20 @@ public class LayoutEngine { private int verticalPadding = 4; private int itemSpacing = 2; private int minWidth = 80; - private LayoutStrategy activeStrategy = new VerticalFlowStrategy(); + private LayoutStrategy activeStrategy; public LayoutEngine() {} public LayoutEngine(int horizontalPadding, int verticalPadding, int itemSpacing, int minWidth) { + this(horizontalPadding,verticalPadding,itemSpacing,minWidth,new VerticalFlowStrategy()); + } + + public LayoutEngine(int horizontalPadding, int verticalPadding, int itemSpacing, int minWidth, LayoutStrategy layoutStrategy) { this.horizontalPadding = horizontalPadding; this.verticalPadding = verticalPadding; this.itemSpacing = itemSpacing; this.minWidth = minWidth; + this.activeStrategy = layoutStrategy; } @FunctionalInterface @@ -31,7 +40,6 @@ public interface LayoutStrategy { void layout(ContextMenu menu, LayoutEngine engine); } - /** * Executes the currently active layout strategy to position and size options dynamically. */ @@ -41,48 +49,6 @@ public void applyLayout(ContextMenu menu) { } } - /** - * Linear layout for skins that need to know their total dimensions - */ - public void performSimpleLayout(ContextMenu menu) { - if (menu == null) return; - - Font font = Minecraft.getInstance().font; - List> visibleOptions = menu.getProperties().getSkin().getOptions(menu); - int paddingValue = menu.getProperties().getPadding(); - - //width calculation - int maxInnerWidth = minWidth; - for (Option option : visibleOptions) { - if (!option.shouldRender()) continue; - - int preferredWidth = option.getWidth() > 0 ? option.getWidth() : font.width(option.getName()); - - maxInnerWidth = Math.max(maxInnerWidth, preferredWidth); - } - - int totalMenuWidth = maxInnerWidth + (horizontalPadding * 2) + paddingValue; - - int currentY = menu.getY() + verticalPadding + 3; - int currentX = menu.getX() + horizontalPadding; - - // height calculation - for (Option option : visibleOptions) { - if (!option.shouldRender()) continue; - - int itemHeight = option.getHeight() > 0 ? option.getHeight() : font.lineHeight; - - option.setWidth(totalMenuWidth - (horizontalPadding * 2) - paddingValue); - option.setHeight(itemHeight); - option.setPosition(currentX, currentY); - - currentY += itemHeight + itemSpacing; - } - - menu.setWidth(totalMenuWidth); - menu.setHeight(currentY - menu.getY()); - } - /** * Helper function for immediate layouts * Automatically updates the option's dimensions and returns the updated Y position for the next element. @@ -133,7 +99,7 @@ public void setActiveStrategy(LayoutStrategy activeStrategy) { public static class VerticalFlowStrategy implements LayoutStrategy { @Override public void layout(ContextMenu menu, LayoutEngine engine) { - if (menu == null || menu.getProperties() == null) return; + if (menu == null) return; Font font = Minecraft.getInstance().font; List> visibleOptions = menu.getProperties().getSkin().getOptions(menu); @@ -163,4 +129,21 @@ public void layout(ContextMenu menu, LayoutEngine engine) { menu.setHeight(currentY - menu.getY()); } } + + public record Offset(int left, int top) { + public Offset(int all) { + this(all, all); + } + + public static Offset zero() { + return new Offset(0); + } + + public Offset add(Offset other) { + return new Offset( + this.left + other.left, + this.top + other.top + ); + } + } } \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/CycleOption.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/CycleOption.java new file mode 100644 index 0000000..fa3a158 --- /dev/null +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/CycleOption.java @@ -0,0 +1,60 @@ +package com.tanishisherewith.dynamichud.utils.contextmenu.options; + +import net.minecraft.network.chat.Component; +import org.lwjgl.glfw.GLFW; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public class CycleOption extends Option { + protected final List values; + protected int currentIndex; + + @SafeVarargs + public CycleOption(Component name, Supplier getter, Consumer setter, T... values) { + this(name, getter, setter, Arrays.asList(values)); + } + + public CycleOption(Component name, Supplier getter, Consumer setter, List values) { + super(name, getter, setter); + this.values = values; + this.currentIndex = values.indexOf(value); + if (currentIndex == -1) { + for (int i = 0; i < values.size(); i++) { + if (values.get(i).toString().equals(value)) { + currentIndex = i; + break; + } + } + } + } + + public void cycle(int direction) { + currentIndex = (currentIndex + direction + values.size()) % values.size(); + if (currentIndex < 0) currentIndex += values.size(); + + set(values.get(currentIndex)); + } + + public T getCurrentValue() { return value; } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (super.mouseClicked(mouseX, mouseY, button)) { + if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { + cycle(1); + } else if (button == GLFW.GLFW_MOUSE_BUTTON_RIGHT) { + cycle(-1); + } + set(value); + return true; + } + return false; + } + + public List getValues() { + return values; + } +} \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/EnumOption.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/EnumOption.java deleted file mode 100644 index ffb0350..0000000 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/EnumOption.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.tanishisherewith.dynamichud.utils.contextmenu.options; - -import net.minecraft.network.chat.Component; - -import java.util.function.Consumer; -import java.util.function.Supplier; - -public class EnumOption> extends Option { - private final E[] values; - private int currentIndex = 0; - - public EnumOption(Component name, Supplier getter, Consumer setter, E[] values) { - super(name, getter, setter); - this.values = values; - this.value = get(); - for (int i = 0; i < values.length; i++) { - if (values[i] == value) { - currentIndex = i; - break; - } - } - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (super.mouseClicked(mouseX, mouseY, button)) { - if (button == 0) { - currentIndex = (currentIndex + 1) % values.length; - if (currentIndex > values.length - 1) { - currentIndex = 0; - } - value = values[currentIndex]; - } else if (button == 1) { - currentIndex = (currentIndex - 1) % values.length; - if (currentIndex < 0) { - currentIndex = values.length - 1; - } - value = values[currentIndex]; - } - set(value); - return true; - } - return false; - } - - public E[] getValues() { - return values; - } -} diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ListOption.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ListOption.java deleted file mode 100644 index f87a648..0000000 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ListOption.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.tanishisherewith.dynamichud.utils.contextmenu.options; - -import net.minecraft.network.chat.Component; - -import java.util.List; -import java.util.function.Consumer; -import java.util.function.Supplier; - -public class ListOption extends Option { - private final List values; - private int currentIndex = 0; - - public ListOption(Component name, Supplier getter, Consumer setter, List values) { - super(name, getter, setter); - this.values = values; - this.value = getter.get(); - for (int i = 0; i < values.size(); i++) { - if (values.get(i).toString().equals(value)) { - currentIndex = i; - break; - } - } - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (super.mouseClicked(mouseX, mouseY, button)) { - if (button == 0) { - currentIndex = (currentIndex + 1) % values.size(); - if (currentIndex > values.size() - 1) { - currentIndex = 0; - } - value = values.get(currentIndex); - } else if (button == 1) { - currentIndex = (currentIndex - 1) % values.size(); - if (currentIndex < 0) { - currentIndex = values.size() - 1; - } - value = values.get(currentIndex); - } - set(value); - return true; - } - return false; - } - - public List getValues() { - return values; - } -} diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/OptionGroup.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/OptionGroup.java index 33b0c5a..b10cd69 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/OptionGroup.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/OptionGroup.java @@ -10,6 +10,7 @@ import java.util.List; // A group is just another type of Option that contains other options +@SuppressWarnings({"rawtypes", "unchecked"}) public class OptionGroup extends Option { private final List> groupOptions = new ArrayList<>(); protected boolean expanded; // Skins can choose to use this or ignore it diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/ContextMenuScreen.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/ContextMenuScreen.java index 28c6cca..2a8f89f 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/ContextMenuScreen.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/ContextMenuScreen.java @@ -8,6 +8,7 @@ import net.minecraft.client.input.KeyEvent; import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.network.chat.Component; +import org.jspecify.annotations.NonNull; public class ContextMenuScreen extends Screen { ContextMenu contextMenu; @@ -41,7 +42,7 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) { } @Override - public void renderBackground(GuiGraphics guiGraphics, int i, int j, float f) { + public void renderBackground(@NonNull GuiGraphics guiGraphics, int i, int j, float f) { } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ClassicSkin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ClassicSkin.java index 89bbe7c..39b51ec 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ClassicSkin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ClassicSkin.java @@ -21,8 +21,7 @@ public ClassicSkin() { super(); addRenderer(BooleanOption.class, ClassicBooleanRenderer::new); addRenderer(ColorOption.class, ClassicColorOptionRenderer::new); - addRenderer(EnumOption.class, ClassicEnumRenderer::new); - addRenderer(ListOption.class, ClassicListRenderer::new); + addRenderer(CycleOption.class, ClassicCycleRenderer::new); addRenderer(SubMenuOption.class, ClassicSubMenuRenderer::new); addRenderer(RunnableOption.class, ClassicRunnableRenderer::new); addRenderer(DoubleOption.class, ClassicDoubleRenderer::new); @@ -35,10 +34,6 @@ public void renderContextMenu(GuiGraphics graphics, ContextMenu contextMenu, this.contextMenu = contextMenu; ContextMenuProperties properties = contextMenu.getProperties(); - if (contextMenu.getLayoutEngine() != null) { - contextMenu.getLayoutEngine().applyLayout(contextMenu); - } - drawBackground(graphics, contextMenu, properties); for (Option option : getOptions(contextMenu)) { @@ -120,19 +115,11 @@ public void render(GuiGraphics graphics, ColorOption option, int x, int y, int m } } - public static class ClassicEnumRenderer> implements SkinRenderer> { + public static class ClassicCycleRenderer implements SkinRenderer> { @Override - public void render(GuiGraphics graphics, EnumOption option, int x, int y, int mouseX, int mouseY) { + public void render(GuiGraphics graphics, CycleOption option, int x, int y, int mouseX, int mouseY) { graphics.drawString(mc.font, option.name.copy().append(": "), x, y, Color.WHITE.getRGB(), false); - graphics.drawString(mc.font, option.get().name(), x + mc.font.width(option.name + ": ") + 1, y, Color.CYAN.getRGB(), false); - } - } - - public static class ClassicListRenderer implements SkinRenderer> { - @Override - public void render(GuiGraphics graphics, ListOption option, int x, int y, int mouseX, int mouseY) { - graphics.drawString(mc.font, option.name.copy().append(": "), x, y + 1, Color.WHITE.getRGB(), false); - graphics.drawString(mc.font, option.get().toString(), x + mc.font.width(option.name + ": ") + 1, y + 1, Color.CYAN.getRGB(), false); + graphics.drawString(mc.font, option.get().toString(), x + mc.font.width(option.name + ": ") + 1, y, Color.CYAN.getRGB(), false); } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java index 9266750..0275199 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java @@ -6,7 +6,7 @@ import com.tanishisherewith.dynamichud.helpers.animationhelper.EasingType; import com.tanishisherewith.dynamichud.helpers.animationhelper.animations.ValueAnimation; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenu; -import com.tanishisherewith.dynamichud.utils.contextmenu.layout.LayoutContext; +import com.tanishisherewith.dynamichud.utils.contextmenu.layout.LayoutEngine; import com.tanishisherewith.dynamichud.utils.contextmenu.options.*; import com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.interfaces.GroupableSkin; import com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.interfaces.SkinRenderer; @@ -49,9 +49,9 @@ public class MinecraftSkin extends Skin implements GroupableSkin { public static final int DEFAULT_SCROLLBAR_WIDTH = 8; public static final int DEFAULT_PANEL_WIDTH = 248; public static final int DEFAULT_PANEL_HEIGHT = 165; - private final int panelWidth; - private final int panelHeight; - private final int groupPanelWidth = 60; // Width for the group panel + private int panelWidth; + private int panelHeight; + private int groupPanelWidth = 60; // Width for the group panel private int imageX, imageY; private final ScrollHandler scrollHandler; @@ -68,12 +68,12 @@ public MinecraftSkin(PanelColor color) { this.panelColor = color; addRenderer(BooleanOption.class, MinecraftBooleanRenderer::new); addRenderer(DoubleOption.class, MinecraftDoubleRenderer::new); - addRenderer(EnumOption.class, MinecraftEnumRenderer::new); - addRenderer(ListOption.class, MinecraftListRenderer::new); + addRenderer(CycleOption.class, MinecraftCycleRenderer::new); addRenderer(SubMenuOption.class, MinecraftSubMenuRenderer::new); addRenderer(RunnableOption.class, MinecraftRunnableRenderer::new); addRenderer(ColorOption.class, MinecraftColorOptionRenderer::new); + // if in case of different texture support. this.panelHeight = DEFAULT_PANEL_HEIGHT; this.panelWidth = DEFAULT_PANEL_WIDTH; this.BACKGROUND_PANEL = DEFAULT_BACKGROUND_PANEL; @@ -322,8 +322,8 @@ public boolean mouseDragged(ContextMenu menu, double mouseX, double mouseY, i } @Override - public LayoutContext.Offset getGroupIndent() { - return LayoutContext.Offset.zero(); + public LayoutEngine.Offset getGroupIndent() { + return LayoutEngine.Offset.zero(); } public void setPanelColor(PanelColor panelColor) { @@ -557,7 +557,6 @@ public void render(GuiGraphics graphics, DoubleOption option, int x, int y, int graphics.blitSprite(RenderPipelines.GUI_TEXTURED, option.isMouseOver(mouseX, mouseY) ? HIGHLIGHTED_TEXTURE : TEXTURE, option.getX(), y, option.getWidth(), 20); graphics.blitSprite(RenderPipelines.GUI_TEXTURED, isMouseOverHandle ? HANDLE_HIGHLIGHTED_TEXTURE : HANDLE_TEXTURE, (int) Math.round(sliderX), y, 8, 20); - // Determine the number of decimal places in option.step int decimalPlaces = String.valueOf(option.step).split("\\.")[1].length(); // Format option.value to the determined number of decimal places @@ -566,37 +565,10 @@ public void render(GuiGraphics graphics, DoubleOption option, int x, int y, int } } - public class MinecraftEnumRenderer> implements SkinRenderer> { + public class MinecraftCycleRenderer implements SkinRenderer> { private int maxWidth = 50; - private void calculateMaxWidth(EnumOption option) { - for (E enumConstant : option.getValues()) { - int width = mc.font.width(enumConstant.name()) + 5; - if (width > maxWidth) { - maxWidth = width; - } - } - } - - @Override - public void render(GuiGraphics graphics, EnumOption option, int x, int y, int mouseX, int mouseY) { - calculateMaxWidth(option); - option.setWidth(maxWidth); - - graphics.drawString(mc.font, option.name.copy().append(": "), x + 15, y + 25 / 2 - 5, -1, true); - - option.setPosition(x + panelWidth - maxWidth - 25, y); - - graphics.blitSprite(RenderPipelines.GUI_TEXTURED, TEXTURES.get(true, option.isMouseOver(mouseX, mouseY)), option.getX(), y, maxWidth, 20); - String Component = option.get().toString(); - graphics.drawString(mc.font, Component, option.getX() + maxWidth / 2 - mc.font.width(Component) / 2, y + 5, Color.CYAN.getRGB(), true); - } - } - - public class MinecraftListRenderer implements SkinRenderer> { - private int maxWidth = 50; - - private void calculateMaxWidth(ListOption option) { + private void calculateMaxWidth(CycleOption option) { for (E listValues : option.getValues()) { int width = mc.font.width(listValues.toString()) + 5; if (width > maxWidth) { @@ -606,7 +578,7 @@ private void calculateMaxWidth(ListOption option) { } @Override - public void render(GuiGraphics graphics, ListOption option, int x, int y, int mouseX, int mouseY) { + public void render(GuiGraphics graphics, CycleOption option, int x, int y, int mouseX, int mouseY) { calculateMaxWidth(option); option.setWidth(maxWidth); diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java index 2ff9eec..5e15ec5 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java @@ -2,10 +2,13 @@ import com.tanishisherewith.dynamichud.helpers.ColorHelper; import com.tanishisherewith.dynamichud.helpers.DrawHelper; +import com.tanishisherewith.dynamichud.helpers.animationhelper.AnimationProperty; import com.tanishisherewith.dynamichud.helpers.animationhelper.EasingType; import com.tanishisherewith.dynamichud.helpers.animationhelper.animations.MathAnimations; +import com.tanishisherewith.dynamichud.helpers.animationhelper.animations.SquishAnimator; +import com.tanishisherewith.dynamichud.helpers.animationhelper.animations.ValueAnimation; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenu; -import com.tanishisherewith.dynamichud.utils.contextmenu.layout.LayoutContext; +import com.tanishisherewith.dynamichud.utils.contextmenu.layout.LayoutEngine; import com.tanishisherewith.dynamichud.utils.contextmenu.options.*; import com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.interfaces.GroupableSkin; import com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.interfaces.SkinRenderer; @@ -19,7 +22,6 @@ import org.lwjgl.glfw.GLFW; import java.awt.*; -import java.util.Arrays; import java.util.List; import static com.tanishisherewith.dynamichud.helpers.ColorHelper.DARK_GREEN; @@ -50,8 +52,7 @@ public ModernSkin(float radius, Component defaultToolTipHeader, Component defaul addRenderer(BooleanOption.class, ModernBooleanRenderer::new); addRenderer(DoubleOption.class, ModernDoubleRenderer::new); - addRenderer(EnumOption.class, ModernEnumRenderer::new); - addRenderer(ListOption.class, ModernListRenderer::new); + addRenderer(CycleOption.class, ModernCycleRenderer::new); addRenderer(SubMenuOption.class, ModernSubMenuRenderer::new); addRenderer(RunnableOption.class, ModernRunnableRenderer::new); addRenderer(ColorOption.class, ModernColorOptionRenderer::new); @@ -70,8 +71,8 @@ public ModernSkin() { } @Override - public LayoutContext.Offset getGroupIndent() { - return new LayoutContext.Offset(4, 4); + public LayoutEngine.Offset getGroupIndent() { + return new LayoutEngine.Offset(4, 4); } public void enableSkinScissor(GuiGraphics graphics) { @@ -85,7 +86,7 @@ public void renderGroup(GuiGraphics graphics, OptionGroup group, int groupX, int } private int calcOptionHeight(Option option) { if (option instanceof BooleanOption || option instanceof DoubleOption) return 14; - if (option instanceof EnumOption || option instanceof ListOption) return mc.font.lineHeight + 2; + if (option instanceof CycleOption) return mc.font.lineHeight + 2; if (option instanceof SubMenuOption) return 16; if (option instanceof RunnableOption) return mc.font.lineHeight + 6; if (option instanceof ColorOption colorOption) { @@ -173,7 +174,7 @@ public void renderContextMenu(GuiGraphics graphics, ContextMenu contextMenu, enableSkinScissor(graphics); - int yOffset = contextMenu.y + 19 + 3 - scrollHandler.getScrollOffset(); + int yPos = contextMenu.y + 22 - scrollHandler.getScrollOffset(); for (Option option : getOptions(contextMenu)) { if (!option.shouldRender()) continue; @@ -183,21 +184,21 @@ public void renderContextMenu(GuiGraphics graphics, ContextMenu contextMenu, } option.setHeight(calcOptionHeight(option)); - int nextY = contextMenu.getLayoutEngine().layoutOption(option, optionStartX + 2, yOffset, targetWidth); + int nextY = contextMenu.getLayoutEngine().layoutOption(option, optionStartX + 2, yPos, targetWidth); if (option instanceof OptionGroup group) { - this.renderGroup(graphics, group, optionStartX + 2, yOffset, targetWidth, mouseX, mouseY); - yOffset += group.getHeight() + contextMenu.getLayoutEngine().getItemSpacing(); + this.renderGroup(graphics, group, optionStartX + 2, yPos, mouseX, mouseY); + yPos += group.getHeight() + contextMenu.getLayoutEngine().getItemSpacing(); } else { option.render(graphics, option.getX(), option.getY(), mouseX, mouseY); - yOffset = nextY; + yPos = nextY; } } DrawHelper.disableScissor(graphics); contextMenu.setWidth(width); - contextMenu.setHeight(yOffset - (contextMenu.y + 19 + 3 - scrollHandler.getScrollOffset()) + 4); + contextMenu.setHeight(yPos - (contextMenu.y + 26 - scrollHandler.getScrollOffset())); scrollHandler.updateScrollOffset(getMaxScrollOffset()); @@ -322,13 +323,13 @@ public boolean mouseClicked(ContextMenu menu, double mouseX, double mouseY, i mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; - if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && isMouseOver(mouseX, mouseY, contextMenuX + width - 5, contextMenuY, 7, height)) { + if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && isMouseOver(mouseX, mouseY, contextMenuX + width - 5, contextMenuY + 19, 7, height)) { scrollHandler.startDragging(mouseY); } if (button == GLFW.GLFW_MOUSE_BUTTON_RIGHT) { int optionStartX = contextMenuX + (int) (width * 0.2f) + 10; - int yOffset = contextMenu.y + 22 - scrollHandler.getScrollOffset(); + int yPos = contextMenu.y + 22 - scrollHandler.getScrollOffset(); int spacing = contextMenu.getLayoutEngine().getItemSpacing(); for (Option option : getOptions(contextMenu)) { @@ -337,15 +338,15 @@ public boolean mouseClicked(ContextMenu menu, double mouseX, double mouseY, i int optHeight = calcOptionHeight(option); if (option instanceof OptionGroup group) { Component groupText = group.name.copy().append(" " + (group.isExpanded() ? "-" : "+")); - if (isMouseOver(mouseX, mouseY, optionStartX + 2, yOffset, + if (isMouseOver(mouseX, mouseY, optionStartX + 2, yPos, mc.font.width(groupText) + 6, 16)) { group.setExpanded(!group.isExpanded()); return true; } - yOffset += group.getHeight() + spacing; + yPos += group.getHeight() + spacing; } else { - yOffset += optHeight + spacing; + yPos += optHeight + spacing; } } } @@ -362,7 +363,7 @@ public boolean mouseDragged(ContextMenu menu, double mouseX, double mouseY, i mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; - if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && isMouseOver(mouseX, mouseY, contextMenuX + width - 5, contextMenuY, 7, height)) { + if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && isMouseOver(mouseX, mouseY, contextMenuX + width - 5, contextMenuY + 19, 7, height)) { scrollHandler.updateScrollPosition(mouseY); } return super.mouseDragged(menu, mouseX, mouseY, button, deltaX, deltaY); @@ -427,6 +428,8 @@ public class ModernColorOptionRenderer implements SkinRenderer { private static final float ANIMATION_SPEED = 0.1f; private float scale = 0f; private boolean display = false; + private final SquishAnimator animator = new SquishAnimator(); + public void update(ColorOption option) { if (option.getColorGradient().shouldDisplay() && display) { @@ -457,7 +460,13 @@ public void render(GuiGraphics graphics, ColorOption option, int x, int y, int m int width = 20; int shadowOpacity = Math.min(option.value.getAlpha(), 45); - Color behindColor = isMouseOver(mouseX, mouseY, x + option.getWidth() - width - 17, y + 1, width + 2, 14) ? getThemeColor().darker().darker() : getThemeColor(); + boolean isHovering = isMouseOver(mouseX, mouseY, x + option.getWidth() - width - 17, y + 1, width + 2, 14); + boolean isDown = isHovering && GLFW.glfwGetMouseButton(mc.getWindow().handle(), GLFW.GLFW_MOUSE_BUTTON_LEFT) == GLFW.GLFW_PRESS; + animator.update(isDown); + + Color behindColor = isHovering ? getThemeColor().darker().darker() : getThemeColor(); + DrawHelper.scaleAndPosition(graphics.pose(), x + option.getWidth() - width - 17, y + 1,width + 2, 14, scale); + DrawHelper.drawRoundedRectangleWithShadowBadWay(graphics, x + option.getWidth() - width - 17, y + 1, @@ -489,6 +498,8 @@ public void render(GuiGraphics graphics, ColorOption option, int x, int y, int m 1, 1); + DrawHelper.stopScaling(graphics.pose()); + int targetHeight = (int) (option.getColorGradient().getBoxSize() + option.getColorGradient().getGradientBox().getSize() * scale); option.setHeight(option.getColorGradient().shouldDisplay() ? targetHeight : 20); @@ -572,7 +583,10 @@ public void render(GuiGraphics graphics, DoubleOption option, int x, int y, int float sliderHandleX = sliderX + activeFillWidth - 5; DrawHelper.drawFilledCircle(graphics, sliderHandleX + 5, y + 1, 2, Color.WHITE.getRGB()); - String label = String.format("%.2f", displayValue); + int decimalPlaces = String.valueOf(option.step).split("\\.")[1].length(); + + // Format option.value to the determined number of decimal places + String label = String.format("%." + decimalPlaces + "f", displayValue); DrawHelper.scaleAndPosition(graphics.pose(), sliderX + sliderBackgroundWidth - mc.font.width(label), y + 7, 0.6f); graphics.drawString( mc.font, @@ -612,159 +626,106 @@ public boolean mouseDragged(DoubleOption option, double mouseX, double mouseY, i public boolean mouseReleased(DoubleOption option, double mouseX, double mouseY, int button) { if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { option.setDragging(false); - return true; } return false; } } - public class ModernEnumRenderer> implements SkinRenderer> { + public class ModernCycleRenderer implements SkinRenderer> { + private final SquishAnimator textAnim = new SquishAnimator(); + private final SquishAnimator leftAnim = new SquishAnimator(1.0f,0.9f); + private final SquishAnimator rightAnim = new SquishAnimator(1.0f,0.9f); + @Override - public void render(GuiGraphics graphics, EnumOption option, int x, int y, int mouseX, int mouseY) { + public void render(GuiGraphics graphics, CycleOption option, int x, int y, int mouseX, int mouseY) { option.setHeight(mc.font.lineHeight + 2); Component mainLabel = option.name.copy().append(": "); - String selectedOption = option.get().toString(); graphics.drawString(mc.font, mainLabel, x + 4, y + 2, -1, false); - boolean isMouseOverText = isMouseOver(mouseX, mouseY, x + 4 + mc.font.width(mainLabel), y, mc.font.width(selectedOption) + 5, mc.font.lineHeight + 2); - Color fillColor = isMouseOverText ? getThemeColor().darker().darker() : getThemeColor(); - DrawHelper.drawRoundedRectangle( - graphics, - x + 4 + mc.font.width(mainLabel), y, mc.font.width(selectedOption) + 5, mc.font.lineHeight + 2, 2, - fillColor.getRGB() - ); - - int leftX = x + option.getWidth() - 30; - boolean hoveredOverLeft = isMouseOver(mouseX, mouseY, leftX, y, mc.font.width("<") + 5, mc.font.lineHeight); - boolean hoveredOverRight = isMouseOver(mouseX, mouseY, leftX + mc.font.width("<") + 6, y, mc.font.width(">") + 5, mc.font.lineHeight); - - DrawHelper.drawRoundedRectangle( - graphics, - leftX + 1, y + 3, - (mc.font.width("<") * 2) + 10, mc.font.lineHeight, 2, - ColorHelper.changeAlpha(Color.BLACK, 128).getRGB() - ); - DrawHelper.drawRoundedRectangle( - graphics, - leftX, y + 2, - true, false, true, false, - mc.font.width("<") + 5, mc.font.lineHeight, 2, - hoveredOverLeft ? getThemeColor().darker().darker().getRGB() : getThemeColor().getRGB() - ); - DrawHelper.drawRoundedRectangle( - graphics, - leftX + mc.font.width("<") + 6, y + 2, - false, true, false, true, - mc.font.width(">") + 5, mc.font.lineHeight, 2, - hoveredOverRight ? getThemeColor().darker().darker().getRGB() : getThemeColor().getRGB() - ); - DrawHelper.drawVerticalLine( - graphics, - leftX + mc.font.width("<") + 5, - y + 2, - mc.font.lineHeight, - 0.7f, - Color.WHITE.getRGB() - ); - graphics.drawString(mc.font, "<", leftX + mc.font.width("<") / 2 + 1, y + 3, -1, false); - graphics.drawString(mc.font, ">", leftX + mc.font.width("<") + 7 + mc.font.width(">") / 2, y + 3, -1, false); - - graphics.drawString(mc.font, selectedOption, x + 6 + mc.font.width(mainLabel), y + 2, Color.LIGHT_GRAY.getRGB(), isMouseOverText); - } - - @Override - public boolean mouseClicked(EnumOption option, double mouseX, double mouseY, int button) { - if (option.getValues().length == 0) return false; - - mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; - mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; - int x = option.getX(); - int y = option.getY(); - Component mainLabel = option.name.copy().append(": "); String selectedOption = option.get().toString(); int leftX = x + option.getWidth() - 30; - boolean hoveredOverLeft = isMouseOver(mouseX, mouseY, leftX, y, mc.font.width("<") + 5, mc.font.lineHeight); - boolean hoveredOverRight = isMouseOver(mouseX, mouseY, leftX + mc.font.width("<") + 6, y, mc.font.width(">") + 5, mc.font.lineHeight); - boolean hoveredOverMainLabel = isMouseOver(mouseX, mouseY, x + 4 + mc.font.width(mainLabel), y, mc.font.width(selectedOption) + 5, mc.font.lineHeight + 2); - if (hoveredOverLeft || hoveredOverRight || hoveredOverMainLabel) { - E[] values = option.getValues(); - int index = Arrays.asList(values).indexOf(option.value); + int mainLabelWidth = mc.font.width(mainLabel); + int selectedOptionWidth = mc.font.width(selectedOption); + int leftWidth = mc.font.width("<"); + int rightWidth = mc.font.width(">"); - if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT || hoveredOverLeft) { - E nextVal = values[(index + 1) % values.length]; - option.set(nextVal); - } else if (button == GLFW.GLFW_MOUSE_BUTTON_RIGHT || hoveredOverRight) { - E nextVal = values[(index - 1 + values.length) % values.length]; - option.set(nextVal); - } else { - return false; - } - return true; - } + boolean hoveredOverText = isMouseOver(mouseX, mouseY, x + 4 + mainLabelWidth, y, selectedOptionWidth + 5, mc.font.lineHeight + 2); + boolean hoveredOverLeft = isMouseOver(mouseX, mouseY, leftX, y, leftWidth + 5, mc.font.lineHeight); + boolean hoveredOverRight = isMouseOver(mouseX, mouseY, leftX + leftWidth + 6, y, rightWidth + 5, mc.font.lineHeight); - return false; - } - } + boolean isPressed = GLFW.glfwGetMouseButton(mc.getWindow().handle(), GLFW.GLFW_MOUSE_BUTTON_LEFT) == GLFW.GLFW_PRESS || GLFW.glfwGetMouseButton(mc.getWindow().handle(), GLFW.GLFW_MOUSE_BUTTON_RIGHT) == GLFW.GLFW_PRESS; + boolean isClickingOnText = hoveredOverText && isPressed; + boolean isClickingOnLeft = hoveredOverLeft && isPressed; + boolean isClickingOnRight = hoveredOverRight && isPressed; - public class ModernListRenderer implements SkinRenderer> { - @Override - public void render(GuiGraphics graphics, ListOption option, int x, int y, int mouseX, int mouseY) { - option.setHeight(mc.font.lineHeight + 2); + textAnim.update(isClickingOnText); + leftAnim.update(isClickingOnLeft); + rightAnim.update(isClickingOnRight); - Component mainLabel = option.name.copy().append(": "); - String selectedOption = option.get().toString(); - graphics.drawString(mc.font, mainLabel, x + 4, y + 2, -1, false); - boolean isMouseOverText = isMouseOver(mouseX, mouseY, x + 4 + mc.font.width(mainLabel), y, mc.font.width(selectedOption) + 5, mc.font.lineHeight + 2); - Color fillColor = isMouseOverText ? getThemeColor().darker().darker() : getThemeColor(); + DrawHelper.scaleAndPosition(graphics.pose(),x + 4 + mainLabelWidth, y, selectedOptionWidth + 5, mc.font.lineHeight + 2, textAnim.getScale()); + + Color fillColor = hoveredOverText ? getThemeColor().darker().darker() : getThemeColor(); DrawHelper.drawRoundedRectangle( graphics, - x + 4 + mc.font.width(mainLabel), y, mc.font.width(selectedOption) + 5, mc.font.lineHeight + 2, 2, + x + 4 + mainLabelWidth, y, selectedOptionWidth + 5, mc.font.lineHeight + 2, 2, fillColor.getRGB() ); + graphics.drawString(mc.font, selectedOption, x + 6 + mainLabelWidth, y + 2, Color.WHITE.getRGB(), hoveredOverText); - int leftX = x + option.getWidth() - 30; - boolean hoveredOverLeft = isMouseOver(mouseX, mouseY, leftX, y, mc.font.width("<") + 5, mc.font.lineHeight); - boolean hoveredOverRight = isMouseOver(mouseX, mouseY, leftX + mc.font.width("<") + 6, y, mc.font.width(">") + 5, mc.font.lineHeight); + DrawHelper.stopScaling(graphics.pose()); + //Shadow DrawHelper.drawRoundedRectangle( graphics, leftX + 1, y + 3, - (mc.font.width("<") * 2) + 10, mc.font.lineHeight, 2, + (leftWidth * 2) + 10, mc.font.lineHeight, 2, ColorHelper.changeAlpha(Color.BLACK, 128).getRGB() ); + + DrawHelper.scaleAndPosition(graphics.pose(),leftX, y + 2, leftWidth + 5, mc.font.lineHeight, leftAnim.getScale()); + DrawHelper.drawRoundedRectangle( graphics, leftX, y + 2, true, false, true, false, - mc.font.width("<") + 5, mc.font.lineHeight, 2, + leftWidth + 5, mc.font.lineHeight, 2, hoveredOverLeft ? getThemeColor().darker().darker().getRGB() : getThemeColor().getRGB() ); + graphics.drawString(mc.font, "<", leftX + leftWidth / 2 + 1, y + 3, -1, false); + + DrawHelper.stopScaling(graphics.pose()); + + DrawHelper.scaleAndPosition(graphics.pose(),leftX + leftWidth + 6, y + 2, rightWidth + 5, mc.font.lineHeight, rightAnim.getScale()); + DrawHelper.drawRoundedRectangle( graphics, - leftX + mc.font.width("<") + 6, y + 2, + leftX + leftWidth + 6, y + 2, false, true, false, true, - mc.font.width(">") + 5, mc.font.lineHeight, 2, + rightWidth + 5, mc.font.lineHeight, 2, hoveredOverRight ? getThemeColor().darker().darker().getRGB() : getThemeColor().getRGB() ); + graphics.drawString(mc.font, ">", leftX + leftWidth + 7 + rightWidth / 2, y + 3, -1, false); + DrawHelper.stopScaling(graphics.pose()); + + //todo: unsure whether to keep this or not? it removes the 3D illusion + /* DrawHelper.drawVerticalLine( graphics, - leftX + mc.font.width("<") + 5, + leftX + leftWidth + 5, y + 2, mc.font.lineHeight, - 0.7f, + 1f, Color.WHITE.getRGB() ); - graphics.drawString(mc.font, "<", leftX + mc.font.width("<") / 2 + 1, y + 3, -1, false); - graphics.drawString(mc.font, ">", leftX + mc.font.width("<") + 7 + mc.font.width(">") / 2, y + 3, -1, false); - graphics.drawString(mc.font, selectedOption, x + 6 + mc.font.width(mainLabel), y + 2, Color.LIGHT_GRAY.getRGB(), isMouseOverText); + */ } @Override - public boolean mouseClicked(ListOption option, double mouseX, double mouseY, int button) { + public boolean mouseClicked(CycleOption option, double mouseX, double mouseY, int button) { if (option.getValues().isEmpty()) return false; mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; @@ -802,6 +763,8 @@ public boolean mouseClicked(ListOption option, double mouseX, double mouseY, } public class ModernSubMenuRenderer implements SkinRenderer { + private final SquishAnimator animator = new SquishAnimator(); + @Override public void render(GuiGraphics graphics, SubMenuOption option, int x, int y, int mouseX, int mouseY) { String textLabel = "Open"; @@ -809,9 +772,18 @@ public void render(GuiGraphics graphics, SubMenuOption option, int x, int y, int option.setHeight(16); + + float width = mc.font.width(textLabel) + 5; + + boolean isHovering = isMouseOver(mouseX, mouseY, xPos + 2, y + 4, width, mc.font.lineHeight + 4); + boolean isDown = isHovering && GLFW.glfwGetMouseButton(mc.getWindow().handle(), GLFW.GLFW_MOUSE_BUTTON_LEFT) == GLFW.GLFW_PRESS; + animator.update(isDown); + graphics.drawString(mc.font, option.name, x + 4, y + 4, -1, false); - Color fillColor = isMouseOver(mouseX, mouseY, xPos + 2, y + 4, mc.font.width(textLabel) + 5, mc.font.lineHeight + 4) ? getThemeColor().darker().darker() : getThemeColor(); + Color fillColor = isHovering ? getThemeColor().darker().darker() : getThemeColor(); + + DrawHelper.scaleAndPosition(graphics.pose(),x,y,width, mc.font.lineHeight + 4, animator.getScale()); DrawHelper.drawRoundedRectangleWithShadowBadWay( graphics, xPos - 1, y + 1, @@ -833,6 +805,9 @@ public void render(GuiGraphics graphics, SubMenuOption option, int x, int y, int graphics.drawString(mc.font, textLabel, xPos + 2, y + 4, Color.WHITE.getRGB(), true); + DrawHelper.stopScaling(graphics.pose()); + + option.getSubMenu().render(graphics, x + option.getParentMenu().getWidth(), y, mouseX, mouseY); } @@ -870,6 +845,8 @@ public boolean mouseClicked(SubMenuOption option, double mouseX, double mouseY, } public class ModernRunnableRenderer implements SkinRenderer { + private final SquishAnimator animator = new SquishAnimator(); + @Override public void render(GuiGraphics graphics, RunnableOption option, int x, int y, int mouseX, int mouseY) { String labelText = "Run â–¶"; @@ -877,14 +854,22 @@ public void render(GuiGraphics graphics, RunnableOption option, int x, int y, in option.setHeight(mc.font.lineHeight + 6); + boolean isHovering = isMouseOver(mouseX, mouseY, xPos + 2, y + 4, width, mc.font.lineHeight + 4); + boolean isDown = isHovering && GLFW.glfwGetMouseButton(mc.getWindow().handle(), GLFW.GLFW_MOUSE_BUTTON_LEFT) == GLFW.GLFW_PRESS; + animator.update(isDown); + graphics.drawString(mc.font, option.name, x + 4, y + 4, -1, false); - Color fillColor = isMouseOver(mouseX, mouseY, xPos + 2, y + 4, mc.font.width(labelText) + 5, mc.font.lineHeight + 4) ? getThemeColor().darker().darker() : getThemeColor(); + float width = mc.font.width(labelText) + 5; + + Color fillColor = isHovering ? getThemeColor().darker().darker() : getThemeColor(); + + DrawHelper.scaleAndPosition(graphics.pose(),xPos - 1, y + 1,width, mc.font.lineHeight + 4, animator.getScale()); DrawHelper.drawRoundedRectangleWithShadowBadWay( graphics, xPos - 1, y + 1, - mc.font.width(labelText) + 5, mc.font.lineHeight + 4, + width, mc.font.lineHeight + 4, 2, fillColor.getRGB(), 180, @@ -893,6 +878,7 @@ public void render(GuiGraphics graphics, RunnableOption option, int x, int y, in ); graphics.drawString(mc.font, labelText, xPos + 2, y + 4, option.value ? DARK_GREEN.getRGB() : DARK_RED.getRGB(), true); + DrawHelper.stopScaling(graphics.pose()); } @Override @@ -905,6 +891,11 @@ public boolean mouseClicked(RunnableOption option, double mouseX, double mouseY, } return false; } + + @Override + public boolean mouseReleased(RunnableOption option, double mouseX, double mouseY, int button) { + return SkinRenderer.super.mouseReleased(option, mouseX, mouseY, button); + } } @Override diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/interfaces/GroupableSkin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/interfaces/GroupableSkin.java index 6319f77..6a7486c 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/interfaces/GroupableSkin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/interfaces/GroupableSkin.java @@ -1,11 +1,11 @@ package com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.interfaces; -import com.tanishisherewith.dynamichud.utils.contextmenu.layout.LayoutContext; +import com.tanishisherewith.dynamichud.utils.contextmenu.layout.LayoutEngine; import com.tanishisherewith.dynamichud.utils.contextmenu.options.OptionGroup; import net.minecraft.client.gui.GuiGraphics; public interface GroupableSkin { - LayoutContext.Offset getGroupIndent(); + LayoutEngine.Offset getGroupIndent(); void renderGroup(GuiGraphics graphics, OptionGroup group, int groupX, int groupY, int mouseX, int mouseY); } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/handlers/ScrollHandler.java b/src/main/java/com/tanishisherewith/dynamichud/utils/handlers/ScrollHandler.java index 4d10ae4..62e54f8 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/handlers/ScrollHandler.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/handlers/ScrollHandler.java @@ -48,10 +48,8 @@ public void updateScrollPosition(double mouseY) { // Calculate the difference in mouse Y position double deltaY = lastMouseY - mouseY; - // Update the scroll offset based on the mouse movement - scrollOffset = Math.clamp(scrollOffset - (int) (deltaY * SCROLL_SPEED), 0, maxScrollOffset); + scrollOffset = Math.clamp(scrollOffset - (int) deltaY, 0, maxScrollOffset); - // Update the last mouse position lastMouseY = mouseY; } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java index 58d568f..c8ccfdc 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java @@ -239,7 +239,7 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { // DrawHelper.enableScissor(widgetBox); - // Draw gradient background with rounded.fsh corners + // Draw gradient background with rounded corners if (!isInEditor) { DrawHelper.drawRoundedRectangle( graphics, @@ -352,7 +352,10 @@ public void createMenu() { menu = new ContextMenu<>(getX(), (int) (getY() + widgetBox.getHeight()), properties); menu.addOption(new BooleanOption(Component.literal("Show Grid"), - () -> this.showGrid, value -> this.showGrid = value, + () -> this.showGrid, value -> { + this.showGrid = value; + this.computeOffset(); + }, BooleanOption.BooleanType.YES_NO) .description(Component.literal("Shows a grid and Y axis values")) ); @@ -360,7 +363,7 @@ public void createMenu() { 1, 25, 1, () -> (double) this.gridLines, value -> { this.setGridLines(value.intValue()); - computeOffset(); + this.computeOffset(); }, menu) .renderWhen(() -> this.showGrid) ); @@ -384,9 +387,13 @@ public void createMenu() { } private void computeOffset(){ + if(!showGrid) { + offset = 0; + return; + } + // The first Component is usually the largest but a negative value may occupy more width so we check the first and last Component. // Idk how this will break. - String firstText = formatValue(maxValue - valueStep); String lastText = formatValue(maxValue - (gridLines * valueStep)); diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java index 2ad95fb..9fccebe 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java @@ -1,7 +1,6 @@ package com.tanishisherewith.dynamichud.widgets; import com.tanishisherewith.dynamichud.DynamicHUD; -import com.tanishisherewith.dynamichud.config.GlobalConfig; import com.tanishisherewith.dynamichud.helpers.DrawHelper; import com.tanishisherewith.dynamichud.integration.IntegrationManager; import com.tanishisherewith.dynamichud.utils.DynamicValueRegistry; @@ -10,7 +9,6 @@ import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenuProperties; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenuProvider; import com.tanishisherewith.dynamichud.utils.contextmenu.options.*; -import com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.MinecraftSkin; import com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.ModernSkin; import com.tanishisherewith.dynamichud.widget.DynamicValueWidget; import com.tanishisherewith.dynamichud.widget.WidgetData; @@ -55,6 +53,8 @@ public TextWidget(String registryID, String registryKey, boolean shadow, boolean public void createMenu() { menu = new ContextMenu<>(getX(), getY(),ContextMenuProperties.builder().skin(new ModernSkin()).build()); + // if(IntegrationManager.IS_TEST_MODE) menu.setLayoutEngine(new LayoutEngine(20,20,20,80)); + menu.addOption(new BooleanOption(Component.literal("Shadow"), () -> this.shadow, value -> this.shadow = value, BooleanOption.BooleanType.ON_OFF) @@ -71,7 +71,7 @@ public void createMenu() { .renderWhen(() -> !this.rainbow) ); menu.addOption(new DoubleOption(Component.literal("Rainbow Speed"), - 1, 5.0f, 1, + 1, 5, 1, () -> (double) this.rainbowSpeed, value -> this.rainbowSpeed = value.intValue(), menu) .renderWhen(() -> this.rainbow) ); @@ -101,19 +101,16 @@ public void createMenu() { () -> this.setPosition(0, 0)) .description(Component.literal("Reset widget to default position"))); - // List Option AtomicReference style = new AtomicReference<>("Style1"); + AtomicReference align = new AtomicReference<>(GroupLayout.Alignment.CENTER); + + // List Option List styles = Arrays.asList("Style1", "Style2", "Style3"); - menu.addOption(new ListOption<>(Component.literal("Text Style"), - style::get, style::set, styles) - .description(Component.literal("Choose a text style"))); + menu.addOption(new CycleOption<>(Component.literal("Text Style"), style::get, style::set, styles)); // Enum Option - AtomicReference align = new AtomicReference<>(GroupLayout.Alignment.CENTER); + menu.addOption(new CycleOption<>(Component.literal("Alignment"), align::get, align::set, GroupLayout.Alignment.values())); - menu.addOption(new EnumOption<>(Component.literal("Alignment"), - align::get, align::set, GroupLayout.Alignment.values()) - .description(Component.literal("Set text alignment"))); // Option Group OptionGroup group = new OptionGroup(Component.literal("Display Options")); From a00b3274e7a853565a52a862d84a5a0534af98bd Mon Sep 17 00:00:00 2001 From: tanishisherewith <120117618+tanishisherewithhh@users.noreply.github.com> Date: Fri, 19 Jun 2026 02:33:29 +0530 Subject: [PATCH 07/22] Added Local Widget and ContextMenu scaling Rename ShouldScale to canScale All scalable widgets can be scaled by holding CTRL and scrolling up or down. --- .../dynamichud/IntegrationTest.java | 4 +- .../utils/contextmenu/ContextMenu.java | 56 +++++++---- .../contextmenu/options/RunnableOption.java | 1 + .../contextmenu/screen/ContextMenuScreen.java | 4 +- .../dynamichud/widget/Widget.java | 64 ++++++++----- .../dynamichud/widget/WidgetBox.java | 92 +++++++++++------- .../dynamichud/widgets/GraphWidget.java | 93 ++++++++----------- .../dynamichud/widgets/ItemWidget.java | 4 +- .../dynamichud/widgets/TextWidget.java | 7 +- 9 files changed, 184 insertions(+), 141 deletions(-) diff --git a/src/main/java/com/tanishisherewith/dynamichud/IntegrationTest.java b/src/main/java/com/tanishisherewith/dynamichud/IntegrationTest.java index 8b260b0..51d4b77 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/IntegrationTest.java +++ b/src/main/java/com/tanishisherewith/dynamichud/IntegrationTest.java @@ -75,8 +75,8 @@ public void init() { .label("FPS Chart") .graphColor(Color.CYAN) .anchor(Widget.Anchor.CENTER) - .height(100) - .width(150) + .gWidth(100) + .gHeight(150) .gridLines(10) .backgroundColor(Color.DARK_GRAY) .lineThickness(1f) diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java index b75fe93..2b6c3ea 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java @@ -40,9 +40,10 @@ public class ContextMenu implements Input { protected int width = 0; protected int height = 0, widgetHeight = 0; protected boolean shouldDisplay = false; - protected float scale = 0.0f; + protected float animScale = 0.0f; protected Screen parentScreen = null; protected boolean newScreenFlag = false; + protected float menuScale = 1.0f; private final ValueAnimation scaleAnimation; @@ -73,18 +74,18 @@ public ContextMenu(int x, int y, @NotNull T properties, ContextMenuScreenFactory this.scaleAnimation = new ValueAnimation(new AnimationProperty<>() { @Override public Float get() { - return scale; + return animScale; } @Override public void set(Float value) { - scale = value; + animScale = value; } }, 0.0f, 1.0f); this.scaleAnimation.easing(EasingType.EASE_IN_CUBIC); this.scaleAnimation.duration(280); this.scaleAnimation.onComplete(() -> { - if (scale <= 0.0f && parentScreen != null && properties.getSkin().shouldCreateNewScreen()) { + if (animScale <= 0.0f && parentScreen != null && properties.getSkin().shouldCreateNewScreen()) { DynamicHUD.MC.setScreen(parentScreen); } }); @@ -99,6 +100,14 @@ public void addOption(Option option) { options.add(option); } + public float getMenuScale() { + return animScale * menuScale; + } + + public void setMenuScale(float menuScale) { + this.menuScale = Math.clamp(menuScale, 0.3f, 2.0f); + } + public void render(GuiGraphics graphics, int xPos, int yPos, int mouseX, int mouseY) { if (newScreenFlag && screenFactory != null) { DynamicHUD.MC.setScreen(screenFactory.create(this, properties)); @@ -110,12 +119,12 @@ public void render(GuiGraphics graphics, int xPos, int yPos, int mouseX, int mou update(); - if (scale <= 0.0f || newScreenFlag) return; + if (animScale <= 0.0f || newScreenFlag) return; - DrawHelper.scaleAndPosition(graphics.pose(), this.x, this.y,this.width,this.height, scale); + DrawHelper.scaleAndPosition(graphics.pose(), this.x, this.y,this.width,this.height, getMenuScale()); properties.getSkin().setContextMenu(this); - properties.getSkin().renderContextMenu(graphics, this, mouseX, mouseY); + properties.getSkin().renderContextMenu(graphics, this, getTMouseX(mouseX), getTMouseY(mouseY)); DrawHelper.stopScaling(graphics.pose()); } @@ -126,7 +135,7 @@ public void update() { } if (!properties.enableAnimations()) { - scale = shouldDisplay ? 1.0f : 0.0f; + animScale = shouldDisplay ? 1.0f : 0.0f; return; } @@ -140,11 +149,11 @@ public void close() { option.onClose(); } if (properties.enableAnimations()) { - scaleAnimation.startValue(scale); + scaleAnimation.startValue(animScale); scaleAnimation.endValue(0.0f); scaleAnimation.start(); } else { - scale = 0.0f; + animScale = 0.0f; if (properties.getSkin().shouldCreateNewScreen() && parentScreen != null) { DynamicHUD.MC.setScreen(parentScreen); } @@ -159,11 +168,11 @@ public void open() { newScreenFlag = true; } if (properties.enableAnimations()) { - scaleAnimation.startValue(scale); + scaleAnimation.startValue(animScale); scaleAnimation.endValue(1.0f); scaleAnimation.start(); } else { - scale = 0.0f; + animScale = 0.0f; if (properties.getSkin().shouldCreateNewScreen() && parentScreen != null) { DynamicHUD.MC.setScreen(parentScreen); } @@ -178,6 +187,14 @@ public void toggleDisplay() { } } + protected int getTMouseX(double mouseX) { + return (int) ((mouseX - getX()) / getMenuScale() + getX()); + } + + protected int getTMouseY(double mouseY) { + return (int) ((mouseY - getY()) / getMenuScale() + getY()); + } + public void toggleDisplay(WidgetBox widgetBox, double mouseX, double mouseY, int button) { if (button == GLFW.GLFW_MOUSE_BUTTON_RIGHT && widgetBox.isMouseOver(mouseX, mouseY)) { toggleDisplay(); @@ -201,8 +218,9 @@ public void setLayoutEngine(LayoutEngine layoutEngine) { @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { if (!shouldDisplay) return false; + for (Option option : options) { - if (option.shouldRender() && option.getRenderer().mouseClicked(option ,mouseX, mouseY, button)) { + if (option.shouldRender() && option.getRenderer().mouseClicked(option ,getTMouseX(mouseX), getTMouseY(mouseY), button)) { return true; } } @@ -214,7 +232,7 @@ public boolean mouseReleased(double mouseX, double mouseY, int button) { if (!shouldDisplay) return false; for (Option option : options) { if(option.shouldRender()){ - option.getRenderer().mouseReleased(option, mouseX, mouseY, button); + option.getRenderer().mouseReleased(option, getTMouseX(mouseX), getTMouseY(mouseY), button); } } return properties.getSkin().mouseReleased(this, mouseX, mouseY, button); @@ -223,8 +241,12 @@ public boolean mouseReleased(double mouseX, double mouseY, int button) { @Override public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { if (!shouldDisplay) return false; + + double tDeltaX = deltaX / getMenuScale(); + double tDeltaY = deltaY / getMenuScale(); + for (Option option : options) { - if(option.shouldRender() && option.getRenderer().mouseDragged(option, mouseX, mouseY, button, deltaX, deltaY)){ + if(option.shouldRender() && option.getRenderer().mouseDragged(option, getTMouseX(mouseX), getTMouseY(mouseY), button, tDeltaX, tDeltaY)){ return true; } } @@ -327,10 +349,6 @@ public ContextMenu createSubMenu(int x, int return new ContextMenu<>(x, y, properties, screenFactory, this); } - public float getScale() { - return scale; - } - public boolean isVisible() { return shouldDisplay; } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/RunnableOption.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/RunnableOption.java index 8605735..21a5ed0 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/RunnableOption.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/RunnableOption.java @@ -37,6 +37,7 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { } return false; } + public void toggle(){ set(true); try { diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/ContextMenuScreen.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/ContextMenuScreen.java index 2a8f89f..4ef4d73 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/ContextMenuScreen.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/ContextMenuScreen.java @@ -29,14 +29,14 @@ public void added() { @Override public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) { contextMenu.update(); - DrawHelper.scaleAndPosition(graphics.pose(), (float) width / 2, (float) height / 2, contextMenu.getScale()); + DrawHelper.scaleAndPosition(graphics.pose(), (float) width / 2, (float) height / 2, contextMenu.getMenuScale()); properties.getSkin().setContextMenu(contextMenu); properties.getSkin().renderContextMenu(graphics, contextMenu, mouseX, mouseY); DrawHelper.stopScaling(graphics.pose()); - if (contextMenu.getScale() <= 0 && !contextMenu.isVisible()) { + if (contextMenu.getMenuScale() <= 0 && !contextMenu.isVisible()) { contextMenu.close(); } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/widget/Widget.java b/src/main/java/com/tanishisherewith/dynamichud/widget/Widget.java index 5c6a89c..7e8a8b6 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widget/Widget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widget/Widget.java @@ -9,6 +9,7 @@ import net.minecraft.client.gui.GuiGraphics; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; +import net.minecraft.util.Mth; import org.lwjgl.glfw.GLFW; public abstract class Widget implements Input { @@ -47,7 +48,7 @@ public abstract class Widget implements Input { // Absolute position of the widget on screen in pixels. protected int x, y; - protected boolean shouldScale = true; + protected boolean canScale = true; protected Anchor anchor; // The chosen anchor point @@ -94,13 +95,12 @@ public int getY() { return y; } - public float getWidth() { - return widgetBox.getWidth(); + public float getScale() { + return canScale ? widgetBox.getScale() * DynamicHUD.getGlobalScale() : 1.0f; } - public float getHeight() { - return widgetBox.getHeight(); - } + public float getWidth() { return widgetBox.getWidth(); } + public float getHeight() { return widgetBox.getHeight(); } private void calculateOffset(int initialX, int initialY, int screenWidth, int screenHeight) { int anchorX = getAnchorX(screenWidth); @@ -163,12 +163,12 @@ public final void render(GuiGraphics graphics, int mouseX, int mouseY) { if (!isVisible()) return; - if (shouldScale) { - DrawHelper.scaleAndPosition(graphics.pose(), getX(), getY(), DynamicHUD.getGlobalScale()); + if (canScale) { + DrawHelper.scaleAndPosition(graphics.pose(), getX(), getY(), getScale()); } renderWidget(graphics, mouseX, mouseY); - if (shouldScale) { + if (canScale) { DrawHelper.stopScaling(graphics.pose()); } clampPosition(); @@ -182,12 +182,12 @@ public final void renderInEditor(GuiGraphics graphics, int mouseX, int mouseY) { drawWidgetBackground(graphics); - if (shouldScale) { - DrawHelper.scaleAndPosition(graphics.pose(), getX(), getY(), DynamicHUD.getGlobalScale()); + if (canScale) { + DrawHelper.scaleAndPosition(graphics.pose(), getX(), getY(), getScale()); } renderWidgetInEditor(graphics, mouseX, mouseY); - if (shouldScale) { + if (canScale) { DrawHelper.stopScaling(graphics.pose()); } clampPosition(); @@ -216,6 +216,14 @@ private void renderWidgetInEditor(GuiGraphics graphics, int mouseX, int mouseY) renderWidget(graphics, mouseX, mouseY); } + protected int getTransformedMouseX(double mouseX) { + return (int) ((mouseX - getX()) / getScale() + getX()); + } + + protected int getTransformedMouseY(double mouseY) { + return (int) ((mouseY - getY()) / getScale() + getY()); + } + @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { if (widgetBox.isMouseOver(mouseX, mouseY) && button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { @@ -233,8 +241,8 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { /* Input related methods. Override with **super call** to add your own input-based code like contextMenu */ public void clampPosition() { - this.x = (int) org.joml.Math.clamp(this.x, 0, mc.getWindow().getGuiScaledWidth() - getWidth()); - this.y = (int) org.joml.Math.clamp(this.y, 0, mc.getWindow().getGuiScaledHeight() - getHeight()); + this.x = (int) Mth.clamp(this.x, 0, mc.getWindow().getGuiScaledWidth() - getWidth()); + this.y = (int) Mth.clamp(this.y, 0, mc.getWindow().getGuiScaledHeight() - getHeight()); } @Override @@ -261,8 +269,8 @@ public boolean mouseDragged(double mouseX, double mouseY, int button, double del newY = (newY / snapBoxHeight) * snapBoxHeight; } - this.x = (int) org.joml.Math.clamp(newX, 0, mc.getWindow().getGuiScaledWidth() - getWidth()); - this.y = (int) org.joml.Math.clamp(newY, 0, mc.getWindow().getGuiScaledHeight() - getHeight()); + this.x = (int) Mth.clamp(newX, 0, mc.getWindow().getGuiScaledWidth() - getWidth()); + this.y = (int) Mth.clamp(newY, 0, mc.getWindow().getGuiScaledHeight() - getHeight()); calculateOffset(x, y, mc.getWindow().getGuiScaledWidth(), mc.getWindow().getGuiScaledHeight()); // Set initial offset @@ -285,6 +293,12 @@ public boolean mouseReleased(double mouseX, double mouseY, int button) { */ @Override public void mouseScrolled(double mouseX, double mouseY, double vAmount, double hAmount) { + if (canScale && widgetBox.isMouseOver(mouseX,mouseY) && GLFW.glfwGetKey(mc.getWindow().handle(),GLFW.GLFW_KEY_LEFT_CONTROL) == GLFW.GLFW_PRESS) { + widgetBox.setScale(widgetBox.getScale() + (float) vAmount * 0.05f); + + clampPosition(); + calculateOffset(x, y, mc.getWindow().getGuiScaledWidth(), mc.getWindow().getGuiScaledHeight()); + } } @Override @@ -309,7 +323,6 @@ public void onClose() { /** * Displays a faint grayish background if enabled or faint reddish background if disabled. - * Drawn with 2 pixel offset to all sides */ protected void drawWidgetBackground(GuiGraphics graphics) { int backgroundColor = this.isVisible() ? GlobalConfig.get().getHudActiveColor().getRGB() : GlobalConfig.get().getHudInactiveColor().getRGB(); @@ -330,6 +343,10 @@ protected void setTooltipText(Component Component) { this.tooltipText = Component; } + public void setWidgetScale(float widgetScale) { + widgetBox.setScale(widgetScale); + } + public void readFromTag(CompoundTag tag) { modId = tag.getString("modId").orElse("unknown"); uid = tag.contains("UID") ? new UID(tag.getString("UID").get()) : UID.generate(); @@ -340,7 +357,9 @@ public void readFromTag(CompoundTag tag) { offsetY = tag.getInt("offsetY").orElse(0); isVisible = tag.getBoolean("isVisible").orElse(true); isDraggable = tag.getBoolean("isDraggable").orElse(true); - shouldScale = tag.getBoolean("shouldScale").orElse(true); + canScale = tag.getBoolean("canScale").orElse(true); + + widgetBox.setScale(tag.getFloat("widgetScale").orElse(1.0f)); } /** @@ -353,7 +372,8 @@ public void writeToTag(CompoundTag tag) { tag.putString("modId", modId); tag.putString("UID", uid.getUniqueID()); tag.putBoolean("isDraggable", isDraggable); - tag.putBoolean("shouldScale", shouldScale); + tag.putBoolean("canScale", canScale); + tag.putFloat("widgetScale", widgetBox.getScale()); // tag.putInt("x", x); // tag.putInt("y", y); tag.putString("anchor", anchor.name()); @@ -374,8 +394,8 @@ public void setUid(UID uid) { this.uid = uid; } - public void setShouldScale(boolean shouldScale) { - this.shouldScale = shouldScale; + public void setCanScale(boolean canScale) { + this.canScale = canScale; } public String getModId() { @@ -393,7 +413,7 @@ public String toString() { ", isVisible=" + isVisible + ", isDraggable=" + isDraggable + ", shiftDown=" + isShiftDown + - ", shouldScale=" + shouldScale + + ", canScale=" + canScale + '}'; } diff --git a/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetBox.java b/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetBox.java index e12da3f..8cd8cc5 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetBox.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetBox.java @@ -1,19 +1,33 @@ package com.tanishisherewith.dynamichud.widget; +import com.tanishisherewith.dynamichud.DynamicHUD; +import net.minecraft.util.Mth; + public class WidgetBox { public float x, y; - private float width; - private float height; + private float width, rawWidth; + private float height, rawHeight; + protected float scale; - public WidgetBox(int x, int y, int width, int height) { + public WidgetBox(float x, float y, float width, float height, float scale) { this.x = x; this.y = y; - this.width = width; - this.height = height; + this.width = width * scale; + this.height = height * scale; + this.rawWidth = width; + this.rawHeight = height; + this.scale = scale; + } + + public WidgetBox(float x, float y, float width, float height) { + this(x,y,width,height,1.0f); } + /** + * Checks if the mouse is over the box, accounting for its scale factor. + */ public boolean isMouseOver(double mouseX, double mouseY) { - return mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height; + return mouseX >= x && mouseX <= x + this.width && mouseY >= y && mouseY <= y + this.height; } public float getWidth() { @@ -24,45 +38,57 @@ public float getHeight() { return height; } - public boolean intersects(WidgetBox other) { - // Check if this box is to the right of the other box - if (this.x > other.x + other.width) { - return false; - } + public boolean intersects(WidgetBox other, float myScale, float otherScale) { + float myWidth = this.width * myScale; + float myHeight = this.height * myScale; + float oWidth = other.width * otherScale; + float oHeight = other.height * otherScale; - // Check if this box is to the left of the other box - if (this.x + this.width < other.x) { - return false; - } + return this.x < other.x + oWidth && this.x + myWidth > other.x && + this.y < other.y + oHeight && this.y + myHeight > other.y; + } - // Check if this box is below the other box - if (this.y > other.y + other.height) { - return false; - } + public void setScale(float scale) { + this.scale = Mth.clamp(scale, 0.2f, 10.0f); + } - // Check if this box is above the other box - // If none of the above conditions are met, the boxes must intersect - return !(this.y + this.height < other.y); + public float getScale() { + return scale * DynamicHUD.getGlobalScale(); } - public void setDimensionsNoScale(float x, float y, float width, float height) { - this.x = x; - this.y = y; - this.height = height; - this.width = width; + public float getRawWidth() { + return rawWidth; + } + + public float getRawHeight() { + return rawHeight; } - public void setDimensions(float x, float y, float width, float height, boolean shouldScale, float scale) { + private void setDimensions(float x, float y, float width, float height, boolean shouldScale, float scale) { this.x = x; this.y = y; this.height = height * (shouldScale ? scale : 1.0f); this.width = width * (shouldScale ? scale : 1.0f); + this.rawWidth = width; + this.rawHeight = height; + } + + private void setSize(float width, float height, boolean shouldScale, float scale) { + if (width >= 0) { + this.width = (float) Math.ceil(width * (shouldScale ? scale : 1.0f)); + this.rawWidth = width; + } + if (height >= 0) { + this.height = (float) Math.ceil(height * (shouldScale ? scale : 1.0f)); + this.rawHeight = height; + } + } + + public void setDimensions(float x, float y, float width, float height, boolean shouldScale) { + this.setDimensions(x,y,width,height,shouldScale,getScale()); } - public void setSize(double width, double height, boolean shouldScale, float scale) { - if (width >= 0) - this.width = (int) Math.ceil(width * (shouldScale ? scale : 1.0f)); - if (height >= 0) - this.height = (int) Math.ceil(height * (shouldScale ? scale : 1.0f)); + public void setSize(float width, float height, boolean shouldScale) { + this.setSize(width,height,shouldScale,getScale()); } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java index c8ccfdc..cb23beb 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java @@ -1,6 +1,5 @@ package com.tanishisherewith.dynamichud.widgets; -import com.tanishisherewith.dynamichud.DynamicHUD; import com.tanishisherewith.dynamichud.helpers.ColorHelper; import com.tanishisherewith.dynamichud.helpers.DrawHelper; import com.tanishisherewith.dynamichud.renderstates.GradientShadowRenderState; @@ -50,8 +49,8 @@ public class GraphWidget extends DynamicValueWidget implements ContextMenuProvid private float lineThickness; private boolean showGrid; private int gridLines; - private float width; - private float height; + private float gWidth; + private float gHeight; private String label; /// Automatically update the min and max of the graph private boolean autoUpdateRange = false; @@ -60,10 +59,10 @@ public class GraphWidget extends DynamicValueWidget implements ContextMenuProvid private float valueScale; int offset = -2; - public GraphWidget(String registryID, String registryKey, String modId, Anchor anchor, float width, float height, int maxDataPoints, float minValue, float maxValue, Color graphColor, Color backgroundColor, float lineThickness, boolean showGrid, int gridLines, String label) { + public GraphWidget(String registryID, String registryKey, String modId, Anchor anchor, float gWidth, float gHeight, int maxDataPoints, float minValue, float maxValue, Color graphColor, Color backgroundColor, float lineThickness, boolean showGrid, int gridLines, String label) { super(DATA, modId, anchor, registryID, registryKey); - this.width = width; - this.height = height; + this.gWidth = gWidth; + this.gHeight = gHeight; this.maxDataPoints = maxDataPoints; this.graphColor = graphColor; this.backgroundColor = backgroundColor; @@ -84,8 +83,8 @@ private void internal_init() { Validate.isTrue(maxDataPoints > 2, "MaxDataPoints should be more than 2."); this.dataPoints = new float[maxDataPoints]; this.label = label.trim(); - this.widgetBox = new WidgetBox(x, y, (int) width, (int) height); - this.stepY = height / (gridLines + 1); + this.widgetBox = new WidgetBox(x, y, (int) gWidth, (int) gHeight); + this.stepY = gHeight / (gridLines + 1); this.valueStep = (maxValue - minValue) / (gridLines + 1); this.valueScale = (float) Math.clamp((stepY / 9.5), 0.0f, 1.0f); @@ -136,14 +135,14 @@ private List getInterpolatedPoints() { List points = new ArrayList<>(); if (dataPoints.length < 2) return points; - float xStep = width / (dataPoints.length - 1); + float xStep = gWidth / (dataPoints.length - 1); float range = Math.max(maxValue - minValue, 0.0001f); //Pre-calculate Y coordinates float[] yVals = new float[dataPoints.length]; for (int i = 0; i < dataPoints.length; i++) { int index = (head + i) % dataPoints.length; - yVals[i] = y + height - ((dataPoints[index] - minValue) / range * height); + yVals[i] = y + gHeight - ((dataPoints[index] - minValue) / range * gHeight); } // Monotone Cubic Spline (Fritsch-Carlson) calculation @@ -213,7 +212,7 @@ private void drawInterpolatedCurve(GuiGraphics graphics, List points, i if (points.size() < 2) return; graphics.guiRenderState.submitGuiElement( - new InterpolatedCurveRenderState(points, thickness, color, new Matrix3x2f(graphics.pose()), CustomRenderLayers.QUADS_CUSTOM_BLEND, (int) width, (int) height, graphics.scissorStack.peek()) + new InterpolatedCurveRenderState(points, thickness, color, new Matrix3x2f(graphics.pose()), CustomRenderLayers.QUADS_CUSTOM_BLEND, (int) gWidth, (int) gHeight, graphics.scissorStack.peek()) ); } @@ -222,7 +221,7 @@ private void drawGradientShadow(GuiGraphics graphics, List points, floa if (points.size() < 2) return; graphics.guiRenderState.submitGuiElement( - new GradientShadowRenderState(points,bottomY, startColor, endColor, new Matrix3x2f(graphics.pose()), RenderPipelines.DEBUG_QUADS, (int) width, (int) height, graphics.scissorStack.peek()) + new GradientShadowRenderState(points,bottomY, startColor, endColor, new Matrix3x2f(graphics.pose()), RenderPipelines.DEBUG_QUADS, (int) gWidth, (int) gHeight, graphics.scissorStack.peek()) ); } @@ -249,8 +248,8 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { true, false, false, - width, - height, + gWidth, + gHeight, 4, backgroundColor.getRGB() ); @@ -262,7 +261,7 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { for (int i = 1; i <= gridLines; i++) { float yPos = y + stepY * i; - DrawHelper.drawHorizontalLine(graphics, x + offset, width, yPos, 0.5f, 0x4DFFFFFF); // Semi-transparent white + DrawHelper.drawHorizontalLine(graphics, x + offset, gWidth, yPos, 0.5f, 0x4DFFFFFF); // Semi-transparent white // Draw value labels on the left axis float value = maxValue - (i * valueStep); @@ -279,10 +278,10 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { x += offset; // Draw vertical grid lines (time axis) - float stepX = width / 5; // 5 vertical lines + float stepX = gWidth / 5; // 5 vertical lines for (int i = 1; i < 5; i++) { float xPos = x + stepX * i; - DrawHelper.drawVerticalLine(graphics, xPos, y, height, 0.5f, 0x4DFFFFFF); + DrawHelper.drawVerticalLine(graphics, xPos, y, gHeight, 0.5f, 0x4DFFFFFF); } } @@ -290,7 +289,7 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { // Draw shadow effect under the graph drawGradientShadow( - graphics, points, y + height, + graphics, points, y + gHeight, ColorHelper.changeAlpha(graphColor, 100).getRGB(), 0x00000000 ); @@ -305,26 +304,26 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { // Draw axes - DrawHelper.drawHorizontalLine(graphics, x, width, y + height - 1, 1.0f, 0xFFFFFFFF); // X-axis - DrawHelper.drawVerticalLine(graphics, x, y, height, 1.0f, 0xFFFFFFFF); // Y-axis + DrawHelper.drawHorizontalLine(graphics, x, gWidth, y + gHeight - 1, 1.0f, 0xFFFFFFFF); // X-axis + DrawHelper.drawVerticalLine(graphics, x, y, gHeight, 1.0f, 0xFFFFFFFF); // Y-axis // Draw min and max value labels with formatted values /* DrawHelper.scaleAndPosition(context.getMatrices(),x - 5,y,0.5f); String formattedMaxVal = formatValue(maxValue); - context.drawText(mc.font, formattedMaxVal, x - 5 - mc.font.width(formattedMaxVal), y - 4, 0xFFFFFFFF, true); + context.drawText(mc.font, formattedMaxVal, x - 5 - mc.font.gWidth(formattedMaxVal), y - 4, 0xFFFFFFFF, true); DrawHelper.stopScaling(context.getMatrices()); */ - DrawHelper.scaleAndPosition(graphics.pose(), x - 5, y + height, 0.5f); + DrawHelper.scaleAndPosition(graphics.pose(), x - 5, y + gHeight, 0.5f); String formattedMinVal = formatValue(minValue); - graphics.drawString(mc.font, formattedMinVal, x - mc.font.width(formattedMinVal), (int) (y + height - 4), 0xFFFFFFFF, true); + graphics.drawString(mc.font, formattedMinVal, x - mc.font.width(formattedMinVal), (int) (y + gHeight - 4), 0xFFFFFFFF, true); DrawHelper.stopScaling(graphics.pose()); if(showGrid) x -= offset; - this.widgetBox.setDimensions(x, y, width + offset, height, shouldScale, DynamicHUD.getGlobalScale()); + this.widgetBox.setDimensions(x, y, gWidth + offset, gHeight, canScale); // DrawHelper.disableScissor(); if (menu != null) menu.set(getX(), getY(), (int) Math.ceil(getHeight())); @@ -392,7 +391,7 @@ private void computeOffset(){ return; } - // The first Component is usually the largest but a negative value may occupy more width so we check the first and last Component. + // The first Component is usually the largest but a negative value may occupy more gWidth so we check the first and last Component. // Idk how this will break. String firstText = formatValue(maxValue - valueStep); String lastText = formatValue(maxValue - (gridLines * valueStep)); @@ -455,31 +454,13 @@ public void setLabel(String label) { this.label = label; } - @Override - public float getHeight() { - return height; - } - - public void setHeight(float height) { - this.height = height; - } - - @Override - public float getWidth() { - return width; - } - - public void setWidth(float width) { - this.width = width; - } - public int getGridLines() { return gridLines; } public void setGridLines(int gridLines) { this.gridLines = gridLines; - this.stepY = height / (gridLines + 1); + this.stepY = gHeight / (gridLines + 1); this.valueStep = (maxValue - minValue) / (gridLines + 1); this.valueScale = (float) Math.clamp((stepY / 9.5), 0.0f, 1.0f); } @@ -517,8 +498,8 @@ public void onClose() { @Override public void writeToTag(CompoundTag tag) { super.writeToTag(tag); - tag.putFloat("width", width); - tag.putFloat("height", height); + tag.putFloat("gWidth", gWidth); + tag.putFloat("gHeight", gHeight); tag.putInt("maxDataPoints", maxDataPoints); tag.putFloat("minValue", minValue); tag.putFloat("maxValue", maxValue); @@ -535,8 +516,8 @@ public void writeToTag(CompoundTag tag) { @Override public void readFromTag(CompoundTag tag) { super.readFromTag(tag); - this.width = tag.getFloat("width").orElse(100f); - this.height = tag.getFloat("height").orElse(50f); + this.gWidth = tag.getFloat("gWidth").orElse(100f); + this.gHeight = tag.getFloat("gHeight").orElse(50f); this.maxDataPoints = tag.getInt("maxDataPoints").orElse(100); this.minValue = tag.getFloat("minValue").orElse(0f); this.maxValue = tag.getFloat("maxValue").orElse(1f); @@ -563,8 +544,8 @@ public ContextMenu getContextMenu() { public static class GraphWidgetBuilder extends DynamicValueWidgetBuilder { private Anchor anchor = Anchor.CENTER; - private float width = 100; - private float height = 50; + private float gWidth = 100; + private float gHeight = 50; private int maxDataPoints = 50; private float minValue = 0; private float maxValue = 100; @@ -588,13 +569,13 @@ public GraphWidgetBuilder anchor(Anchor anchor) { return this; } - public GraphWidgetBuilder width(float width) { - this.width = width; + public GraphWidgetBuilder gWidth(float gWidth) { + this.gWidth = gWidth; return this; } - public GraphWidgetBuilder height(float height) { - this.height = height; + public GraphWidgetBuilder gHeight(float gHeight) { + this.gHeight = gHeight; return this; } @@ -645,10 +626,10 @@ protected GraphWidgetBuilder self() { @Override public GraphWidget build() { - GraphWidget widget = new GraphWidget(registryID, registryKey, modID, anchor, width, height, maxDataPoints, minValue, maxValue, graphColor, backgroundColor, lineThickness, showGrid, gridLines, label); + GraphWidget widget = new GraphWidget(registryID, registryKey, modID, anchor, gWidth, gHeight, maxDataPoints, minValue, maxValue, graphColor, backgroundColor, lineThickness, showGrid, gridLines, label); widget.setPosition(x, y); widget.setDraggable(isDraggable); - widget.setShouldScale(shouldScale); + widget.setCanScale(shouldScale); widget.isVisible = display; return widget; } diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/ItemWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/ItemWidget.java index edb1c71..e7fb3b2 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/ItemWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/ItemWidget.java @@ -1,7 +1,5 @@ package com.tanishisherewith.dynamichud.widgets; -import com.tanishisherewith.dynamichud.DynamicHUD; -import com.tanishisherewith.dynamichud.config.GlobalConfig; import com.tanishisherewith.dynamichud.widget.Widget; import com.tanishisherewith.dynamichud.widget.WidgetData; import net.minecraft.client.gui.GuiGraphics; @@ -28,7 +26,7 @@ public ItemWidget() { @Override public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { graphics.renderItem(item, x, y); - widgetBox.setDimensions(getX(), getY(), 16, 16, this.shouldScale, DynamicHUD.getGlobalScale()); + widgetBox.setDimensions(getX(), getY(), 16, 16, this.canScale); } @Override diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java index 9fccebe..8f741dc 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java @@ -1,6 +1,5 @@ package com.tanishisherewith.dynamichud.widgets; -import com.tanishisherewith.dynamichud.DynamicHUD; import com.tanishisherewith.dynamichud.helpers.DrawHelper; import com.tanishisherewith.dynamichud.integration.IntegrationManager; import com.tanishisherewith.dynamichud.utils.DynamicValueRegistry; @@ -148,10 +147,10 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { } else { graphics.drawString(mc.font, Component, getX() + 2, getY() + 2, color, shadow); } - widgetBox.setDimensions(getX(), getY(), mc.font.width(Component) + 3, mc.font.lineHeight + 2, this.shouldScale, DynamicHUD.getGlobalScale()); + widgetBox.setDimensions(getX(), getY(), mc.font.width(Component) + 3, mc.font.lineHeight + 2, this.canScale); } - menu.set(getX(), getY(), (int) Math.ceil(getHeight())); + menu.set(getX(), getY(), (int) Math.ceil(getHeight())); } @Override @@ -236,7 +235,7 @@ public TextWidget build() { widget.setPosition(x, y); widget.setDraggable(isDraggable); - widget.setShouldScale(shouldScale); + widget.setCanScale(shouldScale); return widget; } } From 2c5ae72b43f194b08f8583279d1d5b96e3fbcb59 Mon Sep 17 00:00:00 2001 From: tanishisherewith <120117618+tanishisherewithhh@users.noreply.github.com> Date: Sat, 20 Jun 2026 13:46:06 +0530 Subject: [PATCH 08/22] OptionGroup animation in ModernSkin A slight fix to Y axis of GraphWidget Anchor default to TOP_LEFT Anchor function refactor Some more docs --- .../dynamichud/DynamicHUD.java | 2 +- .../dynamichud/IntegrationTest.java | 4 +- .../animationhelper/AnimationProperty.java | 2 +- .../contextmenu/skinsystem/ModernSkin.java | 94 ++++++++++++++++--- .../dynamichud/widget/DynamicValueWidget.java | 2 +- .../dynamichud/widget/Widget.java | 58 +++++++----- .../dynamichud/widgets/GraphWidget.java | 30 +++--- 7 files changed, 133 insertions(+), 59 deletions(-) diff --git a/src/main/java/com/tanishisherewith/dynamichud/DynamicHUD.java b/src/main/java/com/tanishisherewith/dynamichud/DynamicHUD.java index 43b9b99..480605e 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/DynamicHUD.java +++ b/src/main/java/com/tanishisherewith/dynamichud/DynamicHUD.java @@ -60,7 +60,7 @@ public void onInitializeClient() { * Using the fabric event {@link HudElementRegistry} to render widgets in the game HUD. * Mouse positions are passed in the negatives even though theoretically it's in the centre of the screen. */ - HudElementRegistryImpl.attachElementAfter(VanillaHudElements.MISC_OVERLAYS, + HudElementRegistryImpl.attachElementBefore(VanillaHudElements.MISC_OVERLAYS, Identifier.fromNamespaceAndPath("dynamichud","hudrender_callback"), (graphics, tickCounter) -> { for (WidgetRenderer widgetRenderer : IntegrationManager.getWidgetRenderers()) { diff --git a/src/main/java/com/tanishisherewith/dynamichud/IntegrationTest.java b/src/main/java/com/tanishisherewith/dynamichud/IntegrationTest.java index 51d4b77..71f0bf9 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/IntegrationTest.java +++ b/src/main/java/com/tanishisherewith/dynamichud/IntegrationTest.java @@ -74,7 +74,7 @@ public void init() { .setY(100) .label("FPS Chart") .graphColor(Color.CYAN) - .anchor(Widget.Anchor.CENTER) + .anchor(Widget.Anchor._default()) .gWidth(100) .gHeight(150) .gridLines(10) @@ -85,7 +85,7 @@ public void init() { .minValue(30) .setModID(DynamicHUD.MOD_ID) .setDraggable(true) - .setDisplay(true) + .setIsVisible(true) .showGrid(true) .shouldScale(true) .registryKey("FPS") diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/AnimationProperty.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/AnimationProperty.java index 40a1b0b..53eab9d 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/AnimationProperty.java +++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/AnimationProperty.java @@ -1,6 +1,6 @@ package com.tanishisherewith.dynamichud.helpers.animationhelper; -// AnimationProperty.java +// Use this to set/get the variable on which the animation should apply to public interface AnimationProperty { T get(); void set(T value); diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java index 5e15ec5..975e4a8 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java @@ -22,7 +22,9 @@ import org.lwjgl.glfw.GLFW; import java.awt.*; +import java.util.HashMap; import java.util.List; +import java.util.Map; import static com.tanishisherewith.dynamichud.helpers.ColorHelper.DARK_GREEN; import static com.tanishisherewith.dynamichud.helpers.ColorHelper.DARK_RED; @@ -42,6 +44,7 @@ public class ModernSkin extends Skin implements GroupableSkin { private Component TOOLTIP_HEAD; private static int SCALE_FACTOR = 4; private final ScrollHandler scrollHandler; + private final Map groupAnimations = new HashMap<>(); public ModernSkin(float radius, Component defaultToolTipHeader, Component defaultToolTipText) { this.radius = radius; @@ -98,13 +101,41 @@ private int calcOptionHeight(Option option) { return option.getHeight() > 0 ? option.getHeight() : mc.font.lineHeight; } + private int computeGroupFullHeight(OptionGroup group, int groupX, int groupY, int targetWidth) { + // If collapsed, just return 20 (the header height) + if (!group.isExpanded()) return 20; + + int yOffset = groupY + 16 + getGroupIndent().top(); // header height + indent + int nestedIndent = getGroupIndent().left(); + int subWidth = targetWidth - nestedIndent - 8; + + for (Option option : group.getGroupOptions()) { + if (!option.shouldRender()) continue; + option.setHeight(calcOptionHeight(option)); + yOffset = contextMenu.getLayoutEngine().layoutOption(option, groupX + nestedIndent, yOffset, subWidth); + } + return yOffset - groupY; // total height + } + + // Adds a nice animation while opening and closing public void renderGroup(GuiGraphics graphics, OptionGroup group, int groupX, int groupY, int targetWidth, int mouseX, int mouseY) { - mouseX = (int) (mc.mouseHandler.xpos() / SCALE_FACTOR); - mouseY = (int) (mc.mouseHandler.ypos() / SCALE_FACTOR); + GroupAnimData animData = groupAnimations.computeIfAbsent(group, g -> new GroupAnimData(20f)); + AnimationProperty heightProp = animData.property; + if (group.isExpanded() && heightProp.get() <= 20f) { + int fullHeight = computeGroupFullHeight(group, groupX, groupY, targetWidth); + heightProp.set((float) fullHeight); + } + + if (animData.animation != null) { + animData.animation.update(); + } + + float animatedHeight = heightProp.get(); + int groupHeight = Math.round(animatedHeight); - if (group.isExpanded() && group.getHeight() > 20) { + if (group.isExpanded() && groupHeight > 20) { DrawHelper.drawRoundedRectangle(graphics, - groupX + 1, groupY + 14, width - groupX - 8 + contextMenuX, group.getHeight() - 16, radius, DARKER_GRAY_2.getRGB()); + groupX + 1, groupY + 14, width - groupX - 8 + contextMenuX, groupHeight - 16, radius, DARKER_GRAY_2.getRGB()); } Component groupText = group.name.copy().append(" " + (group.isExpanded() ? "-" : "+")); @@ -114,24 +145,29 @@ public void renderGroup(GuiGraphics graphics, OptionGroup group, int groupX, int graphics.drawString(mc.font, groupText, groupX + 4, groupY + 4, -1, true); - if (group.isExpanded()) { + if (group.isExpanded() && groupHeight > 20) { + int clipX = groupX + 1; + int clipY = groupY + 16; + int clipWidth = targetWidth + getGroupIndent().left() + 8; + int clipHeight = groupHeight - 16; + DrawHelper.enableScissor(clipX, clipY, clipWidth, clipHeight, SCALE_FACTOR, graphics); + int yOffset = groupY + 16 + getGroupIndent().top(); int nestedIndent = getGroupIndent().left(); int subWidth = targetWidth - nestedIndent - 8; for (Option option : group.getGroupOptions()) { if (!option.shouldRender()) continue; - - // Position child option with layout engine option.setHeight(calcOptionHeight(option)); yOffset = contextMenu.getLayoutEngine().layoutOption(option, groupX + nestedIndent, yOffset, subWidth); option.render(graphics, option.getX(), option.getY(), mouseX, mouseY); } - group.setHeight(yOffset - groupY); - } else { - group.setHeight(20); + DrawHelper.disableScissor(graphics); } + + // actual height for layout + group.setHeight(groupHeight); } private void drawScrollbar(GuiGraphics graphics) { @@ -334,14 +370,30 @@ public boolean mouseClicked(ContextMenu menu, double mouseX, double mouseY, i for (Option option : getOptions(contextMenu)) { if (!option.shouldRender()) continue; - int optHeight = calcOptionHeight(option); if (option instanceof OptionGroup group) { Component groupText = group.name.copy().append(" " + (group.isExpanded() ? "-" : "+")); if (isMouseOver(mouseX, mouseY, optionStartX + 2, yPos, - mc.font.width(groupText) + 6, - 16)) { - group.setExpanded(!group.isExpanded()); + mc.font.width(groupText) + 6, 16)) { + boolean willBeExpanded = !group.isExpanded(); + group.setExpanded(willBeExpanded); + + GroupAnimData animData = groupAnimations.computeIfAbsent(group, g -> new GroupAnimData(20f)); + AnimationProperty heightProp = animData.property; + float current = heightProp.get(); + float target; + if (willBeExpanded) { + int targetWidthForGroup = (int) (width * 0.8f - 18); + int fullHeight = computeGroupFullHeight(group, optionStartX + 2, yPos, targetWidthForGroup); + target = Math.max(fullHeight, 20); + } else { + target = 20f; + } + + ValueAnimation anim = new ValueAnimation(heightProp, current, target, EasingType.EASE_OUT_QUAD); + anim.duration(200); + anim.start(); + animData.animation = anim; return true; } yPos += group.getHeight() + spacing; @@ -902,4 +954,18 @@ public boolean mouseReleased(RunnableOption option, double mouseX, double mouseY public Skin clone() { return new ModernSkin(radius, defaultToolTipHeader, defaultToolTipText); } + + + private static class GroupAnimData { + AnimationProperty property; + ValueAnimation animation; + + GroupAnimData(float initial) { + property = new AnimationProperty() { + private float value = initial; + @Override public Float get() { return value; } + @Override public void set(Float v) { value = v; } + }; + } + } } \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/widget/DynamicValueWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widget/DynamicValueWidget.java index 18cc7b9..10a880f 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widget/DynamicValueWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widget/DynamicValueWidget.java @@ -19,7 +19,7 @@ public abstract class DynamicValueWidget extends Widget { protected Supplier valueSupplier; public DynamicValueWidget(WidgetData data, String modID, String registryID, String registryKey) { - this(data, modID, Anchor.CENTER, registryID, registryKey); + this(data, modID, Anchor._default(), registryID, registryKey); } public DynamicValueWidget(WidgetData data, String modId, Anchor anchor, String registryID, String registryKey) { diff --git a/src/main/java/com/tanishisherewith/dynamichud/widget/Widget.java b/src/main/java/com/tanishisherewith/dynamichud/widget/Widget.java index 7e8a8b6..ef2955c 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widget/Widget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widget/Widget.java @@ -5,6 +5,7 @@ import com.tanishisherewith.dynamichud.helpers.DrawHelper; import com.tanishisherewith.dynamichud.internal.UID; import com.tanishisherewith.dynamichud.utils.Input; +import com.tanishisherewith.dynamichud.widgets.GraphWidget; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.nbt.CompoundTag; @@ -12,6 +13,12 @@ import net.minecraft.util.Mth; import org.lwjgl.glfw.GLFW; +/** + * This is the base Widget class that handles the rendering, scaling, dragging, anchoring and positioning of the Widget. + *

+ * Default fields are made to help with all the basic functions of a widget. + * Main fields include: {@link #uid},{@link #isVisible},{@link #isDraggable},{@link #canScale},{@link #isInEditor},{@link #widgetBox},{@link #DATA} + */ public abstract class Widget implements Input { public static Minecraft mc = Minecraft.getInstance(); public WidgetData DATA; @@ -59,12 +66,12 @@ public abstract class Widget implements Input { protected int offsetX, offsetY; // Offset from the anchor point public Widget(WidgetData DATA, String modId) { - this(DATA, modId, Anchor.CENTER); + this(DATA, modId, Anchor._default()); } public Widget(WidgetData DATA, String modId, Anchor anchor) { this.DATA = DATA; - widgetBox = new WidgetBox(0, 0, 0, 0); + this.widgetBox = new WidgetBox(0, 0, 0, 0); this.modId = modId; this.anchor = anchor; this.tooltipText = Component.literal(DATA.description()); @@ -216,14 +223,6 @@ private void renderWidgetInEditor(GuiGraphics graphics, int mouseX, int mouseY) renderWidget(graphics, mouseX, mouseY); } - protected int getTransformedMouseX(double mouseX) { - return (int) ((mouseX - getX()) / getScale() + getX()); - } - - protected int getTransformedMouseY(double mouseY) { - return (int) ((mouseY - getY()) / getScale() + getY()); - } - @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { if (widgetBox.isMouseOver(mouseX, mouseY) && button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { @@ -238,13 +237,13 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { return false; } - /* Input related methods. Override with **super call** to add your own input-based code like contextMenu */ - public void clampPosition() { this.x = (int) Mth.clamp(this.x, 0, mc.getWindow().getGuiScaledWidth() - getWidth()); this.y = (int) Mth.clamp(this.y, 0, mc.getWindow().getGuiScaledHeight() - getHeight()); } + /** Input related methods. Override with **super call** to add your own input-based code like contextMenu **/ + @Override public final boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { return false; @@ -352,9 +351,9 @@ public void readFromTag(CompoundTag tag) { uid = tag.contains("UID") ? new UID(tag.getString("UID").get()) : UID.generate(); // x = tag.getInt("x"); // y = tag.getInt("y"); - anchor = Anchor.valueOf(tag.getString("anchor").orElse("CENTER")); - offsetX = tag.getInt("offsetX").orElse(0); - offsetY = tag.getInt("offsetY").orElse(0); + anchor = Anchor.valueOf(tag.getString("anchor").orElse("TOP_LEFT")); + offsetX = tag.getIntOr("offsetX", 0); + offsetY = tag.getIntOr("offsetY",0); isVisible = tag.getBoolean("isVisible").orElse(true); isDraggable = tag.getBoolean("isDraggable").orElse(true); canScale = tag.getBoolean("canScale").orElse(true); @@ -390,10 +389,6 @@ public WidgetBox getWidgetBox() { return widgetBox; } - public void setUid(UID uid) { - this.uid = uid; - } - public void setCanScale(boolean canScale) { this.canScale = canScale; } @@ -417,16 +412,26 @@ public String toString() { '}'; } - public enum Anchor {TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT, CENTER} + public enum Anchor { + TOP_LEFT, + TOP_RIGHT, + BOTTOM_LEFT, + BOTTOM_RIGHT, + CENTER; + + public static Anchor _default(){ + return TOP_LEFT; + } + } public abstract static class WidgetBuilder { protected int x; protected int y; - protected boolean display = true; + protected boolean isVisible = true; protected boolean isDraggable = true; protected boolean shouldScale = true; protected String modID = "unknown"; - + protected Anchor anchor = Anchor._default(); /** * X Position of the widget of the scaled screen. @@ -444,8 +449,8 @@ public T setY(int y) { return self(); } - public T setDisplay(boolean display) { - this.display = display; + public T setIsVisible(boolean isVisible) { + this.isVisible = isVisible; return self(); } @@ -464,6 +469,11 @@ public T setModID(String modID) { return self(); } + public T anchor(Anchor anchor) { + this.anchor = anchor; + return self(); + } + /** * Method to be overridden in subclasses to return "this" correctly */ diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java index cb23beb..8b3782f 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java @@ -94,12 +94,12 @@ private void internal_init() { } public GraphWidget() { - this(DynamicValueRegistry.GLOBAL_ID, "unknown", "unknown", Anchor.CENTER, 0, 0, 5, 0, 10, Color.RED, Color.GREEN, 0, false, 0, "empty"); + this(DynamicValueRegistry.GLOBAL_ID, "unknown", "unknown", Anchor._default(), 0, 0, 5, 0, 10, Color.RED, Color.GREEN, 0, false, 0, "empty"); } @Override public void init() { - // Initialize the buffer with minValue, mimicking ArrayList behavior + // init the buffer with minValue for (int i = 0; i < maxDataPoints; i++) { dataPoints[i] = minValue; } @@ -270,7 +270,7 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { float texWidth = mc.font.width(valueText) * valueScale; //Scale the Component to its proper position and size with grid lines - DrawHelper.scaleAndPosition(graphics.pose(), x - 2, yPos, valueScale); + DrawHelper.scaleAndPosition(graphics.pose(), x - 2, yPos,texWidth,mc.font.lineHeight * valueScale, valueScale); graphics.drawString(mc.font, valueText, Math.round(x + offset - texWidth), (int) (yPos - (mc.font.lineHeight * valueScale) / 2.0f), 0xFFFFFFFF, true); DrawHelper.stopScaling(graphics.pose()); } @@ -318,7 +318,7 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { DrawHelper.scaleAndPosition(graphics.pose(), x - 5, y + gHeight, 0.5f); String formattedMinVal = formatValue(minValue); - graphics.drawString(mc.font, formattedMinVal, x - mc.font.width(formattedMinVal), (int) (y + gHeight - 4), 0xFFFFFFFF, true); + graphics.drawString(mc.font, formattedMinVal, (int) (x - mc.font.width(formattedMinVal)), (int) (y + gHeight - 4), 0xFFFFFFFF, true); DrawHelper.stopScaling(graphics.pose()); if(showGrid) x -= offset; @@ -331,12 +331,16 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { // format large values (like: 1000 -> 1K, 1000000 -> 1M) private String formatValue(float value) { - if (Math.abs(value) >= 1_000_000) { - return String.format("%.1fM", value / 1_000_000).trim(); - } else if (Math.abs(value) >= 1_000) { - return String.format("%.1fK", value / 1_000).trim(); + float absVal = Math.abs(value); + + if (absVal >= 1_000_000) { + long rounded = Math.round(value / 1_000_000f); + return String.format("%dM", rounded); + } else if (absVal >= 1_000) { + long rounded = Math.round(value / 1_000f); + return String.format("%dK", rounded); } else { - return String.format("%.0f", value).trim(); + return String.format("%d", (int) value); } } @@ -543,7 +547,6 @@ public ContextMenu getContextMenu() { } public static class GraphWidgetBuilder extends DynamicValueWidgetBuilder { - private Anchor anchor = Anchor.CENTER; private float gWidth = 100; private float gHeight = 50; private int maxDataPoints = 50; @@ -564,11 +567,6 @@ public GraphWidgetBuilder label(String label) { return this; } - public GraphWidgetBuilder anchor(Anchor anchor) { - this.anchor = anchor; - return this; - } - public GraphWidgetBuilder gWidth(float gWidth) { this.gWidth = gWidth; return this; @@ -630,7 +628,7 @@ public GraphWidget build() { widget.setPosition(x, y); widget.setDraggable(isDraggable); widget.setCanScale(shouldScale); - widget.isVisible = display; + widget.isVisible = isVisible; return widget; } } From 20ebf289d279e12a84b661452fd9879920a217c9 Mon Sep 17 00:00:00 2001 From: tanishisherewith <120117618+tanishisherewithhh@users.noreply.github.com> Date: Sat, 20 Jun 2026 20:22:00 +0530 Subject: [PATCH 09/22] Added search to ModernSkin Added Fuzzy Score and apache library Fixed inconsistent height in ModernSkin Fixed charTyped missing call in ContextMenu --- build.gradle | 3 + .../screens/AbstractMoveableScreen.java | 7 +- .../dynamichud/utils/Util.java | 92 ++++++++ .../utils/contextmenu/ContextMenu.java | 7 +- .../utils/contextmenu/options/Option.java | 2 +- .../contextmenu/options/OptionGroup.java | 1 + .../contextmenu/screen/ContextMenuScreen.java | 7 + .../contextmenu/skinsystem/ModernSkin.java | 197 +++++++++++++----- .../utils/contextmenu/skinsystem/Skin.java | 5 +- .../utils/handlers/ScrollHandler.java | 4 + 10 files changed, 267 insertions(+), 58 deletions(-) diff --git a/build.gradle b/build.gradle index 8d9cd23..a9b435e 100644 --- a/build.gradle +++ b/build.gradle @@ -36,6 +36,9 @@ dependencies { modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" modImplementation "dev.isxander:yet-another-config-lib:${project.yacl_version}" + + //fuzzyscore + implementation 'org.apache.commons:commons-text:1.12.0' } processResources { diff --git a/src/main/java/com/tanishisherewith/dynamichud/screens/AbstractMoveableScreen.java b/src/main/java/com/tanishisherewith/dynamichud/screens/AbstractMoveableScreen.java index 5dcf628..8b2860a 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/screens/AbstractMoveableScreen.java +++ b/src/main/java/com/tanishisherewith/dynamichud/screens/AbstractMoveableScreen.java @@ -8,11 +8,13 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.packs.PackSelectionScreen; import net.minecraft.client.input.CharacterEvent; import net.minecraft.client.input.KeyEvent; import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.vehicle.minecart.Minecart; +import org.apache.commons.lang3.StringUtils; import org.jspecify.annotations.NonNull; import org.lwjgl.glfw.GLFW; @@ -59,8 +61,9 @@ public boolean mouseClicked(MouseButtonEvent event, boolean bl) { @Override public boolean charTyped(CharacterEvent event) { - widgetRenderer.charTyped((char) event.codepoint(), event.modifiers()); - ContextMenuManager.getInstance().charTyped((char) event.codepoint(), event.modifiers()); + char c = Character.toString(event.codepoint()).charAt(0); + widgetRenderer.charTyped(c, event.modifiers()); + ContextMenuManager.getInstance().charTyped(c, event.modifiers()); return super.charTyped(event); } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/Util.java b/src/main/java/com/tanishisherewith/dynamichud/utils/Util.java index c6ae850..323b578 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/Util.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/Util.java @@ -1,6 +1,12 @@ package com.tanishisherewith.dynamichud.utils; import com.tanishisherewith.dynamichud.DynamicHUD; +import com.tanishisherewith.dynamichud.utils.contextmenu.options.Option; +import com.tanishisherewith.dynamichud.utils.contextmenu.options.OptionGroup; +import com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.Skin; +import org.apache.commons.text.similarity.FuzzyScore; + +import java.util.*; public class Util { public static Quadrant getQuadrant(int x, int y) { @@ -36,6 +42,92 @@ public static boolean warnIfTrue(boolean expression, String message, Object... o return expression; } + /** + * Returns a list of options sorted by higher fuzzy score from the query string. + */ + public static List> getSearchResults(String query, int minimumScore, List> options) { + if(options.isEmpty()) return new ArrayList<>(); + + if (query == null || query.trim().isEmpty()) { + return new ArrayList<>(options); + } + + FuzzyScore FUZZY_SCORE = new FuzzyScore(Locale.ENGLISH); + + String lowerQuery = query.toLowerCase().trim(); + Map, Integer> scoreMap = new HashMap<>(); + + List> allOptions = Skin.flattenOptions(options); + + for (Option opt : allOptions) { + if (!opt.shouldRender()) continue; + String name = opt.getName().getString(); + String desc = opt.getDescription().getString(); + int nameScore = FUZZY_SCORE.fuzzyScore(name, lowerQuery); + int descScore = FUZZY_SCORE.fuzzyScore(desc, lowerQuery); + int best = Math.max(nameScore, descScore); + scoreMap.put(opt, best); + } + + + if (scoreMap.isEmpty()) return new ArrayList<>(); + + //Allow 2 typos for a min score of -1 using the query length + int threshold = (minimumScore == -1) ? lowerQuery.length() - 2: minimumScore; + + return filterAndSortOptions(options, threshold, scoreMap); + } + + /** + * Recursively processes a list of options, returning a filtered and sorted copy. + * Groups are re‑created with only matching children, and are expanded. + */ + private static List> filterAndSortOptions(List> source, int threshold, Map, Integer> scoreMap) { + List> result = new ArrayList<>(); + for (Option opt : source) { + if (opt instanceof OptionGroup group) { + // Process children first + List> filteredChildren = filterAndSortOptions(group.getGroupOptions(), threshold, scoreMap); + int groupScore = scoreMap.getOrDefault(group, 0); + boolean groupMatches = groupScore >= threshold; + + if (groupMatches || !filteredChildren.isEmpty()) { + OptionGroup newGroup = new OptionGroup(group.name); + newGroup.setExpanded(true); + for (Option child : filteredChildren) { + newGroup.addOption(child); + } + result.add(newGroup); + } + } else if (scoreMap.getOrDefault(opt, 0) >= threshold) { + result.add(opt); + } + } + + // sort by score descending + result.sort((a, b) -> { + int sa = getEffectiveScore(a, scoreMap); + int sb = getEffectiveScore(b, scoreMap); + return Integer.compare(sb, sa); + }); + return result; + } + + /** + * Returns the highest score among all options inside a group (or the group's own score). + */ + private static int getEffectiveScore(Option opt, Map, Integer> scoreMap) { + if (opt instanceof OptionGroup group) { + int max = scoreMap.getOrDefault(group, 0); + for (Option child : group.getGroupOptions()) { + max = Math.max(max, getEffectiveScore(child, scoreMap)); + } + return max; + } + return scoreMap.getOrDefault(opt, 0); + } + + public static boolean isSafeToContinue() { return DynamicHUD.MC.getWindow() != null && DynamicHUD.MC.font != null; } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java index 2b6c3ea..c84837e 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java @@ -20,10 +20,8 @@ import org.lwjgl.glfw.GLFW; import java.awt.*; -import java.util.ArrayList; -import java.util.Collections; +import java.util.*; import java.util.List; -import java.util.Objects; @SuppressWarnings({"rawtypes", "unchecked"}) public class ContextMenu implements Input { @@ -291,11 +289,14 @@ public void mouseScrolled(double mouseX, double mouseY, double horizontalAmount, @Override public void charTyped(char c, int modifiers) { if (!shouldDisplay) return; + for (Option option : options) { if(option.shouldRender()) { option.charTyped(c, modifiers); } } + + properties.getSkin().charTyped(this, c, modifiers); } public void set(int x, int y, int widgetHeight) { diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/Option.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/Option.java index 2142ccc..a42d598 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/Option.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/Option.java @@ -38,7 +38,7 @@ public Option(Component name, Supplier getter, Consumer setter, Supplier getter, Consumer setter, Supplier shouldRender) { diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/OptionGroup.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/OptionGroup.java index b10cd69..d2fea9c 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/OptionGroup.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/OptionGroup.java @@ -28,6 +28,7 @@ public List> getGroupOptions() { return Collections.unmodifiableList(groupOptions); } + @Override public void updateProperties(ContextMenuProperties properties) { super.updateProperties(properties); diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/ContextMenuScreen.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/ContextMenuScreen.java index 4ef4d73..42e940d 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/ContextMenuScreen.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/ContextMenuScreen.java @@ -5,6 +5,7 @@ import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenuProperties; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.input.CharacterEvent; import net.minecraft.client.input.KeyEvent; import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.network.chat.Component; @@ -82,6 +83,12 @@ public boolean keyPressed(KeyEvent event) { return super.keyPressed(event); } + @Override + public boolean charTyped(CharacterEvent characterEvent) { + contextMenu.charTyped(characterEvent.codepointAsString().charAt(0), characterEvent.modifiers()); + return super.charTyped(characterEvent); + } + @Override public void onClose() { contextMenu.close(); diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java index 975e4a8..d1bcced 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java @@ -7,6 +7,7 @@ import com.tanishisherewith.dynamichud.helpers.animationhelper.animations.MathAnimations; import com.tanishisherewith.dynamichud.helpers.animationhelper.animations.SquishAnimator; import com.tanishisherewith.dynamichud.helpers.animationhelper.animations.ValueAnimation; +import com.tanishisherewith.dynamichud.utils.Util; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenu; import com.tanishisherewith.dynamichud.utils.contextmenu.layout.LayoutEngine; import com.tanishisherewith.dynamichud.utils.contextmenu.options.*; @@ -14,6 +15,11 @@ import com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.interfaces.SkinRenderer; import com.tanishisherewith.dynamichud.utils.handlers.ScrollHandler; import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.EditBox; +import net.minecraft.client.input.CharacterEvent; +import net.minecraft.client.input.KeyEvent; +import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.client.input.MouseButtonInfo; import net.minecraft.client.resources.sounds.SimpleSoundInstance; import net.minecraft.sounds.SoundEvents; import net.minecraft.network.chat.Component; @@ -22,6 +28,7 @@ import org.lwjgl.glfw.GLFW; import java.awt.*; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -44,8 +51,17 @@ public class ModernSkin extends Skin implements GroupableSkin { private Component TOOLTIP_HEAD; private static int SCALE_FACTOR = 4; private final ScrollHandler scrollHandler; + + int searchBoxWidth = 0; + int searchBoxHeight = 14; + int searchBoxX = 0; + int searchBoxY = 0; + private final Map groupAnimations = new HashMap<>(); + private EditBox searchBox; + private String searchQuery = ""; + public ModernSkin(float radius, Component defaultToolTipHeader, Component defaultToolTipText) { this.radius = radius; this.TOOLTIP_TEXT = defaultToolTipText; @@ -65,6 +81,14 @@ public ModernSkin(float radius, Component defaultToolTipHeader, Component defaul setCreateNewScreen(true); } + @Override + public List> getOptions(ContextMenu menu) { + if(searchQuery != null && !searchQuery.isEmpty()) { + return Util.getSearchResults(searchQuery,-1, contextMenu.getOptions()); + } + return super.getOptions(menu); + } + public ModernSkin(float radius) { this(radius, Component.literal("Example Tip"), Component.literal("Hover over a setting to see its tool-tip (if present) here!")); } @@ -75,7 +99,7 @@ public ModernSkin() { @Override public LayoutEngine.Offset getGroupIndent() { - return new LayoutEngine.Offset(4, 4); + return new LayoutEngine.Offset(4, 2); } public void enableSkinScissor(GuiGraphics graphics) { @@ -89,21 +113,44 @@ public void renderGroup(GuiGraphics graphics, OptionGroup group, int groupX, int } private int calcOptionHeight(Option option) { if (option instanceof BooleanOption || option instanceof DoubleOption) return 14; - if (option instanceof CycleOption) return mc.font.lineHeight + 2; - if (option instanceof SubMenuOption) return 16; + if (option instanceof CycleOption) return 14; + if (option instanceof SubMenuOption) return 14; if (option instanceof RunnableOption) return mc.font.lineHeight + 6; if (option instanceof ColorOption colorOption) { return colorOption.getHeight() > 0 ? colorOption.getHeight() : 20; } if (option instanceof OptionGroup group) { - return group.isExpanded() ? group.getHeight() : 20; + return group.isExpanded() ? group.getHeight() : 16; } return option.getHeight() > 0 ? option.getHeight() : mc.font.lineHeight; } + private void renderSearchBox(GuiGraphics graphics, int mouseX, int mouseY){ + if (searchBox == null) { + searchBox = new EditBox(mc.font, searchBoxX, searchBoxY, searchBoxWidth, searchBoxHeight, Component.empty()); + searchBox.setMaxLength(50); + searchBox.setEditable(true); + searchBox.active = true; + searchBox.setBordered(true); + searchBox.setVisible(true); + searchBox.setHint(Component.literal("Search...")); + searchBox.setCanLoseFocus(true); + searchBox.setResponder(query -> { + searchQuery = query; + // Reset scroll so results show from top + scrollHandler.setScrollOffset(0); + }); + } + searchBox.setX(searchBoxX); + searchBox.setY(searchBoxY); + searchBox.setWidth(searchBoxWidth); + searchBox.setHeight(searchBoxHeight); + + searchBox.render(graphics, mouseX, mouseY, mc.getDeltaTracker().getGameTimeDeltaTicks()); + } + private int computeGroupFullHeight(OptionGroup group, int groupX, int groupY, int targetWidth) { - // If collapsed, just return 20 (the header height) - if (!group.isExpanded()) return 20; + if (!group.isExpanded()) return 16; int yOffset = groupY + 16 + getGroupIndent().top(); // header height + indent int nestedIndent = getGroupIndent().left(); @@ -119,23 +166,26 @@ private int computeGroupFullHeight(OptionGroup group, int groupX, int groupY, in // Adds a nice animation while opening and closing public void renderGroup(GuiGraphics graphics, OptionGroup group, int groupX, int groupY, int targetWidth, int mouseX, int mouseY) { - GroupAnimData animData = groupAnimations.computeIfAbsent(group, g -> new GroupAnimData(20f)); + GroupAnimData animData = groupAnimations.computeIfAbsent(group, g -> new GroupAnimData(16f)); AnimationProperty heightProp = animData.property; - if (group.isExpanded() && heightProp.get() <= 20f) { + if (group.isExpanded() && heightProp.get() <= 16) { int fullHeight = computeGroupFullHeight(group, groupX, groupY, targetWidth); heightProp.set((float) fullHeight); } if (animData.animation != null) { animData.animation.update(); + if(animData.animation.isFinished()){ + animData.animation = null; + } } float animatedHeight = heightProp.get(); int groupHeight = Math.round(animatedHeight); - if (group.isExpanded() && groupHeight > 20) { + if (group.isExpanded() && groupHeight > 16) { DrawHelper.drawRoundedRectangle(graphics, - groupX + 1, groupY + 14, width - groupX - 8 + contextMenuX, groupHeight - 16, radius, DARKER_GRAY_2.getRGB()); + groupX + 1, groupY + 14, width - groupX - 8 + contextMenuX, groupHeight - 16 + getGroupIndent().top(), radius, DARKER_GRAY_2.getRGB()); } Component groupText = group.name.copy().append(" " + (group.isExpanded() ? "-" : "+")); @@ -143,9 +193,9 @@ public void renderGroup(GuiGraphics graphics, OptionGroup group, int groupX, int DrawHelper.drawRoundedRectangle(graphics, groupX + 1, groupY + 1, true, true, !group.isExpanded(), !group.isExpanded(), mc.font.width(groupText) + 6, 16, radius, DARKER_GRAY_2.getRGB()); - graphics.drawString(mc.font, groupText, groupX + 4, groupY + 4, -1, true); + graphics.drawString(mc.font, groupText, groupX + 4, groupY + 5, -1, true); - if (group.isExpanded() && groupHeight > 20) { + if (group.isExpanded() && groupHeight > 16) { int clipX = groupX + 1; int clipY = groupY + 16; int clipWidth = targetWidth + getGroupIndent().left() + 8; @@ -187,9 +237,6 @@ public void renderContextMenu(GuiGraphics graphics, ContextMenu contextMenu, SCALE_FACTOR = mc.getWindow().calculateScale(0, mc.isEnforceUnicode()); this.contextMenu = contextMenu; - mouseX = (int) (mc.mouseHandler.xpos() / SCALE_FACTOR); - mouseY = (int) (mc.mouseHandler.ypos() / SCALE_FACTOR); - DrawHelper.scaledProjection(SCALE_FACTOR, graphics); updateContextDimensions(); @@ -199,6 +246,11 @@ public void renderContextMenu(GuiGraphics graphics, ContextMenu contextMenu, DrawHelper.drawRoundedRectangle(graphics, contextMenuX, contextMenuY, width, height, radius, DARKER_GRAY.getRGB()); + mouseX = (int) (mc.mouseHandler.xpos() / SCALE_FACTOR); + mouseY = (int) (mc.mouseHandler.ypos() / SCALE_FACTOR); + + renderSearchBox(graphics,mouseX, mouseY); + drawBackButton(graphics, mouseX, mouseY); int optionStartX = contextMenu.x + (int) (width * 0.2f) + 10; @@ -252,6 +304,10 @@ private void updateContextDimensions() { contextMenuY = (int) (scaledHeight * 0.1f); width = (int) (scaledWidth * 0.8f); height = (int) (scaledHeight * 0.8f); + searchBoxWidth = (int)(width * 0.35f); + searchBoxHeight = 14; + searchBoxX = contextMenuX + searchBoxWidth; + searchBoxY = contextMenuY + 2; } public void drawBackButton(GuiGraphics graphics, int mouseX, int mouseY) { @@ -302,6 +358,8 @@ public void renderToolTipText(GuiGraphics graphics, int mouseX, int mouseY) { return; } + DrawHelper.enableScissor(contextMenuX + 2, tooltipY,toolTipWidth,toolTipHeight,SCALE_FACTOR,graphics); + graphics.drawString( mc.font, TOOLTIP_HEAD, @@ -331,6 +389,8 @@ public void renderToolTipText(GuiGraphics graphics, int mouseX, int mouseY) { DrawHelper.stopScaling(graphics.pose()); setTooltipText(defaultToolTipHeader, defaultToolTipText); + + DrawHelper.disableScissor(graphics); } public void setTooltipText(Component head_text, Component tooltip_text) { @@ -348,14 +408,55 @@ public void mouseScrolled(ContextMenu menu, double mouseX, double mouseY, dou scrollHandler.mouseScrolled(verticalAmount); } + @Override + public void keyPressed(ContextMenu menu, int key, int scanCode, int modifiers) { + if (searchBox != null && searchBox.isFocused()) { + searchBox.keyPressed(new KeyEvent(key,scanCode,modifiers)); + return; + } + super.keyPressed(menu, key, scanCode, modifiers); + } + + @Override + public void keyReleased(ContextMenu menu, int key, int scanCode, int modifiers) { + if (searchBox != null && searchBox.isFocused()) { + searchBox.keyReleased(new KeyEvent(key,scanCode,modifiers)); + return; + } + super.keyReleased(menu, key, scanCode, modifiers); + } + + @Override + public void charTyped(ContextMenu menu, char c, int modifiers) { + if (searchBox != null && searchBox.isFocused()) { + searchBox.charTyped(new CharacterEvent((int) c,modifiers)); + return; + } + super.charTyped(menu, c, modifiers); + } + @Override public boolean mouseReleased(ContextMenu menu, double mouseX, double mouseY, int button) { scrollHandler.stopDragging(); + if (searchBox != null) { + MouseButtonEvent event = new MouseButtonEvent(mouseX, mouseY, new MouseButtonInfo(button, 0)); + searchBox.mouseReleased(event); + } return super.mouseReleased(menu, mouseX, mouseY, button); } @Override public boolean mouseClicked(ContextMenu menu, double mouseX, double mouseY, int button) { + if (searchBox != null) { + MouseButtonEvent event = new MouseButtonEvent(mouseX, mouseY, new MouseButtonInfo(button, 0)); + if (searchBox.mouseClicked(event,false)) { + searchBox.setFocused(true); + return true; + } else{ + searchBox.setFocused(false); + } + } + mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; @@ -378,16 +479,16 @@ public boolean mouseClicked(ContextMenu menu, double mouseX, double mouseY, i boolean willBeExpanded = !group.isExpanded(); group.setExpanded(willBeExpanded); - GroupAnimData animData = groupAnimations.computeIfAbsent(group, g -> new GroupAnimData(20f)); + GroupAnimData animData = groupAnimations.computeIfAbsent(group, g -> new GroupAnimData(16f)); AnimationProperty heightProp = animData.property; float current = heightProp.get(); float target; if (willBeExpanded) { int targetWidthForGroup = (int) (width * 0.8f - 18); int fullHeight = computeGroupFullHeight(group, optionStartX + 2, yPos, targetWidthForGroup); - target = Math.max(fullHeight, 20); + target = Math.max(fullHeight, 16f); } else { - target = 20f; + target = 16f; } ValueAnimation anim = new ValueAnimation(heightProp, current, target, EasingType.EASE_OUT_QUAD); @@ -406,12 +507,23 @@ public boolean mouseClicked(ContextMenu menu, double mouseX, double mouseY, i mc.getSoundManager().play(SimpleSoundInstance.forUI( SoundEvents.UI_BUTTON_CLICK, 1.0F)); contextMenu.close(); + if (searchBox != null) { + searchBox.setFocused(false); + searchBox.setValue(""); + } + searchQuery = ""; + groupAnimations.clear(); } return super.mouseClicked(menu, mouseX, mouseY, button); } @Override public boolean mouseDragged(ContextMenu menu, double mouseX, double mouseY, int button, double deltaX, double deltaY) { + if (searchBox != null) { + MouseButtonEvent event = new MouseButtonEvent(mouseX, mouseY, new MouseButtonInfo(button, 0)); + searchBox.mouseDragged(event, deltaX, deltaY); + } + mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; @@ -453,8 +565,8 @@ public void render(GuiGraphics graphics, BooleanOption option, int x, int y, int graphics.drawString( mc.font, option.name, - x + 2, - y + 4, + x + 4, + y + 2, -1, false ); @@ -503,7 +615,7 @@ public void render(GuiGraphics graphics, ColorOption option, int x, int y, int m graphics.drawString( mc.font, option.name, - x + 2, + x + 4, y + 5, -1, false @@ -517,7 +629,8 @@ public void render(GuiGraphics graphics, ColorOption option, int x, int y, int m animator.update(isDown); Color behindColor = isHovering ? getThemeColor().darker().darker() : getThemeColor(); - DrawHelper.scaleAndPosition(graphics.pose(), x + option.getWidth() - width - 17, y + 1,width + 2, 14, scale); + DrawHelper.scaleAndPosition(graphics.pose(), x + option.getWidth() - width - 17, + y + 1,width + 2, 14, animator.getScale()); DrawHelper.drawRoundedRectangleWithShadowBadWay(graphics, x + option.getWidth() - width - 17, @@ -611,8 +724,8 @@ public void render(GuiGraphics graphics, DoubleOption option, int x, int y, int graphics.drawString( mc.font, option.name, - x + 2, - y, + x + 4, + y + 2, -1, false ); @@ -622,18 +735,18 @@ public void render(GuiGraphics graphics, DoubleOption option, int x, int y, int DrawHelper.drawRoundedRectangle( graphics, - sliderX, y, sliderBackgroundWidth, sliderBackgroundHeight, 1, DARKER_GRAY.getRGB() + sliderX, y + 2, sliderBackgroundWidth, sliderBackgroundHeight, 1, DARKER_GRAY.getRGB() ); int activeFillWidth = (int) ((displayValue - option.minValue) / (option.maxValue - option.minValue) * sliderBackgroundWidth); Color fillColor = isMouseOver(mouseX, mouseY, sliderX, y, sliderBackgroundWidth, sliderBackgroundHeight + 4) ? getThemeColor().darker().darker() : getThemeColor(); DrawHelper.drawRoundedRectangle( graphics, - sliderX, y, activeFillWidth, sliderBackgroundHeight, 2, fillColor.getRGB() + sliderX, y + 2, activeFillWidth, sliderBackgroundHeight, 2, fillColor.getRGB() ); float sliderHandleX = sliderX + activeFillWidth - 5; - DrawHelper.drawFilledCircle(graphics, sliderHandleX + 5, y + 1, 2, Color.WHITE.getRGB()); + DrawHelper.drawFilledCircle(graphics, sliderHandleX + 5, y + 3, 2, Color.WHITE.getRGB()); int decimalPlaces = String.valueOf(option.step).split("\\.")[1].length(); @@ -644,7 +757,7 @@ public void render(GuiGraphics graphics, DoubleOption option, int x, int y, int mc.font, label, sliderX + sliderBackgroundWidth + 10 - mc.font.width(label), - y + 2, + y + 4, -1, true ); @@ -690,6 +803,7 @@ public class ModernCycleRenderer implements SkinRenderer> { @Override public void render(GuiGraphics graphics, CycleOption option, int x, int y, int mouseX, int mouseY) { + y += 2; option.setHeight(mc.font.lineHeight + 2); Component mainLabel = option.name.copy().append(": "); @@ -787,6 +901,7 @@ public boolean mouseClicked(CycleOption option, double mouseX, double mouseY, int y = option.getY(); Component mainLabel = option.name.copy().append(": "); String selectedOption = option.get().toString(); + y += 2; int leftX = x + option.getWidth() - 30; boolean hoveredOverLeft = isMouseOver(mouseX, mouseY, leftX, y, mc.font.width("<") + 5, mc.font.lineHeight); @@ -821,10 +936,6 @@ public class ModernSubMenuRenderer implements SkinRenderer { public void render(GuiGraphics graphics, SubMenuOption option, int x, int y, int mouseX, int mouseY) { String textLabel = "Open"; int xPos = x + option.getWidth() - 40; - - option.setHeight(16); - - float width = mc.font.width(textLabel) + 5; boolean isHovering = isMouseOver(mouseX, mouseY, xPos + 2, y + 4, width, mc.font.lineHeight + 4); @@ -838,7 +949,7 @@ public void render(GuiGraphics graphics, SubMenuOption option, int x, int y, int DrawHelper.scaleAndPosition(graphics.pose(),x,y,width, mc.font.lineHeight + 4, animator.getScale()); DrawHelper.drawRoundedRectangleWithShadowBadWay( graphics, - xPos - 1, y + 1, + xPos - 1, y, mc.font.width(textLabel) + 5, mc.font.lineHeight + 4, 2, fillColor.getRGB(), @@ -848,35 +959,19 @@ public void render(GuiGraphics graphics, SubMenuOption option, int x, int y, int ); DrawHelper.drawOutlineRoundedBox( graphics, - xPos - 1, y + 1, + xPos - 1, y, mc.font.width(textLabel) + 5, mc.font.lineHeight + 4, 2, 0.7f, Color.WHITE.getRGB() ); - - graphics.drawString(mc.font, textLabel, xPos + 2, y + 4, Color.WHITE.getRGB(), true); + graphics.drawString(mc.font, textLabel, xPos + 2, y + 3, Color.WHITE.getRGB(), true); DrawHelper.stopScaling(graphics.pose()); - option.getSubMenu().render(graphics, x + option.getParentMenu().getWidth(), y, mouseX, mouseY); } - @Override - public void mouseScrolled(SubMenuOption option, double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { - mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; - mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; - SkinRenderer.super.mouseScrolled(option, mouseX, mouseY, horizontalAmount, verticalAmount); - } - - @Override - public boolean mouseDragged(SubMenuOption option, double mouseX, double mouseY, int button, double deltaX, double deltaY) { - mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; - mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; - return SkinRenderer.super.mouseDragged(option, mouseX, mouseY, button, deltaX, deltaY); - } - @Override public boolean mouseReleased(SubMenuOption option, double mouseX, double mouseY, int button) { mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/Skin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/Skin.java index dc4997d..e6b19a3 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/Skin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/Skin.java @@ -54,7 +54,7 @@ public boolean supportsGroups() { * Flatten a list of options, expanding any groups into their constituent options. * Used by skins that don't support group rendering. */ - protected List> flattenOptions(List> options) { + public static List> flattenOptions(List> options) { List> flattened = new ArrayList<>(); for (Option option : options) { @@ -102,6 +102,9 @@ public void keyPressed(ContextMenu menu, int key, int scanCode, int modifiers public void keyReleased(ContextMenu menu, int key, int scanCode, int modifiers) { } + public void charTyped(ContextMenu menu, char c, int modifiers) { + } + public void mouseScrolled(ContextMenu menu, double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/handlers/ScrollHandler.java b/src/main/java/com/tanishisherewith/dynamichud/utils/handlers/ScrollHandler.java index 62e54f8..06051d1 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/handlers/ScrollHandler.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/handlers/ScrollHandler.java @@ -66,6 +66,10 @@ public int getScrollOffset() { return Math.max(scrollOffset, 0); } + public void setScrollOffset(int scrollOffset) { + this.scrollOffset = Math.clamp(scrollOffset, 0, maxScrollOffset); + } + public boolean isOffsetWithinBounds(int offset) { return scrollOffset + offset >= 0 && scrollOffset + offset <= maxScrollOffset; } From 5bb20b911721443be661f3ed60c46ff61182f1b3 Mon Sep 17 00:00:00 2001 From: tanishisherewith <120117618+tanishisherewithhh@users.noreply.github.com> Date: Sun, 21 Jun 2026 22:55:33 +0530 Subject: [PATCH 10/22] SearchBox in ModernSkin redesigned to match the theme. Fixed animations not working in MathAnimations due to floating point precision --- .../animations/MathAnimations.java | 146 ++++++++++----- .../contextmenu/skinsystem/ModernSkin.java | 166 +++++++++++++++--- 2 files changed, 243 insertions(+), 69 deletions(-) diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/MathAnimations.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/MathAnimations.java index acdfccc..1500ad8 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/MathAnimations.java +++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/MathAnimations.java @@ -2,114 +2,168 @@ import com.tanishisherewith.dynamichud.helpers.animationhelper.Easing; import com.tanishisherewith.dynamichud.helpers.animationhelper.EasingType; +import net.minecraft.util.Mth; import net.minecraft.util.RandomSource; import net.minecraft.world.phys.Vec2; import java.util.Random; public class MathAnimations { - /// SHAKE: Random offset animation with smooth decay + private static final RandomSource RANDOM = RandomSource.create(); + + /** + * SHAKE: Random offset animation with smooth decay. + * @param intensity max displacement + * @param frequency in radians per second (e.g. 20 rad/s = ~3 oscillations/sec) + * @param decay decay rate per second (e.g. 2.0 means amplitude halves every 0.35s) + */ public static float shake(float intensity, float frequency, float decay) { - long time = System.currentTimeMillis(); - return (float) (Math.sin(time * frequency) * - Math.exp(-decay * time) * intensity); + double time = System.currentTimeMillis() / 1000.0; + return (float) (Math.sin(time * frequency) * Math.exp(-decay * time) * intensity); } - /// 2D Shake with different X/Y frequencies + /** + * 2D Shake with different X/Y frequencies. + */ public static Vec2 shake2D(float intensity, float freqX, float freqY) { + double time = System.currentTimeMillis() / 1000.0; return new Vec2( - (float) Math.sin(System.currentTimeMillis() * freqX) * intensity, - (float) Math.cos(System.currentTimeMillis() * freqY) * intensity + (float) Math.sin(time * freqX) * intensity, + (float) Math.cos(time * freqY) * intensity ); } - /// FLICKER: Random flashing effect + /** + * FLICKER: Random flashing effect. + * @param chance probability (0..1) to return a random value in [min, max]; otherwise returns max. + */ public static float flicker(float min, float max, float chance) { - RandomSource rand = RandomSource.create(); - return rand.nextFloat() < chance ? - min + (max - min) * rand.nextFloat() : + return RANDOM.nextFloat() < chance ? + min + (max - min) * RANDOM.nextFloat() : max; } - /// CIRCULAR MOTION: Perfect for rotation/orbital animations + /** + * CIRCULAR MOTION: Orbital animation. + * @param radius orbit radius + * @param speed radians per second + * @param phase initial angle offset in radians + */ public static Vec2 circularMotion(float radius, float speed, float phase) { - double angle = Math.toRadians((System.currentTimeMillis() * speed) % 360 + phase); + double time = System.currentTimeMillis() / 1000.0; + double angle = time * speed + phase; return new Vec2( (float) (Math.cos(angle) * radius), (float) (Math.sin(angle) * radius) ); } - /// SAWTOOTH WAVE: Linear rise with sudden drop + /** + * SAWTOOTH WAVE: Linear rise with sudden drop. + * @param period in seconds + */ public static float sawtooth(float period, float min, float max) { - float phase = (System.currentTimeMillis() % period) / period; - return min + (max - min) * phase; + double time = System.currentTimeMillis() / 1000.0; + double phase = (time % period) / period; + return (float) (min + (max - min) * phase); } - /// TRIANGULAR WAVE: Linear rise and fall + /** + * TRIANGULAR WAVE: Linear rise and fall. + */ public static float triangleWave(float period, float min, float max) { - float halfPeriod = period / 2; - float phase = (System.currentTimeMillis() % period); - float value = phase < halfPeriod ? + double time = System.currentTimeMillis() / 1000.0; + double halfPeriod = period / 2; + double phase = time % period; + double value = phase < halfPeriod ? (phase / halfPeriod) : 2 - (phase / halfPeriod); - return min + (max - min) * value; + return (float) (min + (max - min) * value); } - /// BOUNCE: Simulates physical bouncing + /** + * BOUNCE: Simulates physical bouncing. + * @param dropHeight initial height + * @param gravity acceleration (e.g. 9.8) + * @param dampening damping factor (e.g. 0.5) + */ public static float bounce(float dropHeight, float gravity, float dampening) { - float t = System.currentTimeMillis() / 1000f; + double t = System.currentTimeMillis() / 1000.0; return (float) (dropHeight * Math.abs(Math.sin(t * Math.sqrt(gravity))) * Math.exp(-dampening * t)); } - /// PULSE: Smooth heartbeat-like effect + /** + * PULSE (sine): Smooth heartbeat-like. + * @param frequency in radians per second + */ public static float pulse1(float base, float amplitude, float frequency) { - return (float) (base + amplitude * - (0.5 + 0.5 * Math.sin(System.currentTimeMillis() * frequency))); + double time = System.currentTimeMillis() / 1000.0; + return (float) (base + amplitude * (0.5 + 0.5 * Math.sin(time * frequency))); } - /// SPIRAL: Circular motion with expanding radius + /** + * SPIRAL: Circular motion with expanding radius. + */ public static Vec2 spiral(float baseRadius, float expansionRate, float speed) { - float t = System.currentTimeMillis() / 1000f; + double t = System.currentTimeMillis() / 1000.0; return new Vec2( (float) ((baseRadius + expansionRate * t) * Math.cos(t * speed)), (float) ((baseRadius + expansionRate * t) * Math.sin(t * speed)) ); } - /// Continuous pulsating effect using sine wave + /** + * PULSE (sine) with explicit min/max. + * @param speed radians per second + */ public static float pulse2(float speed, float min, float max) { - return (float) ((Math.sin(System.currentTimeMillis() * speed) + 1) / 2 * (max - min) + min); + double time = System.currentTimeMillis() / 1000.0; // seconds + double val = (float) Math.sin(time * speed); // -1 to 1 + return (float) (val + 1) / 2 * (max - min) + min; // remap to [min, max] } - /// Linear interpolation between values over time + /** + * Linear interpolation between values over time. + * @param startTime time when animation started (System.currentTimeMillis()) + * @param duration in milliseconds + */ public static float lerp(float start, float end, long startTime, float duration) { return lerp(start, end, startTime, duration, EasingType.LINEAR); } - /// Linear interpolation between values over time with easing public static float lerp(float start, float end, long startTime, float duration, EasingType easing) { - float progress = (System.currentTimeMillis() - startTime) / duration; - progress = Math.clamp(progress, 0, 1); - return start + (end - start) * Easing.apply(easing, progress); + double progress = (System.currentTimeMillis() - startTime) / duration; + progress = Mth.clamp(progress, 0f, 1f); + return start + (end - start) * Easing.apply(easing, (float) progress); } - /// Bouncing animation using quadratic ease-out - public static float bounce(float start, float end, long startTime, float duration) { - float time = System.currentTimeMillis() - startTime; - time /= duration; - return end * (1 - (time - 1) * (time - 1)) + start; + /** + * Bounce animation (quadratic ease-out) over time. + * @param startTime when animation started + * @param duration in milliseconds + */ + public static float bounceAnim(float start, float end, long startTime, float duration) { + double time = (System.currentTimeMillis() - startTime) / duration; + time = Mth.clamp(time, 0f, 1f); + return (float) (end * (1 - (time - 1) * (time - 1)) + start); } - /// Continuous rotation using modulo - public static float continuousRotation(float speed) { - return (System.currentTimeMillis() % (360_000 / speed)) * (speed / 1000); + /** + * Continuous rotation (returns degrees 0..360) based on speed in degrees per second. + */ + public static float continuousRotation(float speedDegPerSec) { + double time = System.currentTimeMillis() / 1000.0; + return (float) ((time * speedDegPerSec) % 360); } - /// Elastic wobble effect + /** + * Elastic wobble (damped sine). + * @param speed in radians per second + * @param magnitude initial amplitude + */ public static float elasticWobble(float speed, float magnitude) { - return (float) (Math.sin(System.currentTimeMillis() * speed) * - Math.exp(-0.001 * System.currentTimeMillis()) * magnitude); + double t = System.currentTimeMillis() / 1000.0; + return (float) (Math.sin(t * speed) * Math.exp(-t * 0.5) * magnitude); } } \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java index d1bcced..cb7694b 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java @@ -1,5 +1,6 @@ package com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem; +import com.mojang.blaze3d.platform.cursor.CursorTypes; import com.tanishisherewith.dynamichud.helpers.ColorHelper; import com.tanishisherewith.dynamichud.helpers.DrawHelper; import com.tanishisherewith.dynamichud.helpers.animationhelper.AnimationProperty; @@ -14,6 +15,7 @@ import com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.interfaces.GroupableSkin; import com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.interfaces.SkinRenderer; import com.tanishisherewith.dynamichud.utils.handlers.ScrollHandler; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.EditBox; import net.minecraft.client.input.CharacterEvent; @@ -21,14 +23,15 @@ import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.client.input.MouseButtonInfo; import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.network.chat.Style; import net.minecraft.sounds.SoundEvents; import net.minecraft.network.chat.Component; import net.minecraft.util.FormattedCharSequence; import net.minecraft.util.Mth; +import org.jspecify.annotations.NonNull; import org.lwjgl.glfw.GLFW; import java.awt.*; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -59,7 +62,7 @@ public class ModernSkin extends Skin implements GroupableSkin { private final Map groupAnimations = new HashMap<>(); - private EditBox searchBox; + private ModernSearchBox searchBox; private String searchQuery = ""; public ModernSkin(float radius, Component defaultToolTipHeader, Component defaultToolTipText) { @@ -127,24 +130,14 @@ private int calcOptionHeight(Option option) { private void renderSearchBox(GuiGraphics graphics, int mouseX, int mouseY){ if (searchBox == null) { - searchBox = new EditBox(mc.font, searchBoxX, searchBoxY, searchBoxWidth, searchBoxHeight, Component.empty()); - searchBox.setMaxLength(50); - searchBox.setEditable(true); - searchBox.active = true; - searchBox.setBordered(true); - searchBox.setVisible(true); - searchBox.setHint(Component.literal("Search...")); - searchBox.setCanLoseFocus(true); + searchBox = new ModernSearchBox(searchBoxX, searchBoxY, searchBoxWidth, searchBoxHeight); searchBox.setResponder(query -> { searchQuery = query; // Reset scroll so results show from top scrollHandler.setScrollOffset(0); }); } - searchBox.setX(searchBoxX); - searchBox.setY(searchBoxY); - searchBox.setWidth(searchBoxWidth); - searchBox.setHeight(searchBoxHeight); + searchBox.setTotalBounds(searchBoxX, searchBoxY, searchBoxWidth, searchBoxHeight); searchBox.render(graphics, mouseX, mouseY, mc.getDeltaTracker().getGameTimeDeltaTicks()); } @@ -305,7 +298,7 @@ private void updateContextDimensions() { width = (int) (scaledWidth * 0.8f); height = (int) (scaledHeight * 0.8f); searchBoxWidth = (int)(width * 0.35f); - searchBoxHeight = 14; + searchBoxHeight = mc.font.lineHeight + 5; searchBoxX = contextMenuX + searchBoxWidth; searchBoxY = contextMenuY + 2; } @@ -447,18 +440,13 @@ public boolean mouseReleased(ContextMenu menu, double mouseX, double mouseY, @Override public boolean mouseClicked(ContextMenu menu, double mouseX, double mouseY, int button) { + mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; + mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; if (searchBox != null) { MouseButtonEvent event = new MouseButtonEvent(mouseX, mouseY, new MouseButtonInfo(button, 0)); - if (searchBox.mouseClicked(event,false)) { - searchBox.setFocused(true); - return true; - } else{ - searchBox.setFocused(false); - } + searchBox.mouseClicked(event,false); } - mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; - mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && isMouseOver(mouseX, mouseY, contextMenuX + width - 5, contextMenuY + 19, 7, height)) { scrollHandler.startDragging(mouseY); @@ -1063,4 +1051,136 @@ private static class GroupAnimData { }; } } + public class ModernSearchBox extends EditBox { + private static final int CORNER_RADIUS = 6; + private static final int ICON_PADDING = 6; + private static final int CLEAR_BUTTON_SIZE = 16; + private static final int TEXT_PADDING = 4; + + private final SquishAnimator clearAnimator = new SquishAnimator(); + private int totalX, totalY, totalWidth, totalHeight; + + public ModernSearchBox(int x, int y, int width, int height) { + super(mc.font, x, y, width, height, Component.empty()); + this.setBordered(false); + this.setCentered(false); + this.setTextShadow(true); + this.setEditable(true); + this.setVisible(true); + this.setMaxLength(50); + this.active = true; + this.setCanLoseFocus(true); + this.setHint(Component.literal("Search...")); + setTotalBounds(x, y, width, height); + } + + public void setTotalBounds(int x, int y, int width, int height) { + this.totalX = x; + this.totalY = y; + this.totalWidth = width; + this.totalHeight = height; + + int iconWidth = mc.font.width("\uD83D\uDD0D"); + int textX = totalX + iconWidth + ICON_PADDING + TEXT_PADDING; + int textWidth = totalWidth - (textX - totalX) - (CLEAR_BUTTON_SIZE + ICON_PADDING + TEXT_PADDING); + if (textWidth < 10) textWidth = 10; + + this.setX(textX); + this.setY(totalY); + this.setWidth(textWidth); + this.setHeight(totalHeight); + } + + @Override + public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float delta) { + if (!this.visible) return; + + int x = totalX; + int y = totalY; + int w = totalWidth; + int h = totalHeight; + + // Background + Color bgColor = isFocused() ? new Color(25, 25, 25, 240) : DARKER_GRAY; + DrawHelper.drawRoundedRectangleWithShadowBadWay(graphics, x, y, w, h, CORNER_RADIUS, bgColor.getRGB(),60,1,2); + + if (isFocused()) { + float pulse = MathAnimations.pulse2(2.5f, 0.3f, 1.0f); // 2.5 oscillations/sec + int glowAlpha = (int) (pulse * 200 + 55); // alpha range 55–255 + int glowColor = ColorHelper.changeAlpha(getThemeColor(), glowAlpha).getRGB(); + DrawHelper.drawOutlineRoundedBox(graphics, x, y, w, h, CORNER_RADIUS, 1f, glowColor); + } else { + DrawHelper.drawOutlineRoundedBox(graphics, x, y, w, h, CORNER_RADIUS, 1f, DARK_GRAY.getRGB()); + } + + + String icon = "\uD83D\uDD0D"; + int iconX = x + ICON_PADDING; + int iconY = y + (h - mc.font.lineHeight) / 2 + 1; + int iconColor = isFocused()? Color.WHITE.getRGB() : 0x80FFFFFF; + graphics.drawString(mc.font, icon, iconX, iconY, iconColor, false); + + graphics.pose().pushMatrix(); + graphics.pose().translate(-1,3); + super.renderWidget(graphics, mouseX, mouseY, delta); + graphics.pose().popMatrix(); + + String clearText = "✕"; + int clearWidth = mc.font.width(clearText); + int clearX = x + w - CLEAR_BUTTON_SIZE; + int clearY = y + (h - mc.font.lineHeight) / 2; + boolean isClearHovered = Skin.isMouseOver(mouseX, mouseY, clearX - 2, clearY - 1, clearWidth + 4, mc.font.lineHeight + 2); + clearAnimator.update(isClearHovered && (mouseX != -1 && mouseY != -1)); + + if (!getValue().isEmpty()) { + float scale = clearAnimator.getScale(); + int clearBgColor = isClearHovered ? getThemeColor().darker().getRGB() : ColorHelper.changeAlpha(Color.WHITE, 30).getRGB(); + int bgW = clearWidth + 4; + int bgH = mc.font.lineHeight; + DrawHelper.scaleAndPosition(graphics.pose(), clearX - 0.25f, clearY + 0.5f, bgW, bgH, scale); + DrawHelper.drawRoundedRectangle(graphics, clearX - 0.25f, clearY + 0.5f, bgW, bgH, 4, clearBgColor); + graphics.drawString(mc.font, clearText, clearX + 2, clearY + 1, + isClearHovered ? 0xFFFFFFFF : 0xB0FFFFFF, false); + DrawHelper.stopScaling(graphics.pose()); + } + if (isHovered()) { + graphics.requestCursor(CursorTypes.IBEAM); + } + } + @Override + public boolean mouseClicked(@NonNull MouseButtonEvent event, boolean bl) { + if (!this.isActive()) { + return false; + } + if (!getValue().isEmpty()) { + int clearX = totalX + totalWidth - CLEAR_BUTTON_SIZE - 2; + int clearY = totalY + (totalHeight - mc.font.lineHeight) / 2 - 1; + int clearW = mc.font.width("✕") + 4; + int clearH = mc.font.lineHeight + 2; + if (Skin.isMouseOver(event.x(), event.y(), clearX, clearY, clearW, clearH)) { + setValue(""); + return true; + } + } + + if (this.isValidClickButton(event.buttonInfo()) && Skin.isMouseOver(event.x(), event.y(), totalX, totalY, totalWidth, totalHeight)) { + this.playDownSound(Minecraft.getInstance().getSoundManager()); + this.onClick(event, bl); + setFocused(true); + return true; + } else { + setFocused(false); + } + + return false; + } + + public int getTotalWidth() { + return totalWidth; + } + + private Color getThemeColor() { + return ModernSkin.this.getThemeColor(); + } + } } \ No newline at end of file From c8f8edf86382a732015a10cdd8e3bde683a865e1 Mon Sep 17 00:00:00 2001 From: tanishisherewith <120117618+tanishisherewithhh@users.noreply.github.com> Date: Mon, 22 Jun 2026 10:06:18 +0530 Subject: [PATCH 11/22] Fix jitter when scrolling Fix buggy context menu not closing properly Add cmAnimationTime in GlobalConfig --- .../dynamichud/config/GlobalConfig.java | 13 +++ .../animations/SquishAnimator.java | 4 +- .../animations/ValueAnimation.java | 7 ++ .../utils/contextmenu/ContextMenu.java | 35 ++++--- .../contextmenu/screen/ContextMenuScreen.java | 11 +-- .../contextmenu/skinsystem/ModernSkin.java | 8 +- .../utils/handlers/ScrollHandler.java | 92 +++++++++++-------- 7 files changed, 104 insertions(+), 66 deletions(-) diff --git a/src/main/java/com/tanishisherewith/dynamichud/config/GlobalConfig.java b/src/main/java/com/tanishisherewith/dynamichud/config/GlobalConfig.java index b1dcd44..f3676b5 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/config/GlobalConfig.java +++ b/src/main/java/com/tanishisherewith/dynamichud/config/GlobalConfig.java @@ -29,6 +29,9 @@ public final class GlobalConfig { @SerialEntry private float scale = 1.0f; + @SerialEntry + private int cmAnimationTimeInMs = 200; + @SerialEntry private boolean displayDescriptions = false; @@ -97,6 +100,12 @@ public Screen createYACLGUI() { .binding(100, () -> this.snapSize, newVal -> this.snapSize = newVal) .controller(integerOption -> IntegerFieldControllerBuilder.create(integerOption).range(10, 500)) .build()) + .option(Option.createBuilder() + .name(Component.literal("ContextMenu Animation Time")) + .description(OptionDescription.of(Component.literal("The time in seconds for context menu to open"))) + .binding(200, () -> this.cmAnimationTimeInMs, newVal -> this.cmAnimationTimeInMs = newVal) + .controller(integerOption -> IntegerSliderControllerBuilder.create(integerOption).range(0, 500)) + .build()) .build()) .option(Option.createBuilder() .name(Component.literal("Widget HUD Active Background Color")) @@ -153,6 +162,10 @@ public Color getHudActiveColor() { return hudActiveColor; } + public int getCmAnimationTimeInMs() { + return cmAnimationTimeInMs; + } + public com.tanishisherewith.dynamichud.utils.contextmenu.options.Option.Complexity complexity() { return complexity; } diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/SquishAnimator.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/SquishAnimator.java index 9f9e403..f4ec5ce 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/SquishAnimator.java +++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/SquishAnimator.java @@ -30,9 +30,7 @@ public SquishAnimator(){ public void update(boolean pressed) { if (this.isPressed != pressed) { this.isPressed = pressed; - animation.startValue(property.get()); - animation.endValue(pressed ? pressedScale : normalScale); - animation.start(); + animation.set(property.get(),pressed ? pressedScale : normalScale).start(); } animation.update(); } diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/ValueAnimation.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/ValueAnimation.java index c984e44..1401472 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/ValueAnimation.java +++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/ValueAnimation.java @@ -30,6 +30,12 @@ protected void applyAnimation(float progress) { property.set(value); } + public ValueAnimation set(float startValue, float endValue){ + this.startValue = startValue; + this.endValue = endValue; + return this; + } + public ValueAnimation easing(EasingType easing) { this.easing = easing; return this; @@ -47,6 +53,7 @@ public ValueAnimation endValue(float endValue) { public void setValue(float value) { this.value = value; + property.set(value); } public float getValue() { diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java index c84837e..4c3f553 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java @@ -1,6 +1,7 @@ package com.tanishisherewith.dynamichud.utils.contextmenu; import com.tanishisherewith.dynamichud.DynamicHUD; +import com.tanishisherewith.dynamichud.config.GlobalConfig; import com.tanishisherewith.dynamichud.helpers.DrawHelper; import com.tanishisherewith.dynamichud.helpers.animationhelper.AnimationProperty; import com.tanishisherewith.dynamichud.helpers.animationhelper.EasingType; @@ -81,10 +82,11 @@ public void set(Float value) { } }, 0.0f, 1.0f); this.scaleAnimation.easing(EasingType.EASE_IN_CUBIC); - this.scaleAnimation.duration(280); + this.scaleAnimation.duration(GlobalConfig.get().getCmAnimationTimeInMs()); this.scaleAnimation.onComplete(() -> { if (animScale <= 0.0f && parentScreen != null && properties.getSkin().shouldCreateNewScreen()) { DynamicHUD.MC.setScreen(parentScreen); + parentScreen = null; } }); @@ -109,6 +111,7 @@ public void setMenuScale(float menuScale) { public void render(GuiGraphics graphics, int xPos, int yPos, int mouseX, int mouseY) { if (newScreenFlag && screenFactory != null) { DynamicHUD.MC.setScreen(screenFactory.create(this, properties)); + newScreenFlag = false; return; } @@ -147,13 +150,12 @@ public void close() { option.onClose(); } if (properties.enableAnimations()) { - scaleAnimation.startValue(animScale); - scaleAnimation.endValue(0.0f); - scaleAnimation.start(); + scaleAnimation.set(animScale,0.0f).start(); } else { - animScale = 0.0f; + scaleAnimation.setValue(0.0f); if (properties.getSkin().shouldCreateNewScreen() && parentScreen != null) { DynamicHUD.MC.setScreen(parentScreen); + parentScreen = null; } } } @@ -161,19 +163,24 @@ public void close() { public void open() { shouldDisplay = true; update(); - parentScreen = DynamicHUD.MC.screen; + if(parentScreen == null) { + Screen currentScreen = DynamicHUD.MC.screen; + if (currentScreen != null && !currentScreen.getClass().getSimpleName().contains("ContextMenuScreen")) { + parentScreen = currentScreen; + } + java.lang.System.out.println(parentScreen); + } if (properties.getSkin().shouldCreateNewScreen()) { newScreenFlag = true; } if (properties.enableAnimations()) { - scaleAnimation.startValue(animScale); - scaleAnimation.endValue(1.0f); - scaleAnimation.start(); + scaleAnimation.set(animScale, 1.0f).start(); } else { - animScale = 0.0f; - if (properties.getSkin().shouldCreateNewScreen() && parentScreen != null) { + scaleAnimation.setValue(1.0f); + /*if (properties.getSkin().shouldCreateNewScreen() && parentScreen != null) { DynamicHUD.MC.setScreen(parentScreen); - } + parentScreen = null; + }*/ } } @@ -186,11 +193,11 @@ public void toggleDisplay() { } protected int getTMouseX(double mouseX) { - return (int) ((mouseX - getX()) / getMenuScale() + getX()); + return (int) (mouseX / getMenuScale()); } protected int getTMouseY(double mouseY) { - return (int) ((mouseY - getY()) / getMenuScale() + getY()); + return (int) (mouseY / getMenuScale()); } public void toggleDisplay(WidgetBox widgetBox, double mouseX, double mouseY, int button) { diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/ContextMenuScreen.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/ContextMenuScreen.java index 42e940d..80be8aa 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/ContextMenuScreen.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/screen/ContextMenuScreen.java @@ -38,7 +38,7 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) { DrawHelper.stopScaling(graphics.pose()); if (contextMenu.getMenuScale() <= 0 && !contextMenu.isVisible()) { - contextMenu.close(); + this.onClose(); } } @@ -49,14 +49,12 @@ public void renderBackground(@NonNull GuiGraphics guiGraphics, int i, int j, flo @Override public boolean mouseClicked(MouseButtonEvent event, boolean bl) { - contextMenu.mouseClicked(event.x(), event.y(), event.button()); - return super.mouseClicked(event, bl); + return contextMenu.mouseClicked(event.x(), event.y(), event.button()) || super.mouseClicked(event, bl); } @Override public boolean mouseDragged(MouseButtonEvent event, double dx, double dy) { - contextMenu.mouseDragged(event.x(), event.y(), event.button(), dx, dy); - return super.mouseDragged(event, dx, dy); + return contextMenu.mouseDragged(event.x(), event.y(), event.button(), dx, dy) || super.mouseDragged(event, dx, dy); } @Override @@ -67,8 +65,7 @@ public boolean mouseScrolled(double x, double y, double horizontalAmount, double @Override public boolean mouseReleased(MouseButtonEvent event) { - contextMenu.mouseReleased(event.x(), event.y(), event.button()); - return super.mouseReleased(event); + return contextMenu.mouseReleased(event.x(), event.y(), event.button()) || super.mouseReleased(event); } @Override diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java index cb7694b..e9f9d0b 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java @@ -40,7 +40,7 @@ import static com.tanishisherewith.dynamichud.helpers.ColorHelper.DARK_RED; public class ModernSkin extends Skin implements GroupableSkin { - static Color DARK_GRAY = new Color(20, 20, 20, 229); + static Color DARK_GRAY = new Color(20, 20, 20, 200); static Color DARKER_GRAY = new Color(10, 10, 10, 243); static Color DARKER_GRAY_2 = new Color(12, 12, 12, 246); @@ -442,6 +442,7 @@ public boolean mouseReleased(ContextMenu menu, double mouseX, double mouseY, public boolean mouseClicked(ContextMenu menu, double mouseX, double mouseY, int button) { mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; + if (searchBox != null) { MouseButtonEvent event = new MouseButtonEvent(mouseX, mouseY, new MouseButtonInfo(button, 0)); searchBox.mouseClicked(event,false); @@ -491,7 +492,7 @@ public boolean mouseClicked(ContextMenu menu, double mouseX, double mouseY, i } } } - if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && isMouseOver(mouseX, mouseY, contextMenuX + 2, contextMenuY + 2, mc.font.width("< Back") + 8, 14)) { + if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && isMouseOver(mouseX, mouseY, contextMenuX + 1, contextMenuY + 1, mc.font.width("< Back") + 10, 16)) { mc.getSoundManager().play(SimpleSoundInstance.forUI( SoundEvents.UI_BUTTON_CLICK, 1.0F)); contextMenu.close(); @@ -501,6 +502,7 @@ public boolean mouseClicked(ContextMenu menu, double mouseX, double mouseY, i } searchQuery = ""; groupAnimations.clear(); + return true; } return super.mouseClicked(menu, mouseX, mouseY, button); } @@ -1134,7 +1136,7 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float del if (!getValue().isEmpty()) { float scale = clearAnimator.getScale(); - int clearBgColor = isClearHovered ? getThemeColor().darker().getRGB() : ColorHelper.changeAlpha(Color.WHITE, 30).getRGB(); + int clearBgColor = isClearHovered ? Color.RED.darker().getRGB() : ColorHelper.changeAlpha(Color.WHITE, 30).getRGB(); int bgW = clearWidth + 4; int bgH = mc.font.lineHeight; DrawHelper.scaleAndPosition(graphics.pose(), clearX - 0.25f, clearY + 0.5f, bgW, bgH, scale); diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/handlers/ScrollHandler.java b/src/main/java/com/tanishisherewith/dynamichud/utils/handlers/ScrollHandler.java index 06051d1..b40997c 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/handlers/ScrollHandler.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/handlers/ScrollHandler.java @@ -1,81 +1,95 @@ package com.tanishisherewith.dynamichud.utils.handlers; +import net.minecraft.util.Mth; public class ScrollHandler { - protected int scrollOffset; - protected double scrollVelocity; - protected long lastScrollTime; + protected double scrollOffset; + protected double targetScrollOffset; protected boolean isDragging; protected int maxScrollOffset; - protected double SCROLL_SPEED = 1; + protected double SCROLL_SPEED = 1.0; + protected int trackHeight = 150; protected double lastMouseY; public ScrollHandler() { - this.scrollOffset = 0; - this.scrollVelocity = 0; - this.lastScrollTime = 0; this.isDragging = false; } - public void updateScrollOffset(int maxYOffset) { - if (maxYOffset < 0) maxYOffset = 0; + public void setScrollOffset(int offset) { + this.displayValuePosition(offset); + } + + public void setScrollOffsetDirectly(double offset) { + this.displayValue = offset; + } - this.maxScrollOffset = maxYOffset; - applyMomentum(); - scrollOffset = Math.clamp(scrollOffset, 0, maxScrollOffset); + public int getScrollOffset() { + return Math.toIntExact(Math.round(scrollOffset)); + } + + private double displayValue; + private static final float LERP_SPEED = 0.22f; + + public void updateScrollOffset(int maxScrollOffset) { + if(maxScrollOffset <= 0) return; + this.maxScrollOffset = maxScrollOffset; + displayValue = Mth.lerp(LERP_SPEED, displayValue, targetScrollOffset); + displayValue = Mth.clamp(displayValue, 0.0, maxScrollOffset); + this.scrollOffset = Math.round(displayValue); } public void mouseScrolled(double deltaY) { - scrollVelocity -= deltaY * 10; - lastScrollTime = System.currentTimeMillis(); + double amount = -deltaY * 18.0 * SCROLL_SPEED; + this.targetScrollOffset = Mth.clamp(targetScrollOffset + amount, 0.0, maxScrollOffset); } public void startDragging(double mouseY) { - isDragging = true; - lastMouseY = mouseY; + this.isDragging = true; + this.lastMouseY = mouseY; } public void stopDragging() { - isDragging = false; + this.isDragging = false; } public void addOffset(int offset) { - this.scrollOffset = Math.clamp(scrollOffset + offset, 0, maxScrollOffset); + this.targetScrollOffset = Mth.clamp(targetScrollOffset + offset, 0.0, maxScrollOffset); } public void updateScrollPosition(double mouseY) { - if (isDragging) { - // Calculate the difference in mouse Y position - double deltaY = lastMouseY - mouseY; - - scrollOffset = Math.clamp(scrollOffset - (int) deltaY, 0, maxScrollOffset); - + if (isDragging && maxScrollOffset > 0) { + double deltaY = mouseY - lastMouseY; + double scrollRatio = (double) maxScrollOffset / Math.max(1, trackHeight); + double offsetDelta = deltaY * scrollRatio; + this.targetScrollOffset = Mth.clamp(targetScrollOffset + offsetDelta, 0.0, maxScrollOffset); lastMouseY = mouseY; } } - private void applyMomentum() { - long currentTime = System.currentTimeMillis(); - double timeDelta = (currentTime - lastScrollTime) / 1000.0; - scrollOffset += (int) (scrollVelocity * timeDelta); - scrollVelocity *= 0.9; // Decay factor - scrollOffset = Math.clamp(scrollOffset, 0, maxScrollOffset); - } - - public int getScrollOffset() { - return Math.max(scrollOffset, 0); - } - - public void setScrollOffset(int scrollOffset) { - this.scrollOffset = Math.clamp(scrollOffset, 0, maxScrollOffset); + private void displayValuePosition(double val) { + this.targetScrollOffset = Mth.clamp(val, 0.0, maxScrollOffset); + this.displayValue = this.targetScrollOffset; + this.scrollOffset = this.targetScrollOffset; } public boolean isOffsetWithinBounds(int offset) { - return scrollOffset + offset >= 0 && scrollOffset + offset <= maxScrollOffset; + return targetScrollOffset + offset >= 0 && targetScrollOffset + offset <= maxScrollOffset; } public ScrollHandler setScrollSpeed(double scrollSpeed) { this.SCROLL_SPEED = scrollSpeed; return this; } + + public void setTrackHeight(int trackHeight) { + this.trackHeight = trackHeight; + } + + public int getTrackHeight() { + return trackHeight; + } + + public boolean isDragging() { + return isDragging; + } } \ No newline at end of file From 84bbd48eb256ae9127eccb82df679ac5998af1e9 Mon Sep 17 00:00:00 2001 From: tanishisherewith <120117618+tanishisherewithhh@users.noreply.github.com> Date: Mon, 22 Jun 2026 10:09:27 +0530 Subject: [PATCH 12/22] remove debug msg --- .../dynamichud/utils/contextmenu/ContextMenu.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java index 4c3f553..a7f74e3 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java @@ -164,11 +164,7 @@ public void open() { shouldDisplay = true; update(); if(parentScreen == null) { - Screen currentScreen = DynamicHUD.MC.screen; - if (currentScreen != null && !currentScreen.getClass().getSimpleName().contains("ContextMenuScreen")) { - parentScreen = currentScreen; - } - java.lang.System.out.println(parentScreen); + parentScreen = DynamicHUD.MC.screen; } if (properties.getSkin().shouldCreateNewScreen()) { newScreenFlag = true; From 135dfa0f2c969b4ba3b86eed1a110c46b673852b Mon Sep 17 00:00:00 2001 From: tanishisherewith <120117618+tanishisherewithhh@users.noreply.github.com> Date: Mon, 22 Jun 2026 22:48:12 +0530 Subject: [PATCH 13/22] Add search to MinecraftSkin --- .../dynamichud/helpers/DrawHelper.java | 4 - .../dynamichud/utils/Util.java | 1 + .../contextmenu/skinsystem/MinecraftSkin.java | 87 ++++++++++++++++++- .../contextmenu/skinsystem/ModernSkin.java | 50 ++++------- 4 files changed, 103 insertions(+), 39 deletions(-) diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java index 139d632..fe13c06 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java +++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/DrawHelper.java @@ -197,11 +197,7 @@ public static void drawChromaText(@NotNull GuiGraphics graphics, String Componen for (int i = 0; i < length; i++) { float hue = (time % (int) (5000 / speed)) / (5000f / speed) + (i * spread); // Adjust the hue based on time and character position hue = floorMod(hue, 1.0f); // hue should stay within the range [0, 1] - - // Convert the hue to an RGB color int color = Color.HSBtoRGB(hue, saturation, brightness); - - // Draw the character with the calculated color graphics.drawString(mc.font, String.valueOf(Component.charAt(i)), x + mc.font.width(Component.substring(0, i)), y, color, shadow); } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/Util.java b/src/main/java/com/tanishisherewith/dynamichud/utils/Util.java index 323b578..9a10941 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/Util.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/Util.java @@ -44,6 +44,7 @@ public static boolean warnIfTrue(boolean expression, String message, Object... o /** * Returns a list of options sorted by higher fuzzy score from the query string. + * If minimumScore is -1, then two typos from query string will be tolerated. */ public static List> getSearchResults(String query, int minimumScore, List> options) { if(options.isEmpty()) return new ArrayList<>(); diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java index 0275199..af8451e 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java @@ -5,6 +5,7 @@ import com.tanishisherewith.dynamichud.helpers.animationhelper.AnimationProperty; import com.tanishisherewith.dynamichud.helpers.animationhelper.EasingType; import com.tanishisherewith.dynamichud.helpers.animationhelper.animations.ValueAnimation; +import com.tanishisherewith.dynamichud.utils.Util; import com.tanishisherewith.dynamichud.utils.contextmenu.ContextMenu; import com.tanishisherewith.dynamichud.utils.contextmenu.layout.LayoutEngine; import com.tanishisherewith.dynamichud.utils.contextmenu.options.*; @@ -12,7 +13,12 @@ import com.tanishisherewith.dynamichud.utils.contextmenu.skinsystem.interfaces.SkinRenderer; import com.tanishisherewith.dynamichud.utils.handlers.ScrollHandler; import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.EditBox; import net.minecraft.client.gui.components.WidgetSprites; +import net.minecraft.client.input.CharacterEvent; +import net.minecraft.client.input.KeyEvent; +import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.client.input.MouseButtonInfo; import net.minecraft.client.renderer.RenderPipelines; import net.minecraft.client.resources.sounds.SimpleSoundInstance; import net.minecraft.resources.Identifier; @@ -63,6 +69,13 @@ public class MinecraftSkin extends Skin implements GroupableSkin { private final ScrollHandler groupScrollHandler; private final IntSupplier groupPanelX = () -> imageX - groupPanelWidth - 15; + private final EditBox searchBox; + private String searchQuery = ""; + private int searchBoxWidth = 0; + private int searchBoxHeight = 14; + private int searchBoxX = 0; + private int searchBoxY = 0; + public MinecraftSkin(PanelColor color) { super(); this.panelColor = color; @@ -81,6 +94,21 @@ public MinecraftSkin(PanelColor color) { this.groupScrollHandler = new ScrollHandler(); setCreateNewScreen(true); + + searchBox = new EditBox(mc.font, searchBoxX, searchBoxY, searchBoxWidth, searchBoxHeight, Component.empty()); + searchBox.setResponder(query -> { + searchQuery = query; + scrollHandler.setScrollOffset(0); + }); + searchBox.setHint(Component.literal("Search...")); + } + + @Override + public List> getOptions(ContextMenu menu) { + if(searchQuery != null && !searchQuery.isEmpty()) { + return Util.getSearchResults(searchQuery,-1, contextMenu.getOptions()); + } + return super.getOptions(menu); } private void enableContextMenuScissor(GuiGraphics graphics) { @@ -153,6 +181,13 @@ public void renderContextMenu(GuiGraphics graphics, ContextMenu contextMenu, // graphics.blitSprite(RenderPipelines.GUI_TEXTURED, TEXTURES.get(true, isMouseOver(mouseX, mouseY, imageX + 3, imageY + 3, 14, 14)), imageX + 3, imageY + 3, 14, 14); // graphics.drawString(mc.font, "X", imageX + 10 - mc.font.width("X") / 2, imageY + 6, -1, true); + searchBoxWidth = panelWidth/2; + searchBoxHeight = mc.font.lineHeight + 5; + searchBoxX = imageX + (panelWidth - searchBoxWidth) / 2; + searchBoxY = imageY - 18; + + renderSearchBox(graphics, mouseX, mouseY); + this.enableContextMenuScissor(graphics); contextMenu.setWidth(panelWidth - 4); @@ -171,6 +206,23 @@ public void renderContextMenu(GuiGraphics graphics, ContextMenu contextMenu, DrawHelper.disableScissor(graphics); } + private void renderSearchBox(GuiGraphics graphics, int mouseX, int mouseY) { + searchBox.setX(searchBoxX); + searchBox.setY(searchBoxY); + searchBox.setWidth(searchBoxWidth); + searchBox.setHeight(searchBoxHeight); + + searchBox.render(graphics, mouseX, mouseY, mc.getDeltaTracker().getGameTimeDeltaTicks()); + + String icon = "\uD83D\uDD0D"; + int iconX = searchBoxX - 2 - mc.font.width(icon); + int iconY = searchBoxY + (searchBoxHeight - mc.font.lineHeight) / 2 + 1; + int iconColor = searchBox.isFocused()? Color.WHITE.getRGB() : 0x80FFFFFF; + //DrawHelper.drawRectangle(graphics,iconX - 2, iconY - 1, mc.font.width(icon) + 3, mc.font.lineHeight + 2,Color.BLACK.getRGB()); + //DrawHelper.drawOutlineBox(graphics,iconX - 2, iconY - 1, mc.font.width(icon) + 3,mc.font.lineHeight + 2,1f,Color.GRAY.getRGB()); + graphics.drawString(mc.font, icon, iconX, iconY, iconColor, false); + } + public void drawSingularButton(GuiGraphics graphics, String Component, int mouseX, int mouseY, int x, int y, int width, int height, boolean enabled) { graphics.blitSprite(RenderPipelines.GUI_TEXTURED, TEXTURES.get(enabled, isMouseOver(mouseX, mouseY, x, y, width, height)), x, y, width, height); graphics.drawString(mc.font, Component, x + width / 2 - mc.font.width(Component) / 2, y + mc.font.lineHeight / 2 - 1, Color.WHITE.getRGB(), true); @@ -208,7 +260,14 @@ private int renderSelectedGroupOptions(GuiGraphics graphics, int mouseX, int mou int yOffset = imageY + 12 - scrollHandler.getScrollOffset(); int targetWidth = panelWidth - 25; - for (Option option : selectedGroup.getGroupOptions()) { + List> optionsToRender; + if (searchQuery != null && !searchQuery.isEmpty()) { + optionsToRender = getOptions(contextMenu); + } else { + optionsToRender = selectedGroup.getGroupOptions(); + } + + for (Option option : optionsToRender) { if (!option.shouldRender()) continue; option.setHeight(getOptionHeight(option)); @@ -254,6 +313,15 @@ public void mouseScrolled(ContextMenu menu, double mouseX, double mouseY, dou @Override public boolean mouseClicked(ContextMenu menu, double mouseX, double mouseY, int button) { + MouseButtonEvent event = new MouseButtonEvent(mouseX, mouseY, new MouseButtonInfo(button, 0)); + if (searchBox.mouseClicked(event, false)) { + searchBox.setFocused(true); + return true; + } else{ + searchBox.setFocused(false); + } + + if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { if (isMouseOver(mouseX, mouseY, imageX + 3, imageY + 3, 14, 14)) { mc.getSoundManager().play(SimpleSoundInstance.forUI( @@ -307,11 +375,16 @@ public boolean mouseReleased(ContextMenu menu, double mouseX, double mouseY, scrollHandler.stopDragging(); groupScrollHandler.stopDragging(); } + MouseButtonEvent event = new MouseButtonEvent(mouseX, mouseY, new MouseButtonInfo(button, 0)); + searchBox.mouseReleased(event); return super.mouseReleased(menu, mouseX, mouseY, button); } @Override public boolean mouseDragged(ContextMenu menu, double mouseX, double mouseY, int button, double deltaX, double deltaY) { + MouseButtonEvent event = new MouseButtonEvent(mouseX, mouseY, new MouseButtonInfo(button, 0)); + searchBox.mouseDragged(event, deltaX, deltaY); + if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { if (isMouseOver(mouseX, mouseY, imageX + panelWidth + 5, imageY - 5, DEFAULT_SCROLLBAR_WIDTH + 5, panelHeight + 10)) { scrollHandler.updateScrollPosition(mouseY); @@ -321,6 +394,18 @@ public boolean mouseDragged(ContextMenu menu, double mouseX, double mouseY, i return super.mouseDragged(menu, mouseX, mouseY, button, deltaX, deltaY); } + @Override + public void keyPressed(ContextMenu menu, int key, int scanCode, int modifiers) { + searchBox.keyPressed(new KeyEvent(key, scanCode, modifiers)); + super.keyPressed(menu, key, scanCode, modifiers); + } + + @Override + public void charTyped(ContextMenu menu, char c, int modifiers) { + searchBox.charTyped(new CharacterEvent(c, modifiers)); + super.charTyped(menu, c, modifiers); + } + @Override public LayoutEngine.Offset getGroupIndent() { return LayoutEngine.Offset.zero(); diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java index e9f9d0b..280e183 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java @@ -23,7 +23,6 @@ import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.client.input.MouseButtonInfo; import net.minecraft.client.resources.sounds.SimpleSoundInstance; -import net.minecraft.network.chat.Style; import net.minecraft.sounds.SoundEvents; import net.minecraft.network.chat.Component; import net.minecraft.util.FormattedCharSequence; @@ -40,7 +39,7 @@ import static com.tanishisherewith.dynamichud.helpers.ColorHelper.DARK_RED; public class ModernSkin extends Skin implements GroupableSkin { - static Color DARK_GRAY = new Color(20, 20, 20, 200); + static Color DARK_GRAY = new Color(20, 20, 20, 180); static Color DARKER_GRAY = new Color(10, 10, 10, 243); static Color DARKER_GRAY_2 = new Color(12, 12, 12, 246); @@ -62,7 +61,7 @@ public class ModernSkin extends Skin implements GroupableSkin { private final Map groupAnimations = new HashMap<>(); - private ModernSearchBox searchBox; + private final ModernSearchBox searchBox; private String searchQuery = ""; public ModernSkin(float radius, Component defaultToolTipHeader, Component defaultToolTipText) { @@ -82,6 +81,13 @@ public ModernSkin(float radius, Component defaultToolTipHeader, Component defaul this.scrollHandler = new ScrollHandler(); setCreateNewScreen(true); + + searchBox = new ModernSearchBox(searchBoxX, searchBoxY, searchBoxWidth, searchBoxHeight); + searchBox.setResponder(query -> { + searchQuery = query; + // Reset scroll so results show from top + scrollHandler.setScrollOffset(0); + }); } @Override @@ -129,16 +135,7 @@ private int calcOptionHeight(Option option) { } private void renderSearchBox(GuiGraphics graphics, int mouseX, int mouseY){ - if (searchBox == null) { - searchBox = new ModernSearchBox(searchBoxX, searchBoxY, searchBoxWidth, searchBoxHeight); - searchBox.setResponder(query -> { - searchQuery = query; - // Reset scroll so results show from top - scrollHandler.setScrollOffset(0); - }); - } searchBox.setTotalBounds(searchBoxX, searchBoxY, searchBoxWidth, searchBoxHeight); - searchBox.render(graphics, mouseX, mouseY, mc.getDeltaTracker().getGameTimeDeltaTicks()); } @@ -403,26 +400,16 @@ public void mouseScrolled(ContextMenu menu, double mouseX, double mouseY, dou @Override public void keyPressed(ContextMenu menu, int key, int scanCode, int modifiers) { - if (searchBox != null && searchBox.isFocused()) { - searchBox.keyPressed(new KeyEvent(key,scanCode,modifiers)); + if(searchBox.keyPressed(new KeyEvent(key,scanCode,modifiers))){ return; } - super.keyPressed(menu, key, scanCode, modifiers); - } - @Override - public void keyReleased(ContextMenu menu, int key, int scanCode, int modifiers) { - if (searchBox != null && searchBox.isFocused()) { - searchBox.keyReleased(new KeyEvent(key,scanCode,modifiers)); - return; - } - super.keyReleased(menu, key, scanCode, modifiers); + super.keyPressed(menu, key, scanCode, modifiers); } @Override public void charTyped(ContextMenu menu, char c, int modifiers) { - if (searchBox != null && searchBox.isFocused()) { - searchBox.charTyped(new CharacterEvent((int) c,modifiers)); + if (searchBox.charTyped(new CharacterEvent((int) c,modifiers))) { return; } super.charTyped(menu, c, modifiers); @@ -431,10 +418,8 @@ public void charTyped(ContextMenu menu, char c, int modifiers) { @Override public boolean mouseReleased(ContextMenu menu, double mouseX, double mouseY, int button) { scrollHandler.stopDragging(); - if (searchBox != null) { - MouseButtonEvent event = new MouseButtonEvent(mouseX, mouseY, new MouseButtonInfo(button, 0)); - searchBox.mouseReleased(event); - } + MouseButtonEvent event = new MouseButtonEvent(mouseX, mouseY, new MouseButtonInfo(button, 0)); + searchBox.mouseReleased(event); return super.mouseReleased(menu, mouseX, mouseY, button); } @@ -443,11 +428,8 @@ public boolean mouseClicked(ContextMenu menu, double mouseX, double mouseY, i mouseX = mc.mouseHandler.xpos() / SCALE_FACTOR; mouseY = mc.mouseHandler.ypos() / SCALE_FACTOR; - if (searchBox != null) { - MouseButtonEvent event = new MouseButtonEvent(mouseX, mouseY, new MouseButtonInfo(button, 0)); - searchBox.mouseClicked(event,false); - } - + MouseButtonEvent event = new MouseButtonEvent(mouseX, mouseY, new MouseButtonInfo(button, 0)); + searchBox.mouseClicked(event,false); if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && isMouseOver(mouseX, mouseY, contextMenuX + width - 5, contextMenuY + 19, 7, height)) { scrollHandler.startDragging(mouseY); From 4dbf6972bbccabb32b1c7cea1a67c331f4d505f2 Mon Sep 17 00:00:00 2001 From: tanishisherewith <120117618+tanishisherewithhh@users.noreply.github.com> Date: Tue, 23 Jun 2026 01:27:43 +0530 Subject: [PATCH 14/22] Fixed an issue when trying to open contextmenu when multiple widgets are layered. --- .../dynamichud/config/GlobalConfig.java | 2 +- .../utils/contextmenu/ContextMenu.java | 18 +++++----- .../dynamichud/widget/Widget.java | 33 +++++++++++++++---- .../dynamichud/widget/WidgetRenderer.java | 4 ++- .../dynamichud/widgets/GraphWidget.java | 3 +- .../dynamichud/widgets/TextWidget.java | 3 +- 6 files changed, 40 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/tanishisherewith/dynamichud/config/GlobalConfig.java b/src/main/java/com/tanishisherewith/dynamichud/config/GlobalConfig.java index f3676b5..6be96e4 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/config/GlobalConfig.java +++ b/src/main/java/com/tanishisherewith/dynamichud/config/GlobalConfig.java @@ -104,7 +104,7 @@ public Screen createYACLGUI() { .name(Component.literal("ContextMenu Animation Time")) .description(OptionDescription.of(Component.literal("The time in seconds for context menu to open"))) .binding(200, () -> this.cmAnimationTimeInMs, newVal -> this.cmAnimationTimeInMs = newVal) - .controller(integerOption -> IntegerSliderControllerBuilder.create(integerOption).range(0, 500)) + .controller(integerOption -> IntegerSliderControllerBuilder.create(integerOption).range(0, 500).step(1)) .build()) .build()) .option(Option.createBuilder() diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java index a7f74e3..b8957de 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java @@ -125,7 +125,7 @@ public void render(GuiGraphics graphics, int xPos, int yPos, int mouseX, int mou DrawHelper.scaleAndPosition(graphics.pose(), this.x, this.y,this.width,this.height, getMenuScale()); properties.getSkin().setContextMenu(this); - properties.getSkin().renderContextMenu(graphics, this, getTMouseX(mouseX), getTMouseY(mouseY)); + properties.getSkin().renderContextMenu(graphics, this, (int)getTMouseX(mouseX),(int) getTMouseY(mouseY)); DrawHelper.stopScaling(graphics.pose()); } @@ -173,10 +173,6 @@ public void open() { scaleAnimation.set(animScale, 1.0f).start(); } else { scaleAnimation.setValue(1.0f); - /*if (properties.getSkin().shouldCreateNewScreen() && parentScreen != null) { - DynamicHUD.MC.setScreen(parentScreen); - parentScreen = null; - }*/ } } @@ -188,18 +184,20 @@ public void toggleDisplay() { } } - protected int getTMouseX(double mouseX) { - return (int) (mouseX / getMenuScale()); + protected double getTMouseX(double mouseX) { + return mouseX / getMenuScale(); } - protected int getTMouseY(double mouseY) { - return (int) (mouseY / getMenuScale()); + protected double getTMouseY(double mouseY) { + return mouseY / getMenuScale(); } - public void toggleDisplay(WidgetBox widgetBox, double mouseX, double mouseY, int button) { + public boolean toggleDisplay(WidgetBox widgetBox, double mouseX, double mouseY, int button) { if (button == GLFW.GLFW_MOUSE_BUTTON_RIGHT && widgetBox.isMouseOver(mouseX, mouseY)) { toggleDisplay(); + return true; } + return false; } public void resetAllOptions() { diff --git a/src/main/java/com/tanishisherewith/dynamichud/widget/Widget.java b/src/main/java/com/tanishisherewith/dynamichud/widget/Widget.java index ef2955c..b5a66ed 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widget/Widget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widget/Widget.java @@ -13,6 +13,8 @@ import net.minecraft.util.Mth; import org.lwjgl.glfw.GLFW; +import java.awt.*; + /** * This is the base Widget class that handles the rendering, scaling, dragging, anchoring and positioning of the Widget. *

@@ -35,6 +37,8 @@ public abstract class Widget implements Input { protected boolean isDraggable = true; //Boolean to check if the widget is being dragged public boolean dragging; + private boolean wasDragged = false; + //To enable/disable snapping public boolean isShiftDown = false; /** @@ -187,7 +191,7 @@ public final void render(GuiGraphics graphics, int mouseX, int mouseY) { public final void renderInEditor(GuiGraphics graphics, int mouseX, int mouseY) { if (!isInEditor) return; - drawWidgetBackground(graphics); + drawWidgetBackground(graphics,mouseX,mouseY); if (canScale) { DrawHelper.scaleAndPosition(graphics.pose(), getX(), getY(), getScale()); @@ -214,7 +218,6 @@ public final void renderInEditor(GuiGraphics graphics, int mouseX, int mouseY) { /** * Renders the widget in the editor screen with a background. - * Override this method without super call to remove the background. * Could also be used to display placeholder values. */ private void renderWidgetInEditor(GuiGraphics graphics, int mouseX, int mouseY) { @@ -226,11 +229,13 @@ private void renderWidgetInEditor(GuiGraphics graphics, int mouseX, int mouseY) @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { if (widgetBox.isMouseOver(mouseX, mouseY) && button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { - toggle(); + wasDragged = false; if (isDraggable) { startX = (int) (mouseX - x); startY = (int) (mouseY - y); dragging = true; + } else { + toggle(); // Static widgets toggle immediately } return true; } @@ -251,7 +256,10 @@ public final boolean mouseDragged(double mouseX, double mouseY, int button, doub public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY, int snapSize) { if (!isDraggable) return false; + if (dragging && button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { + wasDragged = true; + int newX = (int) (mouseX - startX); int newY = (int) (mouseY - startY); @@ -280,8 +288,17 @@ public boolean mouseDragged(double mouseX, double mouseY, int button, double del @Override public boolean mouseReleased(double mouseX, double mouseY, int button) { + if (dragging && widgetBox.isMouseOver(mouseX,mouseY) && button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { + if (!wasDragged) { + toggle(); + dragging = false; + wasDragged = false; + return true; + } + } dragging = false; - return true; + wasDragged = false; + return false; } /** @@ -323,16 +340,18 @@ public void onClose() { /** * Displays a faint grayish background if enabled or faint reddish background if disabled. */ - protected void drawWidgetBackground(GuiGraphics graphics) { - int backgroundColor = this.isVisible() ? GlobalConfig.get().getHudActiveColor().getRGB() : GlobalConfig.get().getHudInactiveColor().getRGB(); + protected void drawWidgetBackground(GuiGraphics graphics, int mouseX, int mouseY) { + boolean isHovered = widgetBox.isMouseOver(mouseX, mouseY); + Color backgroundColor = this.isVisible() ? GlobalConfig.get().getHudActiveColor() : GlobalConfig.get().getHudInactiveColor(); WidgetBox box = this.getWidgetBox(); + DrawHelper.drawRectangle(graphics, box.x, box.y, box.getWidth(), box.getHeight(), - backgroundColor); + isHovered ? backgroundColor.darker().darker().getRGB() : backgroundColor.getRGB()); } /** diff --git a/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetRenderer.java b/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetRenderer.java index 05d10a7..1504af2 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetRenderer.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetRenderer.java @@ -173,7 +173,9 @@ public boolean mouseReleased(double mouseX, double mouseY, int button) { } if (currentScreen instanceof AbstractMoveableScreen) { for (Widget widget : widgets) { - widget.mouseReleased(mouseX, mouseY, button); + if(widget.mouseReleased(mouseX, mouseY, button)){ + return true; + } } } return false; diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java index 8b3782f..547c2e6 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java @@ -346,8 +346,7 @@ private String formatValue(float value) { @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { - menu.toggleDisplay(widgetBox, mouseX, mouseY, button); - return super.mouseClicked(mouseX, mouseY, button); + return menu.toggleDisplay(widgetBox, mouseX, mouseY, button) || super.mouseClicked(mouseX, mouseY, button); } public void createMenu() { diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java index 8f741dc..afdea05 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java @@ -155,8 +155,7 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { - menu.toggleDisplay(widgetBox, mouseX, mouseY, button); - return super.mouseClicked(mouseX, mouseY, button); + return menu.toggleDisplay(widgetBox, mouseX, mouseY, button) || super.mouseClicked(mouseX, mouseY, button); } @Override From 199d19a6a2af5c0341d6d5368814254e738a4f8c Mon Sep 17 00:00:00 2001 From: tanishisherewith <120117618+tanishisherewithhh@users.noreply.github.com> Date: Thu, 25 Jun 2026 14:36:09 +0530 Subject: [PATCH 15/22] Improve spline rendering of GraphWidget and position of Y-Axs values --- .../InterpolatedCurveRenderState.java | 73 +++++++++++++------ .../dynamichud/widgets/GraphWidget.java | 46 +++++++----- 2 files changed, 76 insertions(+), 43 deletions(-) diff --git a/src/main/java/com/tanishisherewith/dynamichud/renderstates/InterpolatedCurveRenderState.java b/src/main/java/com/tanishisherewith/dynamichud/renderstates/InterpolatedCurveRenderState.java index f1addda..5d0e115 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/renderstates/InterpolatedCurveRenderState.java +++ b/src/main/java/com/tanishisherewith/dynamichud/renderstates/InterpolatedCurveRenderState.java @@ -25,36 +25,61 @@ public record InterpolatedCurveRenderState( @Override public void buildVertices(@NonNull VertexConsumer consumer) { - consumer.setLineWidth(thickness); - if (points.size() < 2) return; + int numPoints = points.size(); + if (numPoints < 2) return; - // build individual QUADS - for (int i = 0; i < points.size() - 1; i++) { - float[] p1 = points.get(i); - float[] p2 = points.get(i + 1); + float halfThickness = thickness * 0.5f; + + // Pre-calculate continuous smooth joint normals + float[] extX = new float[numPoints]; + float[] extY = new float[numPoints]; + + for (int i = 0; i < numPoints; i++) { + float dx, dy; + if (i == 0) { + dx = points.get(1)[0] - points.get(0)[0]; + dy = points.get(1)[1] - points.get(0)[1]; + } else if (i == numPoints - 1) { + dx = points.get(i)[0] - points.get(i - 1)[0]; + dy = points.get(i)[1] - points.get(i - 1)[1]; + } else { + // Blend vector headings from incoming and outgoing segments + float dx1 = points.get(i)[0] - points.get(i - 1)[0]; + float dy1 = points.get(i)[1] - points.get(i - 1)[1]; + float dx2 = points.get(i + 1)[0] - points.get(i)[0]; + float dy2 = points.get(i + 1)[1] - points.get(i)[1]; + + float len1 = (float) Math.sqrt(dx1 * dx1 + dy1 * dy1); + float len2 = (float) Math.sqrt(dx2 * dx2 + dy2 * dy2); - float x1 = p1[0]; - float y1 = p1[1]; - float x2 = p2[0]; - float y2 = p2[1]; + if (len1 > 0) { dx1 /= len1; dy1 /= len1; } + if (len2 > 0) { dx2 /= len2; dy2 /= len2; } + + dx = dx1 + dx2; + dy = dy1 + dy2; + } - float dx = x2 - x1; - float dy = y2 - y1; float length = (float) Math.sqrt(dx * dx + dy * dy); - if (length == 0) continue; + if (length > 0) { + // Preserves exact original winding orientation to completely prevent culling + extX[i] = (dy / length) * halfThickness; + extY[i] = (-dx / length) * halfThickness; + } else { + extX[i] = 0; + extY[i] = 0; + } + } - // normals for line thickness - float offsetX = (thickness * 0.5f * dy) / length; - float offsetY = (thickness * 0.5f * -dx) / length; + // Stitch the continuous mesh strip + for (int i = 0; i < numPoints - 1; i++) { + float[] p1 = points.get(i); + float[] p2 = points.get(i + 1); - //Topleft - consumer.addVertexWith2DPose(pose, x1 + offsetX, y1 + offsetY).setColor(color); - //Bottomleft - consumer.addVertexWith2DPose(pose, x1 - offsetX, y1 - offsetY).setColor(color); - //Bottomright - consumer.addVertexWith2DPose(pose, x2 - offsetX, y2 - offsetY).setColor(color); - //Topright - consumer.addVertexWith2DPose(pose, x2 + offsetX, y2 + offsetY).setColor(color); + // Winding pattern: TopLeft -> BottomLeft -> BottomRight -> TopRight + consumer.addVertexWith2DPose(pose, p1[0] + extX[i], p1[1] + extY[i]).setColor(color); + consumer.addVertexWith2DPose(pose, p1[0] - extX[i], p1[1] - extY[i]).setColor(color); + consumer.addVertexWith2DPose(pose, p2[0] - extX[i + 1], p2[1] - extY[i + 1]).setColor(color); + consumer.addVertexWith2DPose(pose, p2[0] + extX[i + 1], p2[1] + extY[i + 1]).setColor(color); } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java index 547c2e6..e4bcadf 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java @@ -138,14 +138,13 @@ private List getInterpolatedPoints() { float xStep = gWidth / (dataPoints.length - 1); float range = Math.max(maxValue - minValue, 0.0001f); - //Pre-calculate Y coordinates float[] yVals = new float[dataPoints.length]; for (int i = 0; i < dataPoints.length; i++) { int index = (head + i) % dataPoints.length; yVals[i] = y + gHeight - ((dataPoints[index] - minValue) / range * gHeight); } - // Monotone Cubic Spline (Fritsch-Carlson) calculation + // Calculate Monotone Cubic Spline Tangents float[] m = new float[dataPoints.length]; for (int i = 0; i < dataPoints.length; i++) { if (i == 0) { @@ -157,10 +156,9 @@ private List getInterpolatedPoints() { float sNext = yVals[i + 1] - yVals[i]; if (sPrev * sNext <= 0) { - m[i] = 0; // Local peak/valley so clamp tangent to prevent overshoot + m[i] = 0; } else { m[i] = (sPrev + sNext) / 2.0f; - // Clamp tangent magnitude to max 3x of smallest secant float maxMag = 3.0f * Math.min(Math.abs(sPrev), Math.abs(sNext)); if (Math.abs(m[i]) > maxMag) { m[i] = Math.signum(m[i]) * maxMag; @@ -169,7 +167,9 @@ private List getInterpolatedPoints() { } } - //Generate curve with distance filtering to fix tearing + int stepsPerSegment = 32; + float stepSize = 1.0f / stepsPerSegment; + for (int i = 0; i < dataPoints.length - 1; i++) { float y0 = yVals[i]; float y1 = yVals[i + 1]; @@ -177,11 +177,15 @@ private List getInterpolatedPoints() { float m1 = m[i + 1]; float x0 = x + i * xStep; - for (float t = 0; t <= 1.0f; t += 0.05f) { + for (int step = 0; step <= stepsPerSegment; step++) { + // Avoid redundant overlapping nodes between adjoining segments + if (step == stepsPerSegment && i < dataPoints.length - 2) continue; + + float t = step * stepSize; float t2 = t * t; float t3 = t2 * t; - // Hermite basis functions + // Cubic Hermite Spline formulation float h00 = 2 * t3 - 3 * t2 + 1; float h10 = t3 - 2 * t2 + t; float h01 = -2 * t3 + 3 * t2; @@ -190,15 +194,12 @@ private List getInterpolatedPoints() { float px = x0 + t * xStep; float py = h00 * y0 + h10 * m0 + h01 * y1 + h11 * m1; - // Vertex Simplifier: Only add point if it moved a safe distance. - // This prevents float-precision "divide by zero" errors when normals are if (points.isEmpty()) { points.add(new float[]{px, py}); } else { float[] lastP = points.get(points.size() - 1); - float distSq = (px - lastP[0]) * (px - lastP[0]) + (py - lastP[1]) * (py - lastP[1]); - // Add only if distance is safe OR if it's the strict end of the segment - if (distSq > 0.5f || t >= 0.99f) { + float distanceSq = (px - lastP[0]) * (px - lastP[0]) + (py - lastP[1]) * (py - lastP[1]); + if (distanceSq > 0.005f) { points.add(new float[]{px, py}); } } @@ -267,11 +268,11 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { float value = maxValue - (i * valueStep); String valueText = formatValue(value); - float texWidth = mc.font.width(valueText) * valueScale; + float texWidth = mc.font.width(valueText); //Scale the Component to its proper position and size with grid lines - DrawHelper.scaleAndPosition(graphics.pose(), x - 2, yPos,texWidth,mc.font.lineHeight * valueScale, valueScale); - graphics.drawString(mc.font, valueText, Math.round(x + offset - texWidth), (int) (yPos - (mc.font.lineHeight * valueScale) / 2.0f), 0xFFFFFFFF, true); + DrawHelper.scaleAndPosition(graphics.pose(), x + offset - texWidth/2.0f, yPos - (mc.font.lineHeight * valueScale) / 2.0f,texWidth,mc.font.lineHeight * valueScale, valueScale); + graphics.drawString(mc.font, valueText, Math.round(x + offset - texWidth), (int) (yPos - (mc.font.lineHeight * valueScale) / 2), 0xFFFFFFFF, true); DrawHelper.stopScaling(graphics.pose()); } @@ -290,7 +291,7 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { // Draw shadow effect under the graph drawGradientShadow( graphics, points, y + gHeight, - ColorHelper.changeAlpha(graphColor, 100).getRGB(), + ColorHelper.changeAlpha(graphColor, 60).getRGB(), 0x00000000 ); @@ -307,6 +308,13 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { DrawHelper.drawHorizontalLine(graphics, x, gWidth, y + gHeight - 1, 1.0f, 0xFFFFFFFF); // X-axis DrawHelper.drawVerticalLine(graphics, x, y, gHeight, 1.0f, 0xFFFFFFFF); // Y-axis + + if (!points.isEmpty()) { + float[] livePoint = points.getLast(); + + DrawHelper.drawFilledCircle(graphics, livePoint[0], livePoint[1], 0.9f, 0x26FFFFFF); + } + // Draw min and max value labels with formatted values /* DrawHelper.scaleAndPosition(context.getMatrices(),x - 5,y,0.5f); @@ -316,9 +324,9 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { */ - DrawHelper.scaleAndPosition(graphics.pose(), x - 5, y + gHeight, 0.5f); String formattedMinVal = formatValue(minValue); - graphics.drawString(mc.font, formattedMinVal, (int) (x - mc.font.width(formattedMinVal)), (int) (y + gHeight - 4), 0xFFFFFFFF, true); + DrawHelper.scaleAndPosition(graphics.pose(), x + (offset - mc.font.width(formattedMinVal))/2.0f, y + gHeight, 0.4f); + graphics.drawString(mc.font, formattedMinVal, x + offset - mc.font.width(formattedMinVal), (int) (y + gHeight + 1), 0xFFFFFFFF, true); DrawHelper.stopScaling(graphics.pose()); if(showGrid) x -= offset; @@ -383,7 +391,7 @@ public void createMenu() { .description(Component.literal("Specify the color you want for the graph's background")) ); menu.addOption(new DoubleOption(Component.literal("Line Thickness"), - 0.5f, 5.0f, 0.1f, + 0.5f, 1f, 0.01f, () -> (double) this.lineThickness, value -> this.lineThickness = value.floatValue(), menu) ); } From aaf22a1da0db8217695b7fa16ff8c1262de877fd Mon Sep 17 00:00:00 2001 From: tanishisherewith <120117618+tanishisherewithhh@users.noreply.github.com> Date: Thu, 25 Jun 2026 15:02:04 +0530 Subject: [PATCH 16/22] More improvements to GraphWidget and now alphaHandleY syncs with alpha value of AlphaSlider --- .../contextmenu/options/ColorOption.java | 2 +- .../options/coloroption/AlphaSlider.java | 56 ++++++++++--------- .../dynamichud/widget/DynamicValueWidget.java | 2 +- .../dynamichud/widgets/GraphWidget.java | 27 +++++---- .../dynamichud/widgets/TextWidget.java | 2 - 5 files changed, 46 insertions(+), 43 deletions(-) diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ColorOption.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ColorOption.java index 9f4eb93..cdc678a 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ColorOption.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ColorOption.java @@ -16,7 +16,7 @@ public class ColorOption extends Option { public ColorOption(Component name, Supplier getter, Consumer setter, ContextMenu parentMenu) { super(name, getter, setter); this.parentMenu = parentMenu; - this.colorGradient = new ColorGradient(x + this.parentMenu.getWidth(), y - 10, get(), this::set, 50, 100); + this.colorGradient = new ColorGradient(x + this.parentMenu.getWidth(), y - 10, get(), this::set, 50, 150); } @Override diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/AlphaSlider.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/AlphaSlider.java index 5c37cfd..e3d96c1 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/AlphaSlider.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/AlphaSlider.java @@ -3,6 +3,7 @@ import com.tanishisherewith.dynamichud.helpers.ColorHelper; import com.tanishisherewith.dynamichud.helpers.DrawHelper; import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.util.Mth; import java.awt.*; @@ -22,7 +23,7 @@ public AlphaSlider(int x, int y, int width, int height, Color color) { this.color = color; this.x = x; this.y = y; - this.alpha = color.getAlpha() / 255f; + updateAlphaFromColor(color); } public void render(GuiGraphics graphics, int x, int y) { @@ -40,21 +41,40 @@ public Color getColor() { public void setColor(Color color) { this.color = color; + updateAlphaFromColor(color); + } + + private void updateAlphaFromColor(Color color) { + this.alpha = color.getAlpha() / 255f; + // Maps the 0.0 - 1.0 float range back into screen pixel offset + this.alphaHandleY = Math.round((1.0f - this.alpha) * this.height); } public void onClick(double mouseX, double mouseY, int button) { if (button == 0 && isMouseOver(mouseX, mouseY)) { - alphaHandleY = (int) mouseY - y; - alpha = 1.0f - (alphaHandleY / (float) height); - if (alpha < 0.0f) { - alpha = 0.0f; - } else if (alpha > 1.0f) { - alpha = 1.0f; - } this.isDragging = true; + handleMouseMovement(mouseY); + } + } + + public void onDrag(double mouseX, double mouseY, int button) { + if (this.isDragging) { + handleMouseMovement(mouseY); + } + } + + public void onRelease(double mouseX, double mouseY, int button) { + if (button == 0) { + this.isDragging = false; } } + private void handleMouseMovement(double mouseY) { + // Clamp mouse delta pos so the handle dooesnt jump out of the bar bounds + this.alphaHandleY = Mth.clamp((int) mouseY - this.y, 0, this.height); + this.alpha = 1.0f - (this.alphaHandleY / (float) this.height); + } + public void setY(int y) { this.y = y; } @@ -74,22 +94,4 @@ public int getHeight() { public boolean isMouseOver(double mouseX, double mouseY) { return mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height; } - - public void onRelease(double mouseX, double mouseY, int button) { - if (button == 0) { - isDragging = false; - } - } - - public void onDrag(double mouseX, double mouseY, int button) { - if (isDragging && mouseY >= y && mouseY <= y + height) { - alphaHandleY = (int) mouseY - y; - alpha = 1.0f - (alphaHandleY / (float) height); - if (alpha < 0.0f) { - alpha = 0.0f; - } else if (alpha > 1.0f) { - alpha = 1.0f; - } - } - } -} +} \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/widget/DynamicValueWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widget/DynamicValueWidget.java index 10a880f..a8ea445 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widget/DynamicValueWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widget/DynamicValueWidget.java @@ -50,7 +50,7 @@ public void readFromTag(CompoundTag tag) { initializeValueSupplier(); - if (valueSupplier == null) throw new IllegalStateException("Value supplier remains null"); + if (valueSupplier == null) throw new IllegalStateException("Value supplier cannot be null. Invalid registry data found!"); } /** diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java index e4bcadf..b0aa012 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java @@ -74,8 +74,6 @@ public GraphWidget(String registryID, String registryKey, String modId, Anchor a this.setMaxValue(maxValue); internal_init(); - - createMenu(); ContextMenuManager.getInstance().registerProvider(this); } @@ -91,6 +89,7 @@ private void internal_init() { computeOffset(); setTooltipText(Component.literal("Graph displaying: " + label)); + createMenu(); } public GraphWidget() { @@ -194,10 +193,12 @@ private List getInterpolatedPoints() { float px = x0 + t * xStep; float py = h00 * y0 + h10 * m0 + h01 * y1 + h11 * m1; + py = Math.clamp(py, y, y + gHeight); + if (points.isEmpty()) { points.add(new float[]{px, py}); } else { - float[] lastP = points.get(points.size() - 1); + float[] lastP = points.getLast(); float distanceSq = (px - lastP[0]) * (px - lastP[0]) + (py - lastP[1]) * (py - lastP[1]); if (distanceSq > 0.005f) { points.add(new float[]{px, py}); @@ -288,6 +289,8 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { List points = getInterpolatedPoints(); + DrawHelper.enableScissor((int) x, (int) y, (int) gWidth, (int) gHeight, graphics); + // Draw shadow effect under the graph drawGradientShadow( graphics, points, y + gHeight, @@ -303,18 +306,18 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { 1.0f, 0.8f, 1.0f, 0.05f, true ); - - // Draw axes - DrawHelper.drawHorizontalLine(graphics, x, gWidth, y + gHeight - 1, 1.0f, 0xFFFFFFFF); // X-axis - DrawHelper.drawVerticalLine(graphics, x, y, gHeight, 1.0f, 0xFFFFFFFF); // Y-axis - - if (!points.isEmpty()) { float[] livePoint = points.getLast(); DrawHelper.drawFilledCircle(graphics, livePoint[0], livePoint[1], 0.9f, 0x26FFFFFF); } + DrawHelper.disableScissor(graphics); + + // Draw axes + DrawHelper.drawHorizontalLine(graphics, x, gWidth, y + gHeight - 1, 1.0f, 0xFFFFFFFF); // X-axis + DrawHelper.drawVerticalLine(graphics, x, y, gHeight, 1.0f, 0xFFFFFFFF); // Y-axis + // Draw min and max value labels with formatted values /* DrawHelper.scaleAndPosition(context.getMatrices(),x - 5,y,0.5f); @@ -325,8 +328,9 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { */ String formattedMinVal = formatValue(minValue); - DrawHelper.scaleAndPosition(graphics.pose(), x + (offset - mc.font.width(formattedMinVal))/2.0f, y + gHeight, 0.4f); - graphics.drawString(mc.font, formattedMinVal, x + offset - mc.font.width(formattedMinVal), (int) (y + gHeight + 1), 0xFFFFFFFF, true); + + DrawHelper.scaleAndPosition(graphics.pose(), x - mc.font.width(formattedMinVal)/2.0f, y + gHeight,mc.font.width(formattedMinVal),mc.font.lineHeight * 0.5f, 0.5f); + graphics.drawString(mc.font, formattedMinVal, x - mc.font.width(formattedMinVal), (int) (y + gHeight + 1), 0xFFFFFFFF, true); DrawHelper.stopScaling(graphics.pose()); if(showGrid) x -= offset; @@ -545,7 +549,6 @@ public void readFromTag(CompoundTag tag) { this.setMaxValue(maxValue); internal_init(); - createMenu(); } @Override diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java index afdea05..2c8730b 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/TextWidget.java @@ -186,8 +186,6 @@ public void readFromTag(CompoundTag tag) { rainbowSaturation = tag.getFloat("RainbowSaturation").orElse(1.0f); rainbowBrightness = tag.getFloat("RainbowBrightness").orElse(1.0f); textColor = new Color(tag.getInt("TextColor").orElse(0xFFFFFFFF), true); // default white - registryKey = tag.getString("RegistryKey").orElse("default:key"); - registryID = tag.getString("RegistryID").orElse("default:id"); //createMenu(); } From d0462cb184db6239efc18fd1ab281426e1f0caca Mon Sep 17 00:00:00 2001 From: tanishisherewith <120117618+tanishisherewithhh@users.noreply.github.com> Date: Thu, 25 Jun 2026 20:30:12 +0530 Subject: [PATCH 17/22] Added snap alignment guidelines Patched ghost mouse clicks outside the menu --- .../dynamichud/config/GlobalConfig.java | 17 +- .../contextmenu/skinsystem/MinecraftSkin.java | 16 +- .../contextmenu/skinsystem/ModernSkin.java | 13 +- .../dynamichud/widget/WidgetRenderer.java | 182 +++++++++++++++++- .../dynamichud/widgets/GraphWidget.java | 4 +- 5 files changed, 209 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/tanishisherewith/dynamichud/config/GlobalConfig.java b/src/main/java/com/tanishisherewith/dynamichud/config/GlobalConfig.java index 6be96e4..23240c8 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/config/GlobalConfig.java +++ b/src/main/java/com/tanishisherewith/dynamichud/config/GlobalConfig.java @@ -41,6 +41,9 @@ public final class GlobalConfig { @SerialEntry private boolean renderInDebugScreen = false; + @SerialEntry + private boolean smartSnapping = true; + @SerialEntry private final boolean forceSameContextMenuSkin = true; @@ -79,7 +82,7 @@ public Screen createYACLGUI() { .option(Option.createBuilder() .name(Component.literal("Render in debug screen")) .description(OptionDescription.of(Component.literal("Renders widgets even when the debug screen is on"))) - .binding(true, () -> this.renderInDebugScreen, newVal -> this.renderInDebugScreen = newVal) + .binding(false, () -> this.renderInDebugScreen, newVal -> this.renderInDebugScreen = newVal) .controller(booleanOption -> BooleanControllerBuilder.create(booleanOption).yesNoFormatter()) .build()) .option(Option.createBuilder() @@ -91,7 +94,13 @@ public Screen createYACLGUI() { .option(Option.createBuilder() .name(Component.literal("Show widget descriptions/tooltips")) .description(OptionDescription.of(Component.literal("Shows the description of widgets as tooltips."))) - .binding(true, () -> this.displayDescriptions, newVal -> this.displayDescriptions = newVal) + .binding(false, () -> this.displayDescriptions, newVal -> this.displayDescriptions = newVal) + .controller(booleanOption -> BooleanControllerBuilder.create(booleanOption).yesNoFormatter()) + .build()) + .option(Option.createBuilder() + .name(Component.literal("Smart Snapping")) + .description(OptionDescription.of(Component.literal("Enables widgets to automatically snap to each other or the center of the screen, displaying alignment guidelines while dragging"))) + .binding(true, () -> this.smartSnapping, newVal -> this.smartSnapping = newVal) .controller(booleanOption -> BooleanControllerBuilder.create(booleanOption).yesNoFormatter()) .build()) .option(Option.createBuilder() @@ -166,6 +175,10 @@ public int getCmAnimationTimeInMs() { return cmAnimationTimeInMs; } + public boolean doSmartSnapping() { + return smartSnapping; + } + public com.tanishisherewith.dynamichud.utils.contextmenu.options.Option.Complexity complexity() { return complexity; } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java index af8451e..c9c18f7 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java @@ -491,18 +491,12 @@ public class MinecraftBooleanRenderer implements SkinRenderer { public void render(GuiGraphics graphics, BooleanOption option, int x, int y, int mouseX, int mouseY) { graphics.drawString(mc.font, option.name, x + 15, y + 25 / 2 - 5, -1, true); - option.setPosition(x + panelWidth - 75, y); - int width = 50; - graphics.blitSprite(RenderPipelines.GUI_TEXTURED, TEXTURES.get(true, option.isMouseOver(mouseX, mouseY)), option.getX(), y, width, 20); + graphics.blitSprite(RenderPipelines.GUI_TEXTURED, TEXTURES.get(true, isMouseOver(mouseX, mouseY,x + panelWidth - 75, y, width, 20)), x + panelWidth - 75, y, width, 20); Component Component = option.getBooleanType().getText(option.value); int color = option.value ? Color.GREEN.getRGB() : Color.RED.getRGB(); graphics.drawString(mc.font, Component, (int) (option.getX() + (width / 2.0f) - (mc.font.width(Component) / 2.0f)), y + 5, color, true); - - - //Widths don't matter in this skin - option.setWidth(width); } } @@ -540,17 +534,15 @@ public void render(GuiGraphics graphics, ColorOption option, int x, int y, int m graphics.drawString(mc.font, option.name, x + 15, y + 25 / 2 - 5, -1, true); - option.setPosition(x + panelWidth - 45, y); - int width = 20; - graphics.blitSprite(RenderPipelines.GUI_TEXTURED, TEXTURES.get(!option.isVisible, option.isMouseOver(mouseX, mouseY)), option.getX(), y, width, 20); + graphics.blitSprite(RenderPipelines.GUI_TEXTURED, TEXTURES.get(!option.isVisible, isMouseOver(mouseX, mouseY,x + panelWidth - 45, y, width, 20)), x + panelWidth - 45, y, width, 20); int shadowOpacity = Math.min(option.value.getAlpha(), 45); DrawHelper.drawRectangleWithShadowBadWay(graphics, option.getX() + 4, y + 4, width - 8, - 20 - 8, + 12, option.value.getRGB(), shadowOpacity, 1, @@ -587,7 +579,7 @@ public void render(GuiGraphics graphics, ColorOption option, int x, int y, int m @Override public boolean mouseClicked(ColorOption option, double mouseX, double mouseY, int button) { - if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && isMouseOver(mouseX, mouseY, option.getX(), option.getY(), 20, 20)) { + if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && isMouseOver(mouseX, mouseY, option.getX() + panelWidth - 45, option.getY(), 20, 20)) { boolean isOpening = !option.getColorGradient().shouldDisplay(); scaleAnimation.startValue(scale); if (isOpening) { diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java index 280e183..7d8e1de 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java @@ -969,26 +969,26 @@ public class ModernRunnableRenderer implements SkinRenderer { @Override public void render(GuiGraphics graphics, RunnableOption option, int x, int y, int mouseX, int mouseY) { String labelText = "Run â–¶"; + float labelWidth = mc.font.width(labelText) + 5; + int xPos = x + option.getWidth() - 45; option.setHeight(mc.font.lineHeight + 6); - boolean isHovering = isMouseOver(mouseX, mouseY, xPos + 2, y + 4, width, mc.font.lineHeight + 4); + boolean isHovering = isMouseOver(mouseX, mouseY, xPos + 2, y + 4, labelWidth, mc.font.lineHeight + 4); boolean isDown = isHovering && GLFW.glfwGetMouseButton(mc.getWindow().handle(), GLFW.GLFW_MOUSE_BUTTON_LEFT) == GLFW.GLFW_PRESS; animator.update(isDown); graphics.drawString(mc.font, option.name, x + 4, y + 4, -1, false); - float width = mc.font.width(labelText) + 5; - Color fillColor = isHovering ? getThemeColor().darker().darker() : getThemeColor(); - DrawHelper.scaleAndPosition(graphics.pose(),xPos - 1, y + 1,width, mc.font.lineHeight + 4, animator.getScale()); + DrawHelper.scaleAndPosition(graphics.pose(),xPos - 1, y + 1,labelWidth, mc.font.lineHeight + 4, animator.getScale()); DrawHelper.drawRoundedRectangleWithShadowBadWay( graphics, xPos - 1, y + 1, - width, mc.font.lineHeight + 4, + labelWidth, mc.font.lineHeight + 4, 2, fillColor.getRGB(), 180, @@ -1104,6 +1104,9 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float del int iconColor = isFocused()? Color.WHITE.getRGB() : 0x80FFFFFF; graphics.drawString(mc.font, icon, iconX, iconY, iconColor, false); + + //Rendering the original edit-box widget without its border and background, and translating it to fit inside our search box + // EditBox handles the rest of the text and highlight rendering graphics.pose().pushMatrix(); graphics.pose().translate(-1,3); super.renderWidget(graphics, mouseX, mouseY, delta); diff --git a/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetRenderer.java b/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetRenderer.java index 1504af2..9119129 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetRenderer.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetRenderer.java @@ -2,6 +2,7 @@ import com.tanishisherewith.dynamichud.DynamicHUD; import com.tanishisherewith.dynamichud.config.GlobalConfig; +import com.tanishisherewith.dynamichud.helpers.DrawHelper; import com.tanishisherewith.dynamichud.internal.System; import com.tanishisherewith.dynamichud.screens.AbstractMoveableScreen; import com.tanishisherewith.dynamichud.utils.Input; @@ -11,6 +12,7 @@ import net.minecraft.client.gui.screens.Screen; import org.lwjgl.glfw.GLFW; +import java.awt.*; import java.util.List; import java.util.function.Predicate; @@ -22,6 +24,12 @@ public class WidgetRenderer implements Input { private boolean renderInGameHud = true; //private int Z_Index = -1; + // Snapping Guideline Coordinates + private float snapLineX = -1; + private float snapLineY = -1; + private float screenCenterX = -1; + private float screenCenterY = -1; + /** * Add the list of widgets the widgetRenderer should render *

@@ -104,6 +112,10 @@ public void renderWidgets(GuiGraphics graphics, int mouseX, int mouseY) { widget.isInEditor = true; widget.renderInEditor(graphics, mouseX, mouseY); } + + if(GlobalConfig.get().doSmartSnapping()) { + drawSnapGuides(graphics); + } return; } //Render in any other screen and the inGameHud @@ -154,6 +166,7 @@ public void charTyped(char c, int modifiers) { } public void onCloseScreen() { + clearSnapLines(); if (DynamicHUD.MC.screen instanceof AbstractMoveableScreen) { for (Widget widget : widgets) { widget.onClose(); @@ -167,6 +180,9 @@ public List getWidgets() { @Override public boolean mouseReleased(double mouseX, double mouseY, int button) { + selectedWidget = null; + clearSnapLines(); + Screen currentScreen = DynamicHUD.MC.screen; if (currentScreen == null) { return false; @@ -197,10 +213,14 @@ public boolean mouseDragged(double mouseX, double mouseY, int button, double del // if they are overlapped on each other. if (widget.mouseDragged(mouseX, mouseY, button, deltaX, deltaY, snapSize)) { selectedWidget = widget; + if(GlobalConfig.get().doSmartSnapping()) { + applySnappingAndGuides(selectedWidget); + } return true; } } selectedWidget = null; + clearSnapLines(); } return false; } @@ -225,7 +245,167 @@ public void keyReleased(int key, int scanCode, int modifiers) { } } - // public WidgetRenderer withZIndex(int z_Index) { + /** + * Renders alignment and screen axis guidelines if snapping conditions are met. + */ + private void drawSnapGuides(GuiGraphics graphics) { + int screenWidth = DynamicHUD.MC.getWindow().getGuiScaledWidth(); + int screenHeight = DynamicHUD.MC.getWindow().getGuiScaledHeight(); + + int screenCenterColor = new Color(255, 80, 80, 180).getRGB(); // Light red for screen axes + int widgetSnapColor = new Color(0, 220, 255, 180).getRGB(); // Bright cyan for widget alignments + + // Screen Vertical Center guideline + if (screenCenterX != -1) { + DrawHelper.drawVerticalLine(graphics, screenCenterX, 0, screenHeight, 1.0f, screenCenterColor); + } + + // Screen Horizontal Center guideline + if (screenCenterY != -1) { + DrawHelper.drawHorizontalLine(graphics, 0, screenWidth, screenCenterY, 1.0f, screenCenterColor); + } + + // Neighboring Widget Vertical alignment guideline + if (snapLineX != -1) { + DrawHelper.drawVerticalLine(graphics, snapLineX, 0, screenHeight, 1.0f, widgetSnapColor); + } + + // Neighboring Widget Horizontal alignment guideline + if (snapLineY != -1) { + DrawHelper.drawHorizontalLine(graphics, 0, screenWidth, snapLineY, 1.0f, widgetSnapColor); + } + } + + /** + * Resets active alignment line parameters. + */ + private void clearSnapLines() { + snapLineX = -1; + snapLineY = -1; + screenCenterX = -1; + screenCenterY = -1; + } + + /** + * Evaluates alignment thresholds and snaps the dragged widget to relevant lines or centers. + */ + private void applySnappingAndGuides(Widget dragged) { + clearSnapLines(); + + if (dragged == null) return; + + int screenWidth = DynamicHUD.MC.getWindow().getGuiScaledWidth(); + int screenHeight = DynamicHUD.MC.getWindow().getGuiScaledHeight(); + float threshold = 4f; // Snap tolerance threshold in pixels + + float dw = dragged.getWidth(); + float dh = dragged.getHeight(); + + float dl = dragged.getX(); + float dr = dl + dw; + float dcx = dl + dw / 2.0f; + + float dt = dragged.getY(); + float db = dt + dh; + float dcy = dt + dh / 2.0f; + + boolean snappedX = false; + boolean snappedY = false; + + float screenMidX = screenWidth / 2.0f; + float screenMidY = screenHeight / 2.0f; + + if (Math.abs(dcx - screenMidX) < threshold) { + dragged.setPosition((int) (screenMidX - dw / 2.0f), dragged.getY()); + screenCenterX = screenMidX; + snappedX = true; + // Refresh coordinates + dl = dragged.getX(); + dr = dl + dw; + dcx = dl + dw / 2.0f; + } + + if (Math.abs(dcy - screenMidY) < threshold) { + dragged.setPosition(dragged.getX(), (int) (screenMidY - dh / 2.0f)); + screenCenterY = screenMidY; + snappedY = true; + // Refresh coordinates + dt = dragged.getY(); + db = dt + dh; + dcy = dt + dh / 2.0f; + } + + for (Widget other : widgets) { + if (other == dragged || !other.isVisible()) continue; + + float ow = other.getWidth(); + float oh = other.getHeight(); + + float ol = other.getX(); + float or = ol + ow; + float ocx = ol + ow / 2.0f; + + float ot = other.getY(); + float ob = ot + oh; + float ocy = ot + oh / 2.0f; + + // X-Axis Snap Checks + if (!snappedX) { + if (Math.abs(dl - ol) < threshold) { // Left to Left + dragged.setPosition((int) ol, dragged.getY()); + snapLineX = ol; + snappedX = true; + } else if (Math.abs(dl - or) < threshold) { // Left to Right + dragged.setPosition((int) or, dragged.getY()); + snapLineX = or; + snappedX = true; + } else if (Math.abs(dr - ol) < threshold) { // Right to Left + dragged.setPosition((int) (ol - dw), dragged.getY()); + snapLineX = ol; + snappedX = true; + } else if (Math.abs(dr - or) < threshold) { // Right to Right + dragged.setPosition((int) (or - dw), dragged.getY()); + snapLineX = or; + snappedX = true; + } else if (Math.abs(dcx - ocx) < threshold) { // Center to Center + dragged.setPosition((int) (ocx - dw / 2.0f), dragged.getY()); + snapLineX = ocx; + snappedX = true; + } + } + + // Y-Axis Snap Checks + if (!snappedY) { + if (Math.abs(dt - ot) < threshold) { // Top to Top + dragged.setPosition(dragged.getX(), (int) ot); + snapLineY = ot; + snappedY = true; + } else if (Math.abs(dt - ob) < threshold) { // Top to Bottom + dragged.setPosition(dragged.getX(), (int) ob); + snapLineY = ob; + snappedY = true; + } else if (Math.abs(db - ot) < threshold) { // Bottom to Top + dragged.setPosition(dragged.getX(), (int) (ot - dh)); + snapLineY = ot; + snappedY = true; + } else if (Math.abs(db - ob) < threshold) { // Bottom to Bottom + dragged.setPosition(dragged.getX(), (int) (ob - dh)); + snapLineY = ob; + snappedY = true; + } else if (Math.abs(dcy - ocy) < threshold) { // Center to Center + dragged.setPosition(dragged.getX(), (int) (ocy - dh / 2.0f)); + snapLineY = ocy; + snappedY = true; + } + } + + if (snappedX && snappedY) break; + } + } + + + + // public WidgetRenderer withZIndex(int z_Index) { // this.Z_Index = z_Index; // return this; // } diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java index b0aa012..f8cbcec 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java @@ -289,7 +289,6 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { List points = getInterpolatedPoints(); - DrawHelper.enableScissor((int) x, (int) y, (int) gWidth, (int) gHeight, graphics); // Draw shadow effect under the graph drawGradientShadow( @@ -312,7 +311,6 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { DrawHelper.drawFilledCircle(graphics, livePoint[0], livePoint[1], 0.9f, 0x26FFFFFF); } - DrawHelper.disableScissor(graphics); // Draw axes DrawHelper.drawHorizontalLine(graphics, x, gWidth, y + gHeight - 1, 1.0f, 0xFFFFFFFF); // X-axis @@ -330,7 +328,7 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { String formattedMinVal = formatValue(minValue); DrawHelper.scaleAndPosition(graphics.pose(), x - mc.font.width(formattedMinVal)/2.0f, y + gHeight,mc.font.width(formattedMinVal),mc.font.lineHeight * 0.5f, 0.5f); - graphics.drawString(mc.font, formattedMinVal, x - mc.font.width(formattedMinVal), (int) (y + gHeight + 1), 0xFFFFFFFF, true); + graphics.drawString(mc.font, formattedMinVal, x - mc.font.width(formattedMinVal), (int) (y + gHeight), 0xFFFFFFFF, true); DrawHelper.stopScaling(graphics.pose()); if(showGrid) x -= offset; From 8ff9f76fb25a033bf3286ad089acd5051ad4cd9f Mon Sep 17 00:00:00 2001 From: tanishisherewith <120117618+tanishisherewithhh@users.noreply.github.com> Date: Thu, 25 Jun 2026 20:50:38 +0530 Subject: [PATCH 18/22] Use better animation pattern --- .../animationhelper/AnimationProperty.java | 7 --- .../animations/SquishAnimator.java | 50 ++++++++++++------- .../animations/ValueAnimation.java | 33 +++++++++--- .../utils/contextmenu/ContextMenu.java | 13 +---- .../contextmenu/skinsystem/MinecraftSkin.java | 15 +----- .../contextmenu/skinsystem/ModernSkin.java | 23 +++------ .../dynamichud/widgets/GraphWidget.java | 2 +- 7 files changed, 68 insertions(+), 75 deletions(-) delete mode 100644 src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/AnimationProperty.java diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/AnimationProperty.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/AnimationProperty.java deleted file mode 100644 index 53eab9d..0000000 --- a/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/AnimationProperty.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.tanishisherewith.dynamichud.helpers.animationhelper; - -// Use this to set/get the variable on which the animation should apply to -public interface AnimationProperty { - T get(); - void set(T value); -} \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/SquishAnimator.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/SquishAnimator.java index f4ec5ce..8d78f73 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/SquishAnimator.java +++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/SquishAnimator.java @@ -1,28 +1,31 @@ package com.tanishisherewith.dynamichud.helpers.animationhelper.animations; -import com.tanishisherewith.dynamichud.helpers.animationhelper.AnimationProperty; import com.tanishisherewith.dynamichud.helpers.animationhelper.EasingType; -public class SquishAnimator { - private final ValueAnimation animation; - private final AnimationProperty property; +import java.util.function.Consumer; + +public class SquishAnimator extends ValueAnimation { private boolean isPressed = false; - private float normalScale; - private float pressedScale; + private final float normalScale; + private final float pressedScale; + private final ScaleHolder holder; - public SquishAnimator(float normalScale, float pressedScale) { + private SquishAnimator(ScaleHolder holder, float normalScale, float pressedScale) { + super(holder, normalScale, pressedScale); + this.holder = holder; + this.holder.value = normalScale; this.normalScale = normalScale; this.pressedScale = pressedScale; - this.property = new AnimationProperty<>() { - private float val = normalScale; - public Float get() { return val; } - public void set(Float v) { val = v; } - }; - - this.animation = new ValueAnimation(property, normalScale, pressedScale); - this.animation.easing(EasingType.EASE_OUT_BACK); - this.animation.duration(125); + + // default polished easing configurations + this.easing(EasingType.EASE_OUT_BACK); + this.duration(125); + } + + public SquishAnimator(float normalScale, float pressedScale) { + this(new ScaleHolder(), normalScale, pressedScale); } + public SquishAnimator(){ this(1.0f,0.95f); } @@ -30,10 +33,19 @@ public SquishAnimator(){ public void update(boolean pressed) { if (this.isPressed != pressed) { this.isPressed = pressed; - animation.set(property.get(),pressed ? pressedScale : normalScale).start(); + this.set(holder.value,pressed ? pressedScale : normalScale).start(); } - animation.update(); + this.update(); } - public float getScale() { return property.get(); } + public float getScale() { return holder.value; } + + private static class ScaleHolder implements Consumer { + float value; + + @Override + public void accept(Float v) { + this.value = v; + } + } } \ No newline at end of file diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/ValueAnimation.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/ValueAnimation.java index 1401472..e0bdea7 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/ValueAnimation.java +++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/animationhelper/animations/ValueAnimation.java @@ -1,33 +1,50 @@ package com.tanishisherewith.dynamichud.helpers.animationhelper.animations; import com.tanishisherewith.dynamichud.helpers.animationhelper.Animation; -import com.tanishisherewith.dynamichud.helpers.animationhelper.AnimationProperty; import com.tanishisherewith.dynamichud.helpers.animationhelper.Easing; import com.tanishisherewith.dynamichud.helpers.animationhelper.EasingType; +import java.util.function.Consumer; + public class ValueAnimation extends Animation { - private final AnimationProperty property; + private final Consumer setter; private float startValue; private float endValue; private EasingType easing; private float value; - public ValueAnimation(AnimationProperty property, float start, float end, EasingType easingType) { - this.property = property; + /** + * Creates a new ValueAnimation with an easing type. + * + * @param setter A functional callback (such as a lambda expression) to receive the updated float. + * @param start The starting float value. + * @param end The target ending float value. + * @param easingType The mathematical easing equation to apply. + */ + + public ValueAnimation(Consumer setter, float start, float end, EasingType easingType) { + this.setter = setter; this.startValue = start; this.endValue = end; this.easing = easingType; this.value = startValue; } - public ValueAnimation(AnimationProperty property, float start, float end) { - this(property, start, end, EasingType.LINEAR); + /** + * Creates a new ValueAnimation with linear easing. + * + * @param setter A functional callback (such as a lambda expression) to receive the updated float. + * @param start The starting float value. + * @param end The target ending float value. + */ + public ValueAnimation(Consumer setter, float start, float end) { + this(setter, start, end, EasingType.LINEAR); } @Override protected void applyAnimation(float progress) { this.value = startValue + (endValue - startValue) * Easing.apply(easing, progress); - property.set(value); + setter.accept(value); } public ValueAnimation set(float startValue, float endValue){ @@ -53,7 +70,7 @@ public ValueAnimation endValue(float endValue) { public void setValue(float value) { this.value = value; - property.set(value); + setter.accept(value); } public float getValue() { diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java index b8957de..7b06d6c 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/ContextMenu.java @@ -3,7 +3,6 @@ import com.tanishisherewith.dynamichud.DynamicHUD; import com.tanishisherewith.dynamichud.config.GlobalConfig; import com.tanishisherewith.dynamichud.helpers.DrawHelper; -import com.tanishisherewith.dynamichud.helpers.animationhelper.AnimationProperty; import com.tanishisherewith.dynamichud.helpers.animationhelper.EasingType; import com.tanishisherewith.dynamichud.helpers.animationhelper.animations.ValueAnimation; import com.tanishisherewith.dynamichud.internal.System; @@ -70,17 +69,7 @@ public ContextMenu(int x, int y, @NotNull T properties, ContextMenuScreenFactory this.properties.getSkin().setContextMenu(this); this.layoutEngine = new LayoutEngine(); - this.scaleAnimation = new ValueAnimation(new AnimationProperty<>() { - @Override - public Float get() { - return animScale; - } - - @Override - public void set(Float value) { - animScale = value; - } - }, 0.0f, 1.0f); + this.scaleAnimation = new ValueAnimation(val-> animScale = val, 0.0f, 1.0f); this.scaleAnimation.easing(EasingType.EASE_IN_CUBIC); this.scaleAnimation.duration(GlobalConfig.get().getCmAnimationTimeInMs()); this.scaleAnimation.onComplete(() -> { diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java index c9c18f7..abfbf0b 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java @@ -2,7 +2,6 @@ import com.tanishisherewith.dynamichud.DynamicHUD; import com.tanishisherewith.dynamichud.helpers.DrawHelper; -import com.tanishisherewith.dynamichud.helpers.animationhelper.AnimationProperty; import com.tanishisherewith.dynamichud.helpers.animationhelper.EasingType; import com.tanishisherewith.dynamichud.helpers.animationhelper.animations.ValueAnimation; import com.tanishisherewith.dynamichud.utils.Util; @@ -489,7 +488,7 @@ public int getColor() { public class MinecraftBooleanRenderer implements SkinRenderer { @Override public void render(GuiGraphics graphics, BooleanOption option, int x, int y, int mouseX, int mouseY) { - graphics.drawString(mc.font, option.name, x + 15, y + 25 / 2 - 5, -1, true); + graphics.drawString(mc.font, option.name, x + panelWidth - 75 + 15, y + 25 / 2 - 5, -1, true); int width = 50; graphics.blitSprite(RenderPipelines.GUI_TEXTURED, TEXTURES.get(true, isMouseOver(mouseX, mouseY,x + panelWidth - 75, y, width, 20)), x + panelWidth - 75, y, width, 20); @@ -506,17 +505,7 @@ public class MinecraftColorOptionRenderer implements SkinRenderer { @Override public void init(ColorOption option) { - this.scaleAnimation = new ValueAnimation(new AnimationProperty<>() { - @Override - public Float get() { - return scale; - } - - @Override - public void set(Float value) { - scale = value; - } - }, 0.0f, 1.0f); + this.scaleAnimation = new ValueAnimation(val-> scale = val, 0.0f, 1.0f); scaleAnimation.easing(EasingType.EASE_OUT_BACK); scaleAnimation.duration(200); this.scaleAnimation.onComplete(() -> { diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java index 7d8e1de..b227536 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/ModernSkin.java @@ -3,7 +3,6 @@ import com.mojang.blaze3d.platform.cursor.CursorTypes; import com.tanishisherewith.dynamichud.helpers.ColorHelper; import com.tanishisherewith.dynamichud.helpers.DrawHelper; -import com.tanishisherewith.dynamichud.helpers.animationhelper.AnimationProperty; import com.tanishisherewith.dynamichud.helpers.animationhelper.EasingType; import com.tanishisherewith.dynamichud.helpers.animationhelper.animations.MathAnimations; import com.tanishisherewith.dynamichud.helpers.animationhelper.animations.SquishAnimator; @@ -157,10 +156,9 @@ private int computeGroupFullHeight(OptionGroup group, int groupX, int groupY, in // Adds a nice animation while opening and closing public void renderGroup(GuiGraphics graphics, OptionGroup group, int groupX, int groupY, int targetWidth, int mouseX, int mouseY) { GroupAnimData animData = groupAnimations.computeIfAbsent(group, g -> new GroupAnimData(16f)); - AnimationProperty heightProp = animData.property; - if (group.isExpanded() && heightProp.get() <= 16) { + if (group.isExpanded() && animData.value <= 16) { int fullHeight = computeGroupFullHeight(group, groupX, groupY, targetWidth); - heightProp.set((float) fullHeight); + animData.value = (float) fullHeight; } if (animData.animation != null) { @@ -170,8 +168,7 @@ public void renderGroup(GuiGraphics graphics, OptionGroup group, int groupX, int } } - float animatedHeight = heightProp.get(); - int groupHeight = Math.round(animatedHeight); + int groupHeight = Math.round(animData.value); if (group.isExpanded() && groupHeight > 16) { DrawHelper.drawRoundedRectangle(graphics, @@ -451,8 +448,7 @@ public boolean mouseClicked(ContextMenu menu, double mouseX, double mouseY, i group.setExpanded(willBeExpanded); GroupAnimData animData = groupAnimations.computeIfAbsent(group, g -> new GroupAnimData(16f)); - AnimationProperty heightProp = animData.property; - float current = heightProp.get(); + float current = animData.value; float target; if (willBeExpanded) { int targetWidthForGroup = (int) (width * 0.8f - 18); @@ -462,7 +458,7 @@ public boolean mouseClicked(ContextMenu menu, double mouseX, double mouseY, i target = 16f; } - ValueAnimation anim = new ValueAnimation(heightProp, current, target, EasingType.EASE_OUT_QUAD); + ValueAnimation anim = new ValueAnimation(val -> animData.value = val, current, target, EasingType.EASE_OUT_QUAD); anim.duration(200); anim.start(); animData.animation = anim; @@ -1024,17 +1020,14 @@ public Skin clone() { private static class GroupAnimData { - AnimationProperty property; + float value; ValueAnimation animation; GroupAnimData(float initial) { - property = new AnimationProperty() { - private float value = initial; - @Override public Float get() { return value; } - @Override public void set(Float v) { value = v; } - }; + this.value = initial; } } + public class ModernSearchBox extends EditBox { private static final int CORNER_RADIUS = 6; private static final int ICON_PADDING = 6; diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java index f8cbcec..8ee9254 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java @@ -328,7 +328,7 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { String formattedMinVal = formatValue(minValue); DrawHelper.scaleAndPosition(graphics.pose(), x - mc.font.width(formattedMinVal)/2.0f, y + gHeight,mc.font.width(formattedMinVal),mc.font.lineHeight * 0.5f, 0.5f); - graphics.drawString(mc.font, formattedMinVal, x - mc.font.width(formattedMinVal), (int) (y + gHeight), 0xFFFFFFFF, true); + graphics.drawString(mc.font, formattedMinVal, x - mc.font.width(formattedMinVal), (int) (y + gHeight - 1), 0xFFFFFFFF, true); DrawHelper.stopScaling(graphics.pose()); if(showGrid) x -= offset; From 4aa77ae8e52ff69a1247789635d25f24c6773a3d Mon Sep 17 00:00:00 2001 From: tanishisherewith <120117618+tanishisherewithhh@users.noreply.github.com> Date: Thu, 25 Jun 2026 21:28:23 +0530 Subject: [PATCH 19/22] Patch some more issues --- .../dynamichud/IntegrationTest.java | 3 +- .../contextmenu/skinsystem/MinecraftSkin.java | 6 +- .../dynamichud/widget/WidgetManager.java | 3 + .../dynamichud/widgets/GraphWidget.java | 133 ++++++++++++++++-- 4 files changed, 126 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/tanishisherewith/dynamichud/IntegrationTest.java b/src/main/java/com/tanishisherewith/dynamichud/IntegrationTest.java index 71f0bf9..85bd4c0 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/IntegrationTest.java +++ b/src/main/java/com/tanishisherewith/dynamichud/IntegrationTest.java @@ -76,7 +76,7 @@ public void init() { .graphColor(Color.CYAN) .anchor(Widget.Anchor._default()) .gWidth(100) - .gHeight(150) + .gHeight(75) .gridLines(10) .backgroundColor(Color.DARK_GRAY) .lineThickness(1f) @@ -91,6 +91,7 @@ public void init() { .registryKey("FPS") .registryID(registry.getId()) .build() + .setSampleInterval(120) .autoUpdateRange(); } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java index abfbf0b..cebe042 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java @@ -488,14 +488,14 @@ public int getColor() { public class MinecraftBooleanRenderer implements SkinRenderer { @Override public void render(GuiGraphics graphics, BooleanOption option, int x, int y, int mouseX, int mouseY) { - graphics.drawString(mc.font, option.name, x + panelWidth - 75 + 15, y + 25 / 2 - 5, -1, true); + graphics.drawString(mc.font, option.name, x + 15, y + 25 / 2 - 5, -1, true); int width = 50; graphics.blitSprite(RenderPipelines.GUI_TEXTURED, TEXTURES.get(true, isMouseOver(mouseX, mouseY,x + panelWidth - 75, y, width, 20)), x + panelWidth - 75, y, width, 20); Component Component = option.getBooleanType().getText(option.value); int color = option.value ? Color.GREEN.getRGB() : Color.RED.getRGB(); - graphics.drawString(mc.font, Component, (int) (option.getX() + (width / 2.0f) - (mc.font.width(Component) / 2.0f)), y + 5, color, true); + graphics.drawString(mc.font, Component, (int) (x + panelWidth - 75 + (width / 2.0f) - (mc.font.width(Component) / 2.0f)), y + 5, color, true); } } @@ -528,7 +528,7 @@ public void render(GuiGraphics graphics, ColorOption option, int x, int y, int m int shadowOpacity = Math.min(option.value.getAlpha(), 45); DrawHelper.drawRectangleWithShadowBadWay(graphics, - option.getX() + 4, + x + panelWidth - 45 + 4, y + 4, width - 8, 12, diff --git a/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetManager.java b/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetManager.java index 1e1aab6..889b1e6 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetManager.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetManager.java @@ -1,6 +1,7 @@ package com.tanishisherewith.dynamichud.widget; import com.tanishisherewith.dynamichud.DynamicHUD; +import com.tanishisherewith.dynamichud.config.GlobalConfig; import com.tanishisherewith.dynamichud.mixins.ScreenMixin; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; @@ -175,6 +176,8 @@ public static void saveWidgets(File file, List widgets) throws IOExcepti // If save operation was successful, replace the old file with the new one Files.move(tempFile.toPath(), file.toPath(), StandardCopyOption.REPLACE_EXISTING); + + GlobalConfig.HANDLER.save(); } /** diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java index 8ee9254..cb539d6 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java @@ -23,6 +23,7 @@ import net.minecraft.client.renderer.RenderPipelines; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; +import net.minecraft.util.Util; import org.joml.Matrix3x2f; import java.awt.*; @@ -59,6 +60,9 @@ public class GraphWidget extends DynamicValueWidget implements ContextMenuProvid private float valueScale; int offset = -2; + private long lastSampleTime = 0; + private long sampleIntervalMs = 100; + public GraphWidget(String registryID, String registryKey, String modId, Anchor anchor, float gWidth, float gHeight, int maxDataPoints, float minValue, float maxValue, Color graphColor, Color backgroundColor, float lineThickness, boolean showGrid, int gridLines, String label) { super(DATA, modId, anchor, registryID, registryKey); this.gWidth = gWidth; @@ -110,24 +114,90 @@ public GraphWidget autoUpdateRange() { return this; } - public void addDataPoint(Float value) { - if (value == null) return; - if (autoUpdateRange) { - if (getMaxValue() < value) { - setMaxValue(value + 10); - float diff = getMaxValue() - getPrevMaxValue(); - setMinValue(getMinValue() + diff); - } - if (getMinValue() > value) { - setMinValue(value - 10); - float diff = getPrevMinValue() - getMinValue(); - setMaxValue(getMaxValue() - diff); + /** + * Sets the timeline resolution (how many historical points are drawn on the graph width). + * Resizes the internal array live and shifts elements in order to prevent data loss. + */ + public void setMaxDataPoints(int newMax) { + if (newMax <= 2 || newMax == this.maxDataPoints) return; + + float[] newData = new float[newMax]; + int oldSize = this.maxDataPoints; + + // get historical data in order [oldest -> newest] + float[] chronologicalData = new float[oldSize]; + for (int i = 0; i < oldSize; i++) { + chronologicalData[i] = dataPoints[(head + i) % oldSize]; + } + + if (newMax >= oldSize) { + // Expand graph + float paddingValue = chronologicalData[0]; + int padCount = newMax - oldSize; + for (int i = 0; i < padCount; i++) { + newData[i] = paddingValue; } + System.arraycopy(chronologicalData, 0, newData, padCount, oldSize); + } else { + // Shrink graph + int skipCount = oldSize - newMax; + System.arraycopy(chronologicalData, skipCount, newData, 0, newMax); } + this.dataPoints = newData; + this.maxDataPoints = newMax; + this.head = 0; // Buffer is now sequential, next insertion index is flatly at 0 + + if (autoUpdateRange) { + recalculateDynamicBounds(); + } + } + + /** + * Sets the active polling sample throttle interval + * + * @param ms Time window separation between new samples in milliseconds. + */ + public GraphWidget setSampleInterval(long ms) { + this.sampleIntervalMs = Math.max(1L, ms); + return this; + } + + public long getSampleInterval() { + return this.sampleIntervalMs; + } + + /** + * check the active ring buffer values to adjust min/max boundaries + */ + private void recalculateDynamicBounds() { + float currentMin = Float.MAX_VALUE; + float currentMax = -Float.MAX_VALUE; + + for (float val : dataPoints) { + if (val < currentMin) currentMin = val; + if (val > currentMax) currentMax = val; + } + + float padding = (currentMax - currentMin) * 0.15f; + if (padding <= 0) padding = 2.0f; // Prevent division-by-zero + + setMinValue(currentMin - padding); + setMaxValue(currentMax + padding); + } + + public void addDataPoint(Float value) { + if (value == null) return; + int index = (head) % maxDataPoints; - dataPoints[index] = Math.clamp(value, minValue, maxValue); - head = (head + 1) % maxDataPoints; // Buffer full, overwrite oldest and move head + dataPoints[index] = value; + head = (head + 1) % maxDataPoints; + + if (autoUpdateRange) { + recalculateDynamicBounds(); + } else { + dataPoints[index] = Math.clamp(value, minValue, maxValue); + } } private List getInterpolatedPoints() { @@ -229,8 +299,10 @@ private void drawGradientShadow(GuiGraphics graphics, List points, floa @Override public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { - if (valueSupplier != null) { + long currentTime = Util.getMillis(); + if (valueSupplier != null && (currentTime - lastSampleTime >= sampleIntervalMs)) { addDataPoint(getValue()); + lastSampleTime = currentTime; } // Safety check. Happens on startup @@ -299,11 +371,13 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { drawInterpolatedCurve(graphics, points, graphColor.getRGB(), lineThickness); + DrawHelper.scaleAndPosition(graphics.pose(), x + 5, y + 5, 0.75f); DrawHelper.drawChromaText( graphics, label, x + 5, y + 5, 1.0f, 0.8f, 1.0f, 0.05f, true ); + DrawHelper.stopScaling(graphics.pose()); if (!points.isEmpty()) { float[] livePoint = points.getLast(); @@ -379,6 +453,28 @@ public void createMenu() { }, menu) .renderWhen(() -> this.showGrid) ); + menu.addOption(new BooleanOption(Component.literal("Auto Scale Range"), + () -> this.autoUpdateRange, value -> { + this.autoUpdateRange = value; + if (value) recalculateDynamicBounds(); + }, BooleanOption.BooleanType.YES_NO).description(Component.literal("Automatically updates Y-axis limits dynamically based on current values")) + .withComplexity(Option.Complexity.Simple) + ); + menu.addOption(new DoubleOption(Component.literal("Timeline Points"), + 10, 300, 5, + () -> (double) this.maxDataPoints, value -> { + this.setMaxDataPoints(value.intValue()); + this.computeOffset(); + }, menu).description(Component.literal("Adjusts how many total data points are saved on the visual timeline")) + .withComplexity(Option.Complexity.Enhanced) + ); + menu.addOption(new DoubleOption(Component.literal("Sample Cooldown (ms)"), + 10, 2000, 10, + () -> (double) this.sampleIntervalMs, value -> { + this.setSampleInterval(value.longValue()); + }, menu).description(Component.literal("Sets how often the graph polls for a new data point (in milliseconds)")) + .withComplexity(Option.Complexity.Pro) + ); menu.addOption(new ColorOption(Component.literal("Graph Line Color"), () -> this.graphColor, value -> this.graphColor = value, menu) .description(Component.literal("Specify the color you want for the graph's lines")) @@ -566,6 +662,7 @@ public static class GraphWidgetBuilder extends DynamicValueWidgetBuilder Date: Fri, 26 Jun 2026 12:25:21 +0530 Subject: [PATCH 20/22] Added ColorPicker back Improvements to MinecraftSkin --- .../dynamichud/IntegrationTest.java | 6 +- .../dynamichud/helpers/MouseColorQuery.java | 9 +- .../contextmenu/options/ColorOption.java | 2 +- .../options/coloroption/ColorGradient.java | 110 +++++++++++++----- .../coloroption/ColorPickerButton.java | 2 +- .../contextmenu/skinsystem/MinecraftSkin.java | 11 +- .../dynamichud/widgets/GraphWidget.java | 9 +- 7 files changed, 101 insertions(+), 48 deletions(-) diff --git a/src/main/java/com/tanishisherewith/dynamichud/IntegrationTest.java b/src/main/java/com/tanishisherewith/dynamichud/IntegrationTest.java index 85bd4c0..98b173c 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/IntegrationTest.java +++ b/src/main/java/com/tanishisherewith/dynamichud/IntegrationTest.java @@ -76,10 +76,10 @@ public void init() { .graphColor(Color.CYAN) .anchor(Widget.Anchor._default()) .gWidth(100) - .gHeight(75) + .gHeight(60) .gridLines(10) - .backgroundColor(Color.DARK_GRAY) - .lineThickness(1f) + .backgroundColor(Color.BLACK) + .lineThickness(0.6f) .maxDataPoints(100) .maxValue(120) .minValue(30) diff --git a/src/main/java/com/tanishisherewith/dynamichud/helpers/MouseColorQuery.java b/src/main/java/com/tanishisherewith/dynamichud/helpers/MouseColorQuery.java index 644b8ad..7626aba 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/helpers/MouseColorQuery.java +++ b/src/main/java/com/tanishisherewith/dynamichud/helpers/MouseColorQuery.java @@ -3,6 +3,7 @@ import com.mojang.blaze3d.pipeline.RenderTarget; import com.mojang.blaze3d.platform.Window; import com.mojang.blaze3d.systems.RenderSystem; +import com.tanishisherewith.dynamichud.DynamicHUD; import net.minecraft.client.Minecraft; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; @@ -22,13 +23,15 @@ public static void request(double mouseX, double mouseY, Consumer callbac pendingRequest = new SampleRequest(mouseX, mouseY, callback); } } + public static void request(Consumer callback) { + request(DynamicHUD.MC.mouseHandler.xpos(), DynamicHUD.MC.mouseHandler.ypos(), callback); + } public static void processIfPending() { if (pendingRequest == null) return; - Minecraft client = Minecraft.getInstance(); - RenderTarget framebuffer = client.getMainRenderTarget(); - Window window = client.getWindow(); + RenderTarget framebuffer = DynamicHUD.MC.getMainRenderTarget(); + Window window = DynamicHUD.MC.getWindow(); int windowWidth = window.getWidth(); int windowHeight = window.getHeight(); diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ColorOption.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ColorOption.java index cdc678a..9f4eb93 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ColorOption.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/ColorOption.java @@ -16,7 +16,7 @@ public class ColorOption extends Option { public ColorOption(Component name, Supplier getter, Consumer setter, ContextMenu parentMenu) { super(name, getter, setter); this.parentMenu = parentMenu; - this.colorGradient = new ColorGradient(x + this.parentMenu.getWidth(), y - 10, get(), this::set, 50, 150); + this.colorGradient = new ColorGradient(x + this.parentMenu.getWidth(), y - 10, get(), this::set, 50, 100); } @Override diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/ColorGradient.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/ColorGradient.java index ed82651..209c893 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/ColorGradient.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/ColorGradient.java @@ -4,8 +4,12 @@ import com.tanishisherewith.dynamichud.helpers.MouseColorQuery; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.navigation.ScreenRectangle; +import org.lwjgl.glfw.GLFW; import java.awt.*; +import java.util.ArrayList; +import java.util.List; import java.util.function.Consumer; public class ColorGradient { @@ -19,6 +23,8 @@ public class ColorGradient { private int x, y; private boolean display = false; + private Color hoveredColorPreview = null; + public ColorGradient(int x, int y, Color initialColor, Consumer onColorSelected, int boxSize, int colors) { this.x = x; this.y = y; @@ -49,6 +55,7 @@ public void display() { public void close() { display = false; + this.hoveredColorPreview = null; } public void render(GuiGraphics graphics, int x1, int y1, int mouseX, int mouseY) { @@ -58,51 +65,98 @@ public void render(GuiGraphics graphics, int x1, int y1, int mouseX, int mouseY) } gradientSlider.render(graphics, x, y + client.font.lineHeight + 4); gradientBox.render(graphics, x, y + client.font.lineHeight + gradientSlider.getHeight() + 10); - // colorPickerButton.render(graphics, x + 24 + boxSize, y + client.font.lineHeight + gradientSlider.getHeight() + 8); + colorPickerButton.render(graphics, x + 24 + boxSize, y + client.font.lineHeight + gradientSlider.getHeight() + 8); alphaSlider.render(graphics, x + 10 + boxSize, y + client.font.lineHeight + gradientSlider.getHeight() + 10); - if (colorPickerButton.isPicking() && GlobalConfig.get().showColorPickerPreview()) { - MouseColorQuery.request(mouseX, mouseY, colors -> { - if (colors != null) { - int red = colors[0]; - int green = colors[1]; - int blue = colors[2]; + if (colorPickerButton.isPicking()) { + if (GlobalConfig.get().showColorPickerPreview()) { + // Request the pixel color under the exact cursor position + MouseColorQuery.request(colors -> { + if (colors != null) { + this.hoveredColorPreview = new Color(colors[0], colors[1], colors[2]); + } + }); + + MouseColorQuery.processIfPending(); // process immediately + + renderPickerPreview(graphics, mouseX, mouseY); + } + } else { + this.hoveredColorPreview = null; + } + } + + public void renderPickerPreview(GuiGraphics graphics, int mouseX, int mouseY) { + if (hoveredColorPreview != null && colorPickerButton.isPicking() && GlobalConfig.get().showColorPickerPreview()) { + // Temporarily pop all active clipping zones off the scissor stack + // This will allow the preview to render over all screen scissors + List poppedScissors = new ArrayList<>(); + while (graphics.scissorStack.peek() != null) { + poppedScissors.add(graphics.scissorStack.peek()); + graphics.scissorStack.pop(); + } + + graphics.fill(mouseX + 6, mouseY + 6, mouseX + 22, mouseY + 22, 0xFFFFFFFF); + graphics.fill(mouseX + 7, mouseY + 7, mouseX + 21, mouseY + 21, hoveredColorPreview.getRGB() | 0xFF000000); - //Draw the preview box near the mouse pointer - graphics.fill(mouseX + 10, mouseY, mouseX + 26, mouseY + 16, -1); - graphics.fill(mouseX + 11, mouseY + 1, mouseX + 25, mouseY + 15, (red << 16) | (green << 8) | blue | 0xFF000000); + // Restore all clipping zones back to the stack in reverse order + if(!poppedScissors.isEmpty()) { + for (int i = poppedScissors.size() - 1; i >= 0; i--) { + graphics.scissorStack.push(poppedScissors.get(i)); } - }); + } } } + + /** + * Updates the internal states of the HSV sliders, alpha bar, and alerts the parent option on selection. + */ + private void updateSelectedColor(Color color) { + float[] hsv = Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), null); + gradientSlider.setHue(hsv[0]); + gradientBox.setHue(hsv[0]); + gradientBox.setSaturation(hsv[1]); + gradientBox.setValue(hsv[2]); + + int currentAlpha = alphaSlider.getColor().getAlpha(); + alphaSlider.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), currentAlpha)); + onColorSelected.accept(alphaSlider.getColor()); + } + public boolean mouseClicked(double mouseX, double mouseY, int button) { if (!display) { return false; } - /*if (colorPickerButton.onClick(mouseX, mouseY, button)) { + if (colorPickerButton.isPicking()) { + if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT) { + if (hoveredColorPreview != null) { + updateSelectedColor(hoveredColorPreview); + } else { + MouseColorQuery.processIfPending(); + MouseColorQuery.request(colors -> { + if (colors != null) { + updateSelectedColor(new Color(colors[0], colors[1], colors[2])); + } + }); + MouseColorQuery.processIfPending(); + } + + colorPickerButton.setPicking(false); + return true; + } + } + + if (colorPickerButton.onClick(mouseX, mouseY, button)) { return true; - } else*/ + } + if (gradientSlider.isMouseOver(mouseX, mouseY)) { gradientSlider.onClick(mouseX, mouseY, button); gradientBox.setHue(gradientSlider.getHue()); } else if (gradientBox.isMouseOver(mouseX, mouseY)) { gradientBox.onClick(mouseX, mouseY, button); - } /* else if (colorPickerButton.isPicking()) { - int[] colors = ColorHelper.getMousePixelColor(mouseX,mouseY); - if(colors != null) { - float[] hsv = Color.RGBtoHSB(colors[0], colors[1], colors[2], null); - gradientSlider.setHue(hsv[0]); - gradientBox.setHue(hsv[0]); - gradientBox.setSaturation(hsv[1]); - gradientBox.setValue(hsv[2]); - - colorPickerButton.setPicking(false); - } else { - DynamicHUD.logger.error("Invalid RGB pixel color at mouse pointer"); - } } - */ alphaSlider.setColor(new Color(gradientBox.getColor(), true)); alphaSlider.onClick(mouseX, mouseY, button); onColorSelected.accept(alphaSlider.getColor()); @@ -118,7 +172,7 @@ public boolean mouseReleased(double mouseX, double mouseY, int button) { } public boolean mouseDragged(double mouseX, double mouseY, int button) { - if (!display) { + if (!display || colorPickerButton.isPicking()) { return false; } gradientSlider.onDrag(mouseX, mouseY, button); diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/ColorPickerButton.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/ColorPickerButton.java index c4807bc..dcf0242 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/ColorPickerButton.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/options/coloroption/ColorPickerButton.java @@ -38,7 +38,7 @@ public int getWidth() { public boolean onClick(double mouseX, double mouseY, int button) { if (button == 0) { if (mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height) { - isPicking = true; + isPicking = !isPicking; return true; } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java index cebe042..c6e5fb3 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java +++ b/src/main/java/com/tanishisherewith/dynamichud/utils/contextmenu/skinsystem/MinecraftSkin.java @@ -187,12 +187,13 @@ public void renderContextMenu(GuiGraphics graphics, ContextMenu contextMenu, renderSearchBox(graphics, mouseX, mouseY); - this.enableContextMenuScissor(graphics); - contextMenu.setWidth(panelWidth - 4); contextMenu.y = imageY; renderOptionGroups(graphics, mouseX, mouseY); + + this.enableContextMenuScissor(graphics); + renderSelectedGroupOptions(graphics, mouseX, mouseY); contextMenu.setHeight(getContentHeight() + 15); @@ -491,6 +492,8 @@ public void render(GuiGraphics graphics, BooleanOption option, int x, int y, int graphics.drawString(mc.font, option.name, x + 15, y + 25 / 2 - 5, -1, true); int width = 50; + option.setPosition(x + panelWidth - 75, y); + option.setWidth(width); graphics.blitSprite(RenderPipelines.GUI_TEXTURED, TEXTURES.get(true, isMouseOver(mouseX, mouseY,x + panelWidth - 75, y, width, 20)), x + panelWidth - 75, y, width, 20); Component Component = option.getBooleanType().getText(option.value); @@ -540,7 +543,7 @@ public void render(GuiGraphics graphics, ColorOption option, int x, int y, int m option.setWidth(width); if (option.getColorGradient().getColorPickerButton().isPicking()) { - DrawHelper.disableScissor(graphics); + // DrawHelper.disableScissor(graphics); } int colorGradientWidth = option.getColorGradient().getBoxSize() + option.getColorGradient().getAlphaSlider().getWidth() + option.getColorGradient().getColorPickerButton().getWidth(); @@ -562,7 +565,7 @@ public void render(GuiGraphics graphics, ColorOption option, int x, int y, int m } if (option.getColorGradient().getColorPickerButton().isPicking()) { - DrawHelper.enableScissor(imageX, imageY + 2, panelWidth, panelHeight - 4, graphics); + // DrawHelper.enableScissor(imageX, imageY + 2, panelWidth, panelHeight - 4, graphics); } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java index cb539d6..b915eb7 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java @@ -371,7 +371,7 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { drawInterpolatedCurve(graphics, points, graphColor.getRGB(), lineThickness); - DrawHelper.scaleAndPosition(graphics.pose(), x + 5, y + 5, 0.75f); + DrawHelper.scaleAndPosition(graphics.pose(), x + 5, y + 5, 0.5f); DrawHelper.drawChromaText( graphics, label, x + 5, y + 5, @@ -453,13 +453,6 @@ public void createMenu() { }, menu) .renderWhen(() -> this.showGrid) ); - menu.addOption(new BooleanOption(Component.literal("Auto Scale Range"), - () -> this.autoUpdateRange, value -> { - this.autoUpdateRange = value; - if (value) recalculateDynamicBounds(); - }, BooleanOption.BooleanType.YES_NO).description(Component.literal("Automatically updates Y-axis limits dynamically based on current values")) - .withComplexity(Option.Complexity.Simple) - ); menu.addOption(new DoubleOption(Component.literal("Timeline Points"), 10, 300, 5, () -> (double) this.maxDataPoints, value -> { From fe1214d43ffb68645ac368622a6801dc377ad8f6 Mon Sep 17 00:00:00 2001 From: tanishisherewith <120117618+tanishisherewithhh@users.noreply.github.com> Date: Fri, 26 Jun 2026 13:22:38 +0530 Subject: [PATCH 21/22] Final improvements before release --- .../integration/DynamicHudConfigurator.java | 2 +- .../dynamichud/widget/Widget.java | 3 +- .../dynamichud/widget/WidgetBox.java | 8 ++-- .../dynamichud/widgets/GraphWidget.java | 37 ++++++++++++++++--- 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/tanishisherewith/dynamichud/integration/DynamicHudConfigurator.java b/src/main/java/com/tanishisherewith/dynamichud/integration/DynamicHudConfigurator.java index 7340598..61f80e5 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/integration/DynamicHudConfigurator.java +++ b/src/main/java/com/tanishisherewith/dynamichud/integration/DynamicHudConfigurator.java @@ -121,7 +121,7 @@ public void setupSaveEvents(File widgetsFile) { ServerPlayConnectionEvents.DISCONNECT.register((handler, packetSender) -> saveWidgetsSafely(widgetsFile, FILE_MAP.get(widgetsFile.getName()))); //When minecraft closes - ClientLifecycleEvents.CLIENT_STOPPING.register((mc)-> saveWidgetsSafely(widgetsFile, FILE_MAP.get(widgetsFile.getName()))); + ClientLifecycleEvents.CLIENT_STOPPING.register((mc)-> saveWidgetsSafely(widgetsFile, FILE_MAP.get(widgetsFile.getName()))); } @ApiStatus.Internal diff --git a/src/main/java/com/tanishisherewith/dynamichud/widget/Widget.java b/src/main/java/com/tanishisherewith/dynamichud/widget/Widget.java index b5a66ed..e25fb28 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widget/Widget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widget/Widget.java @@ -64,7 +64,7 @@ public abstract class Widget implements Input { protected Anchor anchor; // The chosen anchor point //Dimensions of the widget - protected WidgetBox widgetBox; + protected final WidgetBox widgetBox; private int startX, startY; protected int offsetX, offsetY; // Offset from the anchor point @@ -376,7 +376,6 @@ public void readFromTag(CompoundTag tag) { isVisible = tag.getBoolean("isVisible").orElse(true); isDraggable = tag.getBoolean("isDraggable").orElse(true); canScale = tag.getBoolean("canScale").orElse(true); - widgetBox.setScale(tag.getFloat("widgetScale").orElse(1.0f)); } diff --git a/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetBox.java b/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetBox.java index 8cd8cc5..efd5591 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetBox.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widget/WidgetBox.java @@ -84,11 +84,11 @@ private void setSize(float width, float height, boolean shouldScale, float scale } } - public void setDimensions(float x, float y, float width, float height, boolean shouldScale) { - this.setDimensions(x,y,width,height,shouldScale,getScale()); + public void setDimensions(float x, float y, float width, float height, boolean canScale) { + this.setDimensions(x,y,width,height,canScale,getScale()); } - public void setSize(float width, float height, boolean shouldScale) { - this.setSize(width,height,shouldScale,getScale()); + public void setSize(float width, float height, boolean canScale) { + this.setSize(width,height,canScale,getScale()); } } diff --git a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java index b915eb7..94b1175 100644 --- a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java +++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java @@ -55,6 +55,9 @@ public class GraphWidget extends DynamicValueWidget implements ContextMenuProvid private String label; /// Automatically update the min and max of the graph private boolean autoUpdateRange = false; + ///The min range between the min/max of graph + public float minRangeSpan = 10f; + private float stepY; private float valueStep; private float valueScale; @@ -85,7 +88,7 @@ private void internal_init() { Validate.isTrue(maxDataPoints > 2, "MaxDataPoints should be more than 2."); this.dataPoints = new float[maxDataPoints]; this.label = label.trim(); - this.widgetBox = new WidgetBox(x, y, (int) gWidth, (int) gHeight); + this.widgetBox.setDimensions(x, y, (int) gWidth, (int) gHeight, canScale); this.stepY = gHeight / (gridLines + 1); this.valueStep = (maxValue - minValue) / (gridLines + 1); this.valueScale = (float) Math.clamp((stepY / 9.5), 0.0f, 1.0f); @@ -179,11 +182,33 @@ private void recalculateDynamicBounds() { if (val > currentMax) currentMax = val; } - float padding = (currentMax - currentMin) * 0.15f; - if (padding <= 0) padding = 2.0f; // Prevent division-by-zero + int intervals = gridLines + 1; + float rawSpan = currentMax - currentMin; + + // Apply 15% padding on top and bottom of the raw range + float paddedSpan = rawSpan * 1.30f; + float requiredSpan = Math.max(paddedSpan, minRangeSpan); + + // Find the most appropriate whole number step size + float stepSize = 1.0f; + float[] candidates = {1f, 2f, 5f, 10f, 20f, 25f, 50f, 100f, 200f, 500f, 1000f, 2000f, 5000f}; + for (float c : candidates) { + if (c * intervals >= requiredSpan) { + stepSize = c; + break; + } + stepSize = c; // Fallback to maximum candidate if range is massive + } + + float center = (currentMin + currentMax) / 2.0f; + float targetMin = center - (intervals * stepSize) / 2.0f; + targetMin = Math.round(targetMin / stepSize) * stepSize; + float targetMax = targetMin + (intervals * stepSize); + + setMinValue(targetMin); + setMaxValue(targetMax); - setMinValue(currentMin - padding); - setMaxValue(currentMax + padding); + this.computeOffset(); } public void addDataPoint(Float value) { @@ -401,7 +426,7 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) { String formattedMinVal = formatValue(minValue); - DrawHelper.scaleAndPosition(graphics.pose(), x - mc.font.width(formattedMinVal)/2.0f, y + gHeight,mc.font.width(formattedMinVal),mc.font.lineHeight * 0.5f, 0.5f); + DrawHelper.scaleAndPosition(graphics.pose(), x - mc.font.width(formattedMinVal)/2.0f, y + gHeight,mc.font.width(formattedMinVal),mc.font.lineHeight * 0.6f, 0.6f); graphics.drawString(mc.font, formattedMinVal, x - mc.font.width(formattedMinVal), (int) (y + gHeight - 1), 0xFFFFFFFF, true); DrawHelper.stopScaling(graphics.pose()); From 682471d8d531cea8f44fab345081e615ef4ca3ea Mon Sep 17 00:00:00 2001 From: tanishisherewith <120117618+tanishisherewithhh@users.noreply.github.com> Date: Fri, 26 Jun 2026 13:24:01 +0530 Subject: [PATCH 22/22] Bump to 4.0.0 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 1c7c0d3..d4c996a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ loom_version=1.14-SNAPSHOT # Mod Properties # need versioning system -mod_version = 3.1.0 +mod_version = 4.0.0 maven_group = com.tanishisherewith archives_base_name = dynamichud