Scrollable GridScreen

This commit is contained in:
Frank 2021-08-25 13:47:08 +02:00
parent f3bdaaac8e
commit 9d7fa9f925
5 changed files with 353 additions and 31 deletions

View file

@ -5,6 +5,7 @@ import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.gui.components.AbstractWidget;
import ru.bclib.gui.gridlayout.GridLayout.GridValueType;
import ru.bclib.util.Pair;
import ru.bclib.util.TriConsumer;
import java.util.LinkedList;
@ -63,7 +64,7 @@ class GridElement extends GridTransform{
}
GridTransform transformWithPadding(int leftPadding, int topPadding){
return new GridTransform(left + leftPadding, top +topPadding, width, height);
return new GridTransform(left + leftPadding, top + topPadding, width, height);
}
}
@ -84,8 +85,10 @@ abstract class GridContainer extends GridCellDefinition{
@Environment(EnvType.CLIENT)
public class GridLayout extends GridColumn {
public static final int COLOR_WHITE = 0xFFFFFFFF;
public static final int COLOR_RED = 0xFFFF0000;
public static final int COLOR_RED = 0xFFDB1F48;
public static final int COLOR_CYAN = 0xFF01949A;
public static final int COLOR_GREEN = 0xFF00FF00;
public static final int COLOR_YELLOW = 0xFFFAD02C;
public static final int COLOR_BLUE = 0xFF0000FF;
public static final int COLOR_GRAY = 0xFF7F7F7F;
@ -130,14 +133,15 @@ public class GridLayout extends GridColumn {
elements = new LinkedList<>();
GridElement el = this.buildElement((int)this.width, 0, 1, 0,0, elements);
this.height = el.height;
if (centerVertically) {
if (centerVertically && el.height + initialTopPadding < screenHeight) {
topPadding = (screenHeight - el.height - initialTopPadding) >> 1;
} else {
topPadding = initialTopPadding;
}
}
public List<Pair<AbstractWidget, Integer>> movableWidgets = new LinkedList<>();
public void finalizeLayout(){
buildLayout();
@ -145,11 +149,14 @@ public class GridLayout extends GridColumn {
.stream()
.filter(element -> element.componentPlacer!=null)
.forEach(element -> {
Object context = element.componentPlacer.apply(element.transformWithPadding(sidePadding, topPadding));
final GridTransform transform = element.transformWithPadding(sidePadding, topPadding);
final Object context = element.componentPlacer.apply(transform);
if (element.customRender != null){
element.renderContext = context;
} else if (context instanceof AbstractWidget) {
screen.addRenderableWidget((AbstractWidget) context);
final AbstractWidget widget = (AbstractWidget)context;
movableWidgets.add(new Pair(widget, widget.y));
screen.addRenderableWidget(widget);
}
});
}

View file

@ -199,7 +199,7 @@ public class GridRow extends GridContainer {
public GridStringCell addString(Component text, int color, GridScreen parent) {
final int width = parent.getWidth(text);
return this.addString(text, width, GridValueType.CONSTANT, GridLayout.COLOR_WHITE, Alignment.CENTER, parent);
return this.addString(text, width, GridValueType.CONSTANT, color, Alignment.CENTER, parent);
}
public GridStringCell addString(Component text, Alignment contentAlignment, GridScreen parent) {

View file

@ -1,14 +1,23 @@
package ru.bclib.gui.gridlayout;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.blaze3d.vertex.VertexFormat;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.components.AbstractSelectionList;
import net.minecraft.client.gui.components.OptionsList;
import net.minecraft.client.gui.components.Widget;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.narration.NarratableEntry;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.network.chat.Component;
import net.minecraft.util.Mth;
import org.jetbrains.annotations.Nullable;
import ru.bclib.gui.gridlayout.GridLayout.Alignment;
@ -21,6 +30,8 @@ public abstract class GridScreen extends Screen {
public final boolean centerVertically;
@Nullable
public final Screen parent;
protected int scrollPos = 0;
public GridScreen(Component title) {
this(null, title);
@ -65,8 +76,6 @@ public abstract class GridScreen extends Screen {
return super.addRenderableWidget(guiEventListener);
}
protected void addTitle(){
grid.addRow().addString(this.title, Alignment.CENTER, this);
grid.addSpacerRow(15);
@ -87,16 +96,32 @@ public abstract class GridScreen extends Screen {
protected void renderScreen(PoseStack poseStack, int i, int j, float f) {
super.render(poseStack, i, j, f);
}
public void render(PoseStack poseStack, int i, int j, float f) {
//this.renderBackground(poseStack);
this.renderDirtBackground(i);
//drawCenteredString(poseStack, this.font, this.title, grid.width / 2, grid.getTopStart(), 16777215);
if (grid!=null) grid.render(poseStack);
renderGrid(poseStack);
super.render(poseStack, i, j, f);
}
protected void renderGrid(PoseStack poseStack) {
if (grid!=null) {
if (isScrollable()) {
for (var item : grid.movableWidgets) {
item.first.y = item.second + scrollPos;
}
renderScroll(poseStack);
poseStack.pushPose();
poseStack.translate(0, scrollPos, 0);
grid.render(poseStack);
poseStack.popPose();
} else {
grid.render(poseStack);
}
}
}
public static int getWidth(Component text, Font font) {
return font.width(text.getVisualOrderText());
}
@ -104,4 +129,127 @@ public abstract class GridScreen extends Screen {
public int getWidth(Component text) {
return getWidth(text, getFont());
}
public void setScrollPos(int sp) {
scrollPos = Math.max(getMaxScrollPos(), Math.min(0, sp));
}
public int getScrollPos() {
return scrollPos;
}
public int getScrollHeight() {
if (grid!=null) return grid.getHeight() + topPadding;
return height;
}
public int getMaxScrollPos() {
return height-getScrollHeight();
}
public boolean isScrollable() {
if (grid==null) return false;
return height<grid.getHeight();
}
public boolean isMouseOverScroller(double x, double y) {
return y >= 0 && y <= height && x >= width-SCROLLER_WIDTH && x <= width;
}
private boolean scrolling = false;
protected void updateScrollingState(double x, double y, int i) {
this.scrolling = i == 0 && x >= width-SCROLLER_WIDTH && x < width;
}
private static final int SCROLLER_WIDTH = 6;
private void renderScroll(PoseStack poseStack){
final int y1 = height;
final int y0 = 0;
final int yd = y1 - y0;
final int maxPosition = getScrollHeight();
final int x0 = width-SCROLLER_WIDTH;
final int x1 = width;
Tesselator tesselator = Tesselator.getInstance();
BufferBuilder bufferBuilder = tesselator.getBuilder();
RenderSystem.disableTexture();
RenderSystem.setShader(GameRenderer::getPositionColorShader);
int widgetHeight = (int)((float)(yd*yd) / (float)maxPosition);
widgetHeight = Mth.clamp(widgetHeight, 32, yd - 8);
float relPos = (float)this.getScrollPos() / this.getMaxScrollPos();
int top = (int)(relPos * (yd - widgetHeight)) + y0;
if (top < y0) {
top = y0;
}
bufferBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR);
//scroller background
bufferBuilder.vertex((double)x0, (double)y1, 0.0D).color(0, 0, 0, 255).endVertex();
bufferBuilder.vertex((double)x1, (double)y1, 0.0D).color(0, 0, 0, 255).endVertex();
bufferBuilder.vertex((double)x1, (double)y0, 0.0D).color(0, 0, 0, 255).endVertex();
bufferBuilder.vertex((double)x0, (double)y0, 0.0D).color(0, 0, 0, 255).endVertex();
//scroll widget shadow
bufferBuilder.vertex((double)x0, (double)(top + widgetHeight), 0.0D).color(128, 128, 128, 255).endVertex();
bufferBuilder.vertex((double)x1, (double)(top + widgetHeight), 0.0D).color(128, 128, 128, 255).endVertex();
bufferBuilder.vertex((double)x1, (double)top, 0.0D).color(128, 128, 128, 255).endVertex();
bufferBuilder.vertex((double)x0, (double)top, 0.0D).color(128, 128, 128, 255).endVertex();
//scroll widget
bufferBuilder.vertex((double)x0, (double)(top + widgetHeight - 1), 0.0D).color(192, 192, 192, 255).endVertex();
bufferBuilder.vertex((double)(x1 - 1), (double)(top + widgetHeight - 1), 0.0D).color(192, 192, 192, 255).endVertex();
bufferBuilder.vertex((double)(x1 - 1), (double)top, 0.0D).color(192, 192, 192, 255).endVertex();
bufferBuilder.vertex((double)x0, (double)top, 0.0D).color(192, 192, 192, 255).endVertex();
tesselator.end();
}
public boolean mouseClicked(double x, double y, int i) {
this.updateScrollingState(x, y, i);
if (this.scrolling) {
return true;
} else {
return super.mouseClicked(x, y, i);
}
}
public boolean mouseDragged(double xAbs, double yAbs, int i, double dX, double dY) {
if (super.mouseDragged(xAbs, yAbs, i, dX, dY)) {
return true;
} else if (i == 0 && this.scrolling) {
if (yAbs < 0) {
this.setScrollPos(0);
} else if (yAbs > height) {
this.setScrollPos(this.getMaxScrollPos());
} else {
this.setScrollPos((int)(this.getScrollPos() - dY * 2));
}
return true;
} else {
return false;
}
}
public boolean mouseScrolled(double d, double e, double f) {
if (isScrollable()) {
setScrollPos((int) (scrollPos + f * 10));
}
return true;
}
public boolean keyPressed(int keyCode, int j, int k) {
if (super.keyPressed(keyCode, j, k)) {
return true;
} else if (keyCode == 264) {
this.mouseScrolled(0, -1.0f, 0);
return true;
} else if (keyCode == 265) {
this.mouseScrolled(0, 1.0, 0);
return true;
} else {
return false;
}
}
}