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)
This commit is contained in:
Krzysztof Wiśniewski 2025-07-07 22:23:33 +02:00 committed by GitHub
parent ffcdf5e91f
commit 76c0d885a5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -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();
}