Scrollable GridScreen
This commit is contained in:
parent
f3bdaaac8e
commit
9d7fa9f925
5 changed files with 353 additions and 31 deletions
|
@ -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;
|
||||
|
@ -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,7 +133,7 @@ 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;
|
||||
|
@ -138,6 +141,7 @@ public class GridLayout extends GridColumn {
|
|||
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -22,6 +31,8 @@ public abstract class GridScreen extends Screen {
|
|||
@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);
|
||||
|
@ -89,14 +98,30 @@ public abstract class GridScreen extends Screen {
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,23 +47,8 @@ abstract class BCLibScreen extends GridScreen {
|
|||
row.addFiller();
|
||||
row.addImage(BCLIB_LOGO_LOCATION, 24, GridValueType.CONSTANT, 24, 512, 512);
|
||||
row.addSpacer(4);
|
||||
row.addString(this.title, font.lineHeight,this);
|
||||
row.addString(this.title, this);
|
||||
row.addFiller();
|
||||
grid.addSpacerRow(15);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(PoseStack poseStack, int i, int j, float f) {
|
||||
this.renderDirtBackground(i);
|
||||
//
|
||||
// RenderSystem.setShader(GameRenderer::getPositionTexShader);
|
||||
// RenderSystem.setShaderTexture(0, BCLIB_LOGO_LOCATION);
|
||||
// RenderSystem.enableBlend();
|
||||
// RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||
// RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0f);
|
||||
// blit(poseStack, 0, 0, 32, 32, 0, 0, 512, 512, 512, 512);
|
||||
|
||||
if (grid!=null) grid.render(poseStack);
|
||||
super.renderScreen(poseStack, i, j, f);
|
||||
}
|
||||
}
|
||||
|
|
182
src/main/java/ru/bclib/gui/screens/ModListScreen.java
Normal file
182
src/main/java/ru/bclib/gui/screens/ModListScreen.java
Normal file
|
@ -0,0 +1,182 @@
|
|||
package ru.bclib.gui.screens;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.loader.api.metadata.ModEnvironment;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.network.chat.CommonComponents;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
import ru.bclib.api.dataexchange.handler.autosync.HelloClient;
|
||||
import ru.bclib.gui.gridlayout.GridColumn;
|
||||
import ru.bclib.gui.gridlayout.GridLayout;
|
||||
import ru.bclib.gui.gridlayout.GridRow;
|
||||
import ru.bclib.gui.gridlayout.GridScreen;
|
||||
import ru.bclib.util.ModUtil;
|
||||
import ru.bclib.util.Pair;
|
||||
import ru.bclib.util.PathUtil;
|
||||
import ru.bclib.util.Triple;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class ModListScreen extends BCLibScreen {
|
||||
|
||||
private final List<ModUtil.ModInfo> mods;
|
||||
private final HelloClient.IServerModMap serverInfo;
|
||||
private final Component description;
|
||||
|
||||
private static List<ModUtil.ModInfo> extractModList(Map<String, ModUtil.ModInfo> mods){
|
||||
List<ModUtil.ModInfo> list = new LinkedList<ModUtil.ModInfo>();
|
||||
ModUtil.getMods().forEach((id, info) -> list.add(info));
|
||||
return list;
|
||||
}
|
||||
|
||||
public ModListScreen(Screen parent, Component title, Component description, Map<String, ModUtil.ModInfo> mods, HelloClient.IServerModMap serverInfo) {
|
||||
this(parent, title, description, extractModList(mods), serverInfo);
|
||||
}
|
||||
|
||||
public ModListScreen(Screen parent, Component title, Component description, List<ModUtil.ModInfo> mods, HelloClient.IServerModMap serverInfo) {
|
||||
super(parent, title, 10, true);
|
||||
this.mods = mods;
|
||||
this.serverInfo = serverInfo;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public static void addModDesc(GridColumn grid, java.util.List<ModUtil.ModInfo> mods, HelloClient.IServerModMap serverInfo, GridScreen parent) {
|
||||
final int STATE_OK = 0;
|
||||
final int STATE_MISSING = 1;
|
||||
final int STATE_SERVER_MISSING = 2;
|
||||
final int STATE_VERSION = 3;
|
||||
final int STATE_SERVER_MISSING_CLIENT_MOD = 4;
|
||||
|
||||
List<Triple<String, Integer, String>> items = new LinkedList<>();
|
||||
if (serverInfo!=null) {
|
||||
serverInfo.keySet()
|
||||
.stream()
|
||||
.filter(modid -> !mods.stream().filter(mod -> mod.metadata.getId().equals(modid)).findFirst().isPresent())
|
||||
.forEach(modid -> {
|
||||
int size = serverInfo.get(modid).second;
|
||||
String stateString = serverInfo.get(modid).first;
|
||||
if (size>0) {
|
||||
stateString = "Version: " + stateString + ", Size: " + PathUtil.humanReadableFileSize(size);
|
||||
}
|
||||
|
||||
items.add(new Triple<>(modid, STATE_MISSING, stateString));
|
||||
});
|
||||
}
|
||||
|
||||
mods.forEach(mod -> {
|
||||
String serverVersion = null;
|
||||
int serverSize = 0;
|
||||
int state = STATE_OK;
|
||||
if (serverInfo != null) {
|
||||
final String modID = mod.metadata.getId();
|
||||
|
||||
|
||||
Pair<String, Integer> data = serverInfo.get(modID);
|
||||
if (data!=null) {
|
||||
final String modVer = data.first;
|
||||
final int size = data.second;
|
||||
if (!modVer.equals(mod.getVersion())) {
|
||||
state = STATE_VERSION;
|
||||
serverVersion = modVer;
|
||||
serverSize = size;
|
||||
}
|
||||
} else if (mod.metadata.getEnvironment() == ModEnvironment.CLIENT){
|
||||
state = STATE_SERVER_MISSING_CLIENT_MOD;
|
||||
} else {
|
||||
state = STATE_SERVER_MISSING;
|
||||
}
|
||||
}
|
||||
|
||||
String stateString = mod.metadata.getVersion().toString();
|
||||
if (serverVersion!=null) {
|
||||
stateString = "Client: " + stateString;
|
||||
stateString += ", Server: " + serverVersion;
|
||||
if (serverSize>0) {
|
||||
stateString += ", Size: " + PathUtil.humanReadableFileSize(serverSize);
|
||||
}
|
||||
}
|
||||
if (mod.metadata.getEnvironment() == ModEnvironment.CLIENT) {
|
||||
stateString+= ", client-only";
|
||||
} else if (mod.metadata.getEnvironment() == ModEnvironment.SERVER) {
|
||||
stateString+= ", server-only";
|
||||
}
|
||||
items.add(new Triple<>(mod.metadata.getName(), state, stateString));
|
||||
});
|
||||
|
||||
items.stream()
|
||||
.sorted(Comparator.comparing(a -> a.first.toLowerCase(Locale.ROOT)))
|
||||
.forEach(t -> {
|
||||
final String name = t.first;
|
||||
final int state = t.second;
|
||||
final String stateString = t.third;
|
||||
|
||||
int color = GridLayout.COLOR_RED;
|
||||
final String typeText;
|
||||
if (state==STATE_VERSION) {
|
||||
typeText = "[VERSION]";
|
||||
} else if (state==STATE_MISSING) {
|
||||
typeText = "[MISSING]";
|
||||
} else if (state==STATE_SERVER_MISSING || state == STATE_SERVER_MISSING_CLIENT_MOD) {
|
||||
typeText = "[NOT ON SERVER]";
|
||||
if (state == STATE_SERVER_MISSING_CLIENT_MOD) {
|
||||
color = GridLayout.COLOR_YELLOW;
|
||||
}
|
||||
} else {
|
||||
color = GridLayout.COLOR_CYAN;
|
||||
typeText = "[OK]";
|
||||
}
|
||||
TextComponent dash = new TextComponent("-");
|
||||
TextComponent typeTextComponent = new TextComponent(typeText);
|
||||
GridRow row = grid.addRow();
|
||||
|
||||
row.addString(dash, parent);
|
||||
|
||||
row.addSpacer(4);
|
||||
row.addString(new TextComponent(name), parent);
|
||||
|
||||
row.addSpacer(4);
|
||||
row.addString(typeTextComponent, color, parent);
|
||||
|
||||
if (!stateString.isEmpty()) {
|
||||
row = grid.addRow();
|
||||
row.addSpacer(4 + parent.getWidth(dash));
|
||||
row.addString(new TextComponent(stateString), GridLayout.COLOR_GRAY, parent);
|
||||
}
|
||||
|
||||
grid.addSpacerRow();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initLayout() {
|
||||
if (description != null) {
|
||||
grid.addSpacerRow();
|
||||
grid.addRow().addMessage(description, font, GridLayout.Alignment.CENTER);
|
||||
grid.addSpacerRow(20);
|
||||
}
|
||||
|
||||
GridRow row = grid.addRow();
|
||||
row.addSpacer(10);
|
||||
GridColumn col = row.addColumn(200, GridLayout.GridValueType.CONSTANT);
|
||||
addModDesc(col, mods, serverInfo, this);
|
||||
|
||||
grid.addSpacerRow(10);
|
||||
row = grid.addRow();
|
||||
row.addFiller();
|
||||
row.addButton(CommonComponents.GUI_BACK, 20, font, (n)-> {
|
||||
onClose();
|
||||
System.out.println("Closing");
|
||||
});
|
||||
row.addFiller();
|
||||
|
||||
grid.addSpacerRow(topPadding);
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue