From fc3b9850bd3f9d3db8d0e0906873d307d2a18f1b Mon Sep 17 00:00:00 2001 From: UnRealDinnerbone Date: Wed, 9 Oct 2024 04:18:50 -0500 Subject: [PATCH] [1.21] Dropdown Menu & Other Tweaks (#127) * Add dropdown menu * Fix textbox allowEditMode * Expose more methods in EditStringConfigOverlay --- .../config/ui/EditStringConfigOverlay.java | 29 +++- .../dev/ftb/mods/ftblibrary/icon/Icons.java | 2 + .../ftb/mods/ftblibrary/ui/BaseScreen.java | 30 +++- .../ftb/mods/ftblibrary/ui/ContextButton.java | 63 ++++++++ .../ftb/mods/ftblibrary/ui/ContextMenu.java | 65 +------- .../mods/ftblibrary/ui/ContextMenuItem.java | 2 +- .../ftb/mods/ftblibrary/ui/DropDownMenu.java | 146 ++++++++++++++++++ .../ftb/mods/ftblibrary/ui/IntTextBox.java | 9 +- .../dev/ftb/mods/ftblibrary/ui/PopupMenu.java | 6 + .../dev/ftb/mods/ftblibrary/ui/TextBox.java | 27 +++- .../assets/ftblibrary/lang/en_us.json | 1 + .../ftblibrary/textures/icons/dropdown_in.png | Bin 0 -> 1493 bytes .../textures/icons/dropdown_out.png | Bin 0 -> 192 bytes 13 files changed, 301 insertions(+), 79 deletions(-) create mode 100644 common/src/main/java/dev/ftb/mods/ftblibrary/ui/ContextButton.java create mode 100644 common/src/main/java/dev/ftb/mods/ftblibrary/ui/DropDownMenu.java create mode 100644 common/src/main/java/dev/ftb/mods/ftblibrary/ui/PopupMenu.java create mode 100644 common/src/main/resources/assets/ftblibrary/textures/icons/dropdown_in.png create mode 100644 common/src/main/resources/assets/ftblibrary/textures/icons/dropdown_out.png diff --git a/common/src/main/java/dev/ftb/mods/ftblibrary/config/ui/EditStringConfigOverlay.java b/common/src/main/java/dev/ftb/mods/ftblibrary/config/ui/EditStringConfigOverlay.java index 80d78235..086664ac 100644 --- a/common/src/main/java/dev/ftb/mods/ftblibrary/config/ui/EditStringConfigOverlay.java +++ b/common/src/main/java/dev/ftb/mods/ftblibrary/config/ui/EditStringConfigOverlay.java @@ -14,12 +14,13 @@ import java.util.Objects; public class EditStringConfigOverlay extends ModalPanel { - private final EditField textBox; + protected final EditField textBox; private final Button accept, cancel; private final ConfigFromString config; private final ConfigCallback callback; private final TextField titleField; private final Component title; + private boolean addAcceptCancelButtons = true; private T currentValue; @@ -60,8 +61,10 @@ public void addWidgets() { add(titleField); } add(textBox); - add(accept); - add(cancel); + if(addAcceptCancelButtons) { + add(accept); + add(cancel); + } } @Override @@ -70,8 +73,11 @@ public void alignWidgets() { titleField.setPosAndSize(2, 2, width, getGui().getTheme().getFontHeight() + 4); } textBox.setPosAndSize(2, titleField.getHeight() + 1, width - 36, 14); - accept.setPos(textBox.width + 2, textBox.getPosY()); - cancel.setPos(accept.getPosX() + accept.width + 2, textBox.getPosY()); + if(addAcceptCancelButtons) { + accept.setPos(textBox.width + 2, textBox.getPosY()); + cancel.setPos(accept.getPosX() + accept.width + 2, textBox.getPosY()); + } + height = title == null ? 16 : 30; } @@ -90,7 +96,7 @@ public void drawBackground(GuiGraphics graphics, Theme theme, int x, int y, int theme.drawContextMenuBackground(graphics, x - 1, y - 1, w + 2, h + 2); } - private void onAccepted(Button btn, MouseButton mb) { + protected void onAccepted(Button btn, MouseButton mb) { if (textBox.isTextValid()) { config.setCurrentValue(currentValue); callback.save(true); @@ -98,11 +104,18 @@ private void onAccepted(Button btn, MouseButton mb) { } } - private void onCancelled(Button btn, MouseButton mb) { + protected void onCancelled(Button btn, MouseButton mb) { callback.save(false); getGui().popModalPanel(); } + /** + * @param addAcceptCancelButtons if true, accept and cancel buttons will be added to the overlay + */ + public void setAddAcceptCancelButtons(boolean addAcceptCancelButtons) { + this.addAcceptCancelButtons = addAcceptCancelButtons; + } + /** * Provides positioning information for when an edit panel needs to be overlaid on the widget */ @@ -114,7 +127,7 @@ record Offset(int x, int y) { } } - private class EditField extends TextBox { + protected class EditField extends TextBox { public EditField() { super(EditStringConfigOverlay.this); diff --git a/common/src/main/java/dev/ftb/mods/ftblibrary/icon/Icons.java b/common/src/main/java/dev/ftb/mods/ftblibrary/icon/Icons.java index b94f75c4..0da88dbc 100644 --- a/common/src/main/java/dev/ftb/mods/ftblibrary/icon/Icons.java +++ b/common/src/main/java/dev/ftb/mods/ftblibrary/icon/Icons.java @@ -78,6 +78,8 @@ public interface Icons { Icon LOCK = get("lock"); Icon LOCK_OPEN = get("lock_open"); Icon SUPPORT = getImage("support"); + Icon DROPDOWN_OUT = get("dropdown_out"); + Icon DROPDOWN_IN = get("dropdown_in"); static Icon get(String id) { return Icon.getIcon(FTBLibrary.MOD_ID + ":icons/" + id); diff --git a/common/src/main/java/dev/ftb/mods/ftblibrary/ui/BaseScreen.java b/common/src/main/java/dev/ftb/mods/ftblibrary/ui/BaseScreen.java index a6377681..5cfdba0a 100644 --- a/common/src/main/java/dev/ftb/mods/ftblibrary/ui/BaseScreen.java +++ b/common/src/main/java/dev/ftb/mods/ftblibrary/ui/BaseScreen.java @@ -311,23 +311,27 @@ public final void draw(GuiGraphics graphics, Theme theme, int x, int y, int w, i } public Optional getContextMenu() { - return modalPanels.stream().filter(p -> p instanceof ContextMenu).findFirst(); + return modalPanels.stream().filter(p -> p instanceof PopupMenu).findFirst(); } - public void openContextMenu(@Nullable ContextMenu newContextMenu) { - if (newContextMenu == null) { - modalPanels.removeIf(p -> p instanceof ContextMenu); + public void openPopupMenu(@Nullable PopupMenu popupMenu) { + if (popupMenu == null) { + modalPanels.removeIf(p -> p instanceof PopupMenu); return; } - pushModalPanel(newContextMenu); + pushModalPanel(popupMenu.getModalPanel()); // default positioning where the mouse was clicked. caller is free to reposition if needed var x = getX(); var y = getY(); - int px = Math.min((getMouseX() - x), screen.getGuiScaledWidth() - newContextMenu.width - x) - 3; - int py = Math.min((getMouseY() - y), screen.getGuiScaledHeight() - newContextMenu.height - y) - 3; - newContextMenu.setPos(px, py); + int px = Math.min((getMouseX() - x), screen.getGuiScaledWidth() - popupMenu.getModalPanel().width - x) - 3; + int py = Math.min((getMouseY() - y), screen.getGuiScaledHeight() - popupMenu.getModalPanel().height - y) - 3; + popupMenu.getModalPanel().setPos(px, py); + } + + public void openContextMenu(@Nullable ContextMenu newContextMenu) { + openPopupMenu(newContextMenu); } public ContextMenu openContextMenu(@NotNull List menuItems) { @@ -336,6 +340,16 @@ public ContextMenu openContextMenu(@NotNull List menuItems) { return contextMenu; } + public void openDropdownMenu(@Nullable DropDownMenu dropDownMenu) { + openPopupMenu(dropDownMenu); + } + + public DropDownMenu openDropdownMenu(@NotNull List menuItems) { + var contextMenu = new DropDownMenu(this, menuItems); + openDropdownMenu(contextMenu); + return contextMenu; + } + @Override public void closeContextMenu() { openContextMenu((ContextMenu) null); diff --git a/common/src/main/java/dev/ftb/mods/ftblibrary/ui/ContextButton.java b/common/src/main/java/dev/ftb/mods/ftblibrary/ui/ContextButton.java new file mode 100644 index 00000000..6c704349 --- /dev/null +++ b/common/src/main/java/dev/ftb/mods/ftblibrary/ui/ContextButton.java @@ -0,0 +1,63 @@ +package dev.ftb.mods.ftblibrary.ui; + +import dev.ftb.mods.ftblibrary.ui.input.MouseButton; +import dev.ftb.mods.ftblibrary.util.TooltipList; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.network.chat.Component; + +public class ContextButton extends Button { + public final ContextMenuItem item; + private final boolean hasIcons; + + public ContextButton(Panel panel, ContextMenuItem item, boolean hasIcons) { + super(panel, item.getTitle(), item.getIcon()); + this.hasIcons = hasIcons; + this.item = item; + setSize(panel.getGui().getTheme().getStringWidth(item.getTitle()) + (hasIcons ? 14 : 4), 12); + } + + @Override + public void addMouseOverText(TooltipList list) { + item.addMouseOverText(list); + } + + @Override + public WidgetType getWidgetType() { + if (!item.isClickable()) { + return WidgetType.NORMAL; // no hovered highlighting + } + + return item.isEnabled() ? super.getWidgetType() : WidgetType.DISABLED; + } + + @Override + public void drawIcon(GuiGraphics graphics, Theme theme, int x, int y, int w, int h) { + item.drawIcon(graphics, theme, x, y, w, h); + } + + @Override + public void draw(GuiGraphics graphics, Theme theme, int x, int y, int w, int h) { + GuiHelper.setupDrawing(); + + if (hasIcons) { + drawIcon(graphics, theme, x + 1, y + 2, 8, 8); + theme.drawString(graphics, getTitle(), x + 11, y + 2, theme.getContentColor(getWidgetType()), Theme.SHADOW); + } else { + theme.drawString(graphics, getTitle(), x + 2, y + 2, theme.getContentColor(getWidgetType()), Theme.SHADOW); + } + } + + @Override + public void onClicked(MouseButton button) { + if (item.isClickable()) { + playClickSound(); + } + + if (item.getYesNoText().getString().isEmpty()) { + item.onClicked(ContextButton.this, parent, button); + } else { + getGui().openYesNo(item.getYesNoText(), Component.literal(""), () -> item.onClicked(ContextButton.this, parent, button)); + } + } + +} diff --git a/common/src/main/java/dev/ftb/mods/ftblibrary/ui/ContextMenu.java b/common/src/main/java/dev/ftb/mods/ftblibrary/ui/ContextMenu.java index df605dd1..2b485f2b 100644 --- a/common/src/main/java/dev/ftb/mods/ftblibrary/ui/ContextMenu.java +++ b/common/src/main/java/dev/ftb/mods/ftblibrary/ui/ContextMenu.java @@ -2,13 +2,11 @@ import dev.ftb.mods.ftblibrary.icon.Color4I; import dev.ftb.mods.ftblibrary.ui.input.MouseButton; -import dev.ftb.mods.ftblibrary.util.TooltipList; import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.network.chat.Component; import java.util.List; -public class ContextMenu extends ModalPanel { +public class ContextMenu extends ModalPanel implements PopupMenu { private static final int MARGIN = 3; private final List items; @@ -113,60 +111,9 @@ public void draw(GuiGraphics graphics, Theme theme, int x, int y, int w, int h) graphics.pose().popPose(); } - public static class CButton extends Button { - public final ContextMenu contextMenu; - public final ContextMenuItem item; - - public CButton(ContextMenu panel, ContextMenuItem item) { - super(panel, item.getTitle(), item.getIcon()); - contextMenu = panel; - this.item = item; - setSize(panel.getGui().getTheme().getStringWidth(item.getTitle()) + (contextMenu.hasIcons ? 14 : 4), 12); - } - - @Override - public void addMouseOverText(TooltipList list) { - item.addMouseOverText(list); - } - - @Override - public WidgetType getWidgetType() { - if (!item.isClickable()) { - return WidgetType.NORMAL; // no hovered highlighting - } - - return item.isEnabled() ? super.getWidgetType() : WidgetType.DISABLED; - } - - @Override - public void drawIcon(GuiGraphics graphics, Theme theme, int x, int y, int w, int h) { - item.drawIcon(graphics, theme, x, y, w, h); - } - - @Override - public void draw(GuiGraphics graphics, Theme theme, int x, int y, int w, int h) { - GuiHelper.setupDrawing(); - - if (contextMenu.hasIcons) { - drawIcon(graphics, theme, x + 1, y + 2, 8, 8); - theme.drawString(graphics, getTitle(), x + 11, y + 2, theme.getContentColor(getWidgetType()), Theme.SHADOW); - } else { - theme.drawString(graphics, getTitle(), x + 2, y + 2, theme.getContentColor(getWidgetType()), Theme.SHADOW); - } - } - - @Override - public void onClicked(MouseButton button) { - if (item.isClickable()) { - playClickSound(); - } - - if (item.getYesNoText().getString().isEmpty()) { - item.onClicked(CButton.this, contextMenu, button); - } else { - getGui().openYesNo(item.getYesNoText(), Component.literal(""), () -> item.onClicked(CButton.this, contextMenu, button)); - } - } + @Override + public ModalPanel getModalPanel() { + return this; } public static class CSeparator extends Button { @@ -185,4 +132,8 @@ public void draw(GuiGraphics graphics, Theme theme, int x, int y, int w, int h) public void onClicked(MouseButton button) { } } + + public boolean hasIcons() { + return hasIcons; + } } diff --git a/common/src/main/java/dev/ftb/mods/ftblibrary/ui/ContextMenuItem.java b/common/src/main/java/dev/ftb/mods/ftblibrary/ui/ContextMenuItem.java index fad34107..b418a49c 100644 --- a/common/src/main/java/dev/ftb/mods/ftblibrary/ui/ContextMenuItem.java +++ b/common/src/main/java/dev/ftb/mods/ftblibrary/ui/ContextMenuItem.java @@ -100,7 +100,7 @@ public boolean isClickable() { } public Widget createWidget(ContextMenu panel) { - return new ContextMenu.CButton(panel, this); + return new ContextButton(panel, this, panel.hasIcons()); } @Override diff --git a/common/src/main/java/dev/ftb/mods/ftblibrary/ui/DropDownMenu.java b/common/src/main/java/dev/ftb/mods/ftblibrary/ui/DropDownMenu.java new file mode 100644 index 00000000..98d464fc --- /dev/null +++ b/common/src/main/java/dev/ftb/mods/ftblibrary/ui/DropDownMenu.java @@ -0,0 +1,146 @@ +package dev.ftb.mods.ftblibrary.ui; + +import dev.ftb.mods.ftblibrary.icon.Color4I; +import dev.ftb.mods.ftblibrary.ui.input.MouseButton; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.network.chat.Component; + +import java.util.List; +import java.util.function.Supplier; + +public class DropDownMenu extends ModalPanel implements PopupMenu { + + private final ScrollBar scrollBar; + private final Panel mainPanel; + private final TextBox textBox; + private float maxHeightPercent = 0.5F; + + public DropDownMenu(Panel panel, List i) { + super(panel); + this.textBox = new TextBox(this) { + @Override + public void onTextChanged() { + refreshWidgets(); + scrollBar.setValue(0); + super.onTextChanged(); + } + }; + this.textBox.ghostText = Component.translatable("ftblibrary.gui.search").getString(); + boolean hasIcons = i.stream().anyMatch(item -> !item.getIcon().isEmpty()); + this.mainPanel = new MainPanel(this, i, hasIcons, textBox::getText); + this.scrollBar = new PanelScrollBar(this, ScrollBar.Plane.VERTICAL, mainPanel); + } + + @Override + public boolean scrollPanel(double scroll) { + return super.scrollPanel(scroll); + } + + @Override + public void addWidgets() { + add(textBox); + add(mainPanel); + add(scrollBar); + } + + @Override + public boolean mousePressed(MouseButton button) { + // close context menu if clicked outside it + var pressed = super.mousePressed(button); + + if (!pressed && !isMouseOver()) { + closeContextMenu(); + return true; + } + + return pressed; + } + + @Override + public void alignWidgets() { + mainPanel.setPos(0, 14); + mainPanel.alignWidgets(); + mainPanel.setHeight(mainPanel.getHeight() + 14); + + + setWidth(mainPanel.width + 14); + setHeight(mainPanel.height + 14); + + scrollBar.setPosAndSize(width - 14, 12, 14, height - 12); + textBox.setPosAndSize(0, 0, width, 12); + } + + + @Override + public void drawBackground(GuiGraphics graphics, Theme theme, int x, int y, int w, int h) { + theme.drawContextMenuBackground(graphics, x, y, w, h); + } + + @Override + public void draw(GuiGraphics graphics, Theme theme, int x, int y, int w, int h) { + GuiHelper.setupDrawing(); + graphics.pose().pushPose(); + graphics.pose().translate(0, 0, 900); + Color4I.BLACK.withAlpha(45).draw(graphics, x + 3, y + 3, w, h); + super.draw(graphics, theme, x, y, w, h); + graphics.pose().popPose(); + } + + public void setMaxHeightPercent(float maxHeightPercent) { + this.maxHeightPercent = maxHeightPercent; + } + + @Override + public ModalPanel getModalPanel() { + return this; + } + + public class MainPanel extends Panel { + + private final List items; + private List activeWidgets; + private final boolean hasIcons; + private final Supplier filter; + + public MainPanel(Panel panel, List items, boolean hasIcons, Supplier filter) { + super(panel); + this.items = items; + this.hasIcons = hasIcons; + this.filter = filter; + } + + @Override + public void addWidgets() { + List list = items.stream() + .filter(item -> { + String string = item.getTitle().getString().toLowerCase(); + String lowerCase = filter.get().toLowerCase(); + return string.contains(lowerCase); + }) + .map(item -> new ContextButton(this, item, hasIcons)) + .toList(); + this.activeWidgets = list; + addAll(list); + } + + @Override + public void alignWidgets() { + int totalHeight = 0; + int maxWidth = 0; + for (Widget widget : activeWidgets) { + maxWidth = Math.max(maxWidth, widget.width); + totalHeight += widget.height; + } + setWidth(Math.max(maxWidth + 12, 128)); + + int wantedHeight = (int) Math.min(totalHeight, parent.parent.getScreen().getGuiScaledHeight() * (maxHeightPercent)); + + setHeight(Math.max(wantedHeight, 32)); + + for (int i = 0; i < activeWidgets.size(); i++) { + Widget widget = activeWidgets.get(i); + widget.setPosAndSize(0, i * 12, widget.width, widget.height); + } + } + } +} diff --git a/common/src/main/java/dev/ftb/mods/ftblibrary/ui/IntTextBox.java b/common/src/main/java/dev/ftb/mods/ftblibrary/ui/IntTextBox.java index f2f91bb8..cc17a589 100644 --- a/common/src/main/java/dev/ftb/mods/ftblibrary/ui/IntTextBox.java +++ b/common/src/main/java/dev/ftb/mods/ftblibrary/ui/IntTextBox.java @@ -6,7 +6,7 @@ public class IntTextBox extends TextBox { - private static final Predicate IS_NUMBER = s -> s.matches("^[0-9]+$"); + private static final Predicate IS_NUMBER = s -> s.matches("^-?[0-9]+$"); private int min = Integer.MIN_VALUE; private int max = Integer.MAX_VALUE; @@ -34,8 +34,11 @@ public void setMinMax(int min, int max) { @Override public boolean mouseScrolled(double scroll) { - setAmount(getIntValue() + (int) scroll); - return true; + if (allowInput()) { + setAmount(getIntValue() + (int) scroll); + return true; + } + return false; } public void setAmount(int amount) { diff --git a/common/src/main/java/dev/ftb/mods/ftblibrary/ui/PopupMenu.java b/common/src/main/java/dev/ftb/mods/ftblibrary/ui/PopupMenu.java new file mode 100644 index 00000000..c5a86cfe --- /dev/null +++ b/common/src/main/java/dev/ftb/mods/ftblibrary/ui/PopupMenu.java @@ -0,0 +1,6 @@ +package dev.ftb.mods.ftblibrary.ui; + +public interface PopupMenu { + + ModalPanel getModalPanel(); +} diff --git a/common/src/main/java/dev/ftb/mods/ftblibrary/ui/TextBox.java b/common/src/main/java/dev/ftb/mods/ftblibrary/ui/TextBox.java index f84cc9de..f92cfdf5 100644 --- a/common/src/main/java/dev/ftb/mods/ftblibrary/ui/TextBox.java +++ b/common/src/main/java/dev/ftb/mods/ftblibrary/ui/TextBox.java @@ -1,6 +1,7 @@ package dev.ftb.mods.ftblibrary.ui; import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; import dev.ftb.mods.ftblibrary.icon.Color4I; import dev.ftb.mods.ftblibrary.icon.Icon; import dev.ftb.mods.ftblibrary.ui.input.Key; @@ -32,6 +33,8 @@ public class TextBox extends Widget implements IFocusableWidget { private boolean validText = true; private int maxLength = 1024; private Predicate filter; + private Component label; + private Color4I labelColor = Color4I.WHITE; public TextBox(Panel panel) { super(panel); @@ -70,6 +73,14 @@ public void setFilter(Predicate filter) { this.filter = filter; } + public void setLabel(Component label) { + this.label = label; + } + + public void setLabelColor(Color4I color) { + this.labelColor = color; + } + public final String getText() { return text; } @@ -276,7 +287,7 @@ public void deleteCharsToPos(int pos) { @Override public boolean mousePressed(MouseButton button) { - if (isMouseOver()) { + if (allowInput() && isMouseOver()) { setFocused(true); if (button.isLeft()) { @@ -305,6 +316,9 @@ public boolean mousePressed(MouseButton button) { @Override public boolean keyPressed(Key key) { + if (!allowInput()) { + return false; + } if (!isFocused()) { return false; } else if (key.selectAll()) { @@ -381,7 +395,7 @@ public boolean keyPressed(Key key) { @Override public boolean charTyped(char c, KeyModifiers modifiers) { - if (isFocused()) { + if (allowInput() && isFocused()) { if (StringUtil.isAllowedChatCharacter(c)) { insertText(Character.toString(c)); } @@ -470,6 +484,15 @@ public void draw(GuiGraphics graphics, Theme theme, int x, int y, int w, int h) public void drawTextBox(GuiGraphics graphics, Theme theme, int x, int y, int w, int h) { theme.drawTextBox(graphics, x, y, w, h); + + if (label != null) { + PoseStack pose = graphics.pose(); + pose.pushPose(); + pose.translate(x + 1, y - 5, 0); + pose.scale(0.5F, 0.5F, 1); + theme.drawString(graphics, label, 0, 0, labelColor, Theme.SHADOW); + pose.popPose(); + } } public boolean isValid(String txt) { diff --git a/common/src/main/resources/assets/ftblibrary/lang/en_us.json b/common/src/main/resources/assets/ftblibrary/lang/en_us.json index dc2281cc..bd9179b6 100644 --- a/common/src/main/resources/assets/ftblibrary/lang/en_us.json +++ b/common/src/main/resources/assets/ftblibrary/lang/en_us.json @@ -70,6 +70,7 @@ "ftblibrary.gui.listSize1": "1 item", "ftblibrary.gui.listSize": "%d items", "ftblibrary.gui.error": "Error!", + "ftblibrary.gui.search": "Search...", "ftblibrary.gui.nbt_copied": "NBT copied to clipboard", "ftblibrary.gui.edit_tag_name": "Edit Tag Name", "ftblibrary.gui.edit_tag_value": "Edit Tag Value", diff --git a/common/src/main/resources/assets/ftblibrary/textures/icons/dropdown_in.png b/common/src/main/resources/assets/ftblibrary/textures/icons/dropdown_in.png new file mode 100644 index 0000000000000000000000000000000000000000..c463e117c8cdd83a797cfe4fa1f0e5a1c8722082 GIT binary patch literal 1493 zcmbVMO>7iZ93PMnAk>zG1mlIt)ELmt=Wcg)o*hf=RCg^?nsyT^iOIgcdAmF5&b(pf zwY%*B6cdvgFNPQsqZgANym;}V;Q(F?2ROii3l}e*YQYue&q7AxQ@wgtZmE z;-5u?MH&v+D%HAC0%%E^n(ii;tWhqn(qgP%K1s(@RM2E3M*SFUEW%# zk*zi21j_WA@>CZAK}0#0yHPvNP}fy@ya@Kux@D<=P_xaL#jChr;b5{XX`!+;LP8(+fKY_>e zE>3h)GlWe&U_f$QvYxhk!ULkyHjQY^Gr*cTHfb@=vKIRn>iqf%0pMHT&t*JSmnh0b zWPEM|%osT2spzb>nNWR+W^6qrbZ!IG92eFkXf~yov$V!odl;$3p~|u~shO61>U;?5Or>-KxrkV!CtY+G1(m_S*b;Cr4(TDmh2pgOKghF_W$S|LPLed17<7a{c zf*LH1FjyQ$xJmUSZYpx_M>NaYECs=!U7@Fi@1ts*aU2s`^;`vv*1|AAWs8zRscfq> zz$MitMO$@BWtc%bN-v|Hm{kb%R+QRMU<`ESqaspMt45GC; zD2Ziyaj3@W~56f7CcW_E)n&7Qx=aUZF z>!K3-hUkB{v3K`a)ehm%3dA;VLU7327>%KKrO>1DI7&d#rw=jZ3Y*?;Ajb7MkP_f9r1kK(=KK^;c<(r$TNyFKy4E5Cev=KT+E zkA3weuK)SPqw>g4-#+~L{^(ILwx>Qh>fJy4>8mf*y>s~Y-O6I&bbV~cfTlcl!n}3! i&M_hUMY>XL_`dWS><_^dfRu~g?4yzkzsU-=7Az|wF4 literal 0 HcmV?d00001 diff --git a/common/src/main/resources/assets/ftblibrary/textures/icons/dropdown_out.png b/common/src/main/resources/assets/ftblibrary/textures/icons/dropdown_out.png new file mode 100644 index 0000000000000000000000000000000000000000..c292ab4c9bc5ed0ba218ea365764306b9395be0a GIT binary patch literal 192 zcmeAS@N?(olHy`uVBq!ia0vp^{2NSwU(7d_r6;EG%XmV`y9g(#ridUI?VFB*-uL|Ns9C4q7X}0QsB+9+AZi419+{ znDKc2iWH!ruBVG*h(vgDf*b3RkCF}yhnR$W91gG~COvLuQHYVLNn_Ix7oV@d%lzZ# bnKKN0l1#pKC2iY)8W}uY{an^LB{Ts5m9R2q literal 0 HcmV?d00001