ComposeContainerScreen¶
abstract class ComposeContainerScreen<T : ComposeContainerMenuBase<T>>(
menu: T,
playerInventory: Inventory,
title: Component,
val asynchronous: Boolean = true
) : AbstractContainerScreen<T> , CoroutineScope, SlotLayerDepthProvider, SlotHighlightClipProvider, ScreenOverlayDeferral, ComposeIdleAware, LayerManagerProvider
A Compose-driven AbstractContainerScreen with layer support, async recomposition, and vanilla Slot rendering kept in sync with the Compose-reported SlotGroup layout.
Behaves like ComposeScreen but additionally bridges vanilla's container/slot machinery: the base layer (layer 0) is rendered from renderBg so it draws under vanilla's slots, and any additional layers (modals) render on top from render via renderSlot/slotClipRect clipping so scrolled-out-of-view slots don't paint over unrelated content.
Extend this class and call start inside your init() override, the same way as ComposeScreen. Works uniformly for both ComposeBlockContainerMenu (BlockEntity-backed) and ComposeItemContainerMenu (ItemStack-backed) subclasses - nothing here is holder-specific.
Parameters¶
-
T: The concrete
ComposeContainerMenuBasesubclass driving this screen. -
menu: The container menu instance for this screen.
-
playerInventory: The opening player's inventory.
-
title: The screen title passed to the vanilla AbstractContainerScreen constructor.
-
asynchronous: When
true(default), recomposition runs off the main thread and the result is joined at the start of the next frame for smooth, non-blocking updates. Set tofalseto force synchronous recomposition (simpler but may stutter).
Constructors¶
ComposeContainerScreen¶
Parameters
-
T: The concrete
ComposeContainerMenuBasesubclass driving this screen. -
menu: The container menu instance for this screen.
-
playerInventory: The opening player's inventory.
-
title: The screen title passed to the vanilla AbstractContainerScreen constructor.
-
asynchronous: When
true(default), recomposition runs off the main thread and the result is joined at the start of the next frame for smooth, non-blocking updates. Set tofalseto force synchronous recomposition (simpler but may stutter).
Types¶
Companion¶
object Companion
Properties¶
asynchronous¶
val asynchronous: Boolean
Parameters
- asynchronous: When
true(default), recomposition runs off the main thread and the result is joined at the start of the next frame for smooth, non-blocking updates. Set tofalseto force synchronous recomposition (simpler but may stutter).
backgroundMusic¶
@get:
Nullable
open val backgroundMusic: Music?
coroutineContext¶
override val coroutineContext: CoroutineContext
currentFocusPath¶
@get:
Nullable
open val currentFocusPath: ComponentPath?
focused¶
@get:
Nullable
open var focused: GuiEventListener?
guiLeft¶
guiTop¶
height¶
inventoryLabelPos¶
inventoryLabelX/inventoryLabelY expressed as an absolute-screen IntCoordinates pair.
isDragging¶
var isDragging: Boolean
isFocused¶
isPauseScreen¶
open override val isPauseScreen: Boolean
layerManager¶
lateinit override var layerManager: LayerStackManager
The layer stack owned by this host.
menu¶
minecraft¶
open val minecraft: Minecraft?
narrationMessage¶
open val narrationMessage: Component?
rectangle¶
open val rectangle: ScreenRectangle?
renderables¶
val renderables: List<Renderable?>?
slotUnderMouse¶
@get:
Nullable
open override val slotUnderMouse: @Nullable
Slot?
tabOrderGroup¶
open val tabOrderGroup: Int
title¶
open val title: Component?
titleLabelPos¶
titleLabelX/titleLabelY expressed as an absolute-screen IntCoordinates pair.
width¶
xSize¶
ySize¶
Functions¶
added¶
open override fun added()
Restarts the Compose runtime with contentFn if a prior removed disposed it - vanilla's Minecraft.setScreen() calls removed on this screen for any swap-away, including one a caller intends to reverse later by handing this exact instance back to setScreen() again (a recipe viewer's "view recipe" navigation, say), not just a genuine close. Without this, such a screen never renders its Compose content again once reactivated - only vanilla's own slot/title rendering (untouched by any of this) keeps working, which is what actually surfaces the bug: the screen looks blank apart from its slots after returning from a recipe lookup.
added rather than the no-arg init() hook - Screen.init(Minecraft, int, int) only calls that hook down a much more conditional path (gated by vanilla's own initialized flag and, on NeoForge, a cancellable ScreenEvent.Init.Pre), so it doesn't reliably fire on every reactivation. Minecraft.setScreen() calls added unconditionally on every activation, fresh construction and reactivation alike - confirmed against the decompiled source, not assumed. A no-op on the very first added (right after construction), since composeDisposed starts false until a real removed call has actually happened.
afterKeyboardAction¶
open fun afterKeyboardAction()
afterMouseAction¶
open fun afterMouseAction()
afterMouseMove¶
open fun afterMouseMove()
charTyped¶
children¶
clearDraggingState¶
open fun clearDraggingState()
clearFocus¶
open fun clearFocus()
defersScreenOverlays¶
open override fun defersScreenOverlays(): Boolean
Only once something is actually drawn over the slot loop. With no layer open there is nothing for the highlight or the carried stack to end up behind, so vanilla's own inline draw is left exactly as it is - this costs a plain screen nothing and can regress nothing.
getChildAt¶
open fun getChildAt(mouseX: Double, mouseY: Double): Optional<GuiEventListener?>?
getMenu¶
getSlotColor¶
open fun getSlotColor(index: Int): Int
handleComponentClicked¶
open fun handleComponentClicked(@Nullable
style: Style?): Boolean
handleDelayedNarration¶
open fun handleDelayedNarration()
init¶
isComposeIdle¶
open override fun isComposeIdle(): Boolean
true when there is no snapshot-write notification, frame request, or recompose job pending.
isMouseOver¶
open fun isMouseOver(mouseX: Double, mouseY: Double): Boolean
keyPressed¶
open override fun keyPressed(
keyCode: Int,
scanCode: Int,
modifiers: Int
): Boolean
keyReleased¶
open override fun keyReleased(
keyCode: Int,
scanCode: Int,
modifiers: Int
): Boolean
mouseClicked¶
open override fun mouseClicked(
mouseX: Double,
mouseY: Double,
button: Int
): Boolean
mouseDragged¶
mouseMoved¶
open override fun mouseMoved(mouseX: Double, mouseY: Double)
mouseReleased¶
open override fun mouseReleased(
mouseX: Double,
mouseY: Double,
button: Int
): Boolean
mouseScrolled¶
nextFocusPath¶
@Nullable
open fun nextFocusPath(event: FocusNavigationEvent?): ComponentPath?
onClose¶
open override fun onClose()
onFilesDrop¶
open fun onFilesDrop(packs: List<Path?>?)
removed¶
open override fun removed()
removeWidget¶
open fun removeWidget(listener: GuiEventListener?)
render¶
renderBackground¶
open fun renderBackground(
guiGraphics: GuiGraphics?,
mouseX: Int,
mouseY: Int,
partialTick: Float
)
renderNodes¶
open fun renderNodes(
baseLayer: Boolean,
guiGraphics: GuiGraphics,
mouseX: Int,
mouseY: Int,
partialTick: Float
)
Measures and renders all active layers.
In async mode the previous recompose job is joined before rendering, then a new job is launched if there are pending frame waiters.
renderTransparentBackground¶
open fun renderTransparentBackground(guiGraphics: GuiGraphics?)
renderWithTooltip¶
fun renderWithTooltip(
guiGraphics: GuiGraphics?,
mouseX: Int,
mouseY: Int,
partialTick: Float
)
resize¶
setTooltipForNextRenderPass¶
open fun setTooltipForNextRenderPass(tooltip: List<FormattedCharSequence?>?)
open fun setTooltipForNextRenderPass(tooltip: Component?)
open fun setTooltipForNextRenderPass(
tooltip: List<FormattedCharSequence?>?,
positioner: ClientTooltipPositioner?,
override: Boolean
)
open fun setTooltipForNextRenderPass(
tooltip: Tooltip?,
positioner: ClientTooltipPositioner?,
override: Boolean
)
shouldCloseOnEsc¶
open fun shouldCloseOnEsc(): Boolean
slotHighlightClipRect¶
open override fun slotHighlightClipRect(x: Int, y: Int): IntRect?
Called by net.kernelpanicsoft.archie.mixin.client.gui.AbstractContainerScreenMixin (via net.kernelpanicsoft.archie.gui.access.SlotHighlightClipProvider) to clip the hover-highlight overlay the same way renderSlot clips the item icon - vanilla only exposes a static renderSlotHighlight(GuiGraphics, x, y, blitOffset) with no per-slot override point, so this has to be reached from a mixin redirect instead of override.
slotRenderLayerOffset¶
open override fun slotRenderLayerOffset(slot: Slot): Float?
tick¶
fun tick()
triggerImmediateNarration¶
open fun triggerImmediateNarration(onlyNarrateNew: Boolean)
updateNarratorStatus¶
open fun updateNarratorStatus(narratorEnabled: Boolean)