Code Patterns

Copy-paste examples for common plugin tasks. Commands, events, ECS, GUI, and more.

← Back to Patterns
ui

UI List with Search and Delete Confirmation

Searchable list UI with delete confirmation on hover pattern

Example Code

java
public class ListGui extends InteractiveCustomUIPage<ListGui.Data> {
    private String searchQuery = "";
    private List<Item> visibleItems = new ArrayList<>();
    private int requestingConfirmation = -1;

    @Override
    public void build(Ref<EntityStore> ref, UICommandBuilder cmd, UIEventBuilder evt, Store<EntityStore> store) {
        cmd.append("Pages/List.ui");
        cmd.set("#SearchInput.Value", this.searchQuery);
        evt.addEventBinding(CustomUIEventBindingType.ValueChanged, "#SearchInput",
            EventData.of("@SearchQuery", "#SearchInput.Value"), false);
        buildList(ref, cmd, evt, store);
    }

    private void buildList(Ref<EntityStore> ref, UICommandBuilder cmd, UIEventBuilder evt, Store<EntityStore> store) {
        // Filter items by search query
        visibleItems.clear();
        for (Item item : allItems) {
            if (searchQuery.isEmpty() || item.name().toLowerCase().contains(searchQuery.toLowerCase())) {
                visibleItems.add(item);
            }
        }

        // Build list UI
        cmd.clear("#Cards");
        cmd.appendInline("#List", "Group #Cards { LayoutMode: Left; }");
        int i = 0;
        for (Item item : visibleItems) {
            cmd.append("#Cards", "Pages/Entry.ui");
            cmd.set("#Cards[" + i + "] #Name.Text", item.name());

            // Delete button with confirmation
            if (this.requestingConfirmation == i) {
                cmd.set("#Cards[" + i + "] #DeleteBtn.Text", "Are you sure?");
                evt.addEventBinding(CustomUIEventBindingType.Activating, "#Cards[" + i + "] #DeleteBtn",
                    EventData.of("Action", "Delete:" + item.id()), false);
                evt.addEventBinding(CustomUIEventBindingType.MouseExited, "#Cards[" + i + "] #DeleteBtn",
                    EventData.of("Action", "Click:-1"), false);
            } else {
                evt.addEventBinding(CustomUIEventBindingType.Activating, "#Cards[" + i + "] #DeleteBtn",
                    EventData.of("Action", "Click:" + i), false);
            }
            ++i;
        }
    }

    @Override
    public void handleDataEvent(Ref<EntityStore> ref, Store<EntityStore> store, Data data) {
        if (data.action != null) {
            var split = data.action.split(":");
            if (split[0].equals("Click")) {
                this.requestingConfirmation = Integer.parseInt(split[1]);
            }
            if (split[0].equals("Delete")) {
                // Perform delete
                this.requestingConfirmation = -1;
            }
            // Refresh UI
            UICommandBuilder cmd = new UICommandBuilder();
            UIEventBuilder evt = new UIEventBuilder();
            buildList(ref, cmd, evt, store);
            this.sendUpdate(cmd, evt, false);
        }
        if (data.searchQuery != null) {
            this.searchQuery = data.searchQuery.trim().toLowerCase();
            // Refresh UI...
        }
    }
}