Image Component

This commit is contained in:
Frank 2022-07-15 15:47:56 +02:00
parent 51da03f3c8
commit 877489c469
13 changed files with 263 additions and 36 deletions

View file

@ -1,7 +1,9 @@
package org.betterx.bclib.client.gui.modmenu; package org.betterx.bclib.client.gui.modmenu;
import org.betterx.bclib.BCLib;
import org.betterx.ui.layout.components.*; import org.betterx.ui.layout.components.*;
import org.betterx.ui.layout.values.DynamicSize; import org.betterx.ui.layout.values.DynamicSize;
import org.betterx.ui.layout.values.Size;
import org.betterx.ui.vanilla.LayoutScreen; import org.betterx.ui.vanilla.LayoutScreen;
import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.Screen;
@ -36,6 +38,13 @@ public class TestScreen extends LayoutScreen {
).centerHorizontal() ).centerHorizontal()
); );
rows.addSpacer(16); rows.addSpacer(16);
rows.add(new Image(
DynamicSize.fixed(24), DynamicSize.fixed(24),
BCLib.makeID("icon.png"),
new Size(512, 512)
).centerHorizontal()
);
rows.addSpacer(16);
rows.add(new Range<>( rows.add(new Range<>(
DynamicSize.fill(), DynamicSize.fit(), DynamicSize.fill(), DynamicSize.fit(),
Component.literal("Integer"), Component.literal("Integer"),
@ -72,7 +81,7 @@ public class TestScreen extends LayoutScreen {
} }
)); ));
rows.add(cb1); rows.add(cb1);
rows.addSpacer(32); rows.addSpacer(16);
rows.add(new Button( rows.add(new Button(
DynamicSize.fit(), DynamicSize.fit(), DynamicSize.fit(), DynamicSize.fit(),
Component.literal("test"), Component.literal("test"),

View file

@ -46,15 +46,15 @@ public abstract class AbstractStack<R extends ComponentRenderer, T extends Abstr
@Override @Override
protected void renderInBounds( protected void renderInBounds(
PoseStack poseStack, PoseStack poseStack,
int x, int mouseX,
int y, int mouseY,
float a, float deltaTicks,
Rectangle renderBounds, Rectangle renderBounds,
Rectangle clipRect Rectangle clipRect
) { ) {
super.renderInBounds(poseStack, x, y, a, renderBounds, clipRect); super.renderInBounds(poseStack, mouseX, mouseY, deltaTicks, renderBounds, clipRect);
for (Component<?> c : components) { for (Component<?> c : components) {
c.render(poseStack, x, y, a, renderBounds, clipRect); c.render(poseStack, mouseX, mouseY, deltaTicks, renderBounds, clipRect);
} }
} }

View file

@ -19,13 +19,20 @@ public class AbstractVanillaComponentRenderer<C extends AbstractWidget, V extend
} }
@Override @Override
public void renderInBounds(PoseStack poseStack, int x, int y, float a, Rectangle bounds, Rectangle clipRect) { public void renderInBounds(
PoseStack poseStack,
int mouseX,
int mouseY,
float deltaTicks,
Rectangle bounds,
Rectangle clipRect
) {
if (linkedComponent != null) { if (linkedComponent != null) {
if (linkedComponent.vanillaComponent != null) { if (linkedComponent.vanillaComponent != null) {
if (!linkedComponent.enabled) { if (!linkedComponent.enabled) {
linkedComponent.vanillaComponent.setAlpha(linkedComponent.alpha / 2); linkedComponent.vanillaComponent.setAlpha(linkedComponent.alpha / 2);
} }
linkedComponent.vanillaComponent.render(poseStack, x, y, a); linkedComponent.vanillaComponent.render(poseStack, mouseX, mouseY, deltaTicks);
if (!linkedComponent.enabled) { if (!linkedComponent.enabled) {
linkedComponent.vanillaComponent.setAlpha(linkedComponent.alpha); linkedComponent.vanillaComponent.setAlpha(linkedComponent.alpha);
} }

View file

@ -82,28 +82,35 @@ public abstract class Component<R extends ComponentRenderer> implements Componen
); );
} }
public void render(PoseStack poseStack, int x, int y, float a, Rectangle parentBounds, Rectangle clipRect) { public void render(
PoseStack poseStack,
int mouseX,
int mouseY,
float deltaTicks,
Rectangle parentBounds,
Rectangle clipRect
) {
Rectangle r = relativeBounds.movedBy(parentBounds.left, parentBounds.top); Rectangle r = relativeBounds.movedBy(parentBounds.left, parentBounds.top);
Rectangle clip = r.intersect(clipRect); Rectangle clip = r.intersect(clipRect);
poseStack.pushPose(); poseStack.pushPose();
poseStack.translate(relativeBounds.left, relativeBounds.top, 0); poseStack.translate(relativeBounds.left, relativeBounds.top, 0);
if (r.overlaps(clip)) { if (r.overlaps(clip)) {
renderInBounds(poseStack, x - relativeBounds.left, y - relativeBounds.top, a, r, clip); renderInBounds(poseStack, mouseX - relativeBounds.left, mouseY - relativeBounds.top, deltaTicks, r, clip);
} }
poseStack.popPose(); poseStack.popPose();
} }
protected void renderInBounds( protected void renderInBounds(
PoseStack poseStack, PoseStack poseStack,
int x, int mouseX,
int y, int mouseY,
float a, float deltaTicks,
Rectangle renderBounds, Rectangle renderBounds,
Rectangle clipRect Rectangle clipRect
) { ) {
if (renderer != null) { if (renderer != null) {
setClippingRect(clipRect); setClippingRect(clipRect);
renderer.renderInBounds(poseStack, x, y, a, renderBounds, clipRect); renderer.renderInBounds(poseStack, mouseX, mouseY, deltaTicks, renderBounds, clipRect);
setClippingRect(null); setClippingRect(null);
} }
} }

View file

@ -0,0 +1,48 @@
package org.betterx.ui.layout.components;
import org.betterx.ui.layout.components.render.ComponentRenderer;
import org.betterx.ui.layout.values.DynamicSize;
import org.betterx.ui.layout.values.Rectangle;
import com.mojang.blaze3d.vertex.PoseStack;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
@Environment(EnvType.CLIENT)
public abstract class CustomRenderComponent<C extends CustomRenderComponent<C>> extends Component<CustomRenderComponent.CustomRenderRenderer<C>> {
public CustomRenderComponent(
DynamicSize width,
DynamicSize height
) {
super(width, height, new CustomRenderRenderer<>());
renderer.linkedComponent = (C) this;
}
protected abstract void customRender(
PoseStack stack,
int x,
int y,
float deltaTicks,
Rectangle bounds,
Rectangle clipRect
);
protected static class CustomRenderRenderer<C extends CustomRenderComponent<C>> implements ComponentRenderer {
C linkedComponent;
@Override
public void renderInBounds(
PoseStack stack,
int mouseX,
int mouseY,
float deltaTicks,
Rectangle bounds,
Rectangle clipRect
) {
if (linkedComponent != null) {
linkedComponent.customRender(stack, mouseX, mouseY, deltaTicks, bounds, clipRect);
}
}
}
}

View file

@ -0,0 +1,115 @@
package org.betterx.ui.layout.components;
import org.betterx.ui.layout.values.DynamicSize;
import org.betterx.ui.layout.values.Rectangle;
import org.betterx.ui.layout.values.Size;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.gui.GuiComponent;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.resources.ResourceLocation;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
@Environment(EnvType.CLIENT)
public class Image extends CustomRenderComponent {
protected Rectangle uvRect;
public final ResourceLocation location;
protected float alpha;
protected Size resourceSize;
public Image(DynamicSize width, DynamicSize height, ResourceLocation location) {
this(width, height, location, new Size(16, 16));
}
public Image(DynamicSize width, DynamicSize height, ResourceLocation location, Size resourceSize) {
super(width, height);
this.location = location;
this.uvRect = new Rectangle(0, 0, resourceSize.width(), resourceSize.height());
this.resourceSize = resourceSize;
this.alpha = 1f;
}
public Image setAlpha(float a) {
alpha = a;
return this;
}
public float getAlpha() {
return alpha;
}
public Image setUvRect(int left, int top, int width, int height) {
uvRect = new Rectangle(left, top, width, height);
return this;
}
public Rectangle getUvRect() {
return uvRect;
}
public Image setResourceSize(int width, int height) {
resourceSize = new Size(width, height);
return this;
}
public Size getResourceSize() {
return resourceSize;
}
@Override
public int getContentWidth() {
return resourceSize.width();
}
@Override
public int getContentHeight() {
return resourceSize.height();
}
@Override
protected void customRender(
PoseStack stack,
int mouseX,
int mouseY,
float deltaTicks,
Rectangle bounds,
Rectangle clipRect
) {
renderImage(stack, bounds, location, uvRect, resourceSize, alpha);
}
protected static void renderImage(
PoseStack stack,
Rectangle bounds,
ResourceLocation location,
Rectangle uvRect,
Size size,
float alpha
) {
RenderSystem.setShader(GameRenderer::getPositionTexShader);
RenderSystem.setShaderTexture(0, location);
RenderSystem.enableBlend();
RenderSystem.blendFunc(
GlStateManager.SourceFactor.SRC_ALPHA,
GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA
);
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, alpha);
GuiComponent.blit(
stack,
0, 0, bounds.width, bounds.height,
uvRect.left,
uvRect.top,
uvRect.width,
uvRect.height,
size.width(),
size.height()
);
}
}

View file

@ -94,9 +94,9 @@ public class Panel implements ComponentWithBounds, RelativeContainerEventHandler
} }
@Override @Override
public void render(PoseStack poseStack, int x, int y, float a) { public void render(PoseStack poseStack, int mouseX, int mouseY, float deltaTicks) {
if (child != null) { if (child != null) {
child.render(poseStack, x - bounds.left, y - bounds.top, a, bounds, bounds); child.render(poseStack, mouseX - bounds.left, mouseY - bounds.top, deltaTicks, bounds, bounds);
} }
} }
// @Override // @Override

View file

@ -54,7 +54,14 @@ public class Text extends Component<Text.TextRenderer> {
} }
@Override @Override
public void renderInBounds(PoseStack stack, int x, int y, float a, Rectangle bounds, Rectangle clipRect) { public void renderInBounds(
PoseStack stack,
int mouseX,
int mouseY,
float deltaTicks,
Rectangle bounds,
Rectangle clipRect
) {
if (linkedComponent != null) { if (linkedComponent != null) {
int left = bounds.width - getWidth(linkedComponent.text); int left = bounds.width - getWidth(linkedComponent.text);
if (linkedComponent.hAlign == Alignment.MIN) left = 0; if (linkedComponent.hAlign == Alignment.MIN) left = 0;

View file

@ -3,6 +3,7 @@ package org.betterx.ui.layout.components;
import org.betterx.ui.layout.components.render.ComponentRenderer; import org.betterx.ui.layout.components.render.ComponentRenderer;
import org.betterx.ui.layout.components.render.NullRenderer; import org.betterx.ui.layout.components.render.NullRenderer;
import org.betterx.ui.layout.components.render.ScrollerRenderer; import org.betterx.ui.layout.components.render.ScrollerRenderer;
import org.betterx.ui.layout.values.Alignment;
import org.betterx.ui.layout.values.DynamicSize; import org.betterx.ui.layout.values.DynamicSize;
import org.betterx.ui.layout.values.Rectangle; import org.betterx.ui.layout.values.Rectangle;
import org.betterx.ui.vanilla.VanillaScrollerRenderer; import org.betterx.ui.vanilla.VanillaScrollerRenderer;
@ -59,7 +60,7 @@ public class VerticalScroll<R extends ComponentRenderer, RS extends ScrollerRend
protected int updateContainerWidth(int containerWidth) { protected int updateContainerWidth(int containerWidth) {
int myWidth = width.calculateOrFill(containerWidth); int myWidth = width.calculateOrFill(containerWidth);
if (child != null) { if (child != null) {
child.width.calculateOrFill(myWidth - (scrollerRenderer.scrollerPadding() + scrollerRenderer.scrollerWidth())); child.width.calculateOrFill(myWidth - scrollerWidth());
child.updateContainerWidth(child.width.calculatedSize()); child.updateContainerWidth(child.width.calculatedSize());
} }
return myWidth; return myWidth;
@ -75,9 +76,13 @@ public class VerticalScroll<R extends ComponentRenderer, RS extends ScrollerRend
return myHeight; return myHeight;
} }
protected int scrollerWidth() {
return scrollerRenderer.scrollerWidth() + scrollerRenderer.scrollerPadding();
}
@Override @Override
public int getContentWidth() { public int getContentWidth() {
return scrollerRenderer.scrollerWidth() + scrollerRenderer.scrollerPadding() + (child != null return scrollerWidth() + (child != null
? child.getContentWidth() ? child.getContentWidth()
: 0); : 0);
} }
@ -91,8 +96,20 @@ public class VerticalScroll<R extends ComponentRenderer, RS extends ScrollerRend
void setRelativeBounds(int left, int top) { void setRelativeBounds(int left, int top) {
super.setRelativeBounds(left, top); super.setRelativeBounds(left, top);
if (child != null) if (child != null) {
child.setRelativeBounds(0, 0); int width = relativeBounds.width;
boolean willNeedScrollBar = child.height.calculatedSize() > relativeBounds.height;
if (willNeedScrollBar) width -= scrollerWidth();
int childTop = width - child.width.calculatedSize();
if (child.hAlign == Alignment.MIN) childTop = 0;
else if (child.hAlign == Alignment.CENTER) childTop /= 2;
int childLeft = relativeBounds.height - child.height.calculatedSize();
if (child.vAlign == Alignment.MIN) childLeft = 0;
else if (child.vAlign == Alignment.CENTER) childLeft /= 2;
child.setRelativeBounds(childLeft, childTop);
}
updateScrollViewMetrics(); updateScrollViewMetrics();
} }
@ -100,13 +117,13 @@ public class VerticalScroll<R extends ComponentRenderer, RS extends ScrollerRend
@Override @Override
protected void renderInBounds( protected void renderInBounds(
PoseStack poseStack, PoseStack poseStack,
int x, int mouseX,
int y, int mouseY,
float a, float deltaTicks,
Rectangle renderBounds, Rectangle renderBounds,
Rectangle clipRect Rectangle clipRect
) { ) {
super.renderInBounds(poseStack, x, y, a, renderBounds, clipRect); super.renderInBounds(poseStack, mouseX, mouseY, deltaTicks, renderBounds, clipRect);
if (showScrollBar()) { if (showScrollBar()) {
if (child != null) { if (child != null) {
@ -114,13 +131,8 @@ public class VerticalScroll<R extends ComponentRenderer, RS extends ScrollerRend
poseStack.translate(0, scrollerOffset(), 0); poseStack.translate(0, scrollerOffset(), 0);
setClippingRect(clipRect); setClippingRect(clipRect);
child.render( child.render(
poseStack, x, y, a, poseStack, mouseX, mouseY, deltaTicks,
renderBounds.movedBy( renderBounds.movedBy(0, scrollerOffset(), scrollerWidth(), 0),
0,
scrollerOffset(),
scrollerRenderer.scrollerWidth() + scrollerRenderer.scrollerPadding(),
0
),
clipRect clipRect
); );
setClippingRect(null); setClippingRect(null);
@ -129,7 +141,7 @@ public class VerticalScroll<R extends ComponentRenderer, RS extends ScrollerRend
scrollerRenderer.renderScrollBar(renderBounds, saveScrollerY(), scrollerHeight); scrollerRenderer.renderScrollBar(renderBounds, saveScrollerY(), scrollerHeight);
} else { } else {
if (child != null) { if (child != null) {
child.render(poseStack, x, y, a, renderBounds, clipRect); child.render(poseStack, mouseX, mouseY, deltaTicks, renderBounds, clipRect);
} }
} }
} }

View file

@ -9,5 +9,12 @@ import net.fabricmc.api.Environment;
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
public interface ComponentRenderer { public interface ComponentRenderer {
void renderInBounds(PoseStack stack, int x, int y, float a, Rectangle bounds, Rectangle clipRect); void renderInBounds(
PoseStack stack,
int mouseX,
int mouseY,
float deltaTicks,
Rectangle bounds,
Rectangle clipRect
);
} }

View file

@ -10,7 +10,14 @@ import net.fabricmc.api.Environment;
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
public class NullRenderer implements ComponentRenderer { public class NullRenderer implements ComponentRenderer {
@Override @Override
public void renderInBounds(PoseStack stack, int x, int y, float a, Rectangle bounds, Rectangle clipRect) { public void renderInBounds(
PoseStack stack,
int mouseX,
int mouseY,
float deltaTicks,
Rectangle bounds,
Rectangle clipRect
) {
} }
} }

View file

@ -3,6 +3,10 @@ package org.betterx.ui.layout.components.render;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font; import net.minecraft.client.gui.Font;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
@Environment(EnvType.CLIENT)
public interface TextProvider { public interface TextProvider {
default Font getFont() { default Font getFont() {
return Minecraft.getInstance().font; return Minecraft.getInstance().font;

View file

@ -0,0 +1,4 @@
package org.betterx.ui.layout.values;
public record Size(int width, int height) {
}