From 76c0d885a5524c5a3b437cf9397a2f940472fa78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Wi=C5=9Bniewski?= Date: Mon, 7 Jul 2025 22:23:33 +0200 Subject: [PATCH] QoL changes for creative inventory (#1635) Although major UI changes are planned, they are expected in rather far future. Unfortunately current state of creative inventory makes it really frustrating to use when building and when testing newly added blocks. Therefore I have implemented a dead simple search bar which filters out all items with IDs that don't contain the searched phrase. I also made a sin of (subjectively) improving the look of item list by padding last row of item list with empty immutable slots if it was not filled with items found. ![Screenshot 2025-06-20 025239](https://github.com/user-attachments/assets/17f6ca67-fc65-4588-b76e-c5cb0fb65ff1) ![Screenshot 2025-06-20 025312](https://github.com/user-attachments/assets/e7af7498-4415-45d8-a72c-ef155683e91e) ![Screenshot 2025-06-20 025245](https://github.com/user-attachments/assets/6dbf2b30-c075-491a-803f-b1dd92efa49c) --- src/gui/windows/creative_inventory.zig | 102 +++++++++++++++++++------ 1 file changed, 80 insertions(+), 22 deletions(-) diff --git a/src/gui/windows/creative_inventory.zig b/src/gui/windows/creative_inventory.zig index 4047a7b4..23f5b6a7 100644 --- a/src/gui/windows/creative_inventory.zig +++ b/src/gui/windows/creative_inventory.zig @@ -9,6 +9,8 @@ const Vec2f = main.vec.Vec2f; const gui = @import("../gui.zig"); const GuiComponent = gui.GuiComponent; const GuiWindow = gui.GuiWindow; +const TextInput = GuiComponent.TextInput; +const Label = GuiComponent.Label; const HorizontalList = GuiComponent.HorizontalList; const VerticalList = GuiComponent.VerticalList; const ItemSlot = GuiComponent.ItemSlot; @@ -18,13 +20,16 @@ pub var window = GuiWindow{ .{.attachedToFrame = .{.selfAttachmentPoint = .lower, .otherAttachmentPoint = .lower}}, .{.attachedToFrame = .{.selfAttachmentPoint = .middle, .otherAttachmentPoint = .middle}}, }, - .contentSize = Vec2f{64*8, 64*4}, + .contentSize = Vec2f{64*8, 64*6}, .scale = 0.75, }; const padding: f32 = 8; +const slotsPerRow: u32 = 10; var items: main.List(Item) = undefined; var inventory: Inventory = undefined; +var searchInput: *TextInput = undefined; +var searchString: []const u8 = undefined; fn lessThan(_: void, lhs: Item, rhs: Item) bool { if(lhs == .baseItem and rhs == .baseItem) { @@ -40,38 +45,91 @@ fn lessThan(_: void, lhs: Item, rhs: Item) bool { } pub fn onOpen() void { - items = .init(main.globalAllocator); - var itemIterator = main.items.iterator(); - while(itemIterator.next()) |item| { - items.append(Item{.baseItem = item.*}); - } - std.mem.sort(Item, items.items, {}, lessThan); - inventory = Inventory.init(main.globalAllocator, items.items.len, .creative, .other); - for(0..items.items.len) |i| { - inventory.fillAmountFromCreative(@intCast(i), items.items[i], 1); - } + searchString = ""; + initContent(); +} - const list = VerticalList.init(.{padding, padding + 16}, 140, 0); - var i: u32 = 0; - while(i < items.items.len) { +pub fn onClose() void { + deinitContent(); + main.globalAllocator.free(searchString); +} + +fn initContent() void { + const root = VerticalList.init(.{padding, padding}, 300, 0); + { + const list = VerticalList.init(.{0, padding + padding}, 48, 0); const row = HorizontalList.init(); - for(0..10) |_| { - if(i >= items.items.len) break; - row.add(ItemSlot.init(.{0, 0}, inventory, i, .default, .takeOnly)); - i += 1; - } + const label = Label.init(.{0, 3}, 56, "Search:", .right); + + searchInput = TextInput.init(.{0, 0}, 288, 22, searchString, .{.callback = &filter}, .{}); + + row.add(label); + row.add(searchInput); list.add(row); + list.finish(.center); + root.add(list); } - list.finish(.center); - window.rootComponent = list.toComponent(); + { + const list = VerticalList.init(.{0, padding}, 144, 0); + items = .init(main.globalAllocator); + var itemIterator = main.items.iterator(); + while(itemIterator.next()) |item| { + if(searchString.len != 0 and !std.mem.containsAtLeast(u8, item.id(), 1, searchString)) continue; + items.append(Item{.baseItem = item.*}); + } + + std.mem.sort(Item, items.items, {}, lessThan); + const slotCount = items.items.len + (slotsPerRow - items.items.len%slotsPerRow); + inventory = Inventory.init(main.globalAllocator, slotCount, .creative, .other); + for(0..items.items.len) |i| { + inventory.fillAmountFromCreative(@intCast(i), items.items[i], 1); + } + var i: u32 = 0; + while(i < items.items.len) { + const row = HorizontalList.init(); + for(0..slotsPerRow) |_| { + if(i >= items.items.len) { + row.add(ItemSlot.init(.{0, 0}, inventory, i, .immutable, .immutable)); + } else { + row.add(ItemSlot.init(.{0, 0}, inventory, i, .default, .takeOnly)); + } + i += 1; + } + list.add(row); + } + list.finish(.center); + root.add(list); + } + root.finish(.center); + window.rootComponent = root.toComponent(); window.contentSize = window.rootComponent.?.pos() + window.rootComponent.?.size() + @as(Vec2f, @splat(padding)); gui.updateWindowPositions(); } -pub fn onClose() void { +fn deinitContent() void { if(window.rootComponent) |*comp| { comp.deinit(); } items.deinit(); inventory.deinit(main.globalAllocator); } + +pub fn update() void { + if(std.mem.eql(u8, searchInput.currentString.items, searchString)) return; + filter(undefined); +} + +fn filter(_: usize) void { + const selectionStart = searchInput.selectionStart; + const cursor = searchInput.cursor; + + main.globalAllocator.free(searchString); + searchString = main.globalAllocator.dupe(u8, searchInput.currentString.items); + deinitContent(); + initContent(); + + searchInput.selectionStart = selectionStart; + searchInput.cursor = cursor; + + searchInput.select(); +}