Skip to content

Commit

Permalink
start to color picker
Browse files Browse the repository at this point in the history
  • Loading branch information
Goby56 committed Oct 20, 2024
1 parent b2d5a80 commit 8050b64
Show file tree
Hide file tree
Showing 5 changed files with 338 additions and 26 deletions.
23 changes: 18 additions & 5 deletions src/main/java/com/goby56/wakes/config/WakesConfigScreen.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package com.goby56.wakes.config;

import com.goby56.wakes.WakesClient;
import com.goby56.wakes.config.gui.ColorPicker;
import com.goby56.wakes.config.gui.GradientSlider;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.Drawable;
import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.LayoutWidgets;
import net.minecraft.client.gui.widget.SliderWidget;
import net.minecraft.client.gui.widget.*;
import net.minecraft.client.option.SimpleOption;
import net.minecraft.text.Text;

import java.util.ArrayList;
import java.util.List;

public class WakesConfigScreen extends Screen {

public WakesConfigScreen() {
Expand All @@ -18,7 +22,12 @@ public WakesConfigScreen() {

@Override
protected void init() {
this.addDrawableChild(new GradientSlider((int) (width / 2 - width * 0.8f / 2), 10, (int) (width * 0.8f), 40, Text.literal("Gradient slider"), WakesClient.CONFIG_INSTANCE.wakeGradientRanges));
this.addDrawableChild(new GradientSlider(
this,
(int) (width / 2 - width * 0.8f / 2), 10,
(int) (width * 0.8f), 40,
Text.literal("Gradient slider"),
new ArrayList<>(List.of(0.1f, 0.5f, 0.7f))));
}

@Override
Expand All @@ -29,6 +38,10 @@ protected void applyBlur(float delta) {
@Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
super.render(context, mouseX, mouseY, delta);
context.drawCenteredTextWithShadow(textRenderer, Text.literal("You must see me"), width / 2, height / 2, 0xffffff);
context.drawCenteredTextWithShadow(textRenderer, Text.literal("Resident evil"), width / 2, height / 2, 0xffffff);
}

public void addWidget(ClickableWidget widget) {
this.addDrawableChild(widget);
}
}
158 changes: 158 additions & 0 deletions src/main/java/com/goby56/wakes/config/gui/ColorPicker.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package com.goby56.wakes.config.gui;

import com.goby56.wakes.config.WakesConfigScreen;
import com.goby56.wakes.render.enums.WakeColor;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
import net.minecraft.client.gui.widget.ClickableWidget;
import net.minecraft.client.gui.widget.SliderWidget;
import net.minecraft.client.gui.widget.TextFieldWidget;
import net.minecraft.client.render.*;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import org.joml.Matrix4f;
import org.joml.Vector2f;
import org.joml.Vector2i;

import java.awt.*;
import java.util.function.Function;

public class ColorPicker extends ClickableWidget {
private static final Identifier BACKGROUND_TEXTURE = Identifier.ofVanilla("widget/button");
private static final Identifier FRAME_TEXTURE = Identifier.ofVanilla("widget/slot_frame");

private final WakesConfigScreen screenContext;
private final TextFieldWidget hexInput;
private final GradientSlider hueSlider;
private final GradientSlider alphaSlider;
private final Vector2i colorPickerPos;
private final Vector2i colorPickerDim;
private PickListener listener;

public interface PickListener {
void onPickedColor(WakeColor color);
}


public ColorPicker(WakesConfigScreen screenContext, int x, int y, int width, int height) {
super(x, y, width, height, Text.of(""));
this.screenContext = screenContext;

var topLeft = globalSpace(new Vector2f(0f, 0f));
var bottomRight = globalSpace(new Vector2f(1f, 2f / 3f));
this.colorPickerPos = topLeft;
this.colorPickerDim = bottomRight.sub(bottomRight);

this.hexInput = new HexInputField(new Vector2f(0f, 5f / 6f), new Vector2f(1f / 3f, 1f), this::globalSpace, screenContext.textRenderer);
this.hueSlider = new GradientSlider(new Vector2f(0f, 2f / 3f), new Vector2f(1f, 5f / 6f), this::globalSpace);
this.alphaSlider = new GradientSlider(new Vector2f(1f / 3f, 5f / 6f), new Vector2f(1f, 1f), this::globalSpace);

screenContext.addWidget(this);
screenContext.addWidget(hueSlider);
screenContext.addWidget(alphaSlider);
}

public void toggleActive() {
boolean active = !this.active;
this.active = active;
this.hexInput.active = active;
this.hueSlider.active = active;
this.alphaSlider.active = active;
}

public void registerListener(PickListener listener) {
this.listener = listener;
}

private Vector2f relativeSpace(Vector2i globalSpace) {
return new Vector2f((float) (globalSpace.x - getX()) / width, (float) (globalSpace.y - getY()) / width);
}

private Vector2i globalSpace(Vector2f relativeSpace) {
return new Vector2i((int) (relativeSpace.x * width + getX()), (int) (relativeSpace.y * height + getY()));
}

@Override
public void onClick(double mouseX, double mouseY) {
System.out.printf("%f, %f\n", (mouseX - getX()) / width, (mouseY - getY()) / height);
super.onClick(mouseX, mouseY);
}

@Override
protected void onDrag(double mouseX, double mouseY, double deltaX, double deltaY) {
super.onDrag(mouseX, mouseY, deltaX, deltaY);
}

@Override
protected void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) {
if (!active) return;
int x = getX();
int y = getY();

context.drawGuiTexture(BACKGROUND_TEXTURE, x, y, width, height);

drawColorPicker(context, colorPickerPos.x, colorPickerPos.y, colorPickerDim.x, colorPickerDim.y);
}

private void drawColorPicker(DrawContext context, int x, int y, int w, int h) {
// Color picker
context.drawGuiTexture(FRAME_TEXTURE, x - 3, y - 3, w + 6, h + 6);
RenderSystem.setShader(GameRenderer::getPositionColorProgram);
BufferBuilder buffer = Tessellator.getInstance().begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR);
Matrix4f matrix = context.getMatrices().peek().getPositionMatrix();
buffer.vertex(matrix, x, y, 5).color(Color.HSBtoRGB(1, 0, 1));
buffer.vertex(matrix, x, y + h, 5).color(Color.HSBtoRGB(1, 0, 0));
buffer.vertex(matrix, x + w, y + h, 5).color(Color.HSBtoRGB(1, 1, 0));
buffer.vertex(matrix, x + w, y, 5).color(Color.HSBtoRGB(1, 1, 1));
BufferRenderer.drawWithGlobalProgram(buffer.end());
}

@Override
protected void appendClickableNarrations(NarrationMessageBuilder builder) {

}

private class HexInputField extends TextFieldWidget {

public HexInputField(Vector2f topLeft, Vector2f bottomRight, Function<Vector2f, Vector2i> globalSpaceConverter, TextRenderer textRenderer) {
super(textRenderer, 0, 0, 0, 0, Text.of(""));
Vector2i globalPos = globalSpaceConverter.apply(topLeft);
Vector2i dimensions = globalSpaceConverter.apply(bottomRight).sub(globalPos);
this.setX(globalPos.x);
this.setY(globalPos.y);
this.setWidth(dimensions.x);
this.setHeight(dimensions.y);
}
}

private class GradientSlider extends SliderWidget {


public GradientSlider(Vector2f topLeft, Vector2f bottomRight, Function<Vector2f, Vector2i> globalSpaceConverter) {
super(0, 0, 0, 0, Text.of(""), 1f);
Vector2i globalPos = globalSpaceConverter.apply(topLeft);
Vector2i dimensions = globalSpaceConverter.apply(bottomRight).sub(globalPos);
this.setX(globalPos.x);
this.setY(globalPos.y);
this.setWidth(dimensions.x);
this.setHeight(dimensions.y);
}

@Override
public void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) {
super.renderWidget(context, mouseX, mouseY, delta);
}

@Override
protected void updateMessage() {

}

@Override
protected void applyValue() {

}
}
}
131 changes: 111 additions & 20 deletions src/main/java/com/goby56/wakes/config/gui/GradientSlider.java
Original file line number Diff line number Diff line change
@@ -1,57 +1,148 @@
package com.goby56.wakes.config.gui;

import com.goby56.wakes.WakesClient;
import com.goby56.wakes.config.WakesConfigScreen;
import com.goby56.wakes.render.enums.WakeColor;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.SliderWidget;
import net.minecraft.text.Text;
import net.minecraft.util.math.MathHelper;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Collections;

public class GradientSlider extends SliderWidget {
private ArrayList<Float> values;
private final WakesConfigScreen screenContext;
private ArrayList<SliderHandle> handles;
private final ColorPicker colorPicker;
private Integer activeSection = null;

public GradientSlider(int x, int y, int width, int height, Text text, ArrayList<Float> values) {
public GradientSlider(WakesConfigScreen screenContext, int x, int y, int width, int height, Text text, ArrayList<Float> normalizedValues) {
super(x, y, width, height, text, 0f);
this.values = values;
this.screenContext = screenContext;
this.handles = new ArrayList<>();
for (float val : normalizedValues) {
this.handles.add(new SliderHandle(val));
}
this.colorPicker = new ColorPicker(screenContext, 10, height / 2 - 100 / 2, 100, 100);
colorPicker.registerListener(this::onColorPicked);
}

private void unfocusHandles() {
for (SliderHandle handle : handles) {
handle.focused = false;
}
}

@Override
public void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) {
MinecraftClient minecraftClient = MinecraftClient.getInstance();
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
RenderSystem.enableDepthTest();

context.drawGuiTexture(this.getTexture(), this.getX(), this.getY(), this.getWidth(), this.getHeight());
context.setShaderColor(1.0F, 1.0F, 1.0F, 0.3f);

values = new ArrayList<>(List.of(0f, 0.1f, 0.5f, 0.7f, 1f));
for (int i = 1; i < values.size(); i++) {
float value = values.get(i - 1);
float diff = values.get(i) - value;
int x = this.getX() + (int)(value * (double)(this.width - 8));
int y = this.getY();
context.fill(x, y + 1, (int) (x + (diff * (this.width - 8))) + 8, y + this.height - 1, WakesClient.CONFIG_INSTANCE.wakeColors.get(i - 1).argb);
context.drawGuiTexture(this.getHandleTexture(), x, y, 8, this.getHeight());
this.hovered = context.scissorContains(mouseX, mouseY) && mouseX >= this.getX() && mouseY >= this.getY() && mouseX < this.getX() + this.width && mouseY < this.getY() + this.height;
int n = handles.size();
int y = this.getY();

int prevX = this.getX();
for (int i = 0; i < n; i++) {
float value = handles.get(i).value;

int currX = this.getX() + (int)(value * (double)(this.width));

context.fill(prevX, y, currX, y + this.height, WakesClient.CONFIG_INSTANCE.wakeColors.get(i).argb);

prevX = currX;
}
context.fill(prevX, y, this.getX() + this.width, y + this.height, WakesClient.CONFIG_INSTANCE.wakeColors.get(n).argb);

float hoveredVal = valueFromMousePos(mouseX);
boolean correctY = mouseY >= getY() && mouseY < getY() + height;
for (SliderHandle handle : handles) {
boolean isHovered = handle.inProximity(hoveredVal, width, 8) && correctY;
context.drawGuiTexture(handle.getHandleTexture(isHovered), this.getX() + (int)(handle.value * (double)(this.width - 4)), this.getY(), 8, this.getHeight());
}
context.drawGuiTexture(this.getHandleTexture(), this.getX() + (int)(this.value * (double)(this.width - 8)), this.getY(), 8, this.getHeight());
context.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
int i = this.active ? 16777215 : 10526880;
this.drawScrollableText(context, minecraftClient.textRenderer, 2, i | MathHelper.ceil(this.alpha * 255.0F) << 24);
}

@Override
public void onClick(double mouseX, double mouseY) {
float value = valueFromMousePos(mouseX);
SliderHandle handle = closestHandle(value);
unfocusHandles();
if (handle.inProximity(value, width, 8)) {
// Mouse on handle
handle.focused = true;
} else {
activeSection = getActiveSection(value);
colorPicker.toggleActive();
// Do color picker
}
}

@Override
public void onRelease(double mouseX, double mouseY) {
unfocusHandles();
super.onRelease(mouseX, mouseY);
}

@Override
protected void onDrag(double mouseX, double mouseY, double deltaX, double deltaY) {
Collections.sort(handles);

float value = valueFromMousePos(mouseX);
for (SliderHandle handle : handles) {
if (handle.focused) {
if (handle.setValue(value)) {
this.applyValue();
}
}
}
}

private void onColorPicked(WakeColor color) {
if (this.activeSection != null) {
WakesClient.CONFIG_INSTANCE.wakeColors.set(this.activeSection, color);
}
}

private float valueFromMousePos(double mouseX) {
return (float) ((mouseX - (double)(this.getX() + 4)) / (double)(this.width - 8));
}

private SliderHandle closestHandle(float value) {
float min = 1f;
SliderHandle closest = null;
for (SliderHandle handle : handles) {
float d = Math.abs(handle.value - value);
if (d < min) {
closest = handle;
min = d;
}
}
return closest;
}

private int getActiveSection(float value) {
for (int i = 0; i < handles.size(); i++) {
if (handles.get(i).value <= value) {
return i+1;
}
}
return 0;
}

@Override
protected void updateMessage() {
this.setMessage(Text.of(String.valueOf(this.value)));
}

@Override
protected void applyValue() {

}

}
Loading

0 comments on commit 8050b64

Please sign in to comment.