mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-12 17:47:32 +00:00
Better Texture Selection GUI
This commit is contained in:
1 parent
4369f99225
commit
8203fc7d6b
4 files changed
+346
-2
No files matched your search
@@ -175,7 +175,7 @@ public class SubGuiChainedAbilityConfig extends SubGuiInterface implements IText
|
||||
java.util.function.BooleanSupplier layerVisible = () -> chainIcon.getLayerCount() > idx;
|
||||
String sectionLabel = net.minecraft.util.StatCollector.translateToLocal("ability.icon.layer") + " " + (idx + 1);
|
||||
fieldDefs.add(FieldDef.section(sectionLabel).tab("Icon").visibleWhen(layerVisible));
|
||||
fieldDefs.add(FieldDef.stringField("gui.texture",
|
||||
fieldDefs.add(FieldDef.textureSubGui("gui.texture",
|
||||
() -> chainIcon.getLayer(idx).texture,
|
||||
t -> chainIcon.setLayerTexture(idx, t))
|
||||
.tab("Icon").visibleWhen(layerVisible));
|
||||
|
||||
@@ -5,6 +5,7 @@ import cpw.mods.fml.relauncher.SideOnly;
|
||||
import noppes.npcs.client.gui.SubGuiColorSelector;
|
||||
import noppes.npcs.client.gui.select.GuiAnimationSelection;
|
||||
import noppes.npcs.client.gui.select.GuiSoundSelection;
|
||||
import noppes.npcs.client.gui.select.GuiTexturePathSelection;
|
||||
import noppes.npcs.client.gui.util.SubGuiInterface;
|
||||
import noppes.npcs.controllers.AnimationController;
|
||||
import noppes.npcs.controllers.data.Animation;
|
||||
@@ -175,6 +176,20 @@ public class FieldDef {
|
||||
.clearable(() -> setter.accept(""));
|
||||
}
|
||||
|
||||
public static FieldDef textureSubGui(String label, Supplier<String> getter, Consumer<String> setter) {
|
||||
return subGuiField(label,
|
||||
() -> new GuiTexturePathSelection(getter.get()),
|
||||
gui -> {
|
||||
GuiTexturePathSelection t = (GuiTexturePathSelection) gui;
|
||||
if (t.selectedResource != null) setter.accept(t.selectedResource.toString());
|
||||
})
|
||||
.buttonLabel(() -> {
|
||||
String s = getter.get();
|
||||
return s == null || s.isEmpty() ? "gui.none" : s;
|
||||
})
|
||||
.clearable(() -> setter.accept(""));
|
||||
}
|
||||
|
||||
public static FieldDef animSubGui(String label,
|
||||
Supplier<Integer> idGetter, Consumer<Integer> idSetter,
|
||||
Supplier<String> nameGetter, Consumer<String> nameSetter) {
|
||||
|
||||
@@ -0,0 +1,319 @@
|
||||
package noppes.npcs.client.gui.select;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.StatCollector;
|
||||
import noppes.npcs.client.ClientCacheHandler;
|
||||
import noppes.npcs.client.gui.util.GuiCustomScroll;
|
||||
import noppes.npcs.client.gui.util.GuiNpcButton;
|
||||
import noppes.npcs.client.gui.util.GuiNpcTextField;
|
||||
import noppes.npcs.client.gui.util.ICustomScrollListener;
|
||||
import noppes.npcs.client.gui.util.SubGuiInterface;
|
||||
import noppes.npcs.client.renderer.ImageData;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Texture path selector SubGui with a texture preview panel instead of NPC rendering.
|
||||
* Reuses the cached texture data from {@link GuiTextureSelection}.
|
||||
*/
|
||||
public class GuiTexturePathSelection extends SubGuiInterface implements ICustomScrollListener {
|
||||
|
||||
private final String up = "..<" + StatCollector.translateToLocal("gui.up") + ">..";
|
||||
private GuiCustomScroll scrollCategories;
|
||||
private GuiCustomScroll scrollTextures;
|
||||
|
||||
private String location = "";
|
||||
private String selectedDomain;
|
||||
public ResourceLocation selectedResource;
|
||||
|
||||
private final HashMap<String, List<GuiTextureSelection.TextureData>> domains = new HashMap<>();
|
||||
private final HashMap<String, GuiTextureSelection.TextureData> textures = new HashMap<>();
|
||||
|
||||
private String catSearch = "";
|
||||
private String texSearch = "";
|
||||
|
||||
// Preview
|
||||
private static final int PREVIEW_SIZE = 90;
|
||||
|
||||
public GuiTexturePathSelection(String texture) {
|
||||
drawDefaultBackground = false;
|
||||
title = "";
|
||||
setBackground("menubg.png");
|
||||
xSize = 366;
|
||||
ySize = 226;
|
||||
|
||||
// Populate from GuiTextureSelection's cache (trigger a scan if needed)
|
||||
long now = System.currentTimeMillis();
|
||||
if (GuiTextureSelection.cachedTextures != null && !GuiTextureSelection.cachedTextures.isEmpty()
|
||||
&& now - GuiTextureSelection.lastCacheTime() < GuiTextureSelection.CACHE_DURATION_MS) {
|
||||
domains.putAll(GuiTextureSelection.cachedDomains());
|
||||
} else {
|
||||
// Force a scan by creating a temporary GuiTextureSelection
|
||||
GuiTextureSelection temp = new GuiTextureSelection(null, null);
|
||||
domains.putAll(GuiTextureSelection.cachedDomains());
|
||||
}
|
||||
|
||||
if (texture != null && !texture.isEmpty()) {
|
||||
selectedResource = new ResourceLocation(texture);
|
||||
selectedDomain = selectedResource.getResourceDomain();
|
||||
if (!domains.containsKey(selectedDomain)) {
|
||||
selectedDomain = null;
|
||||
}
|
||||
int i = selectedResource.getResourcePath().lastIndexOf('/');
|
||||
location = selectedResource.getResourcePath().substring(0, i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initGui() {
|
||||
super.initGui();
|
||||
|
||||
if (selectedDomain != null) {
|
||||
title = selectedDomain + ":" + location;
|
||||
} else {
|
||||
title = "";
|
||||
}
|
||||
|
||||
// Buttons
|
||||
this.addButton(new GuiNpcButton(2, guiLeft + xSize - 46, guiTop + ySize - 28, 42, 20, "gui.done"));
|
||||
this.addButton(new GuiNpcButton(1, guiLeft + xSize - 92, guiTop + ySize - 28, 42, 20, "gui.cancel"));
|
||||
|
||||
// Category scroll
|
||||
if (scrollCategories == null) {
|
||||
scrollCategories = new GuiCustomScroll(this, 0);
|
||||
scrollCategories.setSize(90, 163);
|
||||
}
|
||||
if (selectedDomain == null) {
|
||||
scrollCategories.setList(getCatSearch());
|
||||
} else {
|
||||
List<String> list = new ArrayList<>();
|
||||
list.add(up);
|
||||
List<GuiTextureSelection.TextureData> data = domains.get(selectedDomain);
|
||||
if (data != null) {
|
||||
for (GuiTextureSelection.TextureData td : data) {
|
||||
if (location.isEmpty() || td.path.startsWith(location) && !td.path.equals(location)) {
|
||||
String path = td.path.substring(location.length());
|
||||
int i = path.indexOf('/');
|
||||
if (i < 0) continue;
|
||||
path = path.substring(0, i);
|
||||
if (!path.isEmpty() && !list.contains(path)) {
|
||||
list.add(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
scrollCategories.setList(list);
|
||||
}
|
||||
scrollCategories.guiLeft = guiLeft + 4;
|
||||
scrollCategories.guiTop = guiTop + 14;
|
||||
this.addScroll(scrollCategories);
|
||||
addTextField(new GuiNpcTextField(55, this, fontRendererObj, guiLeft + 4, guiTop + 179, 90, 20, catSearch));
|
||||
|
||||
// Texture scroll
|
||||
if (scrollTextures == null) {
|
||||
scrollTextures = new GuiCustomScroll(this, 1);
|
||||
scrollTextures.setSize(160, 163);
|
||||
}
|
||||
if (selectedDomain != null) {
|
||||
textures.clear();
|
||||
List<GuiTextureSelection.TextureData> data = domains.get(selectedDomain);
|
||||
List<String> allList = new ArrayList<>();
|
||||
String loc = location;
|
||||
if (scrollCategories.hasSelected() && !scrollCategories.getSelected().equals(up)) {
|
||||
loc += scrollCategories.getSelected() + '/';
|
||||
}
|
||||
if (data != null) {
|
||||
for (GuiTextureSelection.TextureData td : data) {
|
||||
if (td.path.equals(loc) && !allList.contains(td.name)) {
|
||||
allList.add(td.name);
|
||||
textures.put(td.name, td);
|
||||
}
|
||||
}
|
||||
}
|
||||
scrollTextures.setList(filterTexSearch(allList));
|
||||
}
|
||||
if (selectedResource != null) {
|
||||
scrollTextures.setSelected(selectedResource.getResourcePath());
|
||||
}
|
||||
scrollTextures.guiLeft = guiLeft + 95;
|
||||
scrollTextures.guiTop = guiTop + 14;
|
||||
this.addScroll(scrollTextures);
|
||||
addTextField(new GuiNpcTextField(66, this, fontRendererObj, guiLeft + 95, guiTop + 179, 160, 20, texSearch));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
|
||||
super.drawScreen(mouseX, mouseY, partialTicks);
|
||||
drawTexturePreview();
|
||||
}
|
||||
|
||||
private void drawTexturePreview() {
|
||||
int previewX = guiLeft + 260;
|
||||
int previewY = guiTop + 14;
|
||||
|
||||
// Draw border/background for preview area
|
||||
drawRect(previewX - 1, previewY - 1, previewX + PREVIEW_SIZE + 1, previewY + PREVIEW_SIZE + 1, 0xFFA0A0A0);
|
||||
drawRect(previewX, previewY, previewX + PREVIEW_SIZE, previewY + PREVIEW_SIZE, 0xFF000000);
|
||||
|
||||
if (selectedResource == null) {
|
||||
String none = StatCollector.translateToLocal("gui.none");
|
||||
int w = fontRendererObj.getStringWidth(none);
|
||||
fontRendererObj.drawString(none, previewX + (PREVIEW_SIZE - w) / 2, previewY + PREVIEW_SIZE / 2 - 4, 0xFF808080);
|
||||
return;
|
||||
}
|
||||
|
||||
ImageData imageData = ClientCacheHandler.getImageData(selectedResource.toString());
|
||||
if (imageData == null || !imageData.imageLoaded()) {
|
||||
String loading = "...";
|
||||
int w = fontRendererObj.getStringWidth(loading);
|
||||
fontRendererObj.drawString(loading, previewX + (PREVIEW_SIZE - w) / 2, previewY + PREVIEW_SIZE / 2 - 4, 0xFF808080);
|
||||
return;
|
||||
}
|
||||
|
||||
int texW = imageData.getTotalWidth();
|
||||
int texH = imageData.getTotalHeight();
|
||||
if (texW <= 0 || texH <= 0) return;
|
||||
|
||||
// Scale to fit within PREVIEW_SIZE while maintaining aspect ratio
|
||||
float scale = Math.min((float) PREVIEW_SIZE / texW, (float) PREVIEW_SIZE / texH);
|
||||
int drawW = (int) (texW * scale);
|
||||
int drawH = (int) (texH * scale);
|
||||
int drawX = previewX + (PREVIEW_SIZE - drawW) / 2;
|
||||
int drawY = previewY + (PREVIEW_SIZE - drawH) / 2;
|
||||
|
||||
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
imageData.bindTexture();
|
||||
drawScaledTexture(drawX, drawY, drawW, drawH);
|
||||
|
||||
// Draw dimensions label below preview
|
||||
String dims = texW + " x " + texH;
|
||||
int dw = fontRendererObj.getStringWidth(dims);
|
||||
fontRendererObj.drawString(dims, previewX + (PREVIEW_SIZE - dw) / 2, previewY + PREVIEW_SIZE + 4, 0xFFCCCCCC);
|
||||
|
||||
// Draw resource path below dimensions
|
||||
String path = selectedResource.toString();
|
||||
if (fontRendererObj.getStringWidth(path) > PREVIEW_SIZE + 4) {
|
||||
// Truncate from the left
|
||||
while (fontRendererObj.getStringWidth("..." + path) > PREVIEW_SIZE + 4 && path.length() > 1) {
|
||||
path = path.substring(1);
|
||||
}
|
||||
path = "..." + path;
|
||||
}
|
||||
int pw = fontRendererObj.getStringWidth(path);
|
||||
fontRendererObj.drawString(path, previewX + (PREVIEW_SIZE - pw) / 2, previewY + PREVIEW_SIZE + 15, 0xFF999999);
|
||||
}
|
||||
|
||||
private void drawScaledTexture(int x, int y, int width, int height) {
|
||||
Tessellator tess = Tessellator.instance;
|
||||
tess.startDrawingQuads();
|
||||
tess.addVertexWithUV(x, y + height, zLevel, 0.0, 1.0);
|
||||
tess.addVertexWithUV(x + width, y + height, zLevel, 1.0, 1.0);
|
||||
tess.addVertexWithUV(x + width, y, zLevel, 1.0, 0.0);
|
||||
tess.addVertexWithUV(x, y, zLevel, 0.0, 0.0);
|
||||
tess.draw();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void actionPerformed(GuiButton guibutton) {
|
||||
super.actionPerformed(guibutton);
|
||||
if (guibutton.id == 1) {
|
||||
// Cancel - clear selection
|
||||
selectedResource = null;
|
||||
}
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customScrollClicked(int i, int j, int k, GuiCustomScroll scroll) {
|
||||
if (scroll == scrollTextures) {
|
||||
if (scroll.id == 1) {
|
||||
GuiTextureSelection.TextureData data = textures.get(scroll.getSelected());
|
||||
if (data != null) {
|
||||
selectedResource = new ResourceLocation(selectedDomain, data.absoluteName);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
initGui();
|
||||
scrollTextures.resetScroll();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customScrollDoubleClicked(String selection, GuiCustomScroll scroll) {
|
||||
if (scroll == scrollCategories) {
|
||||
if (selectedDomain == null) {
|
||||
selectedDomain = selection;
|
||||
} else if (selection.equals(up)) {
|
||||
int i = location.lastIndexOf('/', location.length() - 2);
|
||||
if (i < 0) {
|
||||
if (location.isEmpty()) {
|
||||
selectedDomain = null;
|
||||
}
|
||||
location = "";
|
||||
} else {
|
||||
location = location.substring(0, i + 1);
|
||||
}
|
||||
} else {
|
||||
location = location + selection + '/';
|
||||
}
|
||||
scrollCategories.selected = -1;
|
||||
scrollTextures.selected = -1;
|
||||
initGui();
|
||||
} else {
|
||||
// Double-click on texture = confirm
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyTyped(char c, int i) {
|
||||
super.keyTyped(c, i);
|
||||
if (getTextField(55) != null && getTextField(55).isFocused()) {
|
||||
if (!catSearch.equals(getTextField(55).getText())) {
|
||||
catSearch = getTextField(55).getText().toLowerCase();
|
||||
scrollCategories.resetScroll();
|
||||
if (selectedDomain == null) {
|
||||
scrollCategories.setList(getCatSearch());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (getTextField(66) != null && getTextField(66).isFocused()) {
|
||||
if (!texSearch.equals(getTextField(66).getText())) {
|
||||
texSearch = getTextField(66).getText().toLowerCase();
|
||||
scrollTextures.resetScroll();
|
||||
initGui();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> getCatSearch() {
|
||||
if (catSearch.isEmpty()) {
|
||||
return new ArrayList<>(domains.keySet());
|
||||
}
|
||||
List<String> list = new ArrayList<>();
|
||||
for (String name : domains.keySet()) {
|
||||
if (name.toLowerCase().contains(catSearch))
|
||||
list.add(name);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private List<String> filterTexSearch(List<String> source) {
|
||||
if (texSearch.isEmpty()) {
|
||||
return source;
|
||||
}
|
||||
List<String> list = new ArrayList<>();
|
||||
for (String name : source) {
|
||||
if (name.toLowerCase().contains(texSearch))
|
||||
list.add(name);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
@@ -54,11 +54,21 @@ public class GuiTextureSelection extends SubGuiInterface implements ICustomScrol
|
||||
private final HashMap<String, TextureData> textures = new HashMap<>();
|
||||
|
||||
// --- Cache static fields ---
|
||||
private static final long CACHE_DURATION = 180000L; // 3 minutes in milliseconds
|
||||
static final long CACHE_DURATION = 180000L; // 3 minutes in milliseconds
|
||||
private static long lastCacheTime = 0;
|
||||
private static HashMap<String, List<TextureData>> cachedDomains = new HashMap<>();
|
||||
public static HashMap<String, TextureData> cachedTextures = new HashMap<>();
|
||||
|
||||
public static final long CACHE_DURATION_MS = CACHE_DURATION;
|
||||
|
||||
public static long lastCacheTime() {
|
||||
return lastCacheTime;
|
||||
}
|
||||
|
||||
public static HashMap<String, List<TextureData>> cachedDomains() {
|
||||
return cachedDomains;
|
||||
}
|
||||
|
||||
public GuiTextureSelection(EntityNPCInterface npc, String texture) {
|
||||
this.npc = npc;
|
||||
drawDefaultBackground = false;
|
||||
|
||||
Reference in new issue
Block a user