diff --git a/src/main/java/appeng/client/gui/implementations/GuiCraftConfirm.java b/src/main/java/appeng/client/gui/implementations/GuiCraftConfirm.java index 80a04bd2710..7a993134015 100644 --- a/src/main/java/appeng/client/gui/implementations/GuiCraftConfirm.java +++ b/src/main/java/appeng/client/gui/implementations/GuiCraftConfirm.java @@ -41,6 +41,7 @@ import appeng.api.storage.data.IItemList; import appeng.client.gui.AEBaseGui; import appeng.client.gui.IGuiTooltipHandler; +import appeng.client.gui.widgets.GuiAeButton; import appeng.client.gui.widgets.GuiCraftingCPUTable; import appeng.client.gui.widgets.GuiCraftingTree; import appeng.client.gui.widgets.GuiImgButton; @@ -48,6 +49,7 @@ import appeng.client.gui.widgets.GuiSimpleImgButton; import appeng.client.gui.widgets.GuiTabButton; import appeng.client.gui.widgets.ICraftingCPUTableHolder; +import appeng.client.gui.widgets.MEGuiTextField; import appeng.container.implementations.ContainerCraftConfirm; import appeng.container.implementations.CraftingCPUStatus; import appeng.core.AEConfig; @@ -159,8 +161,14 @@ protected void recalculateScreenSize() { private GuiImgButton sortingModeButton; private GuiImgButton sortingDirectionButton; private GuiSimpleImgButton optimizeButton; + private GuiAeButton findNext; + private GuiAeButton findPrev; + private MEGuiTextField searchField; private int tooltip = -1; private ItemStack hoveredStack; + private ArrayList goToData = new ArrayList<>(); + private int searchGotoIndex = -1; + private IAEItemStack needHighlight; final GuiScrollbar scrollbar; @@ -300,6 +308,40 @@ public void initGui() { ButtonToolTips.OptimizePatterns.getLocal()); this.optimizeButton.enabled = false; this.buttonList.add(this.optimizeButton); + + this.searchField = new MEGuiTextField(52, 12, "Search") { + + @Override + public void onTextChange(String oldText) { + super.onTextChange(oldText); + switch (displayMode) { + case LIST -> updateSearchGoToList(); + case TREE -> craftingTree.updateSearchGoToList(this.getText().toLowerCase()); + } + } + }; + this.searchField.x = this.guiLeft + this.xSize - 101; + this.searchField.y = this.guiTop + 5; + + this.findPrev = new GuiAeButton( + 0, + this.guiLeft + this.xSize - 48, + this.guiTop + 6, + 10, + 10, + "↑", + ButtonToolTips.SearchGotoPrev.getLocal()); + this.buttonList.add(this.findPrev); + + this.findNext = new GuiAeButton( + 0, + this.guiLeft + this.xSize - 36, + this.guiTop + 6, + 10, + 10, + "↓", + ButtonToolTips.SearchGotoNext.getLocal()); + this.buttonList.add(this.findNext); } @Override @@ -423,6 +465,38 @@ public void drawFG(final int offsetX, final int offsetY, final int mouseX, final } } + private void updateSearchGoToList() { + needHighlight = null; + searchGotoIndex = -1; + goToData.clear(); + if (this.searchField.getText().isEmpty()) return; + String s = this.searchField.getText().toLowerCase(); + int visCount = 0; + for (IAEItemStack aeis : this.visual) { + if (aeis != null && Platform.getItemDisplayName(aeis).toLowerCase().contains(s)) { + goToData.add(visCount); + } + visCount++; + } + searchGoTo(true); + } + + private void searchGoTo(boolean forward) { + String s = this.searchField.getText().toLowerCase(); + if (s.isEmpty() || goToData.isEmpty()) return; + if (forward) { + searchGotoIndex++; + if (searchGotoIndex >= goToData.size()) searchGotoIndex = 0; + } else { + if (searchGotoIndex <= 0) searchGotoIndex = goToData.size(); + searchGotoIndex--; + } + + IAEItemStack aeis = this.visual.get(goToData.get(searchGotoIndex)); + this.getScrollBar().setCurrentScroll(goToData.get(searchGotoIndex) / 3 - this.rows / 2); + needHighlight = aeis.copy(); + } + private void drawListFG(final int offsetX, final int offsetY, final int mouseX, final int mouseY) { String dsp = null; @@ -607,6 +681,18 @@ private void drawListFG(final int offsetX, final int offsetY, final int mouseX, GuiColors.CraftConfirmMissingItem.getColor()); } + if (!this.searchField.getText().isEmpty() && goToData.contains(z)) { + final int startX = x * (1 + sectionLength) + xo; + final int startY = posY - 4; + final int color = needHighlight != null && needHighlight.isSameType(refStack) + ? GuiColors.SearchGoToHighlight.getColor() + : GuiColors.SearchHighlight.getColor(); + drawVerticalLine(startX, startY, startY + offY, color); + drawVerticalLine(startX + sectionLength - 1, startY, startY + offY, color); + drawHorizontalLine(startX + 1, startX + sectionLength - 2, startY + 1, color); + drawHorizontalLine(startX + 1, startX + sectionLength - 2, startY + offY - 1, color); + } + x++; if (x > 2) { @@ -683,6 +769,9 @@ public void drawBG(final int offsetX, final int offsetY, final int mouseX, final TREE_VIEW_TEXTURE_HEIGHT); } } + this.bindTexture("guis/searchField.png"); + this.drawTexturedModalRect(this.guiLeft + this.xSize - 101, this.guiTop + 5, 0, 0, 52, 12); + this.searchField.drawTextBox(); } private void setScrollBar() { @@ -870,7 +959,9 @@ protected void keyTyped(final char character, final int key) { if (key == Keyboard.KEY_RETURN || key == Keyboard.KEY_NUMPADENTER) { this.actionPerformed(this.start); } - super.keyTyped(character, key); + if (!(this.searchField.textboxKeyTyped(character, key))) { + super.keyTyped(character, key); + } } } @@ -889,6 +980,7 @@ protected void actionPerformed(final GuiButton btn) { this.displayMode = this.displayMode.next(); recalculateScreenSize(); this.setWorldAndResolution(mc, width, height); + this.searchField.setText(""); } else if (btn == this.takeScreenshot) { if (craftingTree != null) { craftingTree.saveScreenshot(); @@ -929,6 +1021,16 @@ protected void actionPerformed(final GuiButton btn) { } catch (final Throwable e) { AELog.debug(e); } + } else if (btn == this.findNext) { + switch (displayMode) { + case LIST -> searchGoTo(true); + case TREE -> craftingTree.searchGoTo(true); + } + } else if (btn == this.findPrev) { + switch (displayMode) { + case LIST -> searchGoTo(false); + case TREE -> craftingTree.searchGoTo(false); + } } } @@ -953,6 +1055,7 @@ public GuiButton getCancelButton() { protected void mouseClicked(int xCoord, int yCoord, int btn) { super.mouseClicked(xCoord, yCoord, btn); cpuTable.mouseClicked(xCoord - guiLeft, yCoord - guiTop, btn); + this.searchField.mouseClicked(xCoord, yCoord, btn); } @Override diff --git a/src/main/java/appeng/client/gui/implementations/GuiCraftingCPU.java b/src/main/java/appeng/client/gui/implementations/GuiCraftingCPU.java index 345eb16baf8..0aa3c9cde88 100644 --- a/src/main/java/appeng/client/gui/implementations/GuiCraftingCPU.java +++ b/src/main/java/appeng/client/gui/implementations/GuiCraftingCPU.java @@ -39,14 +39,17 @@ import appeng.api.util.DimensionalCoord; import appeng.client.gui.AEBaseGui; import appeng.client.gui.IGuiTooltipHandler; +import appeng.client.gui.widgets.GuiAeButton; import appeng.client.gui.widgets.GuiImgButton; import appeng.client.gui.widgets.GuiScrollbar; import appeng.client.gui.widgets.ISortSource; import appeng.client.gui.widgets.ITooltip; +import appeng.client.gui.widgets.MEGuiTextField; import appeng.client.render.BlockPosHighlighter; import appeng.container.implementations.ContainerCraftingCPU; import appeng.core.AEConfig; import appeng.core.AELog; +import appeng.core.localization.ButtonToolTips; import appeng.core.localization.GuiColors; import appeng.core.localization.GuiText; import appeng.core.localization.PlayerMessages; @@ -168,6 +171,12 @@ public int getStringWidth() { private final RemainingOperations remainingOperations = new RemainingOperations(); private ItemStack hoveredStack; private ItemStack hoveredNbtStack; + private GuiAeButton findNext; + private GuiAeButton findPrev; + private MEGuiTextField searchField; + private ArrayList goToData = new ArrayList<>(); + private int searchGotoIndex = -1; + private IAEItemStack needHighlight; public GuiCraftingCPU(final InventoryPlayer inventoryPlayer, final Object te) { this(new ContainerCraftingCPU(inventoryPlayer, te)); @@ -201,13 +210,17 @@ protected void actionPerformed(final GuiButton btn) { } catch (final IOException e) { AELog.debug(e); } - } - if (this.toggleHideStored == btn) { + } else if (this.toggleHideStored == btn) { this.hideStored ^= true; AEConfig.instance.getConfigManager().putSetting(Settings.HIDE_STORED, hideStored ? YesNo.YES : YesNo.NO); this.toggleHideStored.set(hideStored ? YesNo.YES : YesNo.NO); hideStoredSorting(); this.setScrollBar(); + updateSearchGoToList(true); + } else if (btn == this.findNext) { + searchGoTo(true); + } else if (btn == this.findPrev) { + searchGoTo(false); } } @@ -226,6 +239,7 @@ protected void mouseClicked(final int xCoord, final int yCoord, final int btn) { mc.thePlayer.closeScreen(); } super.mouseClicked(xCoord, yCoord, btn); + this.searchField.mouseClicked(xCoord, yCoord, btn); } @Override @@ -246,6 +260,37 @@ public void initGui() { AEConfig.instance.getConfigManager().getSetting(Settings.HIDE_STORED)); this.buttonList.add(this.toggleHideStored); this.buttonList.add(this.cancel); + + this.searchField = new MEGuiTextField(52, 12, "Search") { + + @Override + public void onTextChange(String oldText) { + super.onTextChange(oldText); + updateSearchGoToList(true); + } + }; + this.searchField.x = this.guiLeft + this.xSize - 101; + this.searchField.y = this.guiTop + 5; + + this.findPrev = new GuiAeButton( + 0, + this.guiLeft + this.xSize - 48, + this.guiTop + 6, + 10, + 10, + "↑", + ButtonToolTips.SearchGotoPrev.getLocal()); + this.buttonList.add(this.findPrev); + + this.findNext = new GuiAeButton( + 0, + this.guiLeft + this.xSize - 36, + this.guiTop + 6, + 10, + 10, + "↓", + ButtonToolTips.SearchGotoNext.getLocal()); + this.buttonList.add(this.findNext); } private void setScrollBar() { @@ -294,6 +339,47 @@ public void drawScreen(final int mouseX, final int mouseY, final float btn) { super.drawScreen(mouseX, mouseY, btn); } + private void updateSearchGoToList(boolean dropIndex) { + needHighlight = null; + goToData.clear(); + if (this.searchField.getText().isEmpty()) return; + String s = this.searchField.getText().toLowerCase(); + int visCount = 0; + for (IAEItemStack aeis : hideStored ? this.visualHiddenStored : this.visual) { + if (aeis != null && Platform.getItemDisplayName(aeis).toLowerCase().contains(s)) { + goToData.add(visCount); + } + visCount++; + } + if (dropIndex) { + searchGotoIndex = -1; + searchGoTo(true); + } + } + + private void searchGoTo(boolean forward) { + String s = this.searchField.getText().toLowerCase(); + if (s.isEmpty() || goToData.isEmpty()) return; + if (forward) { + searchGotoIndex++; + if (searchGotoIndex >= goToData.size()) searchGotoIndex = 0; + } else { + if (searchGotoIndex <= 0) searchGotoIndex = goToData.size(); + searchGotoIndex--; + } + + List visualTemp; + if (this.hideStored) { + visualTemp = this.visualHiddenStored; + } else { + visualTemp = this.visual; + } + + IAEItemStack aeis = visualTemp.get(goToData.get(searchGotoIndex)); + this.getScrollBar().setCurrentScroll(goToData.get(searchGotoIndex) / 3 - this.rows / 2); + needHighlight = aeis.copy(); + } + private void updateRemainingOperations() { int interval = 1000; if (this.remainingOperations.getRefreshTick() >= this.remainingOperations.getLastWorkingTick() + interval) { @@ -326,7 +412,7 @@ public void drawFG(final int offsetX, final int offsetY, final int mouseX, final updateRemainingOperations(); this.fontRendererObj.drawString( String.valueOf(remainingOperations.getRemainingOperations()), - TITLE_LEFT_OFFSET + 200 - this.remainingOperations.getStringWidth(), + TITLE_LEFT_OFFSET + 128 - this.remainingOperations.getStringWidth(), TITLE_TOP_OFFSET, GuiColors.CraftingCPUTitle.getColor()); @@ -473,6 +559,18 @@ public void drawFG(final int offsetX, final int offsetY, final int mouseX, final this.drawItem(posX, posY, is); + if (!this.searchField.getText().isEmpty() && goToData.contains(z)) { + final int startX = x * (1 + SECTION_LENGTH) + ITEMSTACK_LEFT_OFFSET; + final int startY = posY - 4; + final int color = needHighlight != null && needHighlight.isSameType(refStack) + ? GuiColors.SearchGoToHighlight.getColor() + : GuiColors.SearchHighlight.getColor(); + drawVerticalLine(startX, startY, startY + offY, color); + drawVerticalLine(startX + SECTION_LENGTH - 1, startY, startY + offY, color); + drawHorizontalLine(startX + 1, startX + SECTION_LENGTH - 2, startY + 1, color); + drawHorizontalLine(startX + 1, startX + SECTION_LENGTH - 2, startY + offY - 1, color); + } + x++; if (x > 2) { @@ -524,6 +622,20 @@ protected void addItemTooltip(IAEItemStack refStack, List lineList) { public void drawBG(final int offsetX, final int offsetY, final int mouseX, final int mouseY) { this.bindTexture("guis/craftingcpu.png"); this.drawTexturedModalRect(offsetX, offsetY, 0, 0, this.xSize, this.ySize); + drawSearch(); + } + + public void drawSearch() { + this.bindTexture("guis/searchField.png"); + this.drawTexturedModalRect(this.guiLeft + this.xSize - 101, this.guiTop + 5, 0, 0, 52, 12); + this.searchField.drawTextBox(); + } + + @Override + protected void keyTyped(final char character, final int key) { + if (!(this.searchField.textboxKeyTyped(character, key))) { + super.keyTyped(character, key); + } } public void postUpdate(IAEItemStack is) { @@ -565,6 +677,7 @@ public void postUpdate(final List list, final byte ref) { } if (this.hideStored) this.hideStoredSorting(); + updateSearchGoToList(false); this.setScrollBar(); } diff --git a/src/main/java/appeng/client/gui/implementations/GuiCraftingStatus.java b/src/main/java/appeng/client/gui/implementations/GuiCraftingStatus.java index c965533f79d..d9f7317563e 100644 --- a/src/main/java/appeng/client/gui/implementations/GuiCraftingStatus.java +++ b/src/main/java/appeng/client/gui/implementations/GuiCraftingStatus.java @@ -236,6 +236,7 @@ public void drawBG(int offsetX, int offsetY, int mouseX, int mouseY) { this.drawTexturedModalRect(offsetX, offsetY, 0, 0, this.xSize, this.ySize); } this.cpuTable.drawBG(offsetX, offsetY); + drawSearch(); } @Override diff --git a/src/main/java/appeng/client/gui/widgets/GuiCraftingTree.java b/src/main/java/appeng/client/gui/widgets/GuiCraftingTree.java index 8d004b9f7c4..4e36b7636d3 100644 --- a/src/main/java/appeng/client/gui/widgets/GuiCraftingTree.java +++ b/src/main/java/appeng/client/gui/widgets/GuiCraftingTree.java @@ -37,6 +37,7 @@ import appeng.client.gui.AEBaseGui; import appeng.core.AELog; import appeng.core.localization.GuiColors; +import appeng.core.localization.GuiText; import appeng.crafting.v2.CraftingRequest; import appeng.crafting.v2.CraftingRequest.UsedResolverEntry; import appeng.crafting.v2.resolvers.CraftableItemResolver.CraftFromPatternTask; @@ -64,6 +65,10 @@ public class GuiCraftingTree { public static final int RESOLVER_CHILD_Y_SPACING = 12; public final int textColor = GuiColors.SearchboxText.getColor(); private static long animationFrame = System.currentTimeMillis() / 500; + private String search = ""; + private ArrayList goToData = new ArrayList(); + private int searchGotoIndex = -1; + private Node needHighlight; private abstract class Node { @@ -116,7 +121,15 @@ public RequestNode(int x, int y, Node parentNode, CraftingRequest request) { @Override public void drawImpl() { - drawSlotOutline(x, y, request.wasSimulated ? 0xCCAAAA : 0xAAAAAA, false); + int color = request.wasSimulated ? 0xCCAAAA : 0xAAAAAA; + if (!search.isEmpty() && goToData.contains(this)) { + if (needHighlight.equals(this)) { + color = GuiColors.SearchGoToHighlight.getColor(); + } else { + color = GuiColors.SearchHighlight.getColor(); + } + } + drawSlotOutline(x, y, color, false); drawStack(x, y, getDisplayItemForRequest(request), true); if (request.wasSimulated) { parent.bindTexture("guis/states.png"); @@ -148,7 +161,15 @@ public TaskNode(int x, int y, Node parentNode, UsedResolverEntry resolver) { @Override public void drawImpl() { parent.bindTexture("guis/states.png"); - drawSlotOutline(x, y, 0x777777, true); + int color = 0x777777; + if (!search.isEmpty() && goToData.contains(this)) { + if (needHighlight.equals(this)) { + color = GuiColors.SearchGoToHighlight.getColor(); + } else { + color = GuiColors.SearchHighlight.getColor(); + } + } + drawSlotOutline(x, y, color, true); List> children = null; long displayCount = resolver.resolvedStack.getStackSize(); if (resolver.task instanceof ExtractItemTask) { @@ -293,6 +314,55 @@ public void step(List stack) { } } + private String getTaskNodeDescription(final TaskNode nd) { + if (nd.resolver.task instanceof ExtractItemTask) { + return GuiText.StoredItems.getLocal(); + } else if (nd.resolver.task instanceof CraftFromPatternTask) { + return GuiText.Crafting.getLocal(); + } else if (nd.resolver.task instanceof EmitItemTask) { + return GuiText.LevelEmitter.getLocal(); + } else if (nd.resolver.task instanceof SimulateMissingItemResolver.ConjureItemTask + || nd.resolver.task instanceof IgnoreMissingItemTask) { + return GuiText.Missing.getLocal(); + } + return ""; + } + + public void updateSearchGoToList(String s) { + needHighlight = null; + searchGotoIndex = -1; + goToData.clear(); + search = s; + if (search.isEmpty()) return; + + for (ArrayList row : treeNodes.values()) { + for (Node node : row) { + if (node instanceof TaskNode tNode && getTaskNodeDescription(tNode).toLowerCase().contains(search)) { + goToData.add(node); + } else if (node instanceof RequestNode rNode + && Platform.getItemDisplayName(rNode.request.stack).toLowerCase().contains(search)) { + goToData.add(node); + } + } + } + searchGoTo(true); + } + + public void searchGoTo(boolean forward) { + if (search.isEmpty() || goToData.isEmpty()) return; + if (forward) { + searchGotoIndex++; + if (searchGotoIndex >= goToData.size()) searchGotoIndex = 0; + } else { + if (searchGotoIndex <= 0) searchGotoIndex = goToData.size(); + searchGotoIndex--; + } + final Node nd = goToData.get(searchGotoIndex); + needHighlight = nd; + scrollX = nd.x - nd.height; + scrollY = nd.y - nd.width; + } + public void setRequest(final CraftingRequest request) { final boolean isDifferent = (request != this.request); this.request = request; diff --git a/src/main/java/appeng/core/localization/ButtonToolTips.java b/src/main/java/appeng/core/localization/ButtonToolTips.java index 43798e5cfc0..0d87ade7928 100644 --- a/src/main/java/appeng/core/localization/ButtonToolTips.java +++ b/src/main/java/appeng/core/localization/ButtonToolTips.java @@ -225,7 +225,10 @@ public enum ButtonToolTips { StringOrderAlphanum, CellRestrictionLabel, - CellRestrictionHint; + CellRestrictionHint, + + SearchGotoNext, + SearchGotoPrev; private final String root; diff --git a/src/main/java/appeng/core/localization/GuiColors.java b/src/main/java/appeng/core/localization/GuiColors.java index 4398c91299e..b5b5fcb4562 100644 --- a/src/main/java/appeng/core/localization/GuiColors.java +++ b/src/main/java/appeng/core/localization/GuiColors.java @@ -150,7 +150,9 @@ public enum GuiColors { CellStatusOrange(0xFBA900), CellStatusRed(0xFB0000), CellStatusBlue(0x00AAFF), - CellStatusGreen(0x00FF00); + CellStatusGreen(0x00FF00), + SearchHighlight(0xFFFFFF55), + SearchGoToHighlight(0xFFFFAA00); private final String root; private final int color; diff --git a/src/main/resources/assets/appliedenergistics2/lang/en_US.lang b/src/main/resources/assets/appliedenergistics2/lang/en_US.lang index aa1a2e9c366..cdc677a1560 100644 --- a/src/main/resources/assets/appliedenergistics2/lang/en_US.lang +++ b/src/main/resources/assets/appliedenergistics2/lang/en_US.lang @@ -265,7 +265,7 @@ gui.appliedenergistics2.ETAFormat=HH:mm:ss gui.appliedenergistics2.SwitchCraftingSimulationDisplayMode=Switch display mode (List/Tree) gui.appliedenergistics2.Crafting=Crafting gui.appliedenergistics2.Scheduled=Scheduled -gui.appliedenergistics2.CraftingStatus=Crafting Status +gui.appliedenergistics2.CraftingStatus=Status gui.appliedenergistics2.RemainingOperations=Idle Processors gui.appliedenergistics2.FromStorage=Available gui.appliedenergistics2.FromStoragePercent=Used @@ -562,6 +562,9 @@ gui.tooltips.appliedenergistics2.StringOrderNatural=Default gui.tooltips.appliedenergistics2.StringOrderAlphanum=Natural Order gui.tooltips.appliedenergistics2.CellRestrictionLabel=Cell Restriction gui.tooltips.appliedenergistics2.CellRestrictionHint=Setup Cell Restriction + +gui.tooltips.appliedenergistics2.SearchGotoNext=Find next +gui.tooltips.appliedenergistics2.SearchGotoPrev=Find prev # Units gui.appliedenergistics2.units.appliedenergstics=AE gui.appliedenergistics2.units.ic2=Energy Units diff --git a/src/main/resources/assets/appliedenergistics2/textures/guis/craftingreport.png b/src/main/resources/assets/appliedenergistics2/textures/guis/craftingreport.png index e237b3555de..47e930ae8b9 100644 Binary files a/src/main/resources/assets/appliedenergistics2/textures/guis/craftingreport.png and b/src/main/resources/assets/appliedenergistics2/textures/guis/craftingreport.png differ diff --git a/src/main/resources/assets/appliedenergistics2/textures/guis/craftingtree.png b/src/main/resources/assets/appliedenergistics2/textures/guis/craftingtree.png index 594e751e0b1..b07d2da43b0 100644 Binary files a/src/main/resources/assets/appliedenergistics2/textures/guis/craftingtree.png and b/src/main/resources/assets/appliedenergistics2/textures/guis/craftingtree.png differ diff --git a/src/main/resources/assets/appliedenergistics2/textures/guis/searchField.png b/src/main/resources/assets/appliedenergistics2/textures/guis/searchField.png new file mode 100644 index 00000000000..8239071d1f2 Binary files /dev/null and b/src/main/resources/assets/appliedenergistics2/textures/guis/searchField.png differ