Sidebar
This commit is contained in:
@@ -1,82 +0,0 @@
|
|||||||
package de.fullrisk.citrusDev;
|
|
||||||
|
|
||||||
import io.wispforest.owo.ui.base.BaseOwoScreen;
|
|
||||||
import io.wispforest.owo.ui.component.UIComponents;
|
|
||||||
import io.wispforest.owo.ui.container.FlowLayout;
|
|
||||||
import io.wispforest.owo.ui.container.UIContainers;
|
|
||||||
import io.wispforest.owo.ui.core.*;
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.sounds.SoundEvents;
|
|
||||||
import de.fullrisk.citrusDev.ScalableLabel;
|
|
||||||
import de.fullrisk.citrusDev.ScalableButton;
|
|
||||||
import de.fullrisk.citrusDev.ScaleValue;
|
|
||||||
|
|
||||||
public class MyScreen extends BaseOwoScreen<FlowLayout> {
|
|
||||||
|
|
||||||
public MyScreen() {
|
|
||||||
super(Component.literal("Citrus Dev"));
|
|
||||||
Minecraft.getInstance().getSoundManager().play(
|
|
||||||
SimpleSoundInstance.forUI(SoundEvents.UI_TOAST_IN, 1.5F, 2)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected OwoUIAdapter<FlowLayout> createAdapter() {
|
|
||||||
return OwoUIAdapter.create(this, UIContainers::verticalFlow);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void build(FlowLayout rootComponent) {
|
|
||||||
rootComponent
|
|
||||||
.horizontalAlignment(HorizontalAlignment.CENTER)
|
|
||||||
.verticalAlignment(VerticalAlignment.CENTER);
|
|
||||||
|
|
||||||
FlowLayout panel = UIContainers.verticalFlow(Sizing.content(), Sizing.content());
|
|
||||||
panel.gap(6);
|
|
||||||
panel.padding(Insets.of(12));
|
|
||||||
|
|
||||||
panel.horizontalAlignment(HorizontalAlignment.CENTER);
|
|
||||||
panel.verticalAlignment(VerticalAlignment.CENTER);
|
|
||||||
panel.horizontalSizing(Sizing.fixed(0));
|
|
||||||
panel.verticalSizing(Sizing.fixed(0));
|
|
||||||
panel.horizontalSizing().animate(300, Easing.CUBIC, Sizing.fixed(250)).forwards();
|
|
||||||
panel.verticalSizing().animate(300, Easing.CUBIC, Sizing.fixed(150)).forwards();
|
|
||||||
|
|
||||||
var header = new ScalableLabel(Component.literal("Citrus Dev"));
|
|
||||||
panel.child(header);
|
|
||||||
|
|
||||||
var header_button = new ScalableButton(Component.literal("Click me"), btn -> {
|
|
||||||
btn.setMessage(Component.literal("Clicked!"));
|
|
||||||
Minecraft.getInstance().getSoundManager().play(
|
|
||||||
SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK.value(), 2.0F, 2)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
header_button.scale().animate(300, Easing.CUBIC, new ScaleValue(1f)).forwards();
|
|
||||||
panel.child(header_button);
|
|
||||||
header.scale().animate(300, Easing.CUBIC, new ScaleValue(2f)).forwards();
|
|
||||||
|
|
||||||
|
|
||||||
Surface glassPanel = Surface.blur(5f, 15f)
|
|
||||||
.and(Surface.flat(0x40FFFFFF))
|
|
||||||
.and(Surface.outline(0xFFFFFFFF));
|
|
||||||
|
|
||||||
panel.surface(glassPanel);
|
|
||||||
|
|
||||||
var version = new ScalableLabel(Component.literal("Citrus-Dev v2.0"))
|
|
||||||
.horizontalTextAlignment(HorizontalAlignment.RIGHT)
|
|
||||||
.verticalTextAlignment(VerticalAlignment.BOTTOM);
|
|
||||||
|
|
||||||
panel.child(version);
|
|
||||||
rootComponent.child(panel);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isPauseScreen() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
package de.fullrisk.citrusDev;
|
|
||||||
|
|
||||||
import io.wispforest.owo.ui.component.ButtonComponent;
|
|
||||||
import io.wispforest.owo.ui.core.AnimatableProperty;
|
|
||||||
import io.wispforest.owo.ui.core.OwoUIGraphics;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
public class ScalableButton extends ButtonComponent {
|
|
||||||
|
|
||||||
protected final AnimatableProperty<ScaleValue> scale = AnimatableProperty.of(new ScaleValue(0f));
|
|
||||||
|
|
||||||
public ScalableButton(Component message, Consumer<ButtonComponent> onPress) {
|
|
||||||
super(message, onPress);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AnimatableProperty<ScaleValue> scale() {
|
|
||||||
return this.scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update(float delta, int mouseX, int mouseY) {
|
|
||||||
super.update(delta, mouseX, mouseY);
|
|
||||||
this.scale.update(delta);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void draw(OwoUIGraphics graphics, int mouseX, int mouseY, float partialTicks, float delta) {
|
|
||||||
float s = this.scale.get().value();
|
|
||||||
|
|
||||||
float centerX = this.x() + this.width() / 2f;
|
|
||||||
float centerY = this.y() + this.height() / 2f;
|
|
||||||
|
|
||||||
graphics.pose().pushMatrix();
|
|
||||||
graphics.pose().translate(centerX, centerY);
|
|
||||||
graphics.pose().scale(s, s);
|
|
||||||
graphics.pose().translate(-centerX, -centerY);
|
|
||||||
|
|
||||||
super.draw(graphics, mouseX, mouseY, partialTicks, delta);
|
|
||||||
|
|
||||||
graphics.pose().popMatrix();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
package de.fullrisk.citrusDev.UI;
|
||||||
|
|
||||||
|
import io.wispforest.owo.ui.base.BaseOwoScreen;
|
||||||
|
import io.wispforest.owo.ui.component.LabelComponent;
|
||||||
|
import io.wispforest.owo.ui.component.UIComponents;
|
||||||
|
import io.wispforest.owo.ui.container.FlowLayout;
|
||||||
|
import io.wispforest.owo.ui.container.UIContainers;
|
||||||
|
import io.wispforest.owo.ui.core.*;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.resources.sounds.SimpleSoundInstance;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.sounds.SoundEvents;
|
||||||
|
import de.fullrisk.citrusDev.UIHelper.ScalableLabel;
|
||||||
|
import de.fullrisk.citrusDev.UIHelper.ScalableButton;
|
||||||
|
import de.fullrisk.citrusDev.UIHelper.ScaleValue;
|
||||||
|
|
||||||
|
public class MyScreen extends BaseOwoScreen<FlowLayout> {
|
||||||
|
|
||||||
|
public MyScreen() {
|
||||||
|
super(Component.literal("Citrus Dev"));
|
||||||
|
Minecraft.getInstance().getSoundManager().play(
|
||||||
|
SimpleSoundInstance.forUI(SoundEvents.UI_TOAST_IN, 1.5F, 2)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected OwoUIAdapter<FlowLayout> createAdapter() {
|
||||||
|
return OwoUIAdapter.create(this, UIContainers::verticalFlow);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void build(FlowLayout rootComponent) {
|
||||||
|
rootComponent.gap(0);
|
||||||
|
rootComponent
|
||||||
|
.horizontalAlignment(HorizontalAlignment.CENTER)
|
||||||
|
.verticalAlignment(VerticalAlignment.CENTER);
|
||||||
|
|
||||||
|
// ----- Main panel (now a horizontal container: sidebar | divider | content) -----
|
||||||
|
FlowLayout panel = UIContainers.horizontalFlow(Sizing.content(), Sizing.content());
|
||||||
|
panel.gap(0);
|
||||||
|
panel.padding(Insets.of(2));
|
||||||
|
|
||||||
|
panel.horizontalAlignment(HorizontalAlignment.CENTER);
|
||||||
|
panel.verticalAlignment(VerticalAlignment.CENTER);
|
||||||
|
panel.horizontalSizing(Sizing.fixed(0));
|
||||||
|
panel.verticalSizing(Sizing.fixed(0));
|
||||||
|
panel.horizontalSizing().animate(300, Easing.CUBIC, Sizing.fixed(250)).forwards();
|
||||||
|
panel.verticalSizing().animate(300, Easing.CUBIC, Sizing.fixed(150)).forwards();
|
||||||
|
|
||||||
|
// inner content area, accounting for panel's 2px padding on each side
|
||||||
|
int innerHeight = 150 - 4; // 146
|
||||||
|
int sidebarWidth = 34;
|
||||||
|
int dividerWidth = 1;
|
||||||
|
int contentWidth = 250 - 4 - sidebarWidth - dividerWidth; // 211
|
||||||
|
|
||||||
|
// ----- Sidebar -----
|
||||||
|
FlowLayout sidebar = UIContainers.verticalFlow(Sizing.fixed(sidebarWidth), Sizing.fixed(innerHeight));
|
||||||
|
sidebar.horizontalAlignment(HorizontalAlignment.CENTER);
|
||||||
|
sidebar.verticalAlignment(VerticalAlignment.CENTER);
|
||||||
|
sidebar.padding(Insets.of(4));
|
||||||
|
sidebar.gap(2);
|
||||||
|
|
||||||
|
var sidebarButton = new ScalableButton(Component.literal("+"), btn -> {
|
||||||
|
Minecraft.getInstance().getSoundManager().play(
|
||||||
|
SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK.value(), 2.0F, 2)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
0x80FFFFFF, // base fill
|
||||||
|
0xA0FFFFFF, // hovered fill
|
||||||
|
0xFFFFFFFF, // base outline
|
||||||
|
0xFFFFFFFF, // hovered outline
|
||||||
|
1 // outline width
|
||||||
|
);
|
||||||
|
sidebarButton.horizontalSizing(Sizing.fixed(20));
|
||||||
|
sidebarButton.verticalSizing(Sizing.fixed(20));
|
||||||
|
sidebarButton.scale().animate(300, Easing.CUBIC, new ScaleValue(1f)).forwards();
|
||||||
|
|
||||||
|
sidebar.child(sidebarButton);
|
||||||
|
panel.child(sidebar);
|
||||||
|
|
||||||
|
// ----- Divider -----
|
||||||
|
FlowLayout divider = UIContainers.verticalFlow(Sizing.fixed(dividerWidth), Sizing.fixed(innerHeight));
|
||||||
|
divider.surface(Surface.flat(0x80FFFFFF)); // subtle line, matches glass aesthetic
|
||||||
|
panel.child(divider);
|
||||||
|
|
||||||
|
// ----- Content column (header, button, version) -----
|
||||||
|
FlowLayout content = UIContainers.verticalFlow(Sizing.fixed(contentWidth), Sizing.fixed(innerHeight));
|
||||||
|
content.gap(6);
|
||||||
|
content.horizontalAlignment(HorizontalAlignment.CENTER);
|
||||||
|
content.verticalAlignment(VerticalAlignment.CENTER);
|
||||||
|
panel.child(content);
|
||||||
|
|
||||||
|
var header = new ScalableLabel(Component.literal("Citrus Dev"));
|
||||||
|
content.child(header);
|
||||||
|
|
||||||
|
var header_button = new ScalableButton(Component.literal("Click me"), btn -> {
|
||||||
|
btn.setMessage(Component.literal("Clicked!"));
|
||||||
|
Minecraft.getInstance().getSoundManager().play(
|
||||||
|
SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK.value(), 2.0F, 2)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
0x80FFFFFF, // base fill
|
||||||
|
0xA0FFFFFF, // hovered fill
|
||||||
|
0xFFFFFFFF, // base outline
|
||||||
|
0xFFFFFFFF, // hovered outline
|
||||||
|
1 // outline width
|
||||||
|
);
|
||||||
|
|
||||||
|
header_button.scale().animate(300, Easing.CUBIC, new ScaleValue(1f)).forwards();
|
||||||
|
header_button.margins(Insets.top(6));
|
||||||
|
content.child(header_button);
|
||||||
|
header.scale().animate(300, Easing.CUBIC, new ScaleValue(2f)).forwards();
|
||||||
|
|
||||||
|
Surface glassPanel = Surface.blur(5f, 15f)
|
||||||
|
.and(Surface.flat(0x40FFFFFF))
|
||||||
|
.and(Surface.outline(0xFFFFFFFF));
|
||||||
|
|
||||||
|
panel.surface(glassPanel);
|
||||||
|
|
||||||
|
var version = new ScalableLabel(Component.literal("Citrus-Dev v2.0"));
|
||||||
|
version.horizontalTextAlignment(HorizontalAlignment.RIGHT);
|
||||||
|
version.verticalTextAlignment(VerticalAlignment.BOTTOM);
|
||||||
|
version.horizontalSizing(Sizing.fixed(202));
|
||||||
|
version.verticalSizing(Sizing.fixed(12));
|
||||||
|
version.positioning(Positioning.relative(115, 100)); // bottom-right corner of `panel`
|
||||||
|
|
||||||
|
version.scale().set(new ScaleValue(0.7f));
|
||||||
|
|
||||||
|
panel.child(version);
|
||||||
|
|
||||||
|
rootComponent.child(panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPauseScreen() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package de.fullrisk.citrusDev.UIHelper;
|
||||||
|
|
||||||
|
import io.wispforest.owo.ui.core.Animatable;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
|
||||||
|
public record ColorValue(int argb) implements Animatable<ColorValue> {
|
||||||
|
@Override
|
||||||
|
public ColorValue interpolate(ColorValue next, float delta) {
|
||||||
|
int a1 = (this.argb >> 24) & 0xFF, r1 = (this.argb >> 16) & 0xFF, g1 = (this.argb >> 8) & 0xFF, b1 = this.argb & 0xFF;
|
||||||
|
int a2 = (next.argb >> 24) & 0xFF, r2 = (next.argb >> 16) & 0xFF, g2 = (next.argb >> 8) & 0xFF, b2 = next.argb & 0xFF;
|
||||||
|
|
||||||
|
int a = Mth.floor(Mth.lerp(delta, a1, a2));
|
||||||
|
int r = Mth.floor(Mth.lerp(delta, r1, r2));
|
||||||
|
int g = Mth.floor(Mth.lerp(delta, g1, g2));
|
||||||
|
int b = Mth.floor(Mth.lerp(delta, b1, b2));
|
||||||
|
|
||||||
|
return new ColorValue((a << 24) | (r << 16) | (g << 8) | b);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
package de.fullrisk.citrusDev.UIHelper;
|
||||||
|
|
||||||
|
import io.wispforest.owo.ui.component.ButtonComponent;
|
||||||
|
import io.wispforest.owo.ui.core.AnimatableProperty;
|
||||||
|
import io.wispforest.owo.ui.core.Easing;
|
||||||
|
import io.wispforest.owo.ui.core.OwoUIGraphics;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class ScalableButton extends ButtonComponent {
|
||||||
|
|
||||||
|
protected final AnimatableProperty<ScaleValue> scale = AnimatableProperty.of(new ScaleValue(0f));
|
||||||
|
protected final AnimatableProperty<ColorValue> fillColor;
|
||||||
|
protected final AnimatableProperty<ColorValue> outlineColor;
|
||||||
|
|
||||||
|
private final int baseFill;
|
||||||
|
private final int hoveredFill;
|
||||||
|
private final int baseOutline;
|
||||||
|
private final int hoveredOutline;
|
||||||
|
private final int outlineWidth;
|
||||||
|
|
||||||
|
private boolean wasHovered = false;
|
||||||
|
|
||||||
|
public ScalableButton(Component message, Consumer<ButtonComponent> onPress,
|
||||||
|
int baseFill, int hoveredFill,
|
||||||
|
int baseOutline, int hoveredOutline,
|
||||||
|
int outlineWidth) {
|
||||||
|
super(message, onPress);
|
||||||
|
this.baseFill = baseFill;
|
||||||
|
this.hoveredFill = hoveredFill;
|
||||||
|
this.baseOutline = baseOutline;
|
||||||
|
this.hoveredOutline = hoveredOutline;
|
||||||
|
this.outlineWidth = outlineWidth;
|
||||||
|
|
||||||
|
this.fillColor = AnimatableProperty.of(new ColorValue(baseFill));
|
||||||
|
this.outlineColor = AnimatableProperty.of(new ColorValue(baseOutline));
|
||||||
|
|
||||||
|
this.renderer((context, button, delta) -> {
|
||||||
|
int x = button.getX();
|
||||||
|
int y = button.getY();
|
||||||
|
int w = button.getWidth();
|
||||||
|
int h = button.getHeight();
|
||||||
|
|
||||||
|
int fill = this.fillColor.get().argb();
|
||||||
|
int outline = this.outlineColor.get().argb();
|
||||||
|
|
||||||
|
context.fill(x, y, x + w, y + h, fill);
|
||||||
|
context.fill(x, y, x + w, y + this.outlineWidth, outline); // top
|
||||||
|
context.fill(x, y + h - this.outlineWidth, x + w, y + h, outline); // bottom
|
||||||
|
context.fill(x, y, x + this.outlineWidth, y + h, outline); // left
|
||||||
|
context.fill(x + w - this.outlineWidth, y, x + w, y + h, outline); // right
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnimatableProperty<ScaleValue> scale() {
|
||||||
|
return this.scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(float delta, int mouseX, int mouseY) {
|
||||||
|
super.update(delta, mouseX, mouseY);
|
||||||
|
this.scale.update(delta);
|
||||||
|
this.fillColor.update(delta);
|
||||||
|
this.outlineColor.update(delta);
|
||||||
|
|
||||||
|
boolean hovered = this.isHovered();
|
||||||
|
if (hovered != this.wasHovered) {
|
||||||
|
this.fillColor.animate(150, Easing.CUBIC, new ColorValue(hovered ? hoveredFill : baseFill)).forwards();
|
||||||
|
this.outlineColor.animate(150, Easing.CUBIC, new ColorValue(hovered ? hoveredOutline : baseOutline)).forwards();
|
||||||
|
this.wasHovered = hovered;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(OwoUIGraphics graphics, int mouseX, int mouseY, float partialTicks, float delta) {
|
||||||
|
float s = this.scale.get().value();
|
||||||
|
|
||||||
|
float centerX = this.x() + this.width() / 2f;
|
||||||
|
float centerY = this.y() + this.height() / 2f;
|
||||||
|
|
||||||
|
graphics.pose().pushMatrix();
|
||||||
|
graphics.pose().translate(centerX, centerY);
|
||||||
|
graphics.pose().scale(s, s);
|
||||||
|
graphics.pose().translate(-centerX, -centerY);
|
||||||
|
|
||||||
|
super.draw(graphics, mouseX, mouseY, partialTicks, delta);
|
||||||
|
|
||||||
|
graphics.pose().popMatrix();
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package de.fullrisk.citrusDev;
|
package de.fullrisk.citrusDev.UIHelper;
|
||||||
|
|
||||||
import io.wispforest.owo.ui.component.LabelComponent;
|
import io.wispforest.owo.ui.component.LabelComponent;
|
||||||
import io.wispforest.owo.ui.core.AnimatableProperty;
|
import io.wispforest.owo.ui.core.AnimatableProperty;
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package de.fullrisk.citrusDev;
|
package de.fullrisk.citrusDev.UIHelper;
|
||||||
|
|
||||||
import io.wispforest.owo.ui.core.Animatable;
|
import io.wispforest.owo.ui.core.Animatable;
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package de.fullrisk.citrusDev.client;
|
package de.fullrisk.citrusDev.client;
|
||||||
|
|
||||||
import de.fullrisk.citrusDev.MyScreen;
|
import de.fullrisk.citrusDev.UI.MyScreen;
|
||||||
import net.fabricmc.api.ClientModInitializer;
|
import net.fabricmc.api.ClientModInitializer;
|
||||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||||
import net.fabricmc.fabric.api.client.keymapping.v1.KeyMappingHelper;
|
import net.fabricmc.fabric.api.client.keymapping.v1.KeyMappingHelper;
|
||||||
|
|||||||
Reference in New Issue
Block a user