mirror of
https://github.com/GTNewHorizons/StructureLib.git
synced 2026-11-11 15:57:39 +00:00
402 lines
14 KiB
Java
402 lines
14 KiB
Java
package com.gtnewhorizon.structurelib.gui;
|
|
|
|
import com.gtnewhorizon.structurelib.StructureLib;
|
|
import com.gtnewhorizon.structurelib.alignment.constructable.ChannelDataAccessor;
|
|
import com.gtnewhorizon.structurelib.gui.GuiScrollableList.IGuiScreen;
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
import java.util.Map.Entry;
|
|
import java.util.stream.Collectors;
|
|
import net.minecraft.client.gui.GuiButton;
|
|
import net.minecraft.client.gui.GuiScreen;
|
|
import net.minecraft.client.gui.GuiTextField;
|
|
import net.minecraft.client.renderer.Tessellator;
|
|
import net.minecraft.client.resources.I18n;
|
|
import net.minecraft.item.ItemStack;
|
|
import net.minecraft.util.EnumChatFormatting;
|
|
import net.minecraft.util.ResourceLocation;
|
|
import org.apache.commons.lang3.StringUtils;
|
|
import org.lwjgl.input.Keyboard;
|
|
import org.lwjgl.input.Mouse;
|
|
import org.lwjgl.opengl.GL11;
|
|
|
|
public class GuiScreenConfigureChannels extends GuiScreen implements IGuiScreen {
|
|
private static final int KEY_MAX_WIDTH = 50;
|
|
private final ItemStack trigger;
|
|
private final GuiChannelsList list;
|
|
private GuiTextField key, value;
|
|
protected int guiTop, guiLeft;
|
|
|
|
public GuiScreenConfigureChannels(ItemStack trigger) {
|
|
this.trigger = trigger;
|
|
list = new GuiChannelsList(152, 100, 12, 12, 14);
|
|
list.addSelectionListener((list, selectedIndex) -> {
|
|
Entry<String, Integer> e = list.getElementAt(selectedIndex);
|
|
key.setText(e.getKey());
|
|
value.setText(e.getValue().toString());
|
|
updateButtons();
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void initGui() {
|
|
super.initGui();
|
|
// so you can keep holding backspace to delete a long sequence of chars
|
|
Keyboard.enableRepeatEvents(true);
|
|
|
|
guiLeft = (this.width - this.getXSize()) / 2;
|
|
guiTop = (this.height - this.getYSize()) / 2;
|
|
|
|
key = new GuiTextField(fontRendererObj, guiLeft + 45, guiTop + 119, 151 + 12 - 45, 12) {
|
|
@Override
|
|
public void writeText(String text) {
|
|
// force lower case
|
|
super.writeText(text.toLowerCase(Locale.ROOT));
|
|
updateButtons();
|
|
}
|
|
|
|
@Override
|
|
public void mouseClicked(int p_146192_1_, int p_146192_2_, int p_146192_3_) {
|
|
super.mouseClicked(p_146192_1_, p_146192_2_, p_146192_3_);
|
|
boolean flag = p_146192_1_ >= this.xPosition
|
|
&& p_146192_1_ < this.xPosition + this.width
|
|
&& p_146192_2_ >= this.yPosition
|
|
&& p_146192_2_ < this.yPosition + this.height;
|
|
if (flag && p_146192_3_ == 1) {
|
|
key.setText("");
|
|
value.setText("");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setText(String p_146180_1_) {
|
|
super.setText(p_146180_1_);
|
|
updateButtons();
|
|
}
|
|
};
|
|
value = new GuiTextField(fontRendererObj, guiLeft + 45, guiTop + 139, 151 + 12 - 45, 12) {
|
|
@Override
|
|
public void writeText(String text) {
|
|
// ignore write requests containing non digit characters.
|
|
// we don't accept decimals or negative numbers, so we can safely use isDigit instead of something more
|
|
// advanced
|
|
// use codePoints() in case someone pasted an emoji by mistake
|
|
if (text != null && text.codePoints().allMatch(Character::isDigit)) {
|
|
super.writeText(text);
|
|
updateButtons();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setFocused(boolean p_146195_1_) {
|
|
if (!p_146195_1_ && isFocused() && !StringUtils.isBlank(getText())) {
|
|
int result;
|
|
try {
|
|
result = Math.max(Integer.parseInt(getText()), 1);
|
|
} catch (NumberFormatException e) {
|
|
result = 1;
|
|
}
|
|
setText(String.valueOf(result));
|
|
}
|
|
super.setFocused(p_146195_1_);
|
|
}
|
|
|
|
@Override
|
|
public void mouseClicked(int p_146192_1_, int p_146192_2_, int p_146192_3_) {
|
|
super.mouseClicked(p_146192_1_, p_146192_2_, p_146192_3_);
|
|
boolean flag = p_146192_1_ >= this.xPosition
|
|
&& p_146192_1_ < this.xPosition + this.width
|
|
&& p_146192_2_ >= this.yPosition
|
|
&& p_146192_2_ < this.yPosition + this.height;
|
|
if (flag && p_146192_3_ == 1) {
|
|
setText("");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setText(String p_146180_1_) {
|
|
super.setText(p_146180_1_);
|
|
updateButtons();
|
|
}
|
|
};
|
|
|
|
list.onGuiInit(this);
|
|
|
|
addButton(new GuiButton(
|
|
0, guiLeft + 12, guiTop + 157, 47, 20, I18n.format("item.structurelib.constructableTrigger.gui.add")));
|
|
addButton(new GuiButton(
|
|
1,
|
|
guiLeft + 65,
|
|
guiTop + 157,
|
|
47,
|
|
20,
|
|
I18n.format("item.structurelib.constructableTrigger.gui.unset")));
|
|
addButton(new GuiButton(
|
|
2,
|
|
guiLeft + 118,
|
|
guiTop + 157,
|
|
47,
|
|
20,
|
|
I18n.format("item.structurelib.constructableTrigger.gui.wipe")));
|
|
|
|
updateButtons();
|
|
}
|
|
|
|
@Override
|
|
public int getGuiLeft() {
|
|
return guiLeft;
|
|
}
|
|
|
|
@Override
|
|
public int getGuiTop() {
|
|
return guiTop;
|
|
}
|
|
|
|
@Override
|
|
public int getXSize() {
|
|
return 176;
|
|
}
|
|
|
|
@Override
|
|
public int getYSize() {
|
|
return 188;
|
|
}
|
|
|
|
@Override
|
|
public void addButton(GuiButton button) {
|
|
getButtonList().add(button);
|
|
}
|
|
|
|
@Override
|
|
public void removeButton(GuiButton button) {
|
|
getButtonList().remove(button);
|
|
}
|
|
|
|
@Override
|
|
public int getOverlayOffsetX() {
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
public void doActionPerformed(GuiButton but) {
|
|
actionPerformed(but);
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
private List<GuiButton> getButtonList() {
|
|
return buttonList;
|
|
}
|
|
|
|
@Override
|
|
public void handleMouseInput() {
|
|
int delta = Mouse.getEventDWheel();
|
|
if (delta != 0) list.handleDWheel(delta);
|
|
super.handleMouseInput();
|
|
}
|
|
|
|
@Override
|
|
protected void mouseClicked(int mX, int mY, int button) {
|
|
key.mouseClicked(mX, mY, button);
|
|
value.mouseClicked(mX, mY, button);
|
|
super.mouseClicked(mX, mY, button);
|
|
}
|
|
|
|
@Override
|
|
protected void keyTyped(char aChar, int aKey) {
|
|
switch (aKey) {
|
|
case Keyboard.KEY_TAB:
|
|
if (key.isFocused()) {
|
|
key.setFocused(false);
|
|
value.setFocused(true);
|
|
} else {
|
|
key.setFocused(true);
|
|
value.setFocused(false);
|
|
}
|
|
return;
|
|
case Keyboard.KEY_RETURN:
|
|
case Keyboard.KEY_NUMPADENTER:
|
|
GuiButton add = getButtonList().get(0);
|
|
if (add.enabled) doActionPerformed(add);
|
|
return;
|
|
case Keyboard.KEY_UP:
|
|
if (list.selectedIndex > 0) list.setSelection(list.selectedIndex - 1);
|
|
return;
|
|
case Keyboard.KEY_DOWN:
|
|
if (list.selectedIndex < list.getNumElements() - 1) list.setSelection(list.selectedIndex + 1);
|
|
return;
|
|
}
|
|
if (key.textboxKeyTyped(aChar, aKey)) {
|
|
updateButtons();
|
|
return;
|
|
}
|
|
if (value.textboxKeyTyped(aChar, aKey)) return;
|
|
super.keyTyped(aChar, aKey);
|
|
}
|
|
|
|
private void updateButtons() {
|
|
// this will be called from setText of key and value. NEVER UPDATE THE VALUE OF THESE HERE OR GET A
|
|
// STACKOVERFLOW!
|
|
String keyText = key.getText();
|
|
boolean existing = !StringUtils.isEmpty(keyText) && ChannelDataAccessor.hasSubChannel(trigger, keyText);
|
|
getButtonList().get(0).displayString = existing
|
|
? I18n.format("item.structurelib.constructableTrigger.gui.set")
|
|
: I18n.format("item.structurelib.constructableTrigger.gui.add");
|
|
getButtonList().get(0).enabled = !StringUtils.isBlank(value.getText());
|
|
getButtonList().get(1).enabled = existing && !StringUtils.isBlank(value.getText());
|
|
}
|
|
|
|
private int getValue() {
|
|
try {
|
|
return Integer.parseInt(value.getText());
|
|
} catch (NumberFormatException e) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void actionPerformed(GuiButton btn) {
|
|
if (btn == null) return;
|
|
switch (btn.id) {
|
|
case 0:
|
|
int value = getValue();
|
|
if (value <= 0) return;
|
|
ChannelDataAccessor.setChannelData(trigger, key.getText(), value);
|
|
break;
|
|
case 1:
|
|
ChannelDataAccessor.unsetChannelData(trigger, key.getText());
|
|
break;
|
|
case 2:
|
|
ChannelDataAccessor.wipeChannelData(trigger);
|
|
break;
|
|
}
|
|
super.actionPerformed(btn);
|
|
}
|
|
|
|
@Override
|
|
public void onGuiClosed() {
|
|
super.onGuiClosed();
|
|
Keyboard.enableRepeatEvents(false);
|
|
StructureLib.instance().proxy().uploadChannels(trigger);
|
|
}
|
|
|
|
@Override
|
|
public void updateScreen() {
|
|
super.updateScreen();
|
|
key.updateCursorCounter();
|
|
value.updateCursorCounter();
|
|
}
|
|
|
|
@Override
|
|
public boolean doesGuiPauseGame() {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public void drawScreen(int mX, int mY, float partialTick) {
|
|
mc.renderEngine.bindTexture(new ResourceLocation("structurelib", "textures/gui/channels.png"));
|
|
int topLeftX = (this.width - this.getXSize()) / 2;
|
|
int topLeftY = (this.height - this.getYSize()) / 2;
|
|
drawTexturedModalRect(topLeftX, topLeftY, 0, 0, getXSize(), getYSize());
|
|
super.drawScreen(mX, mY, partialTick);
|
|
list.drawScreen(mX, mY, partialTick);
|
|
fontRendererObj.drawString(
|
|
I18n.format("item.structurelib.constructableTrigger.gui.key"), guiLeft + 12, guiTop + 122, 0);
|
|
key.drawTextBox();
|
|
fontRendererObj.drawString(
|
|
I18n.format("item.structurelib.constructableTrigger.gui.value"), guiLeft + 12, guiTop + 142, 0);
|
|
value.drawTextBox();
|
|
}
|
|
|
|
private class GuiChannelsList extends GuiScrollableList<Entry<String, Integer>> {
|
|
private List<Entry<String, Integer>> cache;
|
|
|
|
public GuiChannelsList(int width, int height, int originX, int originY, int slotHeight) {
|
|
super(width, height, originX, originY, slotHeight);
|
|
}
|
|
|
|
@Override
|
|
public Entry<String, Integer> getElementAt(int index) {
|
|
return ChannelDataAccessor.iterateChannelData(trigger)
|
|
.sorted()
|
|
.skip(index)
|
|
.findFirst()
|
|
.orElse(null);
|
|
}
|
|
|
|
@Override
|
|
public int getNumElements() {
|
|
return ChannelDataAccessor.countChannelData(trigger);
|
|
}
|
|
|
|
@Override
|
|
protected boolean elementClicked(int elementIndex, boolean doubleClick, int mXRelative, int mYRelative) {
|
|
if (mXRelative >= margin + 1
|
|
&& mXRelative <= margin + 5
|
|
&& mYRelative >= margin / 2 + 1
|
|
&& mYRelative <= margin / 2 + 5) {
|
|
Entry<String, Integer> e = getElementAt(elementIndex);
|
|
if (e != null) {
|
|
ChannelDataAccessor.unsetChannelData(trigger, e.getKey());
|
|
return false;
|
|
}
|
|
}
|
|
return super.elementClicked(elementIndex, doubleClick, mXRelative, mYRelative);
|
|
}
|
|
|
|
@Override
|
|
protected void prepareDrawElements() {
|
|
cache = ChannelDataAccessor.iterateChannelData(trigger).sorted().collect(Collectors.toList());
|
|
}
|
|
|
|
@Override
|
|
protected void drawElement(
|
|
int elementIndex, int x, int y, int height, Tessellator tessellator, boolean isHovering) {
|
|
if (elementIndex < 0 || elementIndex >= cache.size()) {
|
|
return;
|
|
}
|
|
Entry<String, Integer> e = cache.get(elementIndex);
|
|
if (e == null) return;
|
|
if (elementIndex > 0) {
|
|
// args x1, x2, y1, color
|
|
drawHorizontalLine(minX + 1, maxX - 1, y - 2, 0xffaaaaaa);
|
|
}
|
|
int keyMaxWidth = KEY_MAX_WIDTH * 2;
|
|
if (isHovering) {
|
|
mc.renderEngine.bindTexture(new ResourceLocation("structurelib", "textures/gui/channels.png"));
|
|
GL11.glColor4f(1, 1, 1, 1);
|
|
drawTexturedModalRect(x + margin + 1, y + margin / 2 + 1, 251, 251, 5, 5);
|
|
}
|
|
fontRendererObj.drawString(trim(e.getKey(), keyMaxWidth - 9), x + margin + 8, y + margin / 2, 0xffffff);
|
|
int valueX = x + margin + keyMaxWidth + margin;
|
|
fontRendererObj.drawString(trim(e.getValue().toString(), maxX - valueX), valueX, y + margin / 2, 0xffffff);
|
|
}
|
|
|
|
@Override
|
|
public void drawScreen(int mX, int mY, float partialTick) {
|
|
super.drawScreen(mX, mY, partialTick);
|
|
// args x1, y1, y2, color
|
|
drawVerticalLine(minX + margin + margin / 2 + KEY_MAX_WIDTH * 2, minY + 1, maxY - 1, 0xffaaaaaa);
|
|
}
|
|
|
|
public String trim(String e, int keyMaxWidth) {
|
|
// TODO optimize this to not create a billion string, or maybe cache this
|
|
String s = fontRendererObj.trimStringToWidth(e, keyMaxWidth);
|
|
if (s.length() != e.length()) {
|
|
StringBuilder buffer =
|
|
new StringBuilder(s).deleteCharAt(s.length() - 1).append("...");
|
|
while ((s = fontRendererObj.trimStringToWidth(buffer.toString(), keyMaxWidth)).length()
|
|
!= buffer.length())
|
|
// drop last original char
|
|
buffer.deleteCharAt(s.length() - 4);
|
|
do {
|
|
buffer.append('.');
|
|
} while (fontRendererObj.getStringWidth(buffer.toString()) <= keyMaxWidth);
|
|
s = buffer.deleteCharAt(s.length() - 1)
|
|
.insert(s.length() - 3, EnumChatFormatting.GRAY)
|
|
.toString();
|
|
}
|
|
return s;
|
|
}
|
|
}
|
|
}
|