Skip to content

Commit

Permalink
Create JEI-like Advanced Search (#485)
Browse files Browse the repository at this point in the history
* Create JEI like Search

* add subfilter

* fix extended search pattern

* fix search crash without prefixes

* fix unicode case in search

* add regexp to extended patternMode

* move autofocus config to seatch widget panel

* code refactoring

* add matching language to searh parser

* fix type

* fix modname search

* clean cache after add new provider

---------

Co-authored-by: slprime <[email protected]>
Co-authored-by: Martin Robertz <[email protected]>
  • Loading branch information
3 people authored Jun 27, 2024
1 parent cc9715d commit b1a34c7
Show file tree
Hide file tree
Showing 34 changed files with 1,229 additions and 287 deletions.
251 changes: 251 additions & 0 deletions src/main/java/codechicken/nei/FormattedTextField.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
package codechicken.nei;

import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiTextField;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.util.EnumChatFormatting;

import org.lwjgl.opengl.GL11;

class FormattedTextField extends GuiTextField {

public static interface TextFormatter {

TextFormatter DEFAULT = (text) -> text;

public String format(String text);
}

protected FontRenderer fontRenderer;
protected String rawText = "";
protected String formattedText = "";
protected boolean editable = true;
protected int editableColor = 14737632;
protected int notEditableColor = 7368816;
protected TextFormatter formatter = TextFormatter.DEFAULT;
protected int lineScrollOffset = 0;
protected int frame = 0;

public FormattedTextField(FontRenderer fontRenderer, int xPosition, int yPosition, int width, int height) {
super(fontRenderer, xPosition, yPosition, width, height);
this.fontRenderer = fontRenderer;
}

public void setFormatter(TextFormatter formatter) {
this.formatter = formatter;
}

@Override
public void updateCursorCounter() {
super.updateCursorCounter();
++this.frame;
}

@Override
public void setFocused(boolean focus) {
if (focus && !this.isFocused()) {
this.frame = 0;
}

super.setFocused(focus);
}

@Override
public void setSelectionPos(int p_146199_1_) {
String text = this.getText();
int j = text.length();

super.setSelectionPos(p_146199_1_);

p_146199_1_ = Math.max(0, Math.min(p_146199_1_, j));

if (this.fontRenderer != null) {

if (this.lineScrollOffset > j) {
this.lineScrollOffset = j;
}

int k = this.getWidth();
String s = this.fontRenderer.trimStringToWidth(text.substring(this.lineScrollOffset), k);
int l = s.length() + this.lineScrollOffset;

if (p_146199_1_ == this.lineScrollOffset) {
this.lineScrollOffset -= this.fontRenderer.trimStringToWidth(text, k, true).length();
}

if (p_146199_1_ > l) {
this.lineScrollOffset += p_146199_1_ - l;
} else if (p_146199_1_ <= this.lineScrollOffset) {
this.lineScrollOffset -= this.lineScrollOffset - p_146199_1_;
}

this.lineScrollOffset = Math.max(0, Math.min(this.lineScrollOffset, j));
}
}

@Override
public void setTextColor(int p_146193_1_) {
super.setTextColor(p_146193_1_);
this.editableColor = p_146193_1_;
}

@Override
public void setDisabledTextColour(int p_146204_1_) {
super.setDisabledTextColour(p_146204_1_);
this.notEditableColor = p_146204_1_;
}

@Override
public void setEnabled(boolean p_146184_1_) {
super.setEnabled(p_146184_1_);
this.editable = p_146184_1_;
}

@Override
public void drawTextBox() {
if (this.getVisible()) {
if (this.getEnableBackgroundDrawing()) {
drawRect(
this.xPosition - 1,
this.yPosition - 1,
this.xPosition + this.width + 1,
this.yPosition + this.height + 1,
-6250336);
drawRect(
this.xPosition,
this.yPosition,
this.xPosition + this.width,
this.yPosition + this.height,
-16777216);
}

if (!this.rawText.equals(getText())) {
this.rawText = getText();
this.formattedText = this.formatter.format(this.rawText);
if (!EnumChatFormatting.getTextWithoutFormattingCodes(this.formattedText).toLowerCase()
.equals(this.rawText.toLowerCase())) {
this.formattedText = this.rawText;
}
}

int firstCharacterIndex = getFormattedTextShift(this.lineScrollOffset);
String rawTextClipped = this.fontRenderer
.trimStringToWidth(this.rawText.substring(this.lineScrollOffset), this.getWidth());
String textClipped = this.formattedText.substring(
firstCharacterIndex,
getFormattedTextShift(this.lineScrollOffset + rawTextClipped.length()));
int cursorPosition = getFormattedTextShift(this.getCursorPosition());
int selectionEnd = getFormattedTextShift(this.getSelectionEnd());

int color = this.editable ? this.editableColor : this.notEditableColor;
int cursorA = cursorPosition - firstCharacterIndex;
int cursorB = selectionEnd - firstCharacterIndex;
boolean flag = cursorA >= 0 && cursorA <= textClipped.length();
boolean flag1 = this.isFocused() && this.frame / 6 % 2 == 0 && flag;
boolean flag2 = this.getCursorPosition() < this.rawText.length()
|| this.rawText.length() >= this.getMaxStringLength();
int x = this.getEnableBackgroundDrawing() ? this.xPosition + 4 : this.xPosition;
int y = this.getEnableBackgroundDrawing() ? this.yPosition + (this.height - 8) / 2 : this.yPosition;
int x2 = x;

if (cursorB > textClipped.length()) {
cursorB = textClipped.length();
}

if (textClipped.length() > 0) {
String s1 = flag ? textClipped.substring(0, cursorA) : textClipped;
String colorA = getPreviousColor(firstCharacterIndex);
x2 = this.fontRenderer.drawStringWithShadow(colorA + s1, x, y, color);
}

int k1 = x2;

if (!flag) {
k1 = cursorA > 0 ? x + this.width : x;
} else if (flag2) {
k1 = x2 - 1;
--x2;
}

if (textClipped.length() > 0 && flag && cursorA < textClipped.length()) {
String colorB = getPreviousColor(firstCharacterIndex + cursorA);
this.fontRenderer.drawStringWithShadow(colorB + textClipped.substring(cursorA), x2, y, color);
}

if (flag1) {
if (flag2) {
Gui.drawRect(k1, y - 1, k1 + 1, y + 1 + this.fontRenderer.FONT_HEIGHT, -3092272);
} else {
this.fontRenderer.drawStringWithShadow("_", k1, y, color);
}
}

if (cursorB != cursorA) {
int l1 = x + this.fontRenderer.getStringWidth(textClipped.substring(0, cursorB));
drawCursorVertical(k1, y - 1, l1 - 1, y + 1 + this.fontRenderer.FONT_HEIGHT);
}
}
}

private void drawCursorVertical(int x1, int y1, int x2, int y2) {
int i1;

if (x1 < x2) {
i1 = x1;
x1 = x2;
x2 = i1;
}

if (y1 < y2) {
i1 = y1;
y1 = y2;
y2 = i1;
}

if (x2 > this.xPosition + this.width) {
x2 = this.xPosition + this.width;
}

if (x1 > this.xPosition + this.width) {
x1 = this.xPosition + this.width;
}

Tessellator tessellator = Tessellator.instance;
GL11.glColor4f(0.0F, 0.0F, 255.0F, 255.0F);
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glEnable(GL11.GL_COLOR_LOGIC_OP);
GL11.glLogicOp(GL11.GL_OR_REVERSE);
tessellator.startDrawingQuads();
tessellator.addVertex((double) x1, (double) y2, 0.0D);
tessellator.addVertex((double) x2, (double) y2, 0.0D);
tessellator.addVertex((double) x2, (double) y1, 0.0D);
tessellator.addVertex((double) x1, (double) y1, 0.0D);
tessellator.draw();
GL11.glDisable(GL11.GL_COLOR_LOGIC_OP);
GL11.glEnable(GL11.GL_TEXTURE_2D);
}

private int getFormattedTextShift(int position) {
int shift = 0;

for (int i = 0; i < position; i++) {
while (this.formattedText.length() > i + shift && this.formattedText.charAt(i + shift) == '\u00a7') {
shift += 2;
}
}

return position + shift;
}

private String getPreviousColor(int position) {
while (position >= 0) {
if (this.formattedText.charAt(position) == '\u00a7') {
return this.formattedText.substring(position, position + 2);
}
position--;
}
return "";
}

}
41 changes: 37 additions & 4 deletions src/main/java/codechicken/nei/ItemList.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.StringJoiner;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import net.minecraft.client.Minecraft;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.IIcon;
Expand All @@ -21,7 +23,6 @@
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.guihook.GuiContainerManager;

public class ItemList {

Expand Down Expand Up @@ -63,6 +64,20 @@ public boolean matches(ItemStack item) {
}
}

public static class NegatedItemFilter implements ItemFilter {

public ItemFilter filter;

public NegatedItemFilter(ItemFilter filter) {
this.filter = filter;
}

@Override
public boolean matches(ItemStack item) {
return this.filter == null || !this.filter.matches(item);
}
}

public static class PatternItemFilter implements ItemFilter {

public Pattern pattern;
Expand All @@ -73,7 +88,7 @@ public PatternItemFilter(Pattern pattern) {

@Override
public boolean matches(ItemStack item) {
return pattern.matcher(ItemInfo.getSearchName(item)).find();
return pattern.matcher(item.getDisplayName()).find();
}
}

Expand Down Expand Up @@ -161,7 +176,9 @@ public static ItemFilter getItemListFilter() {
public static List<ItemFilter> getItemFilters() {
LinkedList<ItemFilter> filters = new LinkedList<>();
synchronized (itemFilterers) {
for (ItemFilterProvider p : itemFilterers) filters.add(p.getFilter());
for (ItemFilterProvider p : itemFilterers) {
filters.add(p.getFilter());
}
}
return filters;
}
Expand All @@ -173,7 +190,7 @@ private void damageSearch(Item item, List<ItemStack> permutations) {
for (int damage = 0; damage < 16; damage++) try {
ItemStack itemstack = new ItemStack(item, 1, damage);
IIcon icon = item.getIconIndex(itemstack);
String name = GuiContainerManager.concatenatedDisplayName(itemstack, false);
String name = getTooltip(itemstack);
String s = name + "@" + (icon == null ? 0 : icon.hashCode());
if (!damageIconSet.contains(s)) {
damageIconSet.add(s);
Expand All @@ -190,6 +207,22 @@ private void damageSearch(Item item, List<ItemStack> permutations) {
}
}

private String getTooltip(ItemStack stack) {
try {
@SuppressWarnings("unchecked")
final List<String> namelist = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false);
final StringJoiner sb = new StringJoiner("\n");

for (String name : namelist) {
sb.add(name);
}

return sb.toString();
} catch (Throwable ignored) {}

return "";
}

@Override
@SuppressWarnings("unchecked")
public void execute() {
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/codechicken/nei/ItemSorter.java
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ public static void initConfig(ConfigTagParent tag) {
return compareInt(id1, id2);
});
API.addSortOption("nei.itemsort.name", (o1, o2) -> {
String name1 = ItemInfo.getSearchName(o1);
String name2 = ItemInfo.getSearchName(o2);
String name1 = o1.getDisplayName();
String name2 = o2.getDisplayName();
return name1.compareTo(name2);
});
tag.getTag("inventory.itemsort").setDefaultValue(getSaveString(list));
Expand Down
Loading

0 comments on commit b1a34c7

Please sign in to comment.