Package com.ultikits.ultitools.abstracts.gui.declarative
Built on Flutter's design philosophy, this framework provides a declarative way to build UI. Core idea: UI = f(state)
Status (6.3.0)
This package and its subpackages are still marked @ApiStatus.Experimental; the API
may change incompatibly in a future release.
Three rendering seams were fixed in 6.3.0 — UI = f(state) now holds:
GuiRenderer re-derives the Widget tree from a Supplier<Widget> on every
performBuild() call, not just once from onOpen; Element.update()
marks itself dirty unconditionally; and State.setState() — including a call on a
nested StatefulWidget — now reliably reaches a scheduled repaint. The
setState triggers a partial rebuild bullet below now holds, and the navigation
subsystem that depends on it (Navigator.push / pop) is usable. Click
dispatch was also tightened: GuiRenderer bounds-checks event.getRawSlot()
before any handler lookup, so a numerically-colliding slot in the player's own inventory can
no longer trigger a GUI handler. GridView now writes its computed slot onto any
widget type's render node(s) at render time (previously only ItemDisplay positioned
correctly).
Why the marker stays. As of this release, none of these three changes has real-server feedback from a downstream module — zero adoption is no more grounds for declaring the API stable than it would be for deleting it. The marker is retained for at least one more release pending that feedback.
The three seams are tracked by issue #200.
Main Features:
- Widget tree describes the UI structure
- Element tree manages Widget instances and their lifecycle
- RenderNode tree performs efficient diff-based updates
- Supports both StatelessWidget and StatefulWidget
- setState triggers a partial rebuild
- All updates run on the main thread automatically
- Compatible with obliviate-invs' Gui lifecycle
Quick Start:
// 1. Create your GUI page
public class ShopPage extends DeclarativeGui {
private final List<ItemStack> items;
public ShopPage(Player player, List<ItemStack> items) {
super(player, "shop", "Item Shop", 6);
this.items = items;
}
@Override
public Widget build(BuildContext context) {
return Container.builder()
.children(
// Title
TextButton.builder()
.text("§6§lItem Shop")
.slot(4)
.build(),
// Item grid
GridView.<ItemStack>builder()
.startSlot(10)
.columns(7)
.items(items, item -> ItemDisplay.builder(item)
.onClick(() -> buyItem(item))
.build())
.build(),
// Close button
TextButton.builder()
.text("§cClose")
.color("RED")
.slot(49)
.onClick(player::closeInventory)
.build()
)
.build();
}
private void buyItem(ItemStack item) {
// Handle purchase logic
}
}
// 2. Open the GUI
new ShopPage(player, items).open();
StatefulWidget Example:
public class CounterPage extends DeclarativeGui {
private int count = 0;
public CounterPage(Player player) {
super(player, "counter", "Counter", 3);
}
@Override
public Widget build(BuildContext context) {
return Container.builder()
.child(TextButton.builder()
.text("Count: " + count)
.slot(13)
.onClick(() -> {
// Mutate state and trigger a rebuild
count++;
markNeedsBuild();
})
.build())
.build();
}
}
Package Structure:
com.ultikits.ultitools.abstracts.gui.declarative.core- core abstract classescom.ultikits.ultitools.abstracts.gui.declarative.engine- rendering enginecom.ultikits.ultitools.abstracts.gui.declarative.widgets- built-in widget librarycom.ultikits.ultitools.abstracts.gui.declarative.util- utility classes
- Since:
- 6.2.0
- Version:
- 1.0.0
- Author:
- qianmo
- See Also: