Skip to content

net.kernelpanicsoft.archie.gui.composables.containers

Types

ConnectorAnimation

How NodeTreeView animates the connector between a node and its parent over time. Layered on top of ConnectorStyle, except ConnectorStyle.DISCONNECTED, which ignores this.

ConnectorDirection

Which end of a connector ConnectorStyle.ARROW's arrowhead points into. Purely cosmetic; doesn't affect layout.

ConnectorShape

How NodeTreeView routes/renders a connector's own path shape. Orthogonal to ConnectorStyle/ConnectorAnimation.

ConnectorStyle

How NodeTreeView draws the connector between a node and its parent.

NodeAnimation

How NodeTreeView animates a node's own rendered box over time, independent of any connector. Tints the node's content directly.

NodeBuilder

abstract class NodeBuilder<K : Any, V, Self : NodeBuilder<K, V, Self>>(val id: K)

A node's own payload builder for tree - subclass for a concrete V; only build is abstract. Self is the concrete subclass itself, so every node(id) { ... } block's receiver exposes that subclass's own fields rather than just this base class's.

PannableCanvasState

@Stable



class PannableCanvasState

Mutable pan/zoom state for a PannableCanvas - create via rememberPannableCanvasState to survive recomposition.

RootAlignment

Which side of the drawn forest every tree's own root sits on.

ScrollableState

@Stable



class ScrollableState

Mutable state holder for a Scrollable composable.

ScrollDirection

The axis along which a Scrollable container scrolls its content.

TabContainerDsl

@DslMarker
annotation class TabContainerDsl

Restricts the TabContainerScope.tab DSL to its own receiver scope.

TabContainerScope

Receiver scope for the TabContainer/TabPanel DSL builder lambda.

TabContainerState

@Stable



class TabContainerState

Tracks which tab id is selected in a TabContainer. Create via rememberTabContainerState.

TabIcon

data class TabIcon(
    val texture: ResourceLocation, 
    val uOffset: Float = 0.0f, 
    val vOffset: Float = 0.0f, 
    val regionWidth: Int = 28, 
    val regionHeight: Int = 32, 
    val textureWidth: Int = 256, 
    val textureHeight: Int = 256, 
    val displayWidth: Int = regionWidth, 
    val displayHeight: Int = regionHeight
)

Sprite descriptor used for optional tab icons.

TableColumn

data class TableColumn(
    val header: Component? = null, 
    val alignment: Alignment.Horizontal = Alignment.Start, 
    val width: Int? = null
)

One column of a Table.

TableDsl

@DslMarker
annotation class TableDsl

Restricts the TableScope.row DSL to its own receiver scope.

TableScope

class TableScope

Receiver scope for Table's content lambda.

TabSpec

data class TabSpec(
    val id: String, 
    val title: Component, 
    val icon: TabIcon? = null, 
    val enabled: Boolean = true, 
    val content: @Composable



 () -> Unit
)

Data describing a single Create World style tab.

TabTextures

object TabTextures

Built-in themed texture keys for Tab/TabContainer, matching vanilla tab styles.

TreeDsl

@DslMarker
annotation class TreeDsl

Scopes every TreeNode/NodeBuilder/TreeScope receiver below to its own nesting.

TreeNode

class TreeNode<K : Any, V>

One node built by tree. data is the caller's own arbitrary payload. children/parents hold other TreeNodes directly (not ids) - use TreeRegistry.get to look one up by id later. data/children/parents are genuine Compose state, so mutating any of them after tree returns recomposes NodeTreeView automatically.

TreeRegistry

class TreeRegistry<K : Any, V, B : NodeBuilder<K, V, B>>

tree's own return value - every TreeNode it declared, addressable by TreeNode.id via get, reachable structurally from roots. Backed by Compose state throughout.

TreeScope

class TreeScope<K : Any, V, B : NodeBuilder<K, V, B>>

The receiver tree's own builder block runs with, one per nesting level. node is its only member.

Properties

PLAYER_INVENTORY_GAP

const val PLAYER_INVENTORY_GAP: Int = 14

The gap between a container's own contents and the player inventory below them, in pixels - measured off the vanilla GUI textures, so a screen built out of these composables lines up with one drawn the old way.

Functions

Collapsible

@Composable



fun Collapsible(
    title: Component, 
    modifier: Modifier = Modifier, 
    initiallyExpanded: Boolean = false, 
    onToggled: (isExpanded: Boolean) -> Unit = {}, 
    content: @Composable



 () -> Unit
)

A container that can be expanded or collapsed by clicking its header.

ContainerPanel

@Composable



fun ContainerPanel(
    contentWidth: Int = DEFAULT_CONTENT_WIDTH, 
    modifier: Modifier = Modifier, 
    content: @Composable



 () -> Unit
)

A complete container screen layout following the vanilla chest-screen pattern.

loadTree

inline fun <K : Any, V, B : NodeBuilder<K, V, B>> loadTree(tag: CompoundTag, noinline factory: (K) -> B): TreeRegistry<K, V, B>

Reified convenience over loadTree resolving K/V's own serializers via SerializationManager.module.

fun <K : Any, V, B : NodeBuilder<K, V, B>> loadTree(
    tag: CompoundTag, 
    factory: (K) -> B, 
    keySerializer: KSerializer<K>, 
    dataSerializer: KSerializer<V>
): TreeRegistry<K, V, B>

Rebuilds a TreeRegistry from a CompoundTag produced, wiring nodes back into the same TreeNode.children/TreeNode.parents/TreeRegistry.roots shape. factory is never invoked during loading itself - only kept so the registry can keep growing afterward.

NodeFrame

@Composable



fun NodeFrame(
    modifier: Modifier = Modifier, 
    variant: String = ThemeVariants.DEFAULT, 
    obtained: Boolean = false, 
    contentAlignment: Alignment = Alignment.Center, 
    contentPadding: Int = 8, 
    onClick: (UINode) -> Unit? = null, 
    content: @Composable



 () -> Unit
)

A themed, shaped frame for one NodeTreeView node's own content - the vanilla advancements screen's "normal"/"goal"/"challenge" icon frames (square, rounded, spiky) are exactly this same idea: one differently-bordered box per node kind, chosen by variant rather than by any Kotlin-side shape logic, the same "the theme decides the art, the composable decides the structure" split every other themed container in this package (Panel, Surface) already follows - a theme not declaring a node_frame texture at all just falls back to Surface's own default sprite behavior.

NodeTreeView

@Composable



fun <K : Any, V, B : NodeBuilder<K, V, B>> NodeTreeView(
    roots: TreeRegistry<K, V, B>, 
    modifier: Modifier = Modifier, 
    columnGap: Int = 26, 
    rowGap: Int = 6, 
    connectorStyle: (TreeNode<K, V>) -> ConnectorStyle = { ConnectorStyle.SOLID }, 
    connectorColor: (TreeNode<K, V>) -> Int = { 0xFF808080.toInt() }, 
    connectorThickness: (TreeNode<K, V>) -> Int = { 1 }, 
    connectorAnimation: (TreeNode<K, V>) -> ConnectorAnimation = { ConnectorAnimation.NONE }, 
    connectorShape: (TreeNode<K, V>) -> ConnectorShape = { ConnectorShape.ELBOW }, 
    connectorDirection: (TreeNode<K, V>) -> ConnectorDirection = { ConnectorDirection.CHILD_TO_PARENT }, 
    nodeAnimation: (TreeNode<K, V>) -> NodeAnimation = { NodeAnimation.NONE }, 
    rootAlignment: RootAlignment = RootAlignment.START, 
    visible: (TreeNode<K, V>) -> Boolean = { true }, 
    onVisibilityChanged: (TreeNode<K, V>, Boolean) -> Unit = { _, _ -> }, 
    state: PannableCanvasState = rememberPannableCanvasState(), 
    backgroundTexture: ResourceLocation? = null, 
    backgroundTextureSize: Int = 32, 
    backgroundTint: Int = -1, 
    backgroundParallax: Float = 1.0f, 
    panelTexture: String = "surface", 
    panelVariant: String? = "inset_transparent", 
    panelContentPadding: Int = 5, 
    content: @Composable



 (TreeNode<K, V>) -> Unit
)

NodeTreeView's general-purpose List<T>/children:/parents:/key: surface, specialized for a forest already built as a TreeRegistry. Every structural parameter reads TreeNode.children/ TreeNode.parents/TreeNode.id directly; a caller only supplies cosmetic per-node callbacks and content. dedupe is always on, since a TreeNode's own id already identifies it.

@Composable



fun <T> NodeTreeView(
    roots: List<T>, 
    children: (T) -> List<T>, 
    parents: (T) -> List<T>? = null, 
    modifier: Modifier = Modifier, 
    columnGap: Int = DEFAULT_COLUMN_GAP, 
    rowGap: Int = DEFAULT_ROW_GAP, 
    connectorStyle: (T) -> ConnectorStyle = { ConnectorStyle.SOLID }, 
    connectorColor: (T) -> Int = { DEFAULT_LINE_COLOR }, 
    connectorThickness: (T) -> Int = { DEFAULT_LINE_THICKNESS }, 
    connectorAnimation: (T) -> ConnectorAnimation = { ConnectorAnimation.NONE }, 
    connectorShape: (T) -> ConnectorShape = { ConnectorShape.ELBOW }, 
    connectorDirection: (T) -> ConnectorDirection = { ConnectorDirection.CHILD_TO_PARENT }, 
    nodeAnimation: (T) -> NodeAnimation = { NodeAnimation.NONE }, 
    rootAlignment: RootAlignment = RootAlignment.START, 
    dedupe: Boolean = false, 
    showNodeHints: Boolean = true, 
    key: (T) -> Any? = { it }, 
    visible: (T) -> Boolean = { true }, 
    onVisibilityChanged: (T, Boolean) -> Unit = { _, _ -> }, 
    state: PannableCanvasState = rememberPannableCanvasState(), 
    backgroundTexture: ResourceLocation? = null, 
    backgroundTextureSize: Int = 32, 
    backgroundTint: Int = -1, 
    backgroundParallax: Float = 1.0f, 
    panelTexture: String = "surface", 
    panelVariant: String? = "inset_transparent", 
    panelContentPadding: Int = 2, 
    content: @Composable



 (T) -> Unit
)

A pannable, zoomable, node-based forest view - one or more independent trees (roots, plural), one column per depth, tidily packed rows connected by elbow connectors (see assignRows). children extracts a node's own children; content draws one node's own visual content at its measured natural size. Connectors draw (and, for ConnectorStyle.ARROW/ ConnectorAnimation.FLOWING, animate) child-to-parent by default - see connectorDirection to flip that - and route around, never behind, whatever else sits between their two ends (see pointsFor). Draws a genuine tree by default (a node reachable through more than one parent is drawn once per parent); pass dedupe = true (with key) to collapse repeats into one visual node with multiple incoming connectors instead.

Panel

@Composable



fun Panel(
    modifier: Modifier = Modifier, 
    contentAlignment: Alignment = Alignment.TopStart, 
    contentWidth: Int? = null, 
    texture: String = "surface", 
    variant: String = ThemeVariants.DEFAULT, 
    stateName: String = TextureStates.DEFAULT, 
    contentPadding: Int = 8, 
    drawOverContent: Boolean = false, 
    content: @Composable



 () -> Unit
)

A padded themed Surface used as a general-purpose container for grouped UI content.

PannableCanvas

@Composable



fun PannableCanvas(
    modifier: Modifier = Modifier, 
    state: PannableCanvasState = rememberPannableCanvasState(), 
    backgroundTexture: ResourceLocation? = null, 
    backgroundTextureSize: Int = 32, 
    backgroundTint: Int = -1, 
    backgroundParallax: Float = 1.0f, 
    panelTexture: String = "surface", 
    panelVariant: String? = "inset_transparent", 
    panelContentPadding: Int = 2, 
    content: @Composable



 () -> Unit
)

A fixed-size viewport (modifier's own size) over a single, arbitrarily large child, panned by click-dragging anywhere inside it - the same "pan around a graph" interaction the vanilla advancements screen (and Thaumcraft's Thaumonomicon, and quest-book mods generally) uses, built on the same Layout/Renderer primitives Scrollable is, minus the scrollbar/lerp animation (NodeTreeView's node graph pans 1:1 with the drag, not eased). Content outside the viewport is clipped via a scissor, matching how Scrollable hides its own overflowed content.

rememberPannableCanvasState

rememberScrollableState

Creates and remembers a ScrollableState for use with Scrollable.

rememberTabContainerState

@Composable



fun rememberTabContainerState(tabs: List<TabSpec>, initialSelectedId: String? = tabs.firstOrNull { it.enabled }?.id): TabContainerState

Creates and remembers a TabContainerState, initially selecting initialSelectedId.

rememberTree

@Composable



fun <K : Any, V, B : NodeBuilder<K, V, B>> rememberTree(factory: (K) -> B, block: TreeScope<K, V, B>.() -> Unit): TreeRegistry<K, V, B>

Shorthand for remember { tree(factory, block) } - builds block's own forest once per composable lifetime.

RootContainer

@Composable



fun RootContainer(modifier: Modifier = Modifier, content: @Composable



 () -> Unit)

The top-level layout node for a screen's content, centered within the full screen bounds.

Scrollable

@Composable



fun Scrollable(
    direction: ScrollDirection = ScrollDirection.VERTICAL, 
    scrollbarColor: KColor = KColor.DARK_GRAY, 
    modifier: Modifier = Modifier, 
    state: ScrollableState = rememberScrollableState(), 
    content: @Composable



 () -> Unit
)

A container that allows its single child to be scrolled when the child's content exceeds the container's bounds.

Surface

@Composable



fun Surface(
    contentAlignment: Alignment = Alignment.TopStart, 
    modifier: Modifier = Modifier, 
    texture: String = "surface", 
    variant: String = ThemeVariants.DEFAULT, 
    stateName: String = TextureStates.DEFAULT, 
    drawOverContent: Boolean = false, 
    content: @Composable



 () -> Unit
)

A net.kernelpanicsoft.archie.gui.layout.Box-like layout node that paints a themed background texture behind its children.

Tab

@Composable



fun Tab(
    spec: TabSpec, 
    selected: Boolean, 
    modifier: Modifier = Modifier, 
    elevateSelected: Boolean = false, 
    enabled: Boolean = spec.enabled, 
    texture: String = TabTextures.GAME, 
    variant: String = ThemeVariants.DEFAULT, 
    iconSpacing: Int = DEFAULT_ICON_SPACING, 
    onClick: (TabSpec) -> Unit
)

A single clickable tab button, rendering spec's icon/title and switching its themed texture state based on selected/hover/press. Used internally by TabContainer; use that (or the DSL/TabPanel variants) rather than calling this directly in most cases.

TabContainer

@Composable



fun TabContainer(
    tabs: List<TabSpec>, 
    state: TabContainerState = rememberTabContainerState(tabs), 
    modifier: Modifier = Modifier, 
    onTabSelected: (TabSpec) -> Unit = {}, 
    tabSpacing: Int = 2, 
    scrollable: Boolean = true, 
    scrollState: ScrollableState? = null, 
    contentSpacing: Int = DEFAULT_CONTENT_SPACING, 
    elevateSelected: Boolean = false, 
    tabTexture: String = TabTextures.GAME
)

Declarative tab bar modeled after the vanilla Create World screen tabs.

@Composable



fun TabContainer(
    modifier: Modifier = Modifier, 
    state: TabContainerState? = null, 
    onTabSelected: (TabSpec) -> Unit = {}, 
    tabSpacing: Int = 2, 
    scrollable: Boolean = true, 
    scrollState: ScrollableState? = null, 
    contentSpacing: Int = DEFAULT_CONTENT_SPACING, 
    contentWrapper: @Composable



 (@Composable



 () -> Unit) -> Unit? = null, 
    tabTexture: String = TabTextures.GAME, 
    builder: TabContainerScope.() -> Unit
)

DSL overload allowing tabs to be declared inline via TabContainerScope.tab without manually building a TabSpec list.

TabContainerPanel

@Composable



fun TabContainerPanel(
    contentWidth: Int = DEFAULT_CONTENT_WIDTH, 
    modifier: Modifier = Modifier, 
    builder: TabContainerScope.() -> Unit
)

A ContainerPanel whose contents are switched between tabs, following the same container/player-inventory layout as ContainerPanel.

Table

@Composable



fun Table(
    columns: List<TableColumn>, 
    modifier: Modifier = Modifier, 
    columnSpacing: Int = DEFAULT_COLUMN_SPACING, 
    rowSpacing: Int = DEFAULT_ROW_SPACING, 
    content: TableScope.() -> Unit
)

A grid whose columns size themselves to their widest cell, so entries line up down the page.

TabPanel

@Composable



fun TabPanel(
    modifier: Modifier = Modifier, 
    state: TabContainerState? = null, 
    onTabSelected: (TabSpec) -> Unit = {}, 
    tabSpacing: Int = 2, 
    scrollable: Boolean = true, 
    scrollState: ScrollableState? = null, 
    contentWrapper: @Composable



 (@Composable



 () -> Unit) -> Unit? = null, 
    builder: TabContainerScope.() -> Unit
)

A TabContainer whose selected tab content is wrapped in a Panel by default, elevated (drawn above neighboring tabs) when selected. Used by TabContainerPanel.

Tinted

@Composable



fun Tinted(
    tint: () -> Int, 
    modifier: Modifier = Modifier, 
    content: @Composable



 () -> Unit
)

Tints content's own entire rendered subtree - background sprites, text, everything it draws, not merely something drawn over top of it - by tint (a packed ARGB int; -1/0xFFFFFFFF is fully opaque white, i.e. no tint at all), via RenderSystem.setShaderColor. This is what makes every themed composable's own net.kernelpanicsoft.archie.gui.util.extension.drawThemeState call automatically tint-aware (it reads back whatever RenderSystem.getShaderColor currently has active) without each one needing to know or care that fading/greying is even happening - the same reason vanilla's own hurt-flash/fade-to-black effects use this exact mechanism rather than drawing an overlay quad, which could only ever dim/tint what's underneath, never genuinely desaturate or fade something translucent-looking in and out.

tree

fun <K : Any, V, B : NodeBuilder<K, V, B>> tree(factory: (K) -> B, block: TreeScope<K, V, B>.() -> Unit): TreeRegistry<K, V, B>

Builds a forest of TreeNodes as a TreeRegistry. A top-level TreeScope.node call declares one of TreeRegistry.roots; NodeBuilder.children nests further nodes; NodeBuilder.dependsOn wires an extra prerequisite. factory supplies a fresh B per TreeScope.node call.