From 931be4576dfe889d0c791de1ab1f45eacdd8f538 Mon Sep 17 00:00:00 2001 From: legentpc Date: Sat, 20 Jun 2026 07:37:37 +0530 Subject: [PATCH] Add remove button to draggable lists --- .../editors/GuiOptionEditorDraggableList.java | 151 +++++++++++------- 1 file changed, 97 insertions(+), 54 deletions(-) diff --git a/common/src/main/java/io/github/notenoughupdates/moulconfig/gui/editors/GuiOptionEditorDraggableList.java b/common/src/main/java/io/github/notenoughupdates/moulconfig/gui/editors/GuiOptionEditorDraggableList.java index 06a41eb55..2a284e91a 100644 --- a/common/src/main/java/io/github/notenoughupdates/moulconfig/gui/editors/GuiOptionEditorDraggableList.java +++ b/common/src/main/java/io/github/notenoughupdates/moulconfig/gui/editors/GuiOptionEditorDraggableList.java @@ -107,6 +107,68 @@ public boolean canDeleteRightNow() { return enableDeleting && (activeText.size() > 1 || !requireNonEmpty); } + private GuiComponent makeRemoveButton() { + return new ButtonComponent(new CenterComponent(new TextComponent(StructuredText.of(" Remove "))), 2, () -> { + var pos = IMinecraft.INSTANCE.getMousePosition(); + if (!canDeleteRightNow()) + return; + openDropDownOverlay(pos.getFirst(), pos.getSecond(), true); + }); + } + + private GuiComponent makeTrashCan() { + return new GuiComponent() { + @Override + public int getWidth() { + return 11; + } + + @Override + public int getHeight() { + return 14; + } + + @Override + public void render(@NotNull GuiImmediateContext context) { + if (context.isHovered() && dragStartIndex >= 0 && canDeleteRightNow()) { + trashAnimation.setTarget(0); + } else { + trashAnimation.setTarget(255); + } + int nonRedTints = trashAnimation.getValue(); + context.getRenderContext().drawComplexTexture( + GuiTextures.DELETE, + 0F, 0F, 11F, 14F, + draw -> draw.color(ColourUtil.packARGB(255, 255, nonRedTints, nonRedTints)) + ); + trashCanBoundingBox = Rect.ofGuiImmediateContext(context); + } + }; + } + + private GuiComponent makeButtonRow() { + GuiComponent addButton = new ButtonComponent(new CenterComponent(new TextComponent(StructuredText.of(" Add "))), 2, () -> { + var pos = IMinecraft.INSTANCE.getMousePosition(); + if (activeText.size() == exampleText.size()) + return; + openDropDownOverlay(pos.getFirst(), pos.getSecond(), false); + }); + if (!enableDeleting) { + return new RowComponent( + addButton, + new SpacerComponent(GetSetter.constant(5), GetSetter.constant(0)), + makeTrashCan() + ); + } + return new RowComponent( + addButton, + new SpacerComponent(GetSetter.constant(5), GetSetter.constant(0)), + makeRemoveButton(), + new SpacerComponent(GetSetter.constant(5), GetSetter.constant(0)), + makeTrashCan() + ); + } + GuiComponent delegate; Rect trashCanBoundingBox; @@ -116,42 +178,8 @@ public boolean canDeleteRightNow() { if (delegate == null) delegate = wrapComponent( new FixedComponent( - new RowComponent( - new ButtonComponent(new CenterComponent(new TextComponent(StructuredText.of(" Add "))), 2, () -> { - var pos = IMinecraft.INSTANCE.getMousePosition(); - if (activeText.size() == exampleText.size()) - return; - openDropDownOverlay(pos.getFirst(), pos.getSecond()); - }), - new SpacerComponent(GetSetter.constant(5), GetSetter.constant(0)), - new GuiComponent() { - @Override - public int getWidth() { - return 11; - } - - @Override - public int getHeight() { - return 14; - } - - @Override - public void render(@NotNull GuiImmediateContext context) { - if (context.isHovered() && dragStartIndex >= 0 && canDeleteRightNow()) { - trashAnimation.setTarget(0); - } else { - trashAnimation.setTarget(255); - } - int nonRedTints = trashAnimation.getValue(); - context.getRenderContext().drawComplexTexture( - GuiTextures.DELETE, - 0F, 0F, 11F, 14F, - draw -> draw.color(ColourUtil.packARGB(255, 255, nonRedTints, nonRedTints)) - ); - trashCanBoundingBox = Rect.ofGuiImmediateContext(context); - } - }), - 48, 16), + makeButtonRow(), + enableDeleting ? 105 : 48, 16), new GuiComponent() { @Override public int getWidth() { @@ -339,30 +367,40 @@ private List getRemainingDropDownEntries() { return remaining; } - private int getDropDownContentHeight() { - return Math.max(0, -1 + DROPDOWN_ITEM_HEIGHT * getRemainingDropDownEntries().size()); + private List getRemovableDropDownEntries() { + if (!canDeleteRightNow()) + return Collections.emptyList(); + return new ArrayList<>(activeText); + } + + private List getDropDownEntries(boolean removing) { + return removing ? getRemovableDropDownEntries() : getRemainingDropDownEntries(); + } + + private int getDropDownContentHeight(boolean removing) { + return Math.max(0, -1 + DROPDOWN_ITEM_HEIGHT * getDropDownEntries(removing).size()); } - private int getDropDownVisibleHeight(int overlayY) { + private int getDropDownVisibleHeight(int overlayY, boolean removing) { int screenHeight = IMinecraft.INSTANCE.getScaledHeight(); int maxHeight = Math.max(DROPDOWN_ITEM_HEIGHT, screenHeight - overlayY - DROPDOWN_SCREEN_MARGIN); - return Math.min(getDropDownContentHeight(), maxHeight); + return Math.min(getDropDownContentHeight(removing), maxHeight); } - private void openDropDownOverlay(int mouseX, int mouseY) { + private void openDropDownOverlay(int mouseX, int mouseY, boolean removing) { int screenHeight = IMinecraft.INSTANCE.getScaledHeight(); int screenWidth = IMinecraft.INSTANCE.getScaledWidth(); - int contentHeight = getDropDownContentHeight(); + int contentHeight = getDropDownContentHeight(removing); int maxVisibleHeight = Math.max(DROPDOWN_ITEM_HEIGHT, screenHeight - DROPDOWN_SCREEN_MARGIN * 2); int visibleHeight = Math.min(contentHeight, maxVisibleHeight); int overlayX = Math.min(mouseX, screenWidth - DROPDOWN_WIDTH - DROPDOWN_SCREEN_MARGIN); int overlayY = Math.min(mouseY, screenHeight - visibleHeight - DROPDOWN_SCREEN_MARGIN); overlayX = Math.max(DROPDOWN_SCREEN_MARGIN, overlayX); overlayY = Math.max(DROPDOWN_SCREEN_MARGIN, overlayY); - openOverlay(makeDropDownOverlay(overlayY), overlayX, overlayY); + openOverlay(makeDropDownOverlay(overlayY, removing), overlayX, overlayY); } - GuiComponent makeDropDownOverlay(int overlayY) { + GuiComponent makeDropDownOverlay(int overlayY, boolean removing) { return new GuiComponent() { int scrollOffset; @@ -373,12 +411,12 @@ public int getWidth() { @Override public int getHeight() { - return getDropDownVisibleHeight(overlayY); + return getDropDownVisibleHeight(overlayY, removing); } @Override public boolean mouseEvent(@NotNull MouseEvent mouseEvent, @NotNull GuiImmediateContext context) { - int maxScrollOffset = Math.max(0, getDropDownContentHeight() - context.getHeight()); + int maxScrollOffset = Math.max(0, getDropDownContentHeight(removing) - context.getHeight()); if (scrollOffset > maxScrollOffset) { scrollOffset = maxScrollOffset; } @@ -392,11 +430,16 @@ public boolean mouseEvent(@NotNull MouseEvent mouseEvent, @NotNull GuiImmediateC if (mouseEvent instanceof MouseEvent.Click) { var click = (MouseEvent.Click) mouseEvent; if (click.getMouseState() && context.isHovered()) { - List remaining = getRemainingDropDownEntries(); + List entries = getDropDownEntries(removing); int dropdownY = -1; - for (Object indexObject : remaining) { + for (Object indexObject : entries) { if (context.translated(0, dropdownY + 3 - scrollOffset, context.getWidth(), 10).isHovered()) { - activeText.add(indexObject); + if (removing) { + activeText.remove(indexObject); + } else { + activeText.add(indexObject); + } + saveChanges(); return true; } dropdownY += DROPDOWN_ITEM_HEIGHT; @@ -410,13 +453,13 @@ public boolean mouseEvent(@NotNull MouseEvent mouseEvent, @NotNull GuiImmediateC @Override public void render(@NotNull GuiImmediateContext context) { - List remaining = getRemainingDropDownEntries(); - if (remaining.isEmpty()) { + List entries = getDropDownEntries(removing); + if (entries.isEmpty()) { closeOverlay(); return; } - int maxScrollOffset = Math.max(0, getDropDownContentHeight() - context.getHeight()); + int maxScrollOffset = Math.max(0, getDropDownContentHeight(removing) - context.getHeight()); if (scrollOffset > maxScrollOffset) { scrollOffset = maxScrollOffset; } @@ -442,7 +485,7 @@ public void render(@NotNull GuiImmediateContext context) { renderContext.pushMatrix(); renderContext.translate(0, -scrollOffset); int dropdownY = -1; - for (Object indexObject : remaining) { + for (Object indexObject : entries) { StructuredText str = getExampleText(indexObject); if (str.getText().isEmpty()) { str = StructuredText.of(""); @@ -454,7 +497,7 @@ public void render(@NotNull GuiImmediateContext context) { } renderContext.popMatrix(); renderContext.popScissor(); - int contentHeight = getDropDownContentHeight(); + int contentHeight = getDropDownContentHeight(removing); if (contentHeight > dropdownHeight) { int scrollBarTrackTop = 1; int scrollBarTrackBottom = dropdownHeight - 1;