widgets;
private boolean renderInGameHud = true;
- private int Z_Index = -1;
+ //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
*
- * 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 +95,26 @@ 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);
+ }
+
+ if(GlobalConfig.get().doSmartSnapping()) {
+ drawSnapGuides(graphics);
}
return;
}
@@ -111,15 +122,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 +150,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 +166,8 @@ public void charTyped(char c, int modifiers) {
}
public void onCloseScreen() {
- if (DynamicHUD.MC.currentScreen instanceof AbstractMoveableScreen) {
+ clearSnapLines();
+ if (DynamicHUD.MC.screen instanceof AbstractMoveableScreen) {
for (Widget widget : widgets) {
widget.onClose();
}
@@ -168,13 +180,18 @@ public List getWidgets() {
@Override
public boolean mouseReleased(double mouseX, double mouseY, int button) {
- Screen currentScreen = DynamicHUD.MC.currentScreen;
+ selectedWidget = null;
+ clearSnapLines();
+
+ Screen currentScreen = DynamicHUD.MC.screen;
if (currentScreen == null) {
return false;
}
if (currentScreen instanceof AbstractMoveableScreen) {
for (Widget widget : widgets) {
- widget.mouseReleased(mouseX, mouseY, button);
+ if(widget.mouseReleased(mouseX, mouseY, button)){
+ return true;
+ }
}
}
return false;
@@ -186,7 +203,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;
}
@@ -196,17 +213,21 @@ 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;
}
@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 +237,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 +245,168 @@ public void keyReleased(int key, int scanCode, int modifiers) {
}
}
- public WidgetRenderer withZIndex(int z_Index) {
- this.Z_Index = z_Index;
- return this;
+ /**
+ * 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 e2e0d44..94b1175 100644
--- a/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java
+++ b/src/main/java/com/tanishisherewith/dynamichud/widgets/GraphWidget.java
@@ -1,9 +1,9 @@
package com.tanishisherewith.dynamichud.widgets;
-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.contextmenu.ContextMenu;
@@ -14,16 +14,17 @@
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;
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.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.*;
import java.util.ArrayList;
@@ -49,20 +50,26 @@ 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;
+ ///The min range between the min/max of graph
+ public float minRangeSpan = 10f;
+
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) {
+ 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.width = width;
- this.height = height;
+ this.gWidth = gWidth;
+ this.gHeight = gHeight;
this.maxDataPoints = maxDataPoints;
this.graphColor = graphColor;
this.backgroundColor = backgroundColor;
@@ -74,8 +81,6 @@ public GraphWidget(String registryID, String registryKey, String modId, Anchor a
this.setMaxValue(maxValue);
internal_init();
-
- createMenu();
ContextMenuManager.getInstance().registerProvider(this);
}
@@ -83,22 +88,24 @@ 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.setDimensions(x, y, (int) gWidth, (int) gHeight, canScale);
+ this.stepY = gHeight / (gridLines + 1);
this.valueStep = (maxValue - minValue) / (gridLines + 1);
- this.scale = (float) MathHelper.clamp((stepY / 9.5), 0.0f, 1.0f);
+ this.valueScale = (float) Math.clamp((stepY / 9.5), 0.0f, 1.0f);
+
computeOffset();
- setTooltipText(Text.of("Graph displaying: " + label));
+ setTooltipText(Component.literal("Graph displaying: " + label));
+ createMenu();
}
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;
}
@@ -110,106 +117,217 @@ 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);
+ /**
+ * 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;
}
- if (getMinValue() > value) {
- setMinValue(value - 10);
- float diff = getPrevMinValue() - getMinValue();
- setMaxValue(getMaxValue() - diff);
+ 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;
+ }
+
+ 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);
+
+ this.computeOffset();
+ }
+
+ public void addDataPoint(Float value) {
+ if (value == null) return;
+
int index = (head) % maxDataPoints;
- dataPoints[index] = MathHelper.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() {
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);
+
+ 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);
+ }
+
+ // Calculate Monotone Cubic Spline Tangents
+ 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;
+ } else {
+ m[i] = (sPrev + sNext) / 2.0f;
+ 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;
+ }
+ }
+ }
+ }
+
+ int stepsPerSegment = 32;
+ float stepSize = 1.0f / stepsPerSegment;
+
for (int i = 0; i < dataPoints.length - 1; i++) {
- int index1 = (head + i) % dataPoints.length;
- int index2 = (head + i + 1) % dataPoints.length;
+ float y0 = yVals[i];
+ float y1 = yVals[i + 1];
+ float m0 = m[i];
+ float m1 = m[i + 1];
+ float x0 = x + i * xStep;
- 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);
+ for (int step = 0; step <= stepsPerSegment; step++) {
+ // Avoid redundant overlapping nodes between adjoining segments
+ if (step == stepsPerSegment && i < dataPoints.length - 2) continue;
- // Add interpolated points using hermite spline (simplified)
- for (float t = 0; t <= 1; t += 0.03f) {
+ float t = step * stepSize;
float t2 = t * t;
float t3 = t2 * t;
+
+ // Cubic Hermite Spline formulation
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;
+
+ py = Math.clamp(py, y, y + gHeight);
+
+ if (points.isEmpty()) {
+ points.add(new float[]{px, py});
+ } else {
+ 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});
+ }
+ }
}
}
return points;
}
// 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, new Matrix3x2f(graphics.pose()), CustomRenderLayers.QUADS_CUSTOM_BLEND, (int) gWidth, (int) gHeight, 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, new Matrix3x2f(graphics.pose()), RenderPipelines.DEBUG_QUADS, (int) gWidth, (int) gHeight, graphics.scissorStack.peek())
+ );
}
@Override
- public void renderWidget(DrawContext context, int mouseX, int mouseY) {
- if (valueSupplier != null) {
+ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY) {
+ long currentTime = Util.getMillis();
+ if (valueSupplier != null && (currentTime - lastSampleTime >= sampleIntervalMs)) {
addDataPoint(getValue());
+ lastSampleTime = currentTime;
}
// Safety check. Happens on startup
@@ -217,20 +335,20 @@ 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
+ // Draw gradient background with rounded corners
if (!isInEditor) {
DrawHelper.drawRoundedRectangle(
- context,
+ graphics,
x + offset,
y,
false,
true,
false,
false,
- width,
- height,
+ gWidth,
+ gHeight,
4,
backgroundColor.getRGB()
);
@@ -238,143 +356,176 @@ public void renderWidget(DrawContext context, 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;
- DrawHelper.drawHorizontalLine(context, 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);
String valueText = formatValue(value);
- float texWidth = mc.textRenderer.getWidth(valueText) * scale;
+ float texWidth = mc.font.width(valueText);
- //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 + 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());
}
- // Update the offsets for the rest of the elements drawn.
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(context, xPos, y, height, 0.5f, 0x4DFFFFFF);
+ DrawHelper.drawVerticalLine(graphics, xPos, y, gHeight, 0.5f, 0x4DFFFFFF);
}
}
- // Draw interpolated graph curve
List points = getInterpolatedPoints();
- drawInterpolatedCurve(context, points, graphColor.getRGB(), lineThickness);
+
// Draw shadow effect under the graph
drawGradientShadow(
- context, points, y + height,
- ColorHelper.changeAlpha(graphColor, 50).getRGB(),
+ graphics, points, y + gHeight,
+ ColorHelper.changeAlpha(graphColor, 60).getRGB(),
0x00000000
);
+ drawInterpolatedCurve(graphics, points, graphColor.getRGB(), lineThickness);
+
+ DrawHelper.scaleAndPosition(graphics.pose(), x + 5, y + 5, 0.5f);
DrawHelper.drawChromaText(
- context, label,
+ 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();
+
+ DrawHelper.drawFilledCircle(graphics, livePoint[0], livePoint[1], 0.9f, 0x26FFFFFF);
+ }
// 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, 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.textRenderer, formattedMaxVal, x - 5 - mc.textRenderer.getWidth(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(context.getMatrices(), 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());
+
+ 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());
if(showGrid) x -= offset;
- this.widgetBox.setDimensions(x, y, width + offset, height, shouldScale, GlobalConfig.get().getScale());
- DrawHelper.disableScissor();
+ this.widgetBox.setDimensions(x, y, gWidth + offset, gHeight, canScale);
+ // DrawHelper.disableScissor();
if (menu != null) menu.set(getX(), getY(), (int) Math.ceil(getHeight()));
}
// 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);
}
}
@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() {
- 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(Text.of("Show Grid"),
- () -> this.showGrid, value -> this.showGrid = value,
+ menu.addOption(new BooleanOption(Component.literal("Show Grid"),
+ () -> this.showGrid, value -> {
+ this.showGrid = value;
+ this.computeOffset();
+ },
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());
- computeOffset();
+ this.computeOffset();
}, menu)
.renderWhen(() -> this.showGrid)
);
- menu.addOption(new ColorOption(Text.of("Graph Line Color"),
+ 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(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"),
- 0.5f, 5.0f, 0.1f,
+ menu.addOption(new DoubleOption(Component.literal("Line Thickness"),
+ 0.5f, 1f, 0.01f,
() -> (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.
- // Idk how this will break.
- if(mc.textRenderer == null) return;
+ if(!showGrid) {
+ offset = 0;
+ return;
+ }
+ // 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));
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.valueScale),
+ (int) Math.ceil(mc.font.width(lastText) * this.valueScale)
);
}
@@ -430,33 +581,15 @@ 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.scale = (float) MathHelper.clamp((stepY / 9.5), 0.0f, 1.0f);
+ this.valueScale = (float) Math.clamp((stepY / 9.5), 0.0f, 1.0f);
}
public boolean isShowGrid() {
@@ -490,10 +623,10 @@ 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);
+ tag.putFloat("gWidth", gWidth);
+ tag.putFloat("gHeight", gHeight);
tag.putInt("maxDataPoints", maxDataPoints);
tag.putFloat("minValue", minValue);
tag.putFloat("maxValue", maxValue);
@@ -508,10 +641,10 @@ 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);
+ 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);
@@ -528,7 +661,6 @@ public void readFromTag(NbtCompound tag) {
this.setMaxValue(maxValue);
internal_init();
- createMenu();
}
@Override
@@ -537,9 +669,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;
@@ -549,6 +680,7 @@ public static class GraphWidgetBuilder extends DynamicValueWidgetBuilder 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,71 +50,112 @@ 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"),
+ // 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)
- .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"),
- 1, 5.0f, 1,
+ menu.addOption(new DoubleOption(Component.literal("Rainbow Speed"),
+ 1, 5, 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)
);
+ 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")));
+
+ AtomicReference style = new AtomicReference<>("Style1");
+ AtomicReference align = new AtomicReference<>(GroupLayout.Alignment.CENTER);
+
+ // List Option
+ List styles = Arrays.asList("Style1", "Style2", "Style3");
+ menu.addOption(new CycleOption<>(Component.literal("Text Style"), style::get, style::set, styles));
+
+ // Enum Option
+ menu.addOption(new CycleOption<>(Component.literal("Alignment"), align::get, align::set, GroupLayout.Alignment.values()));
+
+
+ // 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.canScale);
}
- menu.set(getX(), getY(), (int) Math.ceil(getHeight()));
+ menu.set(getX(), getY(), (int) Math.ceil(getHeight()));
}
@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
@@ -118,7 +165,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 +177,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);
@@ -139,8 +186,6 @@ public void readFromTag(NbtCompound 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();
}
@@ -187,7 +232,7 @@ public TextWidget build() {
widget.setPosition(x, y);
widget.setDraggable(isDraggable);
- widget.setShouldScale(shouldScale);
+ widget.setCanScale(shouldScale);
return widget;
}
}
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}",