add GUIScale slider for the client's own hud and clickgui
new 0.5x-2.0x slider in the ClickGui settings scales the clickgui, the hud editor panel and every hud module about its own anchor. mouse coordinates are divided back into layout units on entry so dragging, sliders and hover checks keep working, hud hit boxes and drag clamping use the scaled extents, and the font rasterizer follows the ui scale so text stays one texel per screen pixel at any scale factor
This commit is contained in:
@@ -4,6 +4,7 @@ import cc.fros.Fros;
|
|||||||
import cc.fros.features.Feature;
|
import cc.fros.features.Feature;
|
||||||
import cc.fros.features.gui.items.buttons.ModuleButton;
|
import cc.fros.features.gui.items.buttons.ModuleButton;
|
||||||
import cc.fros.features.modules.Module;
|
import cc.fros.features.modules.Module;
|
||||||
|
import cc.fros.features.modules.client.ClickGuiModule;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
import net.minecraft.client.gui.screens.Screen;
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
@@ -84,27 +85,39 @@ public class FrosGui extends Screen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
context.fill(0, 0, context.guiWidth(), context.guiHeight(), new Color(0, 0, 0, 120).hashCode());
|
context.fill(0, 0, context.guiWidth(), context.guiHeight(), new Color(0, 0, 0, 120).hashCode());
|
||||||
this.widgets.forEach(components -> components.drawScreen(context, mouseX, mouseY, delta));
|
|
||||||
|
// scale the whole clickgui; widgets work in layout units so mouse
|
||||||
|
// coordinates are divided back down before they reach them
|
||||||
|
float scale = ClickGuiModule.scale();
|
||||||
|
int layoutX = (int) (mouseX / scale);
|
||||||
|
int layoutY = (int) (mouseY / scale);
|
||||||
|
context.pose().pushMatrix();
|
||||||
|
context.pose().scale(scale, scale);
|
||||||
|
this.widgets.forEach(components -> components.drawScreen(context, layoutX, layoutY, delta));
|
||||||
|
context.pose().popMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mouseClicked(MouseButtonEvent click, boolean doubled) {
|
public boolean mouseClicked(MouseButtonEvent click, boolean doubled) {
|
||||||
this.widgets.forEach(components -> components.mouseClicked((int) click.x(), (int) click.y(), click.button()));
|
float scale = ClickGuiModule.scale();
|
||||||
|
this.widgets.forEach(components -> components.mouseClicked((int) (click.x() / scale), (int) (click.y() / scale), click.button()));
|
||||||
return super.mouseClicked(click, doubled);
|
return super.mouseClicked(click, doubled);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mouseReleased(MouseButtonEvent click) {
|
public boolean mouseReleased(MouseButtonEvent click) {
|
||||||
this.widgets.forEach(components -> components.mouseReleased((int) click.x(), (int) click.y(), click.button()));
|
float scale = ClickGuiModule.scale();
|
||||||
|
this.widgets.forEach(components -> components.mouseReleased((int) (click.x() / scale), (int) (click.y() / scale), click.button()));
|
||||||
return super.mouseReleased(click);
|
return super.mouseReleased(click);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) {
|
public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) {
|
||||||
|
int step = Math.max(1, Math.round((float) (10 / ClickGuiModule.scale())));
|
||||||
if (verticalAmount < 0) {
|
if (verticalAmount < 0) {
|
||||||
this.widgets.forEach(component -> component.setY(component.getY() - 10));
|
this.widgets.forEach(component -> component.setY(component.getY() - step));
|
||||||
} else if (verticalAmount > 0) {
|
} else if (verticalAmount > 0) {
|
||||||
this.widgets.forEach(component -> component.setY(component.getY() + 10));
|
this.widgets.forEach(component -> component.setY(component.getY() + step));
|
||||||
}
|
}
|
||||||
return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount);
|
return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import cc.fros.Fros;
|
|||||||
import cc.fros.features.Feature;
|
import cc.fros.features.Feature;
|
||||||
import cc.fros.features.gui.items.buttons.ModuleButton;
|
import cc.fros.features.gui.items.buttons.ModuleButton;
|
||||||
import cc.fros.features.modules.Module;
|
import cc.fros.features.modules.Module;
|
||||||
|
import cc.fros.features.modules.client.ClickGuiModule;
|
||||||
import cc.fros.features.modules.client.HudModule;
|
import cc.fros.features.modules.client.HudModule;
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
import net.minecraft.client.gui.screens.Screen;
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
@@ -40,27 +41,37 @@ public class HudEditorScreen extends Screen {
|
|||||||
@Override
|
@Override
|
||||||
public void render(GuiGraphics context, int mouseX, int mouseY, float delta) {
|
public void render(GuiGraphics context, int mouseX, int mouseY, float delta) {
|
||||||
anyHover = false;
|
anyHover = false;
|
||||||
this.components.forEach(component -> component.drawScreen(context, mouseX, mouseY, delta));
|
// same ui scale treatment as the clickgui
|
||||||
|
float scale = ClickGuiModule.scale();
|
||||||
|
int layoutX = (int) (mouseX / scale);
|
||||||
|
int layoutY = (int) (mouseY / scale);
|
||||||
|
context.pose().pushMatrix();
|
||||||
|
context.pose().scale(scale, scale);
|
||||||
|
this.components.forEach(component -> component.drawScreen(context, layoutX, layoutY, delta));
|
||||||
|
context.pose().popMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mouseClicked(MouseButtonEvent click, boolean doubled) {
|
public boolean mouseClicked(MouseButtonEvent click, boolean doubled) {
|
||||||
this.components.forEach(component -> component.mouseClicked((int) click.x(), (int) click.y(), click.button()));
|
float scale = ClickGuiModule.scale();
|
||||||
|
this.components.forEach(component -> component.mouseClicked((int) (click.x() / scale), (int) (click.y() / scale), click.button()));
|
||||||
return super.mouseClicked(click, doubled);
|
return super.mouseClicked(click, doubled);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mouseReleased(MouseButtonEvent click) {
|
public boolean mouseReleased(MouseButtonEvent click) {
|
||||||
this.components.forEach(component -> component.mouseReleased((int) click.x(), (int) click.y(), click.button()));
|
float scale = ClickGuiModule.scale();
|
||||||
|
this.components.forEach(component -> component.mouseReleased((int) (click.x() / scale), (int) (click.y() / scale), click.button()));
|
||||||
return super.mouseReleased(click);
|
return super.mouseReleased(click);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) {
|
public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) {
|
||||||
|
int step = Math.max(1, Math.round((float) (10 / ClickGuiModule.scale())));
|
||||||
if (verticalAmount < 0) {
|
if (verticalAmount < 0) {
|
||||||
this.components.forEach(component -> component.setY(component.getY() - 10));
|
this.components.forEach(component -> component.setY(component.getY() - step));
|
||||||
} else if (verticalAmount > 0) {
|
} else if (verticalAmount > 0) {
|
||||||
this.components.forEach(component -> component.setY(component.getY() + 10));
|
this.components.forEach(component -> component.setY(component.getY() + step));
|
||||||
}
|
}
|
||||||
return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount);
|
return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ public class ClickGuiModule extends Module {
|
|||||||
public final Setting<Boolean> minecraftFont = bool("MinecraftFont", false);
|
public final Setting<Boolean> minecraftFont = bool("MinecraftFont", false);
|
||||||
public final Setting<String> font = str("Font", "SansSerif");
|
public final Setting<String> font = str("Font", "SansSerif");
|
||||||
public final Setting<Integer> fontSize = num("FontSize", 10, 6, 24);
|
public final Setting<Integer> fontSize = num("FontSize", 10, 6, 24);
|
||||||
|
public final Setting<Float> guiScale = num("GUIScale", 1.0f, 0.5f, 2.0f);
|
||||||
public final Setting<String> prefix = str("Prefix", ".");
|
public final Setting<String> prefix = str("Prefix", ".");
|
||||||
public final Setting<Color> color = color("Color", 0, 0, 255, 180);
|
public final Setting<Color> color = color("Color", 0, 0, 255, 180);
|
||||||
public final Setting<Color> topColor = color("TopColor", 0, 0, 150, 240);
|
public final Setting<Color> topColor = color("TopColor", 0, 0, 150, 240);
|
||||||
@@ -75,4 +76,9 @@ public class ClickGuiModule extends Module {
|
|||||||
public static ClickGuiModule getInstance() {
|
public static ClickGuiModule getInstance() {
|
||||||
return INSTANCE;
|
return INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** ui scale factor applied to the client's own hud and clickgui */
|
||||||
|
public static float scale() {
|
||||||
|
return INSTANCE == null ? 1f : Math.max(0.5f, INSTANCE.guiScale.getValue());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -30,19 +30,36 @@ public abstract class HudModule extends Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public float getY() {
|
public float getY() {
|
||||||
|
float scaledHeight = getHeight() * ClickGuiModule.scale();
|
||||||
float heightWithChat = mc.getWindow().getGuiScaledHeight() - 14;
|
float heightWithChat = mc.getWindow().getGuiScaledHeight() - 14;
|
||||||
float baseY = mc.getWindow().getGuiScaledHeight() * pos.getValue().y();
|
float baseY = mc.getWindow().getGuiScaledHeight() * pos.getValue().y();
|
||||||
float combined = baseY + getHeight();
|
float combined = baseY + scaledHeight;
|
||||||
|
|
||||||
if (mc.screen instanceof ChatScreen) {
|
if (mc.screen instanceof ChatScreen) {
|
||||||
baseY = Math.min(combined, heightWithChat) - getHeight();
|
baseY = Math.min(combined, heightWithChat) - scaledHeight;
|
||||||
}
|
}
|
||||||
return baseY;
|
return baseY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void onRender2DHud(Render2DEvent e) {
|
public void onRender2DHud(Render2DEvent e) {
|
||||||
render(e);
|
float scale = ClickGuiModule.scale();
|
||||||
|
if (scale == 1f) {
|
||||||
|
render(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// scale the element about its own position anchor so content,
|
||||||
|
// editor box and hover label all grow together
|
||||||
|
float anchorX = getX();
|
||||||
|
float anchorY = getY();
|
||||||
|
e.getContext().pose().pushMatrix();
|
||||||
|
e.getContext().pose().translate(anchorX * (1f - scale), anchorY * (1f - scale));
|
||||||
|
e.getContext().pose().scale(scale, scale);
|
||||||
|
try {
|
||||||
|
render(e);
|
||||||
|
} finally {
|
||||||
|
e.getContext().pose().popMatrix();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
@@ -75,10 +92,11 @@ public abstract class HudModule extends Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dragging) {
|
if (dragging) {
|
||||||
|
float scale = ClickGuiModule.scale();
|
||||||
float finalX = Math.min(Math.max(getMouseX() - dragX, 0),
|
float finalX = Math.min(Math.max(getMouseX() - dragX, 0),
|
||||||
mc.getWindow().getGuiScaledWidth() - width);
|
mc.getWindow().getGuiScaledWidth() - width * scale);
|
||||||
float finalY = Math.min(Math.max(getMouseY() - dragY, 0),
|
float finalY = Math.min(Math.max(getMouseY() - dragY, 0),
|
||||||
mc.getWindow().getGuiScaledHeight() - height);
|
mc.getWindow().getGuiScaledHeight() - height * scale);
|
||||||
|
|
||||||
pos.setValue(new Vector2f(finalX, finalY)
|
pos.setValue(new Vector2f(finalX, finalY)
|
||||||
.div(mc.getWindow().getGuiScaledWidth(), mc.getWindow().getGuiScaledHeight()));
|
.div(mc.getWindow().getGuiScaledWidth(), mc.getWindow().getGuiScaledHeight()));
|
||||||
@@ -95,8 +113,10 @@ public abstract class HudModule extends Module {
|
|||||||
if (shouldDrawDescription) {
|
if (shouldDrawDescription) {
|
||||||
int textWidth = FrosFont.width(getName());
|
int textWidth = FrosFont.width(getName());
|
||||||
int textHeight = FrosFont.lineHeight();
|
int textHeight = FrosFont.lineHeight();
|
||||||
|
float scale = ClickGuiModule.scale();
|
||||||
float textX = x + width + 5;
|
float textX = x + width + 5;
|
||||||
if (textX + textWidth > mc.getWindow().getGuiScaledWidth()) {
|
// the label is drawn inside the element's scale transform
|
||||||
|
if (x + (textX + textWidth - x) * scale > mc.getWindow().getGuiScaledWidth()) {
|
||||||
textX = x - 5 - textWidth;
|
textX = x - 5 - textWidth;
|
||||||
}
|
}
|
||||||
FrosFont.draw(e.getContext(), getName(),
|
FrosFont.draw(e.getContext(), getName(),
|
||||||
@@ -129,9 +149,10 @@ public abstract class HudModule extends Module {
|
|||||||
float y = getY();
|
float y = getY();
|
||||||
int mouseX = getMouseX();
|
int mouseX = getMouseX();
|
||||||
int mouseY = getMouseY();
|
int mouseY = getMouseY();
|
||||||
|
float scale = ClickGuiModule.scale();
|
||||||
|
|
||||||
return mouseX >= x - 1 && mouseX <= x + width + 1 &&
|
return mouseX >= x - 1 && mouseX <= x + width * scale + 1 &&
|
||||||
mouseY >= y - 1 && mouseY <= y + height + 1;
|
mouseY >= y - 1 && mouseY <= y + height * scale + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getWidth() {
|
public float getWidth() {
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ public final class FrosFont {
|
|||||||
private static FontMetrics metrics;
|
private static FontMetrics metrics;
|
||||||
private static String loadedName;
|
private static String loadedName;
|
||||||
private static float loadedSize = Float.NaN;
|
private static float loadedSize = Float.NaN;
|
||||||
private static int loadedScale = 1;
|
private static float loadedScale = 1;
|
||||||
private static long lastAttempt;
|
private static long lastAttempt;
|
||||||
private static int glyphCounter;
|
private static int glyphCounter;
|
||||||
|
|
||||||
@@ -110,14 +110,16 @@ public final class FrosFont {
|
|||||||
|
|
||||||
/** converts a raster pixel measurement to gui units */
|
/** converts a raster pixel measurement to gui units */
|
||||||
private static int toGui(int pixels) {
|
private static int toGui(int pixels) {
|
||||||
return (pixels + loadedScale - 1) / loadedScale;
|
return (int) Math.ceil(pixels / (double) loadedScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int currentScale() {
|
private static float currentScale() {
|
||||||
try {
|
try {
|
||||||
return Math.max(1, (int) Math.round(mc.getWindow().getGuiScale()));
|
// one raster pixel per screen pixel, following both mc's gui scale
|
||||||
|
// and the client's own ui scale slider
|
||||||
|
return Math.max(0.5f, (float) (mc.getWindow().getGuiScale() * ClickGuiModule.scale()));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return 1;
|
return 1f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,7 +156,7 @@ public final class FrosFont {
|
|||||||
String name = gui == null || vanilla ? "" : gui.font.getValue();
|
String name = gui == null || vanilla ? "" : gui.font.getValue();
|
||||||
int size = gui == null ? 10 : gui.fontSize.getValue();
|
int size = gui == null ? 10 : gui.fontSize.getValue();
|
||||||
if (name == null) name = "";
|
if (name == null) name = "";
|
||||||
int scale = currentScale();
|
float scale = currentScale();
|
||||||
|
|
||||||
boolean changed = !Objects.equals(name, loadedName) || size != loadedSize || scale != loadedScale;
|
boolean changed = !Objects.equals(name, loadedName) || size != loadedSize || scale != loadedScale;
|
||||||
if (!changed) {
|
if (!changed) {
|
||||||
@@ -166,7 +168,7 @@ public final class FrosFont {
|
|||||||
reset(name, size, scale, changed);
|
reset(name, size, scale, changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void reset(String name, float size, int scale, boolean verbose) {
|
private static void reset(String name, float size, float scale, boolean verbose) {
|
||||||
loadedName = name;
|
loadedName = name;
|
||||||
loadedSize = size;
|
loadedSize = size;
|
||||||
loadedScale = scale;
|
loadedScale = scale;
|
||||||
@@ -312,7 +314,7 @@ public final class FrosFont {
|
|||||||
String plain = stripCodes(text);
|
String plain = stripCodes(text);
|
||||||
if (plain.isEmpty()) return null;
|
if (plain.isEmpty()) return null;
|
||||||
|
|
||||||
int pad = loadedScale;
|
int pad = Math.max(1, Math.round(loadedScale));
|
||||||
int width = Math.max(1, metrics.stringWidth(plain));
|
int width = Math.max(1, metrics.stringWidth(plain));
|
||||||
int height = metrics.getHeight();
|
int height = metrics.getHeight();
|
||||||
int imageWidth = width + 2 * pad;
|
int imageWidth = width + 2 * pad;
|
||||||
@@ -345,7 +347,7 @@ public final class FrosFont {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void drawSegments(Graphics2D graphics, String text, int baseColor) {
|
private static void drawSegments(Graphics2D graphics, String text, int baseColor) {
|
||||||
int baseline = metrics.getAscent() + loadedScale;
|
int baseline = metrics.getAscent() + Math.round(loadedScale);
|
||||||
int cursor = 1;
|
int cursor = 1;
|
||||||
int current = baseColor;
|
int current = baseColor;
|
||||||
int segmentStart = 0;
|
int segmentStart = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user