Content Builder
Content Builder
ContentBuilder is the layout DSL most Lotus menus start with. It is the easiest way to describe
what goes where without dropping down to manual slot mutation.
Content content = Content.builder(Capacity.ofRows(3))
.fillBorder(Button.of(filler()))
.set(1, 4, Button.clickable(icon(), buyAction))
.build();
The Core Operations
Place one button
.set(Slot.of(13), button)
.set(1, 4, button)
The (row, column) overload is usually the most readable.
Place many buttons
.buttons(Map.of(
Slot.of(10), leftButton,
Slot.of(13), centerButton,
Slot.of(16), rightButton
))
Fill regions
.fill(mask, button)
.fillAll(button)
.fillBorder(button)
fill(...) becomes especially powerful with SlotMask:
.fill(SlotMask.range(size, Slot.of(9), Slot.of(17)), divider)
.fill(SlotMask.full(size).excluding(Slot.of(13)), filler)
Rows and columns are zero-based. set(1, 4, button) means the second row and the fifth
column.
Drawing Lines
You can draw until the edge:
.draw(Slot.at(1, 1, size), Direction.RIGHT, divider)
Or between two explicit points:
.draw(Slot.at(1, 1, size), Slot.at(1, 7, size), Direction.RIGHT, divider)
This is useful for separators, outlines, diagonal effects, and guides.
apply(...) — The Escape Hatch
If the fluent methods are not enough, apply(...) gives you the raw Content object:
.apply(content -> {
for (int column = 0; column < 9; column++) {
content.set(Slot.at(0, column, size), topRowButton(column));
}
})
That lets you mix a readable DSL with custom loops when needed.
A Complete Beginner Layout
public Content content(MenuView<?, ?> view) {
Capacity size = view.capacity();
return Content.builder(size)
.fillBorder(Button.of(filler()))
.draw(
Slot.at(1, 1, size),
Slot.at(1, 7, size),
Direction.RIGHT,
Button.of(divider())
)
.set(2, 3, Button.clickable(cancelIcon(), (menuView, event) -> {
menuView.viewer().closeInventory();
}))
.set(2, 5, Button.clickable(confirmIcon(), (menuView, event) -> {
commit(menuView.viewer());
menuView.viewer().closeInventory();
}))
.build();
}
What Happens After .build()
The result is still a mutable Content object. That means later you can do:
view.content().set(Slot.of(13), replacement);
view.content().update(Slot.of(13), current -> current.withItem(highlightedIcon()));
view.content().remove(Slot.of(13));
Lotus repaints automatically after button dispatch.
If your mutation happens outside a click handler, call view.refresh() to rebuild the menu
content for that viewer.
When To Prefer The Builder
Reach for ContentBuilder when:
- you are writing the initial menu layout
- the shape of the menu matters to readability
- you want future you to understand the menu at a glance
Next: Data Registry.