Scroller with correct clipping

This commit is contained in:
Frank 2022-07-15 14:52:35 +02:00
parent 472aa16967
commit 67d21f3fba
10 changed files with 142 additions and 27 deletions

View file

@ -2,8 +2,8 @@ package org.betterx.bclib.client.gui.modmenu;
import org.betterx.ui.layout.components.*;
import org.betterx.ui.layout.values.DynamicSize;
import org.betterx.ui.vanilla.LayoutScreen;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
@ -11,23 +11,28 @@ import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
@Environment(EnvType.CLIENT)
public class TestScreen extends Screen {
public class TestScreen extends LayoutScreen {
public TestScreen(Component component) {
super(component);
}
Panel main;
public TestScreen(Screen parent, Component component) {
super(parent, component);
}
@Override
protected void init() {
super.init();
main = new Panel(this.width, this.height);
VerticalStack rows = new VerticalStack(DynamicSize.fit(), DynamicSize.relative(1));
protected org.betterx.ui.layout.components.Component<?> initContent() {
VerticalStack rows = new VerticalStack(DynamicSize.fit(), DynamicSize.fitOrFill());
rows.addFiller();
rows.add(new Text(
DynamicSize.fitOrFill(), DynamicSize.fit(),
Component.literal("Some Text")
).alignRight()
);
rows.add(new Text(
DynamicSize.fitOrFill(), DynamicSize.fit(),
Component.literal("Some other, longer Text")
).centerHorizontal()
);
rows.addSpacer(16);
@ -67,7 +72,7 @@ public class TestScreen extends Screen {
}
));
rows.add(cb1);
rows.addSpacer(16);
rows.addSpacer(32);
rows.add(new Button(
DynamicSize.fit(), DynamicSize.fit(),
Component.literal("test"),
@ -90,15 +95,7 @@ public class TestScreen extends Screen {
).centerHorizontal()
);
rows.addFiller();
main.setChild(HorizontalStack.centered(rows));
main.calculateLayout();
addRenderableWidget(main);
}
@Override
public void render(PoseStack poseStack, int i, int j, float f) {
renderDirtBackground(i);
super.render(poseStack, i, j, f);
return HorizontalStack.centered(VerticalScroll.create(DynamicSize.fit(), DynamicSize.relative(1), rows));
}
}

View file

@ -28,7 +28,7 @@ public class ModMenuEntryPoint implements ModMenuApi {
@Override
public ConfigScreenFactory<?> getModConfigScreenFactory() {
return (parent) -> new TestScreen(Component.literal("Hello Test"));
return (parent) -> new TestScreen(parent, Component.literal("Hello Test"));
//return (parent) -> new MainScreen(parent);
}

View file

@ -5,7 +5,9 @@ import org.betterx.ui.layout.values.Alignment;
import org.betterx.ui.layout.values.DynamicSize;
import org.betterx.ui.layout.values.Rectangle;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.fabricmc.api.EnvType;
@ -65,6 +67,21 @@ public abstract class Component<R extends ComponentRenderer> implements Componen
return height.calculatedSize();
}
protected final void setClippingRect(Rectangle clippingRect) {
if (clippingRect == null) {
RenderSystem.disableScissor();
return;
}
final double uiScale = Minecraft.getInstance().getWindow().getGuiScale();
final int windowHeight = Minecraft.getInstance().getWindow().getHeight();
RenderSystem.enableScissor(
(int) (clippingRect.left * uiScale),
(int) (windowHeight - clippingRect.bottom() * uiScale),
(int) (clippingRect.width * uiScale),
(int) (clippingRect.height * uiScale)
);
}
public void render(PoseStack poseStack, int x, int y, float a, Rectangle parentBounds, Rectangle clipRect) {
Rectangle r = relativeBounds.movedBy(parentBounds.left, parentBounds.top);
Rectangle clip = r.intersect(clipRect);
@ -85,7 +102,9 @@ public abstract class Component<R extends ComponentRenderer> implements Componen
Rectangle clipRect
) {
if (renderer != null) {
setClippingRect(clipRect);
renderer.renderInBounds(poseStack, x, y, a, renderBounds, clipRect);
setClippingRect(null);
}
}

View file

@ -68,11 +68,11 @@ public class HorizontalStack extends AbstractStack<NullRenderer, HorizontalStack
}
public static HorizontalStack centered(Component<?> c) {
return new HorizontalStack(DynamicSize.relative(1), DynamicSize.relative(1)).addFiller().add(c).addFiller();
return new HorizontalStack(DynamicSize.fill(), DynamicSize.fill()).addFiller().add(c).addFiller();
}
public static HorizontalStack bottom(Component<?> c) {
return new HorizontalStack(DynamicSize.relative(1), DynamicSize.relative(1)).add(c).addFiller();
return new HorizontalStack(DynamicSize.fill(), DynamicSize.fill()).add(c).addFiller();
}
protected HorizontalStack addEmpty(DynamicSize size) {

View file

@ -1,9 +1,11 @@
package org.betterx.ui.layout.components;
import org.betterx.ui.layout.components.render.ComponentRenderer;
import org.betterx.ui.layout.components.render.NullRenderer;
import org.betterx.ui.layout.components.render.ScrollerRenderer;
import org.betterx.ui.layout.values.DynamicSize;
import org.betterx.ui.layout.values.Rectangle;
import org.betterx.ui.vanilla.VanillaScrollerRenderer;
import com.mojang.blaze3d.vertex.PoseStack;
@ -30,6 +32,25 @@ public class VerticalScroll<R extends ComponentRenderer, RS extends ScrollerRend
this.scrollerRenderer = scrollerRenderer;
}
public static VerticalScroll<NullRenderer, VanillaScrollerRenderer> create(Component<?> c) {
return create(DynamicSize.relative(1), DynamicSize.relative(1), c);
}
public static VerticalScroll<NullRenderer, VanillaScrollerRenderer> create(
DynamicSize width,
DynamicSize height,
Component<?> c
) {
VerticalScroll<NullRenderer, VanillaScrollerRenderer> res = new VerticalScroll<>(
width,
height,
VanillaScrollerRenderer.DEFAULT,
null
);
res.setChild(c);
return res;
}
public void setChild(Component<?> c) {
this.child = c;
}
@ -38,7 +59,7 @@ public class VerticalScroll<R extends ComponentRenderer, RS extends ScrollerRend
protected int updateContainerWidth(int containerWidth) {
int myWidth = width.calculateOrFill(containerWidth);
if (child != null) {
child.width.calculateOrFill(myWidth);
child.width.calculateOrFill(myWidth - (scrollerRenderer.scrollerPadding() + scrollerRenderer.scrollerWidth()));
child.updateContainerWidth(child.width.calculatedSize());
}
return myWidth;
@ -56,7 +77,9 @@ public class VerticalScroll<R extends ComponentRenderer, RS extends ScrollerRend
@Override
public int getContentWidth() {
return child != null ? child.getContentWidth() : 0;
return scrollerRenderer.scrollerWidth() + scrollerRenderer.scrollerPadding() + (child != null
? child.getContentWidth()
: 0);
}
@Override
@ -87,11 +110,21 @@ public class VerticalScroll<R extends ComponentRenderer, RS extends ScrollerRend
if (showScrollBar()) {
if (child != null) {
poseStack.pushPose();
poseStack.translate(0, scrollerOffset(), 0);
setClippingRect(clipRect);
child.render(
poseStack, x, y, a,
renderBounds.movedBy(0, scrollerOffset(), scrollerRenderer.scrollerWidth(), 0),
renderBounds.movedBy(
0,
scrollerOffset(),
scrollerRenderer.scrollerWidth() + scrollerRenderer.scrollerPadding(),
0
),
clipRect
);
setClippingRect(null);
poseStack.popPose();
}
scrollerRenderer.renderScrollBar(renderBounds, saveScrollerY(), scrollerHeight);
} else {

View file

@ -12,7 +12,11 @@ public interface ScrollerRenderer {
return 16;
}
default int scrollerWidth() {
return 16;
return 8;
}
default int scrollerPadding() {
return 2;
}
default Rectangle getScrollerBounds(Rectangle renderBounds) {

View file

@ -76,7 +76,7 @@ public class DynamicSize {
public int calculateOrFill(int parentSize) {
calculatedSize = calculate(parentSize);
if (sizeType instanceof SizeType.Fill || sizeType instanceof SizeType.FitContentOrFill) {
calculatedSize = parentSize;
calculatedSize = Math.max(parentSize, calculatedSize);
}
return calculatedSize;

View file

@ -26,6 +26,10 @@ public class Rectangle {
return top + height;
}
public Size size() {
return new Size(width, height);
}
public Rectangle movedBy(int left, int top) {
return new Rectangle(this.left + left, this.top + top, this.width, this.height);
}

View file

@ -1,6 +1,7 @@
package org.betterx.ui.vanilla;
import org.betterx.ui.layout.components.Panel;
import org.betterx.ui.layout.components.Text;
import org.betterx.ui.layout.components.VerticalStack;
import org.betterx.ui.layout.values.DynamicSize;
@ -45,16 +46,19 @@ public abstract class LayoutScreen extends Screen {
protected org.betterx.ui.layout.components.Component<?> addTitle(org.betterx.ui.layout.components.Component<?> content) {
VerticalStack rows = new VerticalStack(DynamicSize.relative(1), DynamicSize.relative(1));
//rows.add(this.title, GridLayout.Alignment.CENTER, this);
rows.add(new Text(DynamicSize.fill(), DynamicSize.fit(), title).centerHorizontal());
rows.addSpacer(15);
rows.add(content);
return rows;
}
protected void renderBackground(PoseStack poseStack, int i, int j, float f) {
renderDirtBackground(i);
}
@Override
public void render(PoseStack poseStack, int i, int j, float f) {
renderDirtBackground(i);
renderBackground(poseStack, i, j, f);
super.render(poseStack, i, j, f);
}

View file

@ -0,0 +1,54 @@
package org.betterx.ui.vanilla;
import org.betterx.ui.layout.components.render.ScrollerRenderer;
import org.betterx.ui.layout.values.Rectangle;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.blaze3d.vertex.VertexFormat;
import net.minecraft.client.renderer.GameRenderer;
public class VanillaScrollerRenderer implements ScrollerRenderer {
public static final VanillaScrollerRenderer DEFAULT = new VanillaScrollerRenderer();
@Override
public void renderScrollBar(Rectangle b, int pickerOffset, int pickerSize) {
b = this.getScrollerBounds(b);
Rectangle p = this.getPickerBounds(b, pickerOffset, pickerSize);
Tesselator tesselator = Tesselator.getInstance();
BufferBuilder bufferBuilder = tesselator.getBuilder();
RenderSystem.disableTexture();
RenderSystem.setShader(GameRenderer::getPositionColorShader);
bufferBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR);
//scroller background
bufferBuilder.vertex(b.left, b.bottom(), 0.0D).color(0, 0, 0, 255).endVertex();
bufferBuilder.vertex(b.right(), b.bottom(), 0.0D).color(0, 0, 0, 255).endVertex();
bufferBuilder.vertex(b.right(), b.top, 0.0D).color(0, 0, 0, 255).endVertex();
bufferBuilder.vertex(b.left, b.top, 0.0D).color(0, 0, 0, 255).endVertex();
//scroll widget shadow
bufferBuilder.vertex(p.left, p.bottom(), 0.0D).color(128, 128, 128, 255).endVertex();
bufferBuilder.vertex(p.right(), p.bottom(), 0.0D).color(128, 128, 128, 255).endVertex();
bufferBuilder.vertex(p.right(), p.top, 0.0D).color(128, 128, 128, 255).endVertex();
bufferBuilder.vertex(p.left, p.top, 0.0D).color(128, 128, 128, 255).endVertex();
//scroll widget
bufferBuilder.vertex(p.left, p.bottom() - 1, 0.0D)
.color(192, 192, 192, 255)
.endVertex();
bufferBuilder.vertex(p.right() - 1, p.bottom() - 1, 0.0D)
.color(192, 192, 192, 255)
.endVertex();
bufferBuilder.vertex(p.right() - 1, p.top, 0.0D).color(192, 192, 192, 255).endVertex();
bufferBuilder.vertex(p.left, p.top, 0.0D).color(192, 192, 192, 255).endVertex();
tesselator.end();
}
}