The Menu View

The Menu View

MenuView<C, M> is the live runtime object for one player and one open menu.

If Menu is the blueprint, MenuView is the actual house currently being lived in.

You will see a MenuView in:

  • title(...)
  • capacity(...)
  • content(...)
  • button click handlers
  • menu handler callbacks

What You Can Read From A View

Method Meaning
menu() The menu template behind this view
viewer() The player looking at it
title() The resolved title used when it was opened
capacity() The resolved capacity used when it was opened
content() The current live Content object
data() The per-view DataRegistry
type() The inventory type
getInventory() The Bukkit inventory, or null before open / after close
isOpen() Whether the view is still active
refresh() Rebuild the content and repaint the inventory

The Most Important Distinction

MenuView.refresh() rebuilds content, not the whole menu shell.

for (MenuView<?, ?> view : lotus.openViews()) {
    if (view.menu() instanceof ShopMenu) {
        view.refresh();
    }
}

refresh() does not change the inventory title or capacity. Those were resolved when the view was opened. If you need a new title or a different size, open a new menu.

Runtime Edits Inside A Click

Inside a button handler, you can mutate only the part that changed:

view.content().set(Slot.of(event.getSlot()), replacementButton);
view.content().update(Slot.of(event.getSlot()), current -> current.withItem(brighterIcon));
view.content().remove(Slot.of(event.getSlot()));

Lotus repaints automatically after button dispatch, so these changes show up right away.

If the change happens outside a click, such as a scheduler task or a service callback, call view.refresh() yourself.

Tracking Open Views

Lotus keeps a live registry of open views:

Optional<MenuView<?, ?>> current = lotus.viewOf(player);
Collection<MenuView<?, ?>> allOpen = lotus.openViews();

This is useful for:

  • refreshing every open shop menu after stock changes
  • closing or inspecting a player's current menu
  • syncing all viewers of a shared data source

A Practical Pattern

Use data() to keep the view-specific state close to the UI:

int page = view.data().get(Keys.PAGE).orElse(0);
UUID target = view.data().require(Keys.TARGET);

That keeps the view self-contained instead of scattering temporary menu state across your plugin.

Next: The Menu Handler for lifecycle hooks and click flow.