Scroller with correct clipping
This commit is contained in:
parent
472aa16967
commit
67d21f3fba
10 changed files with 142 additions and 27 deletions
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue