Skip to content

Sort button attempt 2 - #3194

Open
Crepestrom wants to merge 87 commits into
PixelGuys:masterfrom
Crepestrom:Sort-Button-2
Open

Crepestrom wants to merge 87 commits into
PixelGuys:masterfrom
Crepestrom:Sort-Button-2

Conversation

@Crepestrom

@Crepestrom Crepestrom commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Sort button now functions as normal

Before sorting it will compress all items into their max stacks and push them all to the lowest index getting rid of any holes

Then the sort button will first seperate items into procederal items and nonprocedural items
then they will be sorted by tag
items that share the same first tag will be internally sorted by their second tag and so on and so forth
procedural items are sorted by durability

image

Also allows buttons to be hidden
if a button is hidden the icon within it is extended to the size of the whole button (its scaled up).

@Crepestrom Crepestrom mentioned this pull request Jun 8, 2026

@Wunka Wunka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think that std.sort is probably way nicer and easier. Here is an example (not tested) based on your current code (but of course not completly mapped and I with an added getTags method for the Item struct):

pub fn sortItems(source: ClientInventory, ignoredSlotCount: usize) void {
	compressItems(source);
	const ctx: SortContext = .{.inv = source};
	std.sort.insertionContext(ignoredSlotCount, source.super._items.len, ctx);
}

const SortContext = struct {
	inv: ClientInventory,

	pub fn lessThan(ctx: @This(), a: usize, b: usize) bool {
		const itemA = ctx.inv.getItem(a);
		const itemB = ctx.inv.getItem(b);

		if(itemA == .null) return false;
		if(itemB == .null) return true;

		const itemATags = itemA.getTags().?;
		const itemBTags = itemB.getTags().?;

		for(0..@min(itemATags.len, itemBTags.len)) |i| {
			if(itemATags[i] == itemBTags[i]) continue;
			return std.mem.lessThan(u8, itemATags[i].getName(), itemBTags[i].getName());
		}
		if(itemATags.len != itemBTags.len) return itemATags.len < itemBTags.len;

		return std.mem.lessThan(u8, itemA.id().?, itemB.id().?);
	}

	pub fn swap(ctx: @This(), a: usize, b: usize) void {
		main.sync.client.executeCommand(.{.depositOrSwap = .{
			.dest = .{.inv = ctx.inv.super, .slot = @intCast(a)}, 
			.source = .{.inv = ctx.inv.super, .slot = @intCast(b)},
		}});
	}
};

@Crepestrom
Crepestrom marked this pull request as ready for review June 9, 2026 21:16
@Crepestrom

Copy link
Copy Markdown
Contributor Author

also fixes #3195

@Wunka Wunka moved this to Low Priority in PRs to review Jun 10, 2026

@IntegratedQuantum IntegratedQuantum left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About the UI: An icon like this is hard to understand, there is no such thing as a universal sorting icon, and a funnel is often used for filtering.
I think Terraria has a simple and intuitive UI for this:

Image

Comment thread src/Inventory.zig
Comment thread src/Inventory.zig Outdated
Comment thread src/Inventory.zig Outdated
Comment thread src/Inventory.zig Outdated
@IntegratedQuantum IntegratedQuantum moved this from Low Priority to In review in PRs to review Jun 11, 2026
@Crepestrom

Copy link
Copy Markdown
Contributor Author

I still think that std.sort is probably way nicer and easier. Here is an example (not tested) based on your current code (but of course not completly mapped and I with an added getTags method for the Item struct):

pub fn sortItems(source: ClientInventory, ignoredSlotCount: usize) void {
	compressItems(source);
	const ctx: SortContext = .{.inv = source};
	std.sort.insertionContext(ignoredSlotCount, source.super._items.len, ctx);
}

const SortContext = struct {
	inv: ClientInventory,

	pub fn lessThan(ctx: @This(), a: usize, b: usize) bool {
		const itemA = ctx.inv.getItem(a);
		const itemB = ctx.inv.getItem(b);

		if(itemA == .null) return false;
		if(itemB == .null) return true;

		const itemATags = itemA.getTags().?;
		const itemBTags = itemB.getTags().?;

		for(0..@min(itemATags.len, itemBTags.len)) |i| {
			if(itemATags[i] == itemBTags[i]) continue;
			return std.mem.lessThan(u8, itemATags[i].getName(), itemBTags[i].getName());
		}
		if(itemATags.len != itemBTags.len) return itemATags.len < itemBTags.len;

		return std.mem.lessThan(u8, itemA.id().?, itemB.id().?);
	}

	pub fn swap(ctx: @This(), a: usize, b: usize) void {
		main.sync.client.executeCommand(.{.depositOrSwap = .{
			.dest = .{.inv = ctx.inv.super, .slot = @intCast(a)}, 
			.source = .{.inv = ctx.inv.super, .slot = @intCast(b)},
		}});
	}
};

I realized how to turn tags into numbers so I’m gonna try this

@Crepestrom

Copy link
Copy Markdown
Contributor Author

is ready for rereview

@Wunka Wunka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. Now the code looks much better

Comment thread src/Inventory.zig Outdated
Comment thread src/Inventory.zig Outdated
Comment thread src/Inventory.zig Outdated
@IntegratedQuantum IntegratedQuantum moved this from In review to WIP/not ready for review in PRs to review Jun 12, 2026
@Crepestrom Crepestrom changed the title Sort button 2 Sort button attempt 2 Jun 13, 2026
@IntegratedQuantum

Copy link
Copy Markdown
Member

I don't see any changes since my last review. Did you forget to push?

@Crepestrom

Copy link
Copy Markdown
Contributor Author

testing finished

@IntegratedQuantum IntegratedQuantum left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Full stacks should always be placed left of partial stacks of the same type, currently it behaves like this instead:
Image

Comment thread src/gui/components/Button.zig Outdated
Comment thread src/assets.zig Outdated
Comment thread src/Inventory.zig Outdated
Comment thread src/Inventory.zig Outdated
@Crepestrom

Copy link
Copy Markdown
Contributor Author

funny ennough that happens because items were not being sorted by their ammounts

Full stacks should always be placed left of partial stacks of the same type, currently it behaves like this instead: Image

Comment thread src/Inventory.zig Outdated
}
if ((ctx.inv.getAmount(a) > ctx.inv.getAmount(b)) and std.mem.eql(u8, itemA.id().?, itemB.id().?)) return true;

return std.mem.lessThan(u8, itemA.id().?, itemB.id().?);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They should still sort by id first (you did accound for that with items, but not tools).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorts by id first now

Comment thread src/gui/components/Button.zig Outdated
.disabled = options.disabled,
.hideBackground = options.hideBackground,
};
if (self.hideBackground) self.child.mutSize().* = self.size;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here #3194 (comment)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops forgot to remove that line

Comment thread src/Inventory.zig Outdated
Comment thread src/Inventory.zig Outdated
Comment on lines +603 to +604
if (std.mem.lessThan(u8, itemA.id().?, itemB.id().?)) return true;
if (!std.mem.lessThan(u8, itemA.id().?, itemB.id().?) and !std.mem.eql(u8, itemA.id().?, itemB.id().?)) return false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on the second line the first argument is already proven to be false (because of the first line). So either do:

Suggested change
if (std.mem.lessThan(u8, itemA.id().?, itemB.id().?)) return true;
if (!std.mem.lessThan(u8, itemA.id().?, itemB.id().?) and !std.mem.eql(u8, itemA.id().?, itemB.id().?)) return false;
if (std.mem.lessThan(u8, itemA.id().?, itemB.id().?)) return true;
if (!std.mem.eql(u8, itemA.id().?, itemB.id().?)) return false;

or

Suggested change
if (std.mem.lessThan(u8, itemA.id().?, itemB.id().?)) return true;
if (!std.mem.lessThan(u8, itemA.id().?, itemB.id().?) and !std.mem.eql(u8, itemA.id().?, itemB.id().?)) return false;
if (!std.mem.eql(u8, itemA.id().?, itemB.id().?)) return std.mem.lessThan(u8, itemA.id().?, itemB.id().?):

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

applied suggesion

Comment thread src/Inventory.zig Outdated
Comment on lines +606 to +607
if (std.mem.lessThan(u8, itemA.id().?, itemB.id().?)) return true;
if (!std.mem.lessThan(u8, itemA.id().?, itemB.id().?) and !std.mem.eql(u8, itemA.id().?, itemB.id().?)) return false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is already checked a few lines above

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops fixed

@Crepestrom

Copy link
Copy Markdown
Contributor Author

thanks for your help wunka

Comment thread src/gui/components/Button.zig Outdated
pub fn initIcon(pos: Vec2f, iconSize: Vec2f, iconTexture: Texture, options: Options) *Button {
const icon = Icon.init(undefined, iconSize, iconTexture);
pub fn initIcon(pos: Vec2f, givenIconSize: Vec2f, iconTexture: Texture, options: Options) *Button {
const calculatedIconSize: Vec2f = if (options.hideBackground) givenIconSize + @as(Vec2f, @splat(3*border)) else givenIconSize;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks wrong, if there is no background, then it should not add any border around the supplied size.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope getting rid of the border just makes the button smaller or the icon smaller than it needs to be

Comment thread src/Inventory.zig Outdated
Comment thread src/Inventory.zig Outdated
if (!std.mem.eql(u8, itemA.id().?, itemB.id().?)) return false;
if ((itemA == .proceduralItem) and (itemB == .proceduralItem)) {
const itemADurabilityPercent: f32 = @as(f32, @floatFromInt(itemA.proceduralItem.durability))/itemA.proceduralItem.getProperty(.maxDurability);
const itemBDurabilityPercent: f32 = @as(f32, @floatFromInt(itemB.proceduralItem.durability))/itemB.proceduralItem.getProperty(.maxDurability);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think durability should be the last property to consider (→after dps), otherwise items with the identical recipe will not be sorted next to each other.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok done

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In review

Development

Successfully merging this pull request may close these issues.

5 participants